mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-12-24 19:18:12 -05:00
Added multiplayer support (#336)
This commit is contained in:
parent
16dc775be1
commit
2da08884c4
@ -26,8 +26,9 @@ type DS1 struct {
|
||||
|
||||
func LoadDS1(fileData []byte) (*DS1, error) {
|
||||
ds1 := &DS1{
|
||||
NumberOfFloors: 1,
|
||||
NumberOfWalls: 1,
|
||||
Act: 1,
|
||||
NumberOfFloors: 0,
|
||||
NumberOfWalls: 0,
|
||||
NumberOfShadowLayers: 1,
|
||||
NumberOfSubstitutionLayers: 0,
|
||||
}
|
||||
@ -61,7 +62,7 @@ func LoadDS1(fileData []byte) (*DS1, error) {
|
||||
}
|
||||
if ds1.Version >= 9 && ds1.Version <= 13 {
|
||||
// Skipping two dwords because they are "meaningless"?
|
||||
br.SkipBytes(16)
|
||||
br.SkipBytes(8)
|
||||
}
|
||||
if ds1.Version >= 4 {
|
||||
ds1.NumberOfWalls = br.GetInt32()
|
||||
@ -179,8 +180,7 @@ func LoadDS1(fileData []byte) (*DS1, error) {
|
||||
newObject.X = int(br.GetInt32())
|
||||
newObject.Y = int(br.GetInt32())
|
||||
newObject.Flags = int(br.GetInt32())
|
||||
//TODO: There's a crash here, we aren't loading this data right....
|
||||
newObject.Lookup = d2datadict.LookupObject(int(ds1.Act), int(newObject.Type), int(newObject.Id))
|
||||
newObject.Lookup = d2datadict.LookupObject(int(ds1.Act), newObject.Type, newObject.Id)
|
||||
if newObject.Lookup != nil && newObject.Lookup.ObjectsTxtId != -1 {
|
||||
newObject.ObjectInfo = d2datadict.Objects[newObject.Lookup.ObjectsTxtId]
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ const (
|
||||
|
||||
TrademarkScreen = "/data/global/ui/FrontEnd/trademarkscreenEXP.dc6"
|
||||
GameSelectScreen = "/data/global/ui/FrontEnd/gameselectscreenEXP.dc6"
|
||||
TcpIpBackground = "/data/global/ui/FrontEnd/TCPIPscreen.dc6"
|
||||
Diablo2LogoFireLeft = "/data/global/ui/FrontEnd/D2logoFireLeft.DC6"
|
||||
Diablo2LogoFireRight = "/data/global/ui/FrontEnd/D2logoFireRight.DC6"
|
||||
Diablo2LogoBlackLeft = "/data/global/ui/FrontEnd/D2logoBlackLeft.DC6"
|
||||
|
@ -92,16 +92,16 @@ func LoadDictionary(dictionaryData []byte) {
|
||||
|
||||
}
|
||||
// Use the following code to write out the values
|
||||
/*
|
||||
f, err := os.OpenFile(`C:\Users\lunat\Desktop\D2\langdict.txt`,
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := f.WriteString("\n[" + key + "] " + value); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
/*=
|
||||
f, err := os.OpenFile(`C:\Users\lunat\Desktop\D2\langdict.txt`,
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := f.WriteString("\n[" + key + "] " + value); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
@ -18,12 +18,14 @@ type MapEntity interface {
|
||||
GetPosition() (float64, float64)
|
||||
}
|
||||
|
||||
// Represents the map data for a specific location
|
||||
type MapEngine struct {
|
||||
seed int64
|
||||
regions []*MapRegion
|
||||
entities MapEntitiesSearcher
|
||||
}
|
||||
|
||||
// Creates a new instance of the map engine
|
||||
func CreateMapEngine() *MapEngine {
|
||||
engine := &MapEngine{
|
||||
seed: 0,
|
||||
@ -48,6 +50,7 @@ func (m *MapEngine) GetStartPosition() (float64, float64) {
|
||||
return startX, startY
|
||||
}
|
||||
|
||||
// Returns the center of the map
|
||||
func (m *MapEngine) GetCenterPosition() (float64, float64) {
|
||||
var centerX, centerY float64
|
||||
if len(m.regions) > 0 {
|
||||
@ -83,11 +86,14 @@ func (m *MapEngine) GenerateAct1Overworld(cacheTiles bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// Appends a region to the map
|
||||
func (m *MapEngine) AppendRegion(region *MapRegion) {
|
||||
// TODO: Stitch together region.walkableArea
|
||||
log.Printf("Warning: Walkable areas are not currently implemented")
|
||||
m.regions = append(m.regions, region)
|
||||
}
|
||||
|
||||
// Returns the region located at the specified tile location
|
||||
func (m *MapEngine) GetRegionAtTile(x, y int) *MapRegion {
|
||||
for _, region := range m.regions {
|
||||
if region.tileRect.IsInRect(x, y) {
|
||||
|
@ -1,11 +1,14 @@
|
||||
package d2map
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
type Player struct {
|
||||
@ -14,9 +17,11 @@ type Player struct {
|
||||
Id string
|
||||
mode d2enum.AnimationMode
|
||||
direction int
|
||||
Name string
|
||||
nameLabel d2ui.Label
|
||||
}
|
||||
|
||||
func CreatePlayer(id string, x, y int, direction int, heroType d2enum.Hero, equipment d2inventory.CharacterEquipment) *Player {
|
||||
func CreatePlayer(id, name string, x, y int, direction int, heroType d2enum.Hero, equipment d2inventory.CharacterEquipment) *Player {
|
||||
object := &d2datadict.ObjectLookupRecord{
|
||||
Mode: d2enum.AnimationModePlayerNeutral.String(),
|
||||
Base: "/data/global/chars",
|
||||
@ -44,18 +49,32 @@ func CreatePlayer(id string, x, y int, direction int, heroType d2enum.Hero, equi
|
||||
Equipment: equipment,
|
||||
mode: d2enum.AnimationModePlayerTownNeutral,
|
||||
direction: direction,
|
||||
Name: name,
|
||||
nameLabel: d2ui.CreateLabel(d2resource.FontFormal11, d2resource.PaletteStatic),
|
||||
}
|
||||
result.nameLabel.Alignment = d2ui.LabelAlignCenter
|
||||
result.nameLabel.SetText(name)
|
||||
result.nameLabel.Color = color.White
|
||||
err = result.SetMode(result.mode.String(), equipment.RightHand.GetWeaponClass(), direction)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
result.SetMode(result.mode.String(), equipment.RightHand.GetWeaponClass(), direction)
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *Player) Advance(tickTime float64) {
|
||||
v.Step(tickTime)
|
||||
v.AnimatedComposite.Advance(tickTime)
|
||||
|
||||
}
|
||||
|
||||
func (v *Player) Render(target d2render.Surface) {
|
||||
v.AnimatedComposite.Render(target)
|
||||
offX := v.AnimatedComposite.offsetX + int((v.AnimatedComposite.subcellX-v.AnimatedComposite.subcellY)*16)
|
||||
offY := v.AnimatedComposite.offsetY + int(((v.AnimatedComposite.subcellX+v.AnimatedComposite.subcellY)*8)-5)
|
||||
v.nameLabel.X = offX
|
||||
v.nameLabel.Y = offY - 100
|
||||
v.nameLabel.Render(target)
|
||||
}
|
||||
|
||||
func (v *Player) GetPosition() (float64, float64) {
|
||||
|
@ -676,6 +676,10 @@ func (mr *MapRegion) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX, t
|
||||
tileData = &tileOptions[tileIndex]
|
||||
}
|
||||
|
||||
if tileData.Width == 0 || tileData.Height == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
tile.RandomIndex = tileIndex
|
||||
tileMinY := int32(0)
|
||||
tileMaxY := int32(0)
|
||||
|
@ -23,12 +23,14 @@ type TextBox struct {
|
||||
bgSprite *Sprite
|
||||
textLabel Label
|
||||
lineBar Label
|
||||
filter string
|
||||
}
|
||||
|
||||
func CreateTextbox() TextBox {
|
||||
animation, _ := d2asset.LoadAnimation(d2resource.TextBox2, d2resource.PaletteUnits)
|
||||
bgSprite, _ := LoadSprite(animation)
|
||||
result := TextBox{
|
||||
filter: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||
bgSprite: bgSprite,
|
||||
textLabel: CreateLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
|
||||
lineBar: CreateLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
|
||||
@ -39,6 +41,10 @@ func CreateTextbox() TextBox {
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *TextBox) SetFilter(filter string) {
|
||||
v.filter = filter
|
||||
}
|
||||
|
||||
func repeatingKeyPressed(key ebiten.Key) bool {
|
||||
const (
|
||||
delay = 30
|
||||
@ -93,7 +99,7 @@ func (v *TextBox) GetText() string {
|
||||
func (v *TextBox) SetText(newText string) {
|
||||
result := ""
|
||||
for _, c := range newText {
|
||||
if !strings.Contains("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", string(c)) {
|
||||
if !strings.Contains(v.filter, string(c)) {
|
||||
continue
|
||||
}
|
||||
result += string(c)
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
|
||||
@ -17,7 +19,6 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
@ -43,14 +44,20 @@ type CharacterSelect struct {
|
||||
characterStatsLabel [8]d2ui.Label
|
||||
characterExpLabel [8]d2ui.Label
|
||||
characterImage [8]*d2map.Player
|
||||
gameStates []*d2gamestate.GameState
|
||||
gameStates []*d2player.PlayerState
|
||||
selectedCharacter int
|
||||
mouseButtonPressed bool
|
||||
showDeleteConfirmation bool
|
||||
connectionType d2clientconnectiontype.ClientConnectionType
|
||||
connectionHost string
|
||||
}
|
||||
|
||||
func CreateCharacterSelect() *CharacterSelect {
|
||||
return &CharacterSelect{selectedCharacter: -1}
|
||||
func CreateCharacterSelect(connectionType d2clientconnectiontype.ClientConnectionType, connectionHost string) *CharacterSelect {
|
||||
return &CharacterSelect{
|
||||
selectedCharacter: -1,
|
||||
connectionType: connectionType,
|
||||
connectionHost: connectionHost,
|
||||
}
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) OnLoad() error {
|
||||
@ -158,7 +165,7 @@ func (v *CharacterSelect) updateCharacterBoxes() {
|
||||
v.characterStatsLabel[i].SetText("Level 1 " + v.gameStates[idx].HeroType.String())
|
||||
v.characterExpLabel[i].SetText(expText)
|
||||
// TODO: Generate or load the object from the actual player data...
|
||||
v.characterImage[i] = d2map.CreatePlayer("", 0, 0, 0,
|
||||
v.characterImage[i] = d2map.CreatePlayer("", "", 0, 0, 0,
|
||||
v.gameStates[idx].HeroType,
|
||||
d2inventory.HeroObjects[v.gameStates[idx].HeroType],
|
||||
)
|
||||
@ -166,12 +173,12 @@ func (v *CharacterSelect) updateCharacterBoxes() {
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) onNewCharButtonClicked() {
|
||||
d2screen.SetNextScreen(CreateSelectHeroClass())
|
||||
d2screen.SetNextScreen(CreateSelectHeroClass(v.connectionType, v.connectionHost))
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) onExitButtonClicked() {
|
||||
mainMenu := CreateMainMenu()
|
||||
mainMenu.ShowTrademarkScreen = false
|
||||
mainMenu.SetScreenMode(ScreenModeMainMenu)
|
||||
d2screen.SetNextScreen(mainMenu)
|
||||
}
|
||||
|
||||
@ -278,7 +285,7 @@ func (v *CharacterSelect) toggleDeleteCharacterDialog(showDialog bool) {
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) refreshGameStates() {
|
||||
v.gameStates = d2gamestate.GetAllGameStates()
|
||||
v.gameStates = d2player.GetAllPlayerStates()
|
||||
v.updateCharacterBoxes()
|
||||
if len(v.gameStates) > 0 {
|
||||
v.selectedCharacter = 0
|
||||
@ -293,7 +300,13 @@ func (v *CharacterSelect) refreshGameStates() {
|
||||
}
|
||||
|
||||
func (v *CharacterSelect) onOkButtonClicked() {
|
||||
gameClient, _ := d2client.Create(d2clientconnectiontype.Local)
|
||||
gameClient.Open(v.gameStates[v.selectedCharacter].FilePath)
|
||||
gameClient, _ := d2client.Create(v.connectionType)
|
||||
switch v.connectionType {
|
||||
case d2clientconnectiontype.LANClient:
|
||||
gameClient.Open(v.connectionHost, v.gameStates[v.selectedCharacter].FilePath)
|
||||
default:
|
||||
gameClient.Open("", v.gameStates[v.selectedCharacter].FilePath)
|
||||
}
|
||||
|
||||
d2screen.SetNextScreen(CreateGame(gameClient))
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ func (v *Credits) Advance(tickTime float64) error {
|
||||
|
||||
func (v *Credits) onExitButtonClicked() {
|
||||
mainMenu := CreateMainMenu()
|
||||
mainMenu.ShowTrademarkScreen = false
|
||||
mainMenu.SetScreenMode(ScreenModeMainMenu)
|
||||
d2screen.SetNextScreen(mainMenu)
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@ package d2gamescreen
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
@ -33,39 +35,6 @@ func CreateGame(gameClient *d2client.GameClient) *Game {
|
||||
}
|
||||
|
||||
func (v *Game) OnLoad() error {
|
||||
//animation, _ := d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
|
||||
//v.pentSpinLeft, _ = d2ui.LoadSprite(animation)
|
||||
//v.pentSpinLeft.PlayBackward()
|
||||
//v.pentSpinLeft.SetPlayLengthMs(475)
|
||||
//v.pentSpinLeft.SetPosition(100, 300)
|
||||
//
|
||||
//animation, _ = d2asset.LoadAnimation(d2resource.PentSpin, d2resource.PaletteSky)
|
||||
//v.pentSpinRight, _ = d2ui.LoadSprite(animation)
|
||||
//v.pentSpinRight.PlayForward()
|
||||
//v.pentSpinRight.SetPlayLengthMs(475)
|
||||
//v.pentSpinRight.SetPosition(650, 300)
|
||||
//
|
||||
//v.testLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
//v.testLabel.Alignment = d2ui.LabelAlignCenter
|
||||
//v.testLabel.SetText("Soon :tm:")
|
||||
//v.testLabel.SetPosition(400, 250)
|
||||
|
||||
/*
|
||||
startX, startY := v.mapEngine.GetStartPosition()
|
||||
v.hero = d2map.CreateHero(
|
||||
int(startX*5)+3,
|
||||
int(startY*5)+3,
|
||||
0,
|
||||
v.gameState.HeroType,
|
||||
v.gameState.Equipment,
|
||||
)
|
||||
v.mapEngine.AddEntity(v.hero)
|
||||
|
||||
v.gameControls = d2player.NewGameControls(v.hero, v.mapEngine)
|
||||
v.gameControls.Load()
|
||||
d2input.BindHandler(v.gameControls)
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -93,7 +62,7 @@ func (v *Game) Advance(tickTime float64) error {
|
||||
continue
|
||||
}
|
||||
v.localPlayer = player
|
||||
v.gameControls = d2player.NewGameControls(player, v.gameClient.MapEngine, v.mapRenderer, v.gameClient)
|
||||
v.gameControls = d2player.NewGameControls(player, v.gameClient.MapEngine, v.mapRenderer, v)
|
||||
v.gameControls.Load()
|
||||
d2input.BindHandler(v.gameControls)
|
||||
|
||||
@ -108,3 +77,9 @@ func (v *Game) Advance(tickTime float64) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Game) OnPlayerMove(x, y float64) {
|
||||
heroPosX := v.localPlayer.AnimatedComposite.LocationX / 5.0
|
||||
heroPosY := v.localPlayer.AnimatedComposite.LocationY / 5.0
|
||||
v.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(v.gameClient.PlayerId, heroPosX, heroPosY, x, y))
|
||||
}
|
||||
|
@ -8,46 +8,72 @@ import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
)
|
||||
|
||||
type MainMenuScreenMode int
|
||||
|
||||
const (
|
||||
ScreenModeUnknown MainMenuScreenMode = iota
|
||||
ScreenModeTrademark
|
||||
ScreenModeMainMenu
|
||||
ScreenModeMultiplayer
|
||||
ScreenModeTcpIp
|
||||
ScreenModeServerIp
|
||||
)
|
||||
|
||||
// MainMenu represents the main menu
|
||||
type MainMenu struct {
|
||||
tcpIpBackground *d2ui.Sprite
|
||||
trademarkBackground *d2ui.Sprite
|
||||
background *d2ui.Sprite
|
||||
diabloLogoLeft *d2ui.Sprite
|
||||
diabloLogoRight *d2ui.Sprite
|
||||
diabloLogoLeftBack *d2ui.Sprite
|
||||
diabloLogoRightBack *d2ui.Sprite
|
||||
serverIpBackground *d2ui.Sprite
|
||||
singlePlayerButton d2ui.Button
|
||||
multiplayerButton d2ui.Button
|
||||
githubButton d2ui.Button
|
||||
exitDiabloButton d2ui.Button
|
||||
creditsButton d2ui.Button
|
||||
cinematicsButton d2ui.Button
|
||||
mapTestButton d2ui.Button
|
||||
networkTcpIpButton d2ui.Button
|
||||
networkCancelButton d2ui.Button
|
||||
btnTcpIpCancel d2ui.Button
|
||||
btnTcpIpHostGame d2ui.Button
|
||||
btnTcpIpJoinGame d2ui.Button
|
||||
btnServerIpCancel d2ui.Button
|
||||
btnServerIpOk d2ui.Button
|
||||
copyrightLabel d2ui.Label
|
||||
copyrightLabel2 d2ui.Label
|
||||
openDiabloLabel d2ui.Label
|
||||
versionLabel d2ui.Label
|
||||
commitLabel d2ui.Label
|
||||
|
||||
ShowTrademarkScreen bool
|
||||
tcpIpOptionsLabel d2ui.Label
|
||||
tcpJoinGameLabel d2ui.Label
|
||||
tcpJoinGameEntry d2ui.TextBox
|
||||
screenMode MainMenuScreenMode
|
||||
leftButtonHeld bool
|
||||
}
|
||||
|
||||
// CreateMainMenu creates an instance of MainMenu
|
||||
func CreateMainMenu() *MainMenu {
|
||||
return &MainMenu{
|
||||
ShowTrademarkScreen: true,
|
||||
leftButtonHeld: true,
|
||||
screenMode: ScreenModeUnknown,
|
||||
leftButtonHeld: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,6 +119,10 @@ func (v *MainMenu) OnLoad() error {
|
||||
v.trademarkBackground, _ = d2ui.LoadSprite(animation)
|
||||
v.trademarkBackground.SetPosition(0, 0)
|
||||
|
||||
animation, _ = d2asset.LoadAnimation(d2resource.TcpIpBackground, d2resource.PaletteSky)
|
||||
v.tcpIpBackground, _ = d2ui.LoadSprite(animation)
|
||||
v.tcpIpBackground.SetPosition(0, 0)
|
||||
|
||||
animation, _ = d2asset.LoadAnimation(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
|
||||
v.diabloLogoLeft, _ = d2ui.LoadSprite(animation)
|
||||
v.diabloLogoLeft.SetBlend(true)
|
||||
@ -115,39 +145,99 @@ func (v *MainMenu) OnLoad() error {
|
||||
|
||||
v.exitDiabloButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1625"))
|
||||
v.exitDiabloButton.SetPosition(264, 535)
|
||||
v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||
d2ui.AddWidget(&v.exitDiabloButton)
|
||||
|
||||
v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1627"))
|
||||
v.creditsButton.SetPosition(264, 505)
|
||||
v.creditsButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
|
||||
d2ui.AddWidget(&v.creditsButton)
|
||||
|
||||
v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, d2common.TranslateString("#1639"))
|
||||
v.cinematicsButton.SetPosition(401, 505)
|
||||
v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
d2ui.AddWidget(&v.cinematicsButton)
|
||||
|
||||
v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1620"))
|
||||
v.singlePlayerButton.SetPosition(264, 290)
|
||||
v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
|
||||
d2ui.AddWidget(&v.singlePlayerButton)
|
||||
|
||||
v.multiplayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "MULTIPLAYER")
|
||||
v.multiplayerButton.SetPosition(264, 330)
|
||||
v.multiplayerButton.OnActivated(func() { v.onMultiplayerClicked() })
|
||||
d2ui.AddWidget(&v.multiplayerButton)
|
||||
|
||||
v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "PROJECT WEBSITE")
|
||||
v.githubButton.SetPosition(264, 330)
|
||||
v.githubButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.githubButton.SetPosition(264, 400)
|
||||
v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
|
||||
d2ui.AddWidget(&v.githubButton)
|
||||
|
||||
v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "MAP ENGINE TEST")
|
||||
v.mapTestButton.SetPosition(264, 450)
|
||||
v.mapTestButton.SetVisible(!v.ShowTrademarkScreen)
|
||||
v.mapTestButton.SetPosition(264, 440)
|
||||
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
|
||||
|
||||
d2ui.AddWidget(&v.mapTestButton)
|
||||
|
||||
v.networkTcpIpButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1666"))
|
||||
v.networkTcpIpButton.SetPosition(264, 280)
|
||||
v.networkTcpIpButton.OnActivated(func() { v.onNetworkTcpIpClicked() })
|
||||
d2ui.AddWidget(&v.networkTcpIpButton)
|
||||
|
||||
v.networkCancelButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("cancel"))
|
||||
v.networkCancelButton.SetPosition(264, 540)
|
||||
v.networkCancelButton.OnActivated(func() { v.onNetworkCancelClicked() })
|
||||
d2ui.AddWidget(&v.networkCancelButton)
|
||||
|
||||
v.btnTcpIpCancel = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("cancel"))
|
||||
v.btnTcpIpCancel.SetPosition(33, 543)
|
||||
v.btnTcpIpCancel.OnActivated(func() { v.onTcpIpCancelClicked() })
|
||||
d2ui.AddWidget(&v.btnTcpIpCancel)
|
||||
|
||||
v.btnTcpIpHostGame = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1675"))
|
||||
v.btnTcpIpHostGame.SetPosition(264, 280)
|
||||
v.btnTcpIpHostGame.OnActivated(func() { v.onTcpIpHostGameClicked() })
|
||||
d2ui.AddWidget(&v.btnTcpIpHostGame)
|
||||
|
||||
v.btnTcpIpJoinGame = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("#1676"))
|
||||
v.btnTcpIpJoinGame.SetPosition(264, 320)
|
||||
v.btnTcpIpJoinGame.OnActivated(func() { v.onTcpIpJoinGameClicked() })
|
||||
d2ui.AddWidget(&v.btnTcpIpJoinGame)
|
||||
|
||||
v.tcpIpOptionsLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
|
||||
v.tcpIpOptionsLabel.SetPosition(400, 23)
|
||||
v.tcpIpOptionsLabel.Alignment = d2ui.LabelAlignCenter
|
||||
v.tcpIpOptionsLabel.SetText(d2common.TranslateString("#1667"))
|
||||
|
||||
animation, _ = d2asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
||||
v.serverIpBackground, _ = d2ui.LoadSprite(animation)
|
||||
v.serverIpBackground.SetPosition(270, 175)
|
||||
|
||||
v.tcpJoinGameLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.tcpJoinGameLabel.Alignment = d2ui.LabelAlignCenter
|
||||
v.tcpJoinGameLabel.SetText(d2common.CombineStrings(d2common.
|
||||
SplitIntoLinesWithMaxWidth(d2common.TranslateString("#327"), 23)))
|
||||
v.tcpJoinGameLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
|
||||
v.tcpJoinGameLabel.SetPosition(400, 190)
|
||||
|
||||
v.tcpJoinGameEntry = d2ui.CreateTextbox()
|
||||
v.tcpJoinGameEntry.SetPosition(318, 245)
|
||||
v.tcpJoinGameEntry.SetFilter("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:")
|
||||
d2ui.AddWidget(&v.tcpJoinGameEntry)
|
||||
|
||||
v.btnServerIpCancel = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#1612"))
|
||||
v.btnServerIpCancel.SetPosition(285, 305)
|
||||
v.btnServerIpCancel.OnActivated(func() { v.onBtnTcpIpCancelClicked() })
|
||||
d2ui.AddWidget(&v.btnServerIpCancel)
|
||||
|
||||
v.btnServerIpOk = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, d2common.TranslateString("#971"))
|
||||
v.btnServerIpOk.SetPosition(420, 305)
|
||||
v.btnServerIpOk.OnActivated(func() { v.onBtnTcpIpOkClicked() })
|
||||
d2ui.AddWidget(&v.btnServerIpOk)
|
||||
|
||||
if v.screenMode == ScreenModeUnknown {
|
||||
v.SetScreenMode(ScreenModeTrademark)
|
||||
} else {
|
||||
v.SetScreenMode(ScreenModeMainMenu)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -176,11 +266,11 @@ func openbrowser(url string) {
|
||||
|
||||
func (v *MainMenu) onSinglePlayerClicked() {
|
||||
// Go here only if existing characters are available to select
|
||||
if d2gamestate.HasGameStates() {
|
||||
d2screen.SetNextScreen(CreateCharacterSelect())
|
||||
if d2player.HasGameStates() {
|
||||
d2screen.SetNextScreen(CreateCharacterSelect(d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText()))
|
||||
return
|
||||
}
|
||||
d2screen.SetNextScreen(CreateSelectHeroClass())
|
||||
d2screen.SetNextScreen(CreateSelectHeroClass(d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText()))
|
||||
}
|
||||
|
||||
func (v *MainMenu) onGithubButtonClicked() {
|
||||
@ -197,20 +287,40 @@ func (v *MainMenu) onCreditsButtonClicked() {
|
||||
|
||||
// Render renders the main menu
|
||||
func (v *MainMenu) Render(screen d2render.Surface) error {
|
||||
if v.ShowTrademarkScreen {
|
||||
switch v.screenMode {
|
||||
case ScreenModeTrademark:
|
||||
v.trademarkBackground.RenderSegmented(screen, 4, 3, 0)
|
||||
} else {
|
||||
case ScreenModeServerIp:
|
||||
fallthrough
|
||||
case ScreenModeTcpIp:
|
||||
v.tcpIpBackground.RenderSegmented(screen, 4, 3, 0)
|
||||
default:
|
||||
v.background.RenderSegmented(screen, 4, 3, 0)
|
||||
}
|
||||
v.diabloLogoLeftBack.Render(screen)
|
||||
v.diabloLogoRightBack.Render(screen)
|
||||
v.diabloLogoLeft.Render(screen)
|
||||
v.diabloLogoRight.Render(screen)
|
||||
|
||||
if v.ShowTrademarkScreen {
|
||||
switch v.screenMode {
|
||||
case ScreenModeTrademark:
|
||||
fallthrough
|
||||
case ScreenModeMainMenu:
|
||||
fallthrough
|
||||
case ScreenModeMultiplayer:
|
||||
v.diabloLogoLeftBack.Render(screen)
|
||||
v.diabloLogoRightBack.Render(screen)
|
||||
v.diabloLogoLeft.Render(screen)
|
||||
v.diabloLogoRight.Render(screen)
|
||||
}
|
||||
|
||||
switch v.screenMode {
|
||||
case ScreenModeServerIp:
|
||||
v.tcpIpOptionsLabel.Render(screen)
|
||||
v.serverIpBackground.RenderSegmented(screen, 2, 1, 0)
|
||||
v.tcpJoinGameLabel.Render(screen)
|
||||
case ScreenModeTcpIp:
|
||||
v.tcpIpOptionsLabel.Render(screen)
|
||||
case ScreenModeTrademark:
|
||||
v.copyrightLabel.Render(screen)
|
||||
v.copyrightLabel2.Render(screen)
|
||||
} else {
|
||||
case ScreenModeMainMenu:
|
||||
v.openDiabloLabel.Render(screen)
|
||||
v.versionLabel.Render(screen)
|
||||
v.commitLabel.Render(screen)
|
||||
@ -221,29 +331,89 @@ func (v *MainMenu) Render(screen d2render.Surface) error {
|
||||
|
||||
// Update runs the update logic on the main menu
|
||||
func (v *MainMenu) Advance(tickTime float64) error {
|
||||
v.diabloLogoLeftBack.Advance(tickTime)
|
||||
v.diabloLogoRightBack.Advance(tickTime)
|
||||
v.diabloLogoLeft.Advance(tickTime)
|
||||
v.diabloLogoRight.Advance(tickTime)
|
||||
switch v.screenMode {
|
||||
case ScreenModeMainMenu:
|
||||
fallthrough
|
||||
case ScreenModeTrademark:
|
||||
fallthrough
|
||||
case ScreenModeMultiplayer:
|
||||
v.diabloLogoLeftBack.Advance(tickTime)
|
||||
v.diabloLogoRightBack.Advance(tickTime)
|
||||
v.diabloLogoLeft.Advance(tickTime)
|
||||
v.diabloLogoRight.Advance(tickTime)
|
||||
case ScreenModeServerIp:
|
||||
v.tcpJoinGameEntry.Update()
|
||||
}
|
||||
|
||||
if v.ShowTrademarkScreen {
|
||||
switch v.screenMode {
|
||||
case ScreenModeTrademark:
|
||||
if d2ui.CursorButtonPressed(d2ui.CursorButtonLeft) {
|
||||
if v.leftButtonHeld {
|
||||
return nil
|
||||
}
|
||||
d2ui.WaitForMouseRelease()
|
||||
v.SetScreenMode(ScreenModeMainMenu)
|
||||
v.leftButtonHeld = true
|
||||
v.ShowTrademarkScreen = false
|
||||
v.exitDiabloButton.SetVisible(true)
|
||||
v.creditsButton.SetVisible(true)
|
||||
v.cinematicsButton.SetVisible(true)
|
||||
v.singlePlayerButton.SetVisible(true)
|
||||
v.githubButton.SetVisible(true)
|
||||
v.mapTestButton.SetVisible(true)
|
||||
} else {
|
||||
v.leftButtonHeld = false
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *MainMenu) SetScreenMode(screenMode MainMenuScreenMode) {
|
||||
v.screenMode = screenMode
|
||||
isMainMenu := screenMode == ScreenModeMainMenu
|
||||
isMultiplayer := screenMode == ScreenModeMultiplayer
|
||||
isTcpIp := screenMode == ScreenModeTcpIp
|
||||
isServerIp := screenMode == ScreenModeServerIp
|
||||
v.exitDiabloButton.SetVisible(isMainMenu)
|
||||
v.creditsButton.SetVisible(isMainMenu)
|
||||
v.cinematicsButton.SetVisible(isMainMenu)
|
||||
v.singlePlayerButton.SetVisible(isMainMenu)
|
||||
v.githubButton.SetVisible(isMainMenu)
|
||||
v.mapTestButton.SetVisible(isMainMenu)
|
||||
v.multiplayerButton.SetVisible(isMainMenu)
|
||||
v.networkTcpIpButton.SetVisible(isMultiplayer)
|
||||
v.networkCancelButton.SetVisible(isMultiplayer)
|
||||
v.btnTcpIpCancel.SetVisible(isTcpIp)
|
||||
v.btnTcpIpHostGame.SetVisible(isTcpIp)
|
||||
v.btnTcpIpJoinGame.SetVisible(isTcpIp)
|
||||
v.tcpJoinGameEntry.SetVisible(isServerIp)
|
||||
v.btnServerIpOk.SetVisible(isServerIp)
|
||||
v.btnServerIpCancel.SetVisible(isServerIp)
|
||||
}
|
||||
|
||||
func (v *MainMenu) onNetworkCancelClicked() {
|
||||
v.SetScreenMode(ScreenModeMainMenu)
|
||||
}
|
||||
|
||||
func (v *MainMenu) onMultiplayerClicked() {
|
||||
v.SetScreenMode(ScreenModeMultiplayer)
|
||||
}
|
||||
|
||||
func (v *MainMenu) onNetworkTcpIpClicked() {
|
||||
v.SetScreenMode(ScreenModeTcpIp)
|
||||
}
|
||||
|
||||
func (v *MainMenu) onTcpIpCancelClicked() {
|
||||
v.SetScreenMode(ScreenModeMultiplayer)
|
||||
}
|
||||
|
||||
func (v *MainMenu) onTcpIpHostGameClicked() {
|
||||
d2screen.SetNextScreen(CreateCharacterSelect(d2clientconnectiontype.LANServer, ""))
|
||||
}
|
||||
|
||||
func (v *MainMenu) onTcpIpJoinGameClicked() {
|
||||
v.SetScreenMode(ScreenModeServerIp)
|
||||
}
|
||||
|
||||
func (v *MainMenu) onBtnTcpIpCancelClicked() {
|
||||
v.SetScreenMode(ScreenModeTcpIp)
|
||||
}
|
||||
|
||||
func (v *MainMenu) onBtnTcpIpOkClicked() {
|
||||
d2screen.SetNextScreen(CreateCharacterSelect(d2clientconnectiontype.LANClient, v.tcpJoinGameEntry.GetText()))
|
||||
}
|
||||
|
@ -4,10 +4,11 @@ import (
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
@ -76,7 +77,7 @@ var regions = []RegionSpec{
|
||||
}
|
||||
|
||||
type MapEngineTest struct {
|
||||
gameState *d2gamestate.GameState
|
||||
gameState *d2player.PlayerState
|
||||
mapEngine *d2map.MapEngine
|
||||
mapRenderer *d2map.MapRenderer
|
||||
|
||||
@ -97,7 +98,7 @@ func CreateMapEngineTest(currentRegion int, levelPreset int) *MapEngineTest {
|
||||
regionSpec: RegionSpec{},
|
||||
filesCount: 0,
|
||||
}
|
||||
result.gameState = d2gamestate.CreateTestGameState()
|
||||
result.gameState = d2player.CreateTestGameState()
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
|
||||
@ -14,7 +16,6 @@ import (
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
@ -64,12 +65,16 @@ type SelectHeroClass struct {
|
||||
expansionCharLabel d2ui.Label
|
||||
hardcoreCheckbox d2ui.Checkbox
|
||||
hardcoreCharLabel d2ui.Label
|
||||
connectionType d2clientconnectiontype.ClientConnectionType
|
||||
connectionHost string
|
||||
}
|
||||
|
||||
func CreateSelectHeroClass() *SelectHeroClass {
|
||||
func CreateSelectHeroClass(connectionType d2clientconnectiontype.ClientConnectionType, connectionHost string) *SelectHeroClass {
|
||||
result := &SelectHeroClass{
|
||||
heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo),
|
||||
selectedHero: d2enum.HeroNone,
|
||||
connectionType: connectionType,
|
||||
connectionHost: connectionHost,
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -420,13 +425,13 @@ func (v *SelectHeroClass) OnUnload() error {
|
||||
}
|
||||
|
||||
func (v SelectHeroClass) onExitButtonClicked() {
|
||||
d2screen.SetNextScreen(CreateCharacterSelect())
|
||||
d2screen.SetNextScreen(CreateCharacterSelect(v.connectionType, v.connectionHost))
|
||||
}
|
||||
|
||||
func (v SelectHeroClass) onOkButtonClicked() {
|
||||
gameState := d2gamestate.CreateGameState(v.heroNameTextbox.GetText(), v.selectedHero, v.hardcoreCheckbox.GetCheckState())
|
||||
gameState := d2player.CreatePlayerState(v.heroNameTextbox.GetText(), v.selectedHero, v.hardcoreCheckbox.GetCheckState())
|
||||
gameClient, _ := d2client.Create(d2clientconnectiontype.Local)
|
||||
gameClient.Open(gameState.FilePath)
|
||||
gameClient.Open(v.connectionHost, gameState.FilePath)
|
||||
d2screen.SetNextScreen(CreateGame(gameClient))
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,6 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
)
|
||||
|
||||
type Panel interface {
|
||||
@ -25,12 +23,12 @@ type Panel interface {
|
||||
var missileID = 59
|
||||
|
||||
type GameControls struct {
|
||||
hero *d2map.Player
|
||||
mapEngine *d2map.MapEngine
|
||||
mapRenderer *d2map.MapRenderer
|
||||
inventory *Inventory
|
||||
heroStats *HeroStats
|
||||
gameClient *d2client.GameClient
|
||||
hero *d2map.Player
|
||||
mapEngine *d2map.MapEngine
|
||||
mapRenderer *d2map.MapRenderer
|
||||
inventory *Inventory
|
||||
heroStats *HeroStats
|
||||
inputListener InputCallbackListener
|
||||
|
||||
// UI
|
||||
globeSprite *d2ui.Sprite
|
||||
@ -39,19 +37,18 @@ type GameControls struct {
|
||||
skillIcon *d2ui.Sprite
|
||||
}
|
||||
|
||||
func NewGameControls(hero *d2map.Player, mapEngine *d2map.MapEngine, mapRenderer *d2map.MapRenderer,
|
||||
gameClient *d2client.GameClient) *GameControls {
|
||||
func NewGameControls(hero *d2map.Player, mapEngine *d2map.MapEngine, mapRenderer *d2map.MapRenderer, inputListener InputCallbackListener) *GameControls {
|
||||
d2term.BindAction("setmissile", "set missile id to summon on right click", func(id int) {
|
||||
missileID = id
|
||||
})
|
||||
|
||||
return &GameControls{
|
||||
hero: hero,
|
||||
mapEngine: mapEngine,
|
||||
gameClient: gameClient,
|
||||
mapRenderer: mapRenderer,
|
||||
inventory: NewInventory(),
|
||||
heroStats: NewHeroStats(),
|
||||
hero: hero,
|
||||
mapEngine: mapEngine,
|
||||
inputListener: inputListener,
|
||||
mapRenderer: mapRenderer,
|
||||
inventory: NewInventory(),
|
||||
heroStats: NewHeroStats(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,19 +69,9 @@ func (g *GameControls) OnMouseButtonDown(event d2input.MouseEvent) bool {
|
||||
px, py := g.mapRenderer.ScreenToWorld(event.X, event.Y)
|
||||
px = float64(int(px*10)) / 10.0
|
||||
py = float64(int(py*10)) / 10.0
|
||||
heroPosX := g.hero.AnimatedComposite.LocationX / 5.0
|
||||
heroPosY := g.hero.AnimatedComposite.LocationY / 5.0
|
||||
|
||||
if event.Button == d2input.MouseButtonLeft {
|
||||
g.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(g.gameClient.PlayerId, heroPosX, heroPosY, px, py))
|
||||
//path, _, found := g.mapEngine.PathFind(heroPosX, heroPosY, px, py)
|
||||
//if found {
|
||||
// g.hero.AnimatedComposite.SetPath(path, func() {
|
||||
// g.hero.AnimatedComposite.SetAnimationMode(
|
||||
// d2enum.AnimationModeObjectNeutral.String(),
|
||||
// )
|
||||
// })
|
||||
//}
|
||||
g.inputListener.OnPlayerMove(px, py)
|
||||
return true
|
||||
}
|
||||
|
||||
|
5
d2game/d2player/input_callback_listener.go
Normal file
5
d2game/d2player/input_callback_listener.go
Normal file
@ -0,0 +1,5 @@
|
||||
package d2player
|
||||
|
||||
type InputCallbackListener interface {
|
||||
OnPlayerMove(x, y float64)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package d2gamestate
|
||||
package d2player
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -8,41 +8,38 @@ import (
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
|
||||
)
|
||||
|
||||
type GameState struct {
|
||||
Seed int64 `json:"seed"` // TODO: Seed needs to be regenerated every time the game starts
|
||||
type PlayerState struct {
|
||||
HeroName string `json:"heroName"`
|
||||
HeroType d2enum.Hero `json:"heroType"`
|
||||
HeroLevel int `json:"heroLevel"`
|
||||
Act int `json:"act"`
|
||||
FilePath string `json:"-"`
|
||||
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
||||
X float64 `json:"x"`
|
||||
Y float64 `json:"y"`
|
||||
}
|
||||
|
||||
const GameStateVersion = uint32(2) // Update this when you make breaking changes
|
||||
|
||||
func HasGameStates() bool {
|
||||
basePath, _ := getGameBaseSavePath()
|
||||
files, _ := ioutil.ReadDir(basePath)
|
||||
return len(files) > 0
|
||||
}
|
||||
|
||||
func GetAllGameStates() []*GameState {
|
||||
func GetAllPlayerStates() []*PlayerState {
|
||||
basePath, _ := getGameBaseSavePath()
|
||||
files, _ := ioutil.ReadDir(basePath)
|
||||
result := make([]*GameState, 0)
|
||||
result := make([]*PlayerState, 0)
|
||||
for _, file := range files {
|
||||
fileName := file.Name()
|
||||
if file.IsDir() || len(fileName) < 5 || strings.ToLower(fileName[len(fileName)-4:]) != ".od2" {
|
||||
continue
|
||||
}
|
||||
gameState := LoadGameState(path.Join(basePath, file.Name()))
|
||||
gameState := LoadPlayerState(path.Join(basePath, file.Name()))
|
||||
if gameState == nil {
|
||||
continue
|
||||
}
|
||||
@ -52,20 +49,18 @@ func GetAllGameStates() []*GameState {
|
||||
}
|
||||
|
||||
// CreateTestGameState is used for the map engine previewer
|
||||
func CreateTestGameState() *GameState {
|
||||
result := &GameState{
|
||||
Seed: time.Now().UnixNano(),
|
||||
}
|
||||
func CreateTestGameState() *PlayerState {
|
||||
result := &PlayerState{}
|
||||
return result
|
||||
}
|
||||
|
||||
func LoadGameState(path string) *GameState {
|
||||
func LoadPlayerState(path string) *PlayerState {
|
||||
strData, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := &GameState{
|
||||
result := &PlayerState{
|
||||
FilePath: path,
|
||||
}
|
||||
err = json.Unmarshal(strData, result)
|
||||
@ -75,12 +70,11 @@ func LoadGameState(path string) *GameState {
|
||||
return result
|
||||
}
|
||||
|
||||
func CreateGameState(heroName string, hero d2enum.Hero, hardcore bool) *GameState {
|
||||
result := &GameState{
|
||||
func CreatePlayerState(heroName string, hero d2enum.Hero, hardcore bool) *PlayerState {
|
||||
result := &PlayerState{
|
||||
HeroName: heroName,
|
||||
HeroType: hero,
|
||||
Act: 1,
|
||||
Seed: time.Now().UnixNano(),
|
||||
Equipment: d2inventory.HeroObjects[hero],
|
||||
FilePath: "",
|
||||
}
|
||||
@ -110,7 +104,7 @@ func getFirstFreeFileName() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *GameState) Save() {
|
||||
func (v *PlayerState) Save() {
|
||||
if v.FilePath == "" {
|
||||
v.FilePath = getFirstFreeFileName()
|
||||
}
|
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type ClientConnection interface {
|
||||
Open(connectionString string) error
|
||||
Open(connectionString string, saveFilePath string) error
|
||||
Close() error
|
||||
SendPacketToServer(packet d2netpacket.NetPacket) error
|
||||
SetClientListener(listener d2networking.ClientListener)
|
||||
|
@ -3,5 +3,7 @@ package d2clientconnectiontype
|
||||
type ClientConnectionType int
|
||||
|
||||
const (
|
||||
Local ClientConnectionType = 1
|
||||
Local ClientConnectionType = iota
|
||||
LANServer
|
||||
LANClient
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2localclient
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2server"
|
||||
@ -8,8 +9,10 @@ import (
|
||||
)
|
||||
|
||||
type LocalClientConnection struct {
|
||||
clientListener d2networking.ClientListener
|
||||
uniqueId string
|
||||
clientListener d2networking.ClientListener
|
||||
uniqueId string
|
||||
openNetworkServer bool
|
||||
playerState *d2player.PlayerState
|
||||
}
|
||||
|
||||
func (l LocalClientConnection) GetUniqueId() string {
|
||||
@ -24,16 +27,18 @@ func (l *LocalClientConnection) SendPacketToClient(packet d2netpacket.NetPacket)
|
||||
return l.clientListener.OnPacketReceived(packet)
|
||||
}
|
||||
|
||||
func Create() *LocalClientConnection {
|
||||
func Create(openNetworkServer bool) *LocalClientConnection {
|
||||
result := &LocalClientConnection{
|
||||
uniqueId: uuid.NewV4().String(),
|
||||
uniqueId: uuid.NewV4().String(),
|
||||
openNetworkServer: openNetworkServer,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (l *LocalClientConnection) Open(gameStatePath string) error {
|
||||
d2server.Create(gameStatePath)
|
||||
func (l *LocalClientConnection) Open(connectionString string, saveFilePath string) error {
|
||||
l.SetPlayerState(d2player.LoadPlayerState(saveFilePath))
|
||||
d2server.Create(l.openNetworkServer)
|
||||
go d2server.Run()
|
||||
d2server.OnClientConnected(l)
|
||||
return nil
|
||||
@ -53,3 +58,11 @@ func (l *LocalClientConnection) SendPacketToServer(packet d2netpacket.NetPacket)
|
||||
func (l *LocalClientConnection) SetClientListener(listener d2networking.ClientListener) {
|
||||
l.clientListener = listener
|
||||
}
|
||||
|
||||
func (l *LocalClientConnection) GetPlayerState() *d2player.PlayerState {
|
||||
return l.playerState
|
||||
}
|
||||
|
||||
func (l *LocalClientConnection) SetPlayerState(playerState *d2player.PlayerState) {
|
||||
l.playerState = playerState
|
||||
}
|
||||
|
155
d2networking/d2client/d2remoteclient/remote_client_connection.go
Normal file
155
d2networking/d2client/d2remoteclient/remote_client_connection.go
Normal file
@ -0,0 +1,155 @@
|
||||
package d2remoteclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
type RemoteClientConnection struct {
|
||||
clientListener d2networking.ClientListener
|
||||
uniqueId string
|
||||
udpConnection *net.UDPConn
|
||||
active bool
|
||||
}
|
||||
|
||||
func (l RemoteClientConnection) GetUniqueId() string {
|
||||
return l.uniqueId
|
||||
}
|
||||
|
||||
func (l RemoteClientConnection) GetConnectionType() string {
|
||||
return "Remote Client"
|
||||
}
|
||||
|
||||
func (l *RemoteClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error { // WHAT IS THIS
|
||||
return l.clientListener.OnPacketReceived(packet)
|
||||
}
|
||||
|
||||
func Create() *RemoteClientConnection {
|
||||
result := &RemoteClientConnection{
|
||||
uniqueId: uuid.NewV4().String(),
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (l *RemoteClientConnection) Open(connectionString string, saveFilePath string) error {
|
||||
if strings.Index(connectionString, ":") == -1 {
|
||||
connectionString += ":6669"
|
||||
}
|
||||
|
||||
// TODO: Connect to the server
|
||||
udpAddress, err := net.ResolveUDPAddr("udp", connectionString)
|
||||
|
||||
// TODO: Show connection error screen if connection fails
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.udpConnection, err = net.DialUDP("udp", nil, udpAddress)
|
||||
// TODO: Show connection error screen if connection fails
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.active = true
|
||||
go l.serverListener()
|
||||
|
||||
log.Printf("Connected to server at %s", l.udpConnection.RemoteAddr().String())
|
||||
gameState := d2player.LoadPlayerState(saveFilePath)
|
||||
l.SendPacketToServer(d2netpacket.CreatePlayerConnectionRequestPacket(l.GetUniqueId(), gameState))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *RemoteClientConnection) Close() error {
|
||||
l.active = false
|
||||
// TODO: Disconnect from the server - send a disconnect packet
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *RemoteClientConnection) SendPacketToServer(packet d2netpacket.NetPacket) error {
|
||||
data, err := json.Marshal(packet.PacketData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var buff bytes.Buffer
|
||||
buff.WriteByte(byte(packet.PacketType))
|
||||
writer, _ := gzip.NewWriterLevel(&buff, gzip.BestCompression)
|
||||
writer.Write(data)
|
||||
writer.Close()
|
||||
if _, err = l.udpConnection.Write(buff.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *RemoteClientConnection) SetClientListener(listener d2networking.ClientListener) {
|
||||
l.clientListener = listener
|
||||
}
|
||||
|
||||
func (l *RemoteClientConnection) serverListener() {
|
||||
buffer := make([]byte, 4096)
|
||||
for l.active {
|
||||
n, _, err := l.udpConnection.ReadFromUDP(buffer)
|
||||
if err != nil {
|
||||
fmt.Printf("Socket error: %s\n", err)
|
||||
continue
|
||||
}
|
||||
if n <= 0 {
|
||||
continue
|
||||
}
|
||||
buff := bytes.NewBuffer(buffer)
|
||||
packetTypeId, err := buff.ReadByte()
|
||||
packetType := d2netpackettype.NetPacketType(packetTypeId)
|
||||
reader, err := gzip.NewReader(buff)
|
||||
sb := new(strings.Builder)
|
||||
io.Copy(sb, reader)
|
||||
stringData := sb.String()
|
||||
switch packetType {
|
||||
case d2netpackettype.GenerateMap:
|
||||
var packet d2netpacket.GenerateMapPacket
|
||||
json.Unmarshal([]byte(stringData), &packet)
|
||||
l.SendPacketToClient(d2netpacket.NetPacket{
|
||||
PacketType: packetType,
|
||||
PacketData: packet,
|
||||
})
|
||||
case d2netpackettype.MovePlayer:
|
||||
var packet d2netpacket.MovePlayerPacket
|
||||
json.Unmarshal([]byte(stringData), &packet)
|
||||
l.SendPacketToClient(d2netpacket.NetPacket{
|
||||
PacketType: packetType,
|
||||
PacketData: packet,
|
||||
})
|
||||
case d2netpackettype.UpdateServerInfo:
|
||||
var packet d2netpacket.UpdateServerInfoPacket
|
||||
json.Unmarshal([]byte(stringData), &packet)
|
||||
l.SendPacketToClient(d2netpacket.NetPacket{
|
||||
PacketType: packetType,
|
||||
PacketData: packet,
|
||||
})
|
||||
case d2netpackettype.AddPlayer:
|
||||
var packet d2netpacket.AddPlayerPacket
|
||||
json.Unmarshal([]byte(stringData), &packet)
|
||||
l.SendPacketToClient(d2netpacket.NetPacket{
|
||||
PacketType: packetType,
|
||||
PacketData: packet,
|
||||
})
|
||||
default:
|
||||
fmt.Printf("Unknown packet type %d\n", packetType)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -4,21 +4,21 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2clientconnectiontype"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2localclient"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client/d2remoteclient"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
)
|
||||
|
||||
type GameClient struct {
|
||||
clientConnection ClientConnection
|
||||
GameState *d2gamestate.GameState
|
||||
connectionType d2clientconnectiontype.ClientConnectionType
|
||||
GameState *d2player.PlayerState
|
||||
MapEngine *d2map.MapEngine
|
||||
PlayerId string
|
||||
Players map[string]*d2map.Player
|
||||
@ -26,23 +26,27 @@ type GameClient struct {
|
||||
|
||||
func Create(connectionType d2clientconnectiontype.ClientConnectionType) (*GameClient, error) {
|
||||
result := &GameClient{
|
||||
MapEngine: d2map.CreateMapEngine(),
|
||||
Players: make(map[string]*d2map.Player, 0),
|
||||
MapEngine: d2map.CreateMapEngine(),
|
||||
Players: make(map[string]*d2map.Player, 0),
|
||||
connectionType: connectionType,
|
||||
}
|
||||
|
||||
switch connectionType {
|
||||
case d2clientconnectiontype.LANClient:
|
||||
result.clientConnection = d2remoteclient.Create()
|
||||
case d2clientconnectiontype.LANServer:
|
||||
result.clientConnection = d2localclient.Create(true)
|
||||
case d2clientconnectiontype.Local:
|
||||
result.clientConnection = d2localclient.Create()
|
||||
result.clientConnection.SetClientListener(result)
|
||||
result.clientConnection = d2localclient.Create(false)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown client connection type specified: %d", connectionType)
|
||||
}
|
||||
|
||||
result.clientConnection.SetClientListener(result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (g *GameClient) Open(connectionString string) error {
|
||||
return g.clientConnection.Open(connectionString)
|
||||
func (g *GameClient) Open(connectionString string, saveFilePath string) error {
|
||||
return g.clientConnection.Open(connectionString, saveFilePath)
|
||||
}
|
||||
|
||||
func (g *GameClient) Close() error {
|
||||
@ -67,7 +71,7 @@ func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error {
|
||||
break
|
||||
case d2netpackettype.AddPlayer:
|
||||
player := packet.PacketData.(d2netpacket.AddPlayerPacket)
|
||||
newPlayer := d2map.CreatePlayer(player.Id, player.X, player.Y, 0, player.HeroType, player.Equipment)
|
||||
newPlayer := d2map.CreatePlayer(player.Id, player.Name, player.X, player.Y, 0, player.HeroType, player.Equipment)
|
||||
g.Players[newPlayer.Id] = newPlayer
|
||||
g.MapEngine.AddEntity(newPlayer)
|
||||
break
|
||||
|
@ -4,9 +4,12 @@ type NetPacketType uint32
|
||||
|
||||
// Warning: Do NOT re-arrange the order of these packet values unless you want to
|
||||
// break compatibility between clients of slightly different versions.
|
||||
// Also note that the packet id is a byte, so if we use more than 256
|
||||
// of these then we are doing something very wrong.
|
||||
const (
|
||||
UpdateServerInfo NetPacketType = iota
|
||||
GenerateMap
|
||||
AddPlayer
|
||||
MovePlayer
|
||||
UpdateServerInfo NetPacketType = iota
|
||||
GenerateMap // Sent by the server to generate a map
|
||||
AddPlayer // Server sends to the client to add a player
|
||||
MovePlayer // Sent to the client or server to indicate player movement
|
||||
PlayerConnectionRequest // Client sends to server to request a connection
|
||||
)
|
||||
|
@ -8,17 +8,19 @@ import (
|
||||
|
||||
type AddPlayerPacket struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
HeroType d2enum.Hero `json:"hero"`
|
||||
Equipment d2inventory.CharacterEquipment `json:"equipment"`
|
||||
}
|
||||
|
||||
func CreateAddPlayerPacket(id string, x, y int, heroType d2enum.Hero, equipment d2inventory.CharacterEquipment) NetPacket {
|
||||
func CreateAddPlayerPacket(id, name string, x, y int, heroType d2enum.Hero, equipment d2inventory.CharacterEquipment) NetPacket {
|
||||
return NetPacket{
|
||||
PacketType: d2netpackettype.AddPlayer,
|
||||
PacketData: AddPlayerPacket{
|
||||
Id: id,
|
||||
Name: name,
|
||||
X: x,
|
||||
Y: y,
|
||||
HeroType: heroType,
|
||||
|
21
d2networking/d2netpacket/packet_player_connection_request.go
Normal file
21
d2networking/d2netpacket/packet_player_connection_request.go
Normal file
@ -0,0 +1,21 @@
|
||||
package d2netpacket
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
)
|
||||
|
||||
type PlayerConnectionRequestPacket struct {
|
||||
Id string `json:"id"`
|
||||
PlayerState *d2player.PlayerState `json:"gameState"`
|
||||
}
|
||||
|
||||
func CreatePlayerConnectionRequestPacket(id string, playerState *d2player.PlayerState) NetPacket {
|
||||
return NetPacket{
|
||||
PacketType: d2netpackettype.PlayerConnectionRequest,
|
||||
PacketData: PlayerConnectionRequestPacket{
|
||||
Id: id,
|
||||
PlayerState: playerState,
|
||||
},
|
||||
}
|
||||
}
|
@ -1,9 +1,14 @@
|
||||
package d2server
|
||||
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
)
|
||||
|
||||
type ClientConnection interface {
|
||||
GetUniqueId() string
|
||||
GetConnectionType() string
|
||||
SendPacketToClient(packet d2netpacket.NetPacket) error
|
||||
GetPlayerState() *d2player.PlayerState
|
||||
SetPlayerState(playerState *d2player.PlayerState)
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
package d2udpclientconnection
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"net"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
)
|
||||
|
||||
type UDPClientConnection struct {
|
||||
id string
|
||||
address *net.UDPAddr
|
||||
udpConnection *net.UDPConn
|
||||
playerState *d2player.PlayerState
|
||||
}
|
||||
|
||||
func CreateUDPClientConnection(udpConnection *net.UDPConn, id string, address *net.UDPAddr) *UDPClientConnection {
|
||||
result := &UDPClientConnection{
|
||||
id: id,
|
||||
address: address,
|
||||
udpConnection: udpConnection,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (u UDPClientConnection) GetUniqueId() string {
|
||||
return u.id
|
||||
}
|
||||
|
||||
func (u UDPClientConnection) GetConnectionType() string {
|
||||
return "Remote Client"
|
||||
}
|
||||
|
||||
func (u *UDPClientConnection) SendPacketToClient(packet d2netpacket.NetPacket) error {
|
||||
data, err := json.Marshal(packet.PacketData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var buff bytes.Buffer
|
||||
buff.WriteByte(byte(packet.PacketType))
|
||||
writer, _ := gzip.NewWriterLevel(&buff, gzip.BestCompression)
|
||||
writer.Write(data)
|
||||
writer.Close()
|
||||
u.udpConnection.WriteToUDP(buff.Bytes(), u.address)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *UDPClientConnection) SetPlayerState(playerState *d2player.PlayerState) {
|
||||
u.playerState = playerState
|
||||
}
|
||||
|
||||
func (u *UDPClientConnection) GetPlayerState() *d2player.PlayerState {
|
||||
return u.playerState
|
||||
}
|
@ -1,27 +1,37 @@
|
||||
package d2server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket/d2netpackettype"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2server/d2udpclientconnection"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2script"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
type GameServer struct {
|
||||
gameState *d2gamestate.GameState
|
||||
clientConnections map[string]ClientConnection
|
||||
mapEngines []*d2map.MapEngine
|
||||
scriptEngine *d2script.ScriptEngine
|
||||
udpConnection *net.UDPConn
|
||||
seed int64
|
||||
running bool
|
||||
}
|
||||
|
||||
var singletonServer *GameServer
|
||||
|
||||
func Create(gameStatePath string) {
|
||||
func Create(openNetworkServer bool) {
|
||||
log.Print("Creating GameServer")
|
||||
if singletonServer != nil {
|
||||
return
|
||||
@ -30,20 +40,95 @@ func Create(gameStatePath string) {
|
||||
singletonServer = &GameServer{
|
||||
clientConnections: make(map[string]ClientConnection),
|
||||
mapEngines: make([]*d2map.MapEngine, 0),
|
||||
gameState: d2gamestate.LoadGameState(gameStatePath),
|
||||
//gameState: d2player.LoadPlayerState(gameStatePath),
|
||||
scriptEngine: d2script.CreateScriptEngine(),
|
||||
seed: time.Now().UnixNano(),
|
||||
}
|
||||
|
||||
mapEngine := d2map.CreateMapEngine()
|
||||
mapEngine.GenerateMap(d2enum.RegionAct1Town, 1, 0, false)
|
||||
singletonServer.mapEngines = append(singletonServer.mapEngines, mapEngine)
|
||||
|
||||
singletonServer.scriptEngine.AddFunction("getMapEngines", func(call otto.FunctionCall) otto.Value {
|
||||
val, err := singletonServer.scriptEngine.ToValue(singletonServer.mapEngines)
|
||||
if err != nil {
|
||||
fmt.Print(err.Error())
|
||||
}
|
||||
return val
|
||||
})
|
||||
|
||||
if openNetworkServer {
|
||||
createNetworkServer()
|
||||
}
|
||||
}
|
||||
|
||||
func createNetworkServer() {
|
||||
s, err := net.ResolveUDPAddr("udp4", "0.0.0.0:6669")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
singletonServer.udpConnection, err = net.ListenUDP("udp4", s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
singletonServer.udpConnection.SetReadBuffer(4096)
|
||||
}
|
||||
|
||||
func runNetworkServer() {
|
||||
buffer := make([]byte, 4096)
|
||||
for singletonServer.running {
|
||||
_, addr, err := singletonServer.udpConnection.ReadFromUDP(buffer)
|
||||
if err != nil {
|
||||
fmt.Printf("Socket error: %s\n", err)
|
||||
continue
|
||||
}
|
||||
buff := bytes.NewBuffer(buffer)
|
||||
packetTypeId, err := buff.ReadByte()
|
||||
packetType := d2netpackettype.NetPacketType(packetTypeId)
|
||||
reader, err := gzip.NewReader(buff)
|
||||
sb := new(strings.Builder)
|
||||
io.Copy(sb, reader)
|
||||
stringData := sb.String()
|
||||
switch packetType {
|
||||
case d2netpackettype.PlayerConnectionRequest:
|
||||
packetData := d2netpacket.PlayerConnectionRequestPacket{}
|
||||
json.Unmarshal([]byte(stringData), &packetData)
|
||||
clientConnection := d2udpclientconnection.CreateUDPClientConnection(singletonServer.udpConnection, packetData.Id, addr)
|
||||
clientConnection.SetPlayerState(packetData.PlayerState)
|
||||
OnClientConnected(clientConnection)
|
||||
case d2netpackettype.MovePlayer:
|
||||
packetData := d2netpacket.MovePlayerPacket{}
|
||||
json.Unmarshal([]byte(stringData), &packetData)
|
||||
netPacket := d2netpacket.NetPacket{
|
||||
PacketType: packetType,
|
||||
PacketData: packetData,
|
||||
}
|
||||
|
||||
for _, player := range singletonServer.clientConnections {
|
||||
player.SendPacketToClient(netPacket)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func Run() {
|
||||
log.Print("Starting GameServer")
|
||||
singletonServer.running = true
|
||||
singletonServer.scriptEngine.RunScript("scripts/server/server.js")
|
||||
if singletonServer.udpConnection != nil {
|
||||
go runNetworkServer()
|
||||
}
|
||||
log.Print("Network server has been started")
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
log.Print("Stopping GameServer")
|
||||
singletonServer.running = false
|
||||
if singletonServer.udpConnection != nil {
|
||||
singletonServer.udpConnection.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func Destroy() {
|
||||
@ -55,17 +140,30 @@ func Destroy() {
|
||||
}
|
||||
|
||||
func OnClientConnected(client ClientConnection) {
|
||||
// Temporary position hack --------------------------------------------
|
||||
sx, sy := singletonServer.mapEngines[0].GetStartPosition() // TODO: Another temporary hack
|
||||
clientPlayerState := client.GetPlayerState()
|
||||
clientPlayerState.X = sx
|
||||
clientPlayerState.Y = sy
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
log.Printf("Client connected with an id of %s", client.GetUniqueId())
|
||||
singletonServer.clientConnections[client.GetUniqueId()] = client
|
||||
client.SendPacketToClient(d2netpacket.CreateUpdateServerInfoPacket(singletonServer.gameState.Seed, client.GetUniqueId()))
|
||||
client.SendPacketToClient(d2netpacket.CreateUpdateServerInfoPacket(singletonServer.seed, client.GetUniqueId()))
|
||||
client.SendPacketToClient(d2netpacket.CreateGenerateMapPacket(d2enum.RegionAct1Town, 1, 0))
|
||||
|
||||
// TODO: This needs to use a real method of loading characters instead of cloning the 'save file character'
|
||||
sx, sy := singletonServer.mapEngines[0].GetStartPosition() // TODO: Another temporary hack
|
||||
createPlayerPacket := d2netpacket.CreateAddPlayerPacket(client.GetUniqueId(), int(sx*5)+3, int(sy*5)+3,
|
||||
singletonServer.gameState.HeroType, singletonServer.gameState.Equipment)
|
||||
playerState := client.GetPlayerState()
|
||||
createPlayerPacket := d2netpacket.CreateAddPlayerPacket(client.GetUniqueId(), playerState.HeroName, int(sx*5)+3, int(sy*5)+3,
|
||||
playerState.HeroType, playerState.Equipment)
|
||||
for _, connection := range singletonServer.clientConnections {
|
||||
connection.SendPacketToClient(createPlayerPacket)
|
||||
if connection.GetUniqueId() == client.GetUniqueId() {
|
||||
continue
|
||||
}
|
||||
|
||||
conPlayerState := connection.GetPlayerState()
|
||||
client.SendPacketToClient(d2netpacket.CreateAddPlayerPacket(connection.GetUniqueId(), conPlayerState.HeroName,
|
||||
int(conPlayerState.X*5)+3, int(conPlayerState.Y*5)+3, conPlayerState.HeroType, conPlayerState.Equipment))
|
||||
}
|
||||
|
||||
}
|
||||
@ -79,6 +177,12 @@ func OnPacketReceived(client ClientConnection, packet d2netpacket.NetPacket) err
|
||||
switch packet.PacketType {
|
||||
case d2netpackettype.MovePlayer:
|
||||
// TODO: This needs to be verified on the server (here) before sending to other clients....
|
||||
// TODO: Hacky, this should be updated in realtime ----------------
|
||||
// TODO: Verify player id
|
||||
playerState := singletonServer.clientConnections[client.GetUniqueId()].GetPlayerState()
|
||||
playerState.X = packet.PacketData.(d2netpacket.MovePlayerPacket).DestX
|
||||
playerState.Y = packet.PacketData.(d2netpacket.MovePlayerPacket).DestY
|
||||
// ----------------------------------------------------------------
|
||||
for _, player := range singletonServer.clientConnections {
|
||||
player.SendPacketToClient(packet)
|
||||
}
|
||||
|
44
d2script/scriptengine.go
Normal file
44
d2script/scriptengine.go
Normal file
@ -0,0 +1,44 @@
|
||||
package d2script
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
_ "github.com/robertkrimen/otto/underscore" // This causes the runtime to support underscore.js
|
||||
)
|
||||
|
||||
type ScriptEngine struct {
|
||||
vm *otto.Otto
|
||||
}
|
||||
|
||||
func CreateScriptEngine() *ScriptEngine {
|
||||
result := &ScriptEngine{
|
||||
vm: otto.New(),
|
||||
}
|
||||
|
||||
result.vm.Set("debugPrint", func(call otto.FunctionCall) otto.Value {
|
||||
fmt.Printf("Script: %s\n", call.Argument(0).String())
|
||||
return otto.Value{}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *ScriptEngine) ToValue(source interface{}) (otto.Value, error) {
|
||||
return s.vm.ToValue(source)
|
||||
}
|
||||
|
||||
func (s *ScriptEngine) AddFunction(name string, value interface{}) {
|
||||
s.vm.Set(name, value)
|
||||
}
|
||||
|
||||
func (s *ScriptEngine) RunScript(fileName string) (*otto.Value, error) {
|
||||
fileData, _ := ioutil.ReadFile(fileName)
|
||||
val, err := s.vm.Run(string(fileData))
|
||||
if err != nil {
|
||||
fmt.Printf("Error running script: %s\n", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
return &val, nil
|
||||
}
|
2
go.mod
2
go.mod
@ -11,10 +11,12 @@ require (
|
||||
github.com/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200102072751-e66f1fb71e2e
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/pebbe/zmq4 v1.2.1 // indirect
|
||||
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff
|
||||
github.com/satori/go.uuid v1.2.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect
|
||||
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba // indirect
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777 // indirect
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||
gopkg.in/sourcemap.v1 v1.0.5 // indirect
|
||||
)
|
||||
|
32
go.sum
32
go.sum
@ -14,6 +14,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1 h1:LoN2wx/aN8JPGebG+2DaUyk4M+xRcqJXfuIbs8AWHdE=
|
||||
github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk=
|
||||
github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc=
|
||||
@ -22,12 +24,18 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw
|
||||
github.com/hajimehoshi/bitmapfont v1.2.0/go.mod h1:h9QrPk6Ktb2neObTlAbma6Ini1xgMjbJ3w7ysmD7IOU=
|
||||
github.com/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200102072751-e66f1fb71e2e h1:NRGAeXOSMrAo0f4GPaUoiF61eo0wWrfgONPSTZA6Zhg=
|
||||
github.com/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200102072751-e66f1fb71e2e/go.mod h1:0SLvfr8iI2NxzpNB/olBM+dLN9Ur5a9szG13wOgQ0nQ=
|
||||
github.com/hajimehoshi/ebiten v1.12.0-alpha.2.0.20200614175121-0b94e2e03645 h1:4h6uuzsCz94SOxvEZl+w8ICu90QHvn4l/G9VB7poNyw=
|
||||
github.com/hajimehoshi/ebiten v1.12.0-alpha.2.0.20200614175121-0b94e2e03645/go.mod h1:T+uHfxpwulzepUikvWZ4F0G9gt8RzZnrKjH6BgoWDgw=
|
||||
github.com/hajimehoshi/go-mp3 v0.2.1/go.mod h1:Rr+2P46iH6PwTPVgSsEwBkon0CK5DxCAeX/Rp65DCTE=
|
||||
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||
github.com/hajimehoshi/oto v0.3.4/go.mod h1:PgjqsBJff0efqL2nlMJidJgVJywLn6M4y8PI4TfeWfA=
|
||||
github.com/hajimehoshi/oto v0.5.4 h1:Dn+WcYeF310xqStKm0tnvoruYUV5Sce8+sfUaIvWGkE=
|
||||
github.com/hajimehoshi/oto v0.5.4/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto v0.6.1 h1:7cJz/zRQV4aJvMSSRqzN2TImoVVMpE0BCY4nrNJaDOM=
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/jakecoffman/cp v0.1.0/go.mod h1:a3xPx9N8RyFAACD644t2dj/nK4SuLg1v+jL61m2yVo4=
|
||||
github.com/jfreymuth/oggvorbis v1.0.0/go.mod h1:abe6F9QRjuU9l+2jek3gj46lu40N4qlYxh2grqkLEDM=
|
||||
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
|
||||
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@ -37,6 +45,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-sqlite3 v1.13.0 h1:LnJI81JidiW9r7pS/hXe6cFeO5EXNq7KbfvoJLRI69c=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pebbe/zmq4 v1.2.1 h1:jrXQW3mD8Si2mcSY/8VBs2nNkK/sKCOEM0rHAfxyc8c=
|
||||
github.com/pebbe/zmq4 v1.2.1/go.mod h1:7N4y5R18zBiu3l0vajMUWQgZyjv464prE8RCyBcmnZM=
|
||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||
@ -44,13 +53,17 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff h1:+6NUiITWwE5q1KO6SAfUX918c+Tab0+tGAM/mtdlUyA=
|
||||
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
|
||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw=
|
||||
@ -60,17 +73,26 @@ golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+o
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg=
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20191025110607-73ccc5ba0426/go.mod h1:p895TfNkDgPEmEQrNiOtIl3j98d/tGU95djDj7NfyjQ=
|
||||
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba h1:NVszahdZPQTROdO0F5gnXdZhGl2lXFb9w7Ek1F2Pbmk=
|
||||
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba/go.mod h1:p895TfNkDgPEmEQrNiOtIl3j98d/tGU95djDj7NfyjQ=
|
||||
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007 h1:JxsyO7zPDWn1rBZW8FV5RFwCKqYeXnyaS/VQPLpXu6I=
|
||||
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -78,16 +100,26 @@ golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777 h1:wejkGHRTr38uaKRqECZlsCsJ1/TGxIyFbH32x5zUdu4=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775 h1:TC0v2RSO1u2kn1ZugjrFXkRZAEaqMN/RW+OTZkBzmLE=
|
||||
golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190909214602-067311248421/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191026034945-b2104f82a97d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200330175517-31583a0dbbc8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
|
||||
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
4
main.go
4
main.go
@ -13,6 +13,8 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2script"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2gamescreen"
|
||||
@ -190,6 +192,8 @@ func initialize() error {
|
||||
|
||||
d2ui.Initialize()
|
||||
|
||||
d2script.CreateScriptEngine()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
1
scripts/server/server.js
Normal file
1
scripts/server/server.js
Normal file
@ -0,0 +1 @@
|
||||
debugPrint('Server script initialized.')
|
3
scripts/test.js
Normal file
3
scripts/test.js
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
// debugPrint(test())
|
||||
|
Loading…
Reference in New Issue
Block a user