Javascript console commands (#572)

* Allow the execution of JS from the terminal when hosting a local game or playing a single game

Signed-off-by: William Claude <w.claude@thebeat.co>

* Reorganise imports on edited files

Signed-off-by: William Claude <w.claude@thebeat.co>

* Remove Reset

Signed-off-by: William Claude <w.claude@thebeat.co>
This commit is contained in:
William 2020-07-11 17:24:04 +02:00 committed by GitHub
parent c66a3d5e7a
commit d85e2bdd51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 133 additions and 84 deletions

View File

@ -48,6 +48,7 @@ type App struct {
gitBranch string
gitCommit string
terminal d2interface.Terminal
scriptEngine *d2script.ScriptEngine
audio d2interface.AudioProvider
renderer d2interface.Renderer
tAllocSamples *ring.Ring
@ -69,12 +70,14 @@ const (
// Create creates a new instance of the application
func Create(gitBranch, gitCommit string,
terminal d2interface.Terminal,
scriptEngine *d2script.ScriptEngine,
audio d2interface.AudioProvider,
renderer d2interface.Renderer) *App {
result := &App{
gitBranch: gitBranch,
gitCommit: gitCommit,
terminal: terminal,
scriptEngine: scriptEngine,
audio: audio,
renderer: renderer,
tAllocSamples: createZeroedRing(nSamplesTAlloc),
@ -105,7 +108,7 @@ func (p *App) Run() error {
return err
}
d2screen.SetNextScreen(d2gamescreen.CreateMainMenu(p.renderer, p.audio, p.terminal))
d2screen.SetNextScreen(d2gamescreen.CreateMainMenu(p.renderer, p.audio, p.terminal, p.scriptEngine))
if p.gitBranch == "" {
p.gitBranch = "Local Build"
@ -142,6 +145,7 @@ func (p *App) initialize() error {
{"timescale", "set scalar for elapsed time", p.setTimeScale},
{"quit", "exits the game", p.quitGame},
{"screen-gui", "enters the gui playground screen", p.enterGuiPlayground},
{"js", "eval JS scripts", p.evalJS},
}
for idx := range terminalActions {
@ -174,8 +178,6 @@ func (p *App) initialize() error {
d2ui.Initialize(p.audio)
d2script.CreateScriptEngine()
return nil
}
@ -470,6 +472,16 @@ func (p *App) dumpHeap() {
}
}
func (p *App) evalJS(code string) {
val, err := p.scriptEngine.Eval(code)
if err != nil {
p.terminal.OutputErrorf("%s", err)
return
}
p.terminal.OutputInfof("%s", val)
}
func (p *App) toggleFullScreen() {
fullscreen := !p.renderer.IsFullScreen()
p.renderer.SetFullScreen(fullscreen)

View File

@ -3,7 +3,6 @@ package d2term
import (
"errors"
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"image/color"
"log"
"math"
@ -13,8 +12,8 @@ import (
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
)
// TermCategory applies styles to the lines in the Terminal

View File

@ -2,17 +2,16 @@ package d2gamescreen
import (
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"image/color"
"math"
"os"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
@ -20,6 +19,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
// CharacterSelect represents the character select screen
@ -48,6 +48,7 @@ type CharacterSelect struct {
connectionHost string
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
scriptEngine *d2script.ScriptEngine
renderer d2interface.Renderer
}
@ -56,7 +57,7 @@ func CreateCharacterSelect(
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
connectionType d2clientconnectiontype.ClientConnectionType,
connectionHost string, term d2interface.Terminal,
connectionHost string, term d2interface.Terminal, scriptEngine *d2script.ScriptEngine,
) *CharacterSelect {
return &CharacterSelect{
selectedCharacter: -1,
@ -65,6 +66,7 @@ func CreateCharacterSelect(
connectionHost: connectionHost,
audioProvider: audioProvider,
terminal: term,
scriptEngine: scriptEngine,
}
}
@ -211,11 +213,12 @@ func (v *CharacterSelect) updateCharacterBoxes() {
}
func (v *CharacterSelect) onNewCharButtonClicked() {
d2screen.SetNextScreen(CreateSelectHeroClass(v.renderer, v.audioProvider, v.connectionType, v.connectionHost, v.terminal))
d2screen.SetNextScreen(CreateSelectHeroClass(v.renderer, v.audioProvider, v.connectionType, v.connectionHost,
v.terminal, v.scriptEngine))
}
func (v *CharacterSelect) onExitButtonClicked() {
mainMenu := CreateMainMenu(v.renderer, v.audioProvider, v.terminal)
mainMenu := CreateMainMenu(v.renderer, v.audioProvider, v.terminal, v.scriptEngine)
mainMenu.setScreenMode(screenModeMainMenu)
d2screen.SetNextScreen(mainMenu)
}
@ -361,7 +364,7 @@ func (v *CharacterSelect) refreshGameStates() {
}
func (v *CharacterSelect) onOkButtonClicked() {
gameClient, _ := d2client.Create(v.connectionType)
gameClient, _ := d2client.Create(v.connectionType, v.scriptEngine)
host := ""
if v.connectionType == d2clientconnectiontype.LANClient {
@ -373,5 +376,5 @@ func (v *CharacterSelect) onOkButtonClicked() {
fmt.Printf("can not connect to the host: %s", host)
}
d2screen.SetNextScreen(CreateGame(v.renderer, v.audioProvider, gameClient, v.terminal))
d2screen.SetNextScreen(CreateGame(v.renderer, v.audioProvider, gameClient, v.terminal, v.scriptEngine))
}

View File

@ -9,14 +9,13 @@ import (
"path"
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"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/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
type labelItem struct {
@ -37,10 +36,11 @@ type Credits struct {
renderer d2interface.Renderer
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
scriptEngine *d2script.ScriptEngine
}
// CreateCredits creates an instance of the credits screen
func CreateCredits(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider) *Credits {
func CreateCredits(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, scriptEngine *d2script.ScriptEngine) *Credits {
result := &Credits{
labels: make([]*labelItem, 0),
cycleTime: 0,
@ -48,6 +48,7 @@ func CreateCredits(renderer d2interface.Renderer, audioProvider d2interface.Audi
cyclesTillNextLine: 0,
renderer: renderer,
audioProvider: audioProvider,
scriptEngine: scriptEngine,
}
return result
@ -159,7 +160,7 @@ func (v *Credits) Advance(tickTime float64) error {
}
func (v *Credits) onExitButtonClicked() {
mainMenu := CreateMainMenu(v.renderer, v.audioProvider, v.terminal)
mainMenu := CreateMainMenu(v.renderer, v.audioProvider, v.terminal, v.scriptEngine)
mainMenu.setScreenMode(screenModeMainMenu)
d2screen.SetNextScreen(mainMenu)
}

View File

@ -2,13 +2,13 @@ package d2gamescreen
import (
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
// TODO: fix pentagram
@ -71,6 +71,7 @@ type EscapeMenu struct {
renderer d2interface.Renderer
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
scriptEngine *d2script.ScriptEngine
}
type layout struct {
@ -124,11 +125,13 @@ type actionableElement interface {
}
// NewEscapeMenu creates a new escape menu
func NewEscapeMenu(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, term d2interface.Terminal) *EscapeMenu {
func NewEscapeMenu(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, term d2interface.Terminal,
scriptEngine *d2script.ScriptEngine) *EscapeMenu {
m := &EscapeMenu{
audioProvider: audioProvider,
terminal: term,
renderer: renderer,
scriptEngine: scriptEngine,
}
m.layouts = []*layout{
@ -368,7 +371,7 @@ func (m *EscapeMenu) showLayout(id layoutID) {
}
if id == saveLayoutID {
mainMenu := CreateMainMenu(m.renderer, m.audioProvider, m.terminal)
mainMenu := CreateMainMenu(m.renderer, m.audioProvider, m.terminal, m.scriptEngine)
mainMenu.setScreenMode(screenModeMainMenu)
d2screen.SetNextScreen(mainMenu)

View File

@ -1,23 +1,21 @@
package d2gamescreen
import (
"fmt"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
const hideZoneTextAfterSeconds = 2.0
@ -39,7 +37,7 @@ type Game struct {
// CreateGame creates the Gameplay screen and returns a pointer to it
func CreateGame(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, gameClient *d2client.GameClient,
term d2interface.Terminal) *Game {
term d2interface.Terminal, scriptEngine *d2script.ScriptEngine) *Game {
result := &Game{
gameClient: gameClient,
gameControls: nil,
@ -47,7 +45,7 @@ func CreateGame(renderer d2interface.Renderer, audioProvider d2interface.AudioPr
lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(renderer, gameClient.MapEngine, term),
escapeMenu: NewEscapeMenu(renderer, audioProvider, term),
escapeMenu: NewEscapeMenu(renderer, audioProvider, term, scriptEngine),
audioProvider: audioProvider,
renderer: renderer,
terminal: term,

View File

@ -3,28 +3,24 @@ package d2gamescreen
import (
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"image/color"
"log"
"os"
"os/exec"
"runtime"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
type mainMenuScreenMode int
@ -75,16 +71,19 @@ type MainMenu struct {
renderer d2interface.Renderer
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
scriptEngine *d2script.ScriptEngine
}
// CreateMainMenu creates an instance of MainMenu
func CreateMainMenu(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, term d2interface.Terminal) *MainMenu {
func CreateMainMenu(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, term d2interface.Terminal,
scriptEngine *d2script.ScriptEngine) *MainMenu {
return &MainMenu{
screenMode: screenModeUnknown,
leftButtonHeld: true,
renderer: renderer,
audioProvider: audioProvider,
terminal: term,
scriptEngine: scriptEngine,
}
}
@ -154,7 +153,7 @@ func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
loading.Progress(0.3)
v.copyrightLabel2 = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel2.Alignment =d2gui.HorizontalAlignCenter
v.copyrightLabel2.Alignment = d2gui.HorizontalAlignCenter
v.copyrightLabel2.SetText("All Rights Reserved.")
v.copyrightLabel2.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel2.SetPosition(400, 525)
@ -287,12 +286,12 @@ func (v *MainMenu) onSinglePlayerClicked() {
// Go here only if existing characters are available to select
if d2player.HasGameStates() {
d2screen.SetNextScreen(CreateCharacterSelect(v.renderer, v.audioProvider, d2clientconnectiontype.Local,
v.tcpJoinGameEntry.GetText(), v.terminal))
v.tcpJoinGameEntry.GetText(), v.terminal, v.scriptEngine))
return
}
d2screen.SetNextScreen(CreateSelectHeroClass(v.renderer, v.audioProvider,
d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText(), v.terminal))
d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText(), v.terminal, v.scriptEngine))
}
func (v *MainMenu) onGithubButtonClicked() {
@ -321,7 +320,7 @@ func (v *MainMenu) onExitButtonClicked() {
}
func (v *MainMenu) onCreditsButtonClicked() {
d2screen.SetNextScreen(CreateCredits(v.renderer, v.audioProvider))
d2screen.SetNextScreen(CreateCredits(v.renderer, v.audioProvider, v.scriptEngine))
}
// Render renders the main menu
@ -487,7 +486,7 @@ func (v *MainMenu) onTCPIPCancelClicked() {
func (v *MainMenu) onTCPIPHostGameClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.renderer, v.audioProvider,
d2clientconnectiontype.LANServer, "", v.terminal))
d2clientconnectiontype.LANServer, "", v.terminal, v.scriptEngine))
}
func (v *MainMenu) onTCPIPJoinGameClicked() {
@ -500,5 +499,5 @@ func (v *MainMenu) onBtnTCPIPCancelClicked() {
func (v *MainMenu) onBtnTCPIPOkClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.renderer, v.audioProvider,
d2clientconnectiontype.LANClient, v.tcpJoinGameEntry.GetText(), v.terminal))
d2clientconnectiontype.LANClient, v.tcpJoinGameEntry.GetText(), v.terminal, v.scriptEngine))
}

View File

@ -2,25 +2,22 @@ package d2gamescreen
import (
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"image"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
type heroRenderConfig struct {
@ -187,6 +184,7 @@ type SelectHeroClass struct {
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
renderer d2interface.Renderer
scriptEngine *d2script.ScriptEngine
}
// CreateSelectHeroClass creates an instance of a SelectHeroClass
@ -196,6 +194,7 @@ func CreateSelectHeroClass(
connectionType d2clientconnectiontype.ClientConnectionType,
connectionHost string,
terminal d2interface.Terminal,
scriptEngine *d2script.ScriptEngine,
) *SelectHeroClass {
result := &SelectHeroClass{
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
@ -205,6 +204,7 @@ func CreateSelectHeroClass(
audioProvider: audioProvider,
terminal: terminal,
renderer: renderer,
scriptEngine: scriptEngine,
}
return result
@ -341,7 +341,7 @@ func (v *SelectHeroClass) OnUnload() error {
func (v *SelectHeroClass) onExitButtonClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.renderer, v.audioProvider, v.connectionType,
v.connectionHost, v.terminal))
v.connectionHost, v.terminal, v.scriptEngine))
}
func (v *SelectHeroClass) onOkButtonClicked() {
@ -351,13 +351,13 @@ func (v *SelectHeroClass) onOkButtonClicked() {
d2datadict.CharStats[v.selectedHero],
v.hardcoreCheckbox.GetCheckState(),
)
gameClient, _ := d2client.Create(d2clientconnectiontype.Local)
gameClient, _ := d2client.Create(d2clientconnectiontype.Local, v.scriptEngine)
if err := gameClient.Open(v.connectionHost, gameState.FilePath); err != nil {
fmt.Printf("can not connect to the host: %s\n", v.connectionHost)
}
d2screen.SetNextScreen(CreateGame(v.renderer, v.audioProvider, gameClient, v.terminal))
d2screen.SetNextScreen(CreateGame(v.renderer, v.audioProvider, gameClient, v.terminal, v.scriptEngine))
}
// Render renders the Select Hero Class screen

View File

@ -7,19 +7,17 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2localclient"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2remoteclient"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
// GameClient manages a connection to d2server.GameServer
@ -27,20 +25,22 @@ import (
type GameClient struct {
clientConnection ServerConnection // Abstract local/remote connection
connectionType d2clientconnectiontype.ClientConnectionType // Type of connection (local or remote)
GameState *d2player.PlayerState // local player state
MapEngine *d2mapengine.MapEngine // Map and entities
PlayerId string // ID of the local player
Players map[string]*d2mapentity.Player // IDs of the other players
Seed int64 // Map seed
RegenMap bool // Regenerate tile cache on render (map has changed)
scriptEngine *d2script.ScriptEngine
GameState *d2player.PlayerState // local player state
MapEngine *d2mapengine.MapEngine // Map and entities
PlayerId string // ID of the local player
Players map[string]*d2mapentity.Player // IDs of the other players
Seed int64 // Map seed
RegenMap bool // Regenerate tile cache on render (map has changed)
}
// Create constructs a new GameClient and returns a pointer to it.
func Create(connectionType d2clientconnectiontype.ClientConnectionType) (*GameClient, error) {
func Create(connectionType d2clientconnectiontype.ClientConnectionType, scriptEngine *d2script.ScriptEngine) (*GameClient, error) {
result := &GameClient{
MapEngine: d2mapengine.CreateMapEngine(), // TODO: Mapgen - Needs levels.txt stuff
Players: make(map[string]*d2mapentity.Player),
connectionType: connectionType,
scriptEngine: scriptEngine,
}
switch connectionType {
@ -61,18 +61,26 @@ func Create(connectionType d2clientconnectiontype.ClientConnectionType) (*GameCl
// If the client is remote it sends a PlayerConnectionRequestPacket to the
// server (see d2netpacket).
func (g *GameClient) Open(connectionString string, saveFilePath string) error {
switch g.connectionType {
case d2clientconnectiontype.LANServer, d2clientconnectiontype.Local:
g.scriptEngine.AllowEval()
}
return g.clientConnection.Open(connectionString, saveFilePath)
}
// Close destroys the server if the client is local. For remote clients
// it sends a DisconnectRequestPacket (see d2netpacket).
func (g *GameClient) Close() error {
switch g.connectionType {
case d2clientconnectiontype.LANServer, d2clientconnectiontype.Local:
g.scriptEngine.DisallowEval()
}
return g.clientConnection.Close()
}
// Destroy does the same thing as Close.
func (g *GameClient) Destroy() error {
return g.clientConnection.Close()
return g.Close()
}
// OnPacketReceived is called by the ClientConection and processes incoming

View File

@ -1,6 +1,7 @@
package d2script
import (
"errors"
"fmt"
"io/ioutil"
"path/filepath"
@ -11,24 +12,34 @@ import (
// ScriptEngine allows running JavaScript scripts
type ScriptEngine struct {
vm *otto.Otto
vm *otto.Otto
isEvalAllowed bool
}
// CreateScriptEngine creates the script engine and returns a pointer to it.
func CreateScriptEngine() *ScriptEngine {
result := &ScriptEngine{
vm: otto.New(),
}
err := result.vm.Set("debugPrint", func(call otto.FunctionCall) otto.Value {
vm := otto.New()
err := vm.Set("debugPrint", func(call otto.FunctionCall) otto.Value {
fmt.Printf("Script: %s\n", call.Argument(0).String())
return otto.Value{}
})
if err != nil {
fmt.Printf("could not bind the 'debugPrint' to the given function in script engine")
}
return &ScriptEngine{
vm: vm,
isEvalAllowed: false,
}
}
return result
// AllowEval allows the evaluation of JS code.
func (s *ScriptEngine) AllowEval() {
s.isEvalAllowed = true
}
// AllowEval disallows the evaluation of JS code.
func (s *ScriptEngine) DisallowEval() {
s.isEvalAllowed = false
}
// ToValue converts the given interface{} value to a otto.Value
@ -60,3 +71,16 @@ func (s *ScriptEngine) RunScript(fileName string) (*otto.Value, error) {
return &val, nil
}
// Eval JS code.
func (s *ScriptEngine) Eval(code string) (string, error) {
if !s.isEvalAllowed {
return "", errors.New("disabled")
}
val, err := s.vm.Eval(code)
if err != nil {
return "", err
}
return val.String(), nil
}

View File

@ -9,6 +9,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
"github.com/OpenDiablo2/OpenDiablo2/d2script"
)
// GitBranch is set by the CI build process to the name of the branch
@ -40,12 +41,13 @@ func main() {
d2input.Create() // TODO d2input singleton must be init before d2term
term, err := d2term.Initialize()
if err != nil {
log.Fatal(err)
}
app := d2app.Create(GitBranch, GitCommit, term, audio, renderer)
scriptEngine := d2script.CreateScriptEngine()
app := d2app.Create(GitBranch, GitCommit, term, scriptEngine, audio, renderer)
if err := app.Run(); err != nil {
log.Fatal(err)
}