From 84c87b2eb808a5ff0d72640aebf20045a1e9060f Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Mon, 1 Feb 2021 12:53:32 +0100 Subject: [PATCH 1/6] data encoding: DC6 --- d2common/d2fileformats/d2dc6/dc6.go | 35 +++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/d2common/d2fileformats/d2dc6/dc6.go b/d2common/d2fileformats/d2dc6/dc6.go index 0ea28329..e903f022 100644 --- a/d2common/d2fileformats/d2dc6/dc6.go +++ b/d2common/d2fileformats/d2dc6/dc6.go @@ -146,6 +146,41 @@ func (d *DC6) loadFrames(r *d2datautils.StreamReader) error { return nil } +// Marshal encodes dc6 animation back into byte slice +func (d *DC6) Marshal() []byte { + sw := d2datautils.CreateStreamWriter() + + // Encode header + sw.PushInt32(d.Version) + sw.PushUint32(d.Flags) + sw.PushUint32(d.Encoding) + + sw.PushBytes(d.Termination...) + + sw.PushUint32(d.Directions) + sw.PushUint32(d.FramesPerDirection) + + // load frames + for _, i := range d.FramePointers { + sw.PushUint32(i) + } + + for i := range d.Frames { + sw.PushUint32(d.Frames[i].Flipped) + sw.PushUint32(d.Frames[i].Width) + sw.PushUint32(d.Frames[i].Height) + sw.PushInt32(d.Frames[i].OffsetX) + sw.PushInt32(d.Frames[i].OffsetY) + sw.PushUint32(d.Frames[i].Unknown) + sw.PushUint32(d.Frames[i].NextBlock) + sw.PushUint32(d.Frames[i].Length) + sw.PushBytes(d.Frames[i].FrameData...) + sw.PushBytes(d.Frames[i].Terminator...) + } + + return sw.GetBytes() +} + // DecodeFrame decodes the given frame to an indexed color texture func (d *DC6) DecodeFrame(frameIndex int) []byte { frame := d.Frames[frameIndex] From 2ebb36eba8604ff9af6ba9a90e3bf9963361748d Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Mon, 1 Feb 2021 20:56:23 +0100 Subject: [PATCH 2/6] fixed stream-writer's test bug --- d2common/d2datautils/stream_writer_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/d2common/d2datautils/stream_writer_test.go b/d2common/d2datautils/stream_writer_test.go index 126425b4..1f7dd95c 100644 --- a/d2common/d2datautils/stream_writer_test.go +++ b/d2common/d2datautils/stream_writer_test.go @@ -8,14 +8,12 @@ func TestStreamWriterByte(t *testing.T) { sr := CreateStreamWriter() data := []byte{0x12, 0x34, 0x56, 0x78} - for _, d := range data { - sr.PushByte(d) - } + sr.PushBytes(data...) output := sr.GetBytes() for i, d := range data { if output[i] != d { - t.Fatalf("sr.PushByte() pushed %X, but wrote %X instead", d, output[i]) + t.Fatalf("sr.PushBytes() pushed %X, but wrote %X instead", d, output[i]) } } } From 20f2649b653af2f7e3eb31408452712bde5db2fd Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Thu, 28 Jan 2021 11:20:59 +0100 Subject: [PATCH 3/6] asset manager: merged TranslateLabel to TranslateString --- d2common/d2enum/numeric_labels.go | 2 +- d2core/d2asset/asset_manager.go | 34 ++++++++++---------- d2core/d2ui/button.go | 4 +-- d2game/d2gamescreen/character_select.go | 10 +++--- d2game/d2gamescreen/cinematics.go | 4 +-- d2game/d2gamescreen/credits.go | 2 +- d2game/d2gamescreen/main_menu.go | 40 ++++++++++++------------ d2game/d2gamescreen/select_hero_class.go | 12 +++---- 8 files changed, 54 insertions(+), 54 deletions(-) diff --git a/d2common/d2enum/numeric_labels.go b/d2common/d2enum/numeric_labels.go index eb2253b6..8d8bd62c 100644 --- a/d2common/d2enum/numeric_labels.go +++ b/d2common/d2enum/numeric_labels.go @@ -1,6 +1,6 @@ package d2enum -// there are labels for "numeric labels (see AssetManager.TranslateLabel) +// there are labels for "numeric labels (see AssetManager.TranslateString) const ( RepairAll = iota _ diff --git a/d2core/d2asset/asset_manager.go b/d2core/d2asset/asset_manager.go index d6f0b3dd..99678238 100644 --- a/d2core/d2asset/asset_manager.go +++ b/d2core/d2asset/asset_manager.go @@ -64,17 +64,18 @@ const ( type AssetManager struct { *d2util.Logger *d2loader.Loader - tables []d2tbl.TextDictionary - dt1s d2interface.Cache - ds1s d2interface.Cache - cofs d2interface.Cache - dccs d2interface.Cache - animations d2interface.Cache - fonts d2interface.Cache - palettes d2interface.Cache - transforms d2interface.Cache - Records *d2records.RecordManager - language string + tables []d2tbl.TextDictionary + dt1s d2interface.Cache + ds1s d2interface.Cache + cofs d2interface.Cache + dccs d2interface.Cache + animations d2interface.Cache + fonts d2interface.Cache + palettes d2interface.Cache + transforms d2interface.Cache + Records *d2records.RecordManager + language string + languageModifier int } // SetLogLevel sets the log level for the asset manager, record manager, and file loader @@ -141,6 +142,7 @@ func (am *AssetManager) LoadLanguage(languagePath string) string { am.Infof("Language: %s", language) am.language = language + am.languageModifier = d2resource.GetLabelModifier(language) return language } @@ -287,7 +289,8 @@ func (am *AssetManager) LoadStringTable(tablePath string) (d2tbl.TextDictionary, } // TranslateString returns the translation of the given string. The string is retrieved from -// the loaded string tables. +// the loaded string tables. If input value is int (e.g. from d2enum/numeric_labels.go) +// output string is translation for # + input func (am *AssetManager) TranslateString(input interface{}) string { var key string @@ -296,6 +299,8 @@ func (am *AssetManager) TranslateString(input interface{}) string { key = s case fmt.Stringer: key = s.String() + case int: + key = fmt.Sprintf("#%d", d2enum.BaseLabelNumbers(s+am.languageModifier)) } for idx := range am.tables { @@ -309,11 +314,6 @@ func (am *AssetManager) TranslateString(input interface{}) string { return key } -// TranslateLabel translates the label taking into account its shift in the table -func (am *AssetManager) TranslateLabel(label int) string { - return am.TranslateString(fmt.Sprintf("#%d", d2enum.BaseLabelNumbers(label+d2resource.GetLabelModifier(am.language)))) -} - // LoadPaletteTransform loads a palette transform file func (am *AssetManager) LoadPaletteTransform(path string) (*d2pl2.PL2, error) { if pl2, found := am.transforms.Retrieve(path); found { diff --git a/d2core/d2ui/button.go b/d2core/d2ui/button.go index f3614941..f02e635d 100644 --- a/d2core/d2ui/button.go +++ b/d2core/d2ui/button.go @@ -923,7 +923,7 @@ func (v *Button) createTooltip() { t.SetText(v.manager.asset.TranslateString("strClose")) case buttonTooltipOk: t = v.manager.NewTooltip(d2resource.Font16, d2resource.PaletteSky, TooltipXCenter, TooltipYBottom) - t.SetText(v.manager.asset.TranslateLabel(d2enum.OKLabel)) + t.SetText(v.manager.asset.TranslateString(d2enum.OKLabel)) case buttonTooltipBuy: t = v.manager.NewTooltip(d2resource.Font16, d2resource.PaletteSky, TooltipXCenter, TooltipYBottom) t.SetText(v.manager.asset.TranslateString("NPCPurchaseItems")) @@ -935,7 +935,7 @@ func (v *Button) createTooltip() { t.SetText(v.manager.asset.TranslateString("NPCRepairItems")) case buttonTooltipRepairAll: t = v.manager.NewTooltip(d2resource.Font16, d2resource.PaletteSky, TooltipXCenter, TooltipYBottom) - t.SetText(v.manager.asset.TranslateLabel(d2enum.RepairAll)) + t.SetText(v.manager.asset.TranslateString(d2enum.RepairAll)) case buttonTooltipLeftArrow: t = v.manager.NewTooltip(d2resource.Font16, d2resource.PaletteSky, TooltipXCenter, TooltipYBottom) t.SetText(v.manager.asset.TranslateString("KeyLeft")) diff --git a/d2game/d2gamescreen/character_select.go b/d2game/d2gamescreen/character_select.go index feecc61a..0ea37a7a 100644 --- a/d2game/d2gamescreen/character_select.go +++ b/d2game/d2gamescreen/character_select.go @@ -229,7 +229,7 @@ func (v *CharacterSelect) loadHeroTitle() { func (v *CharacterSelect) loadDeleteCharConfirm() { v.deleteCharConfirmLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits) - lines := strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateLabel(d2enum.DelCharConfLabel), 29), "\n") + lines := strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateString(d2enum.DelCharConfLabel), 29), "\n") v.deleteCharConfirmLabel.SetText(lines) v.deleteCharConfirmLabel.Alignment = d2ui.HorizontalAlignCenter deleteConfirmX, deleteConfirmY := 400, 185 @@ -282,23 +282,23 @@ func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) { v.deleteCharButton.OnActivated(func() { v.onDeleteCharButtonClicked() }) v.deleteCharButton.SetPosition(deleteCharBtnX, deleteCharBtnY) - v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateLabel(d2enum.ExitLabel)) + v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateString(d2enum.ExitLabel)) v.exitButton.SetPosition(exitBtnX, exitBtnY) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) loading.Progress(twentyPercent) - v.deleteCharCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateLabel(d2enum.NoLabel)) + v.deleteCharCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateString(d2enum.NoLabel)) v.deleteCharCancelButton.SetPosition(deleteCancelX, deleteCancelY) v.deleteCharCancelButton.SetVisible(false) v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() }) - v.deleteCharOkButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateLabel(d2enum.YesLabel)) + v.deleteCharOkButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateString(d2enum.YesLabel)) v.deleteCharOkButton.SetPosition(deleteOkX, deleteOkY) v.deleteCharOkButton.SetVisible(false) v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() }) - v.okButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateLabel(d2enum.OKLabel)) + v.okButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateString(d2enum.OKLabel)) v.okButton.SetPosition(okBtnX, okBtnY) v.okButton.OnActivated(func() { v.onOkButtonClicked() }) } diff --git a/d2game/d2gamescreen/cinematics.go b/d2game/d2gamescreen/cinematics.go index de3c95e6..e6fe6fd8 100644 --- a/d2game/d2gamescreen/cinematics.go +++ b/d2game/d2gamescreen/cinematics.go @@ -97,14 +97,14 @@ func (v *Cinematics) OnLoad(_ d2screen.LoadingState) { v.cinematicsLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteStatic) v.cinematicsLabel.Alignment = d2ui.HorizontalAlignCenter - v.cinematicsLabel.SetText(v.asset.TranslateLabel(d2enum.SelectCinematicLabel)) + v.cinematicsLabel.SetText(v.asset.TranslateString(d2enum.SelectCinematicLabel)) v.cinematicsLabel.Color[0] = d2util.Color(lightBrown) v.cinematicsLabel.SetPosition(cinematicsLabelX, cinematicsLabelY) } func (v *Cinematics) createButtons() { v.cinematicsExitBtn = v.uiManager.NewButton(d2ui.ButtonTypeMedium, - v.asset.TranslateString(v.asset.TranslateLabel(d2enum.CancelLabel))) + v.asset.TranslateString(v.asset.TranslateString(d2enum.CancelLabel))) v.cinematicsExitBtn.SetPosition(cinematicsExitBtnX, cinematicsExitBtnY) v.cinematicsExitBtn.OnActivated(func() { v.onCinematicsExitBtnClicked() }) diff --git a/d2game/d2gamescreen/credits.go b/d2game/d2gamescreen/credits.go index eae3714f..d94b4720 100644 --- a/d2game/d2gamescreen/credits.go +++ b/d2game/d2gamescreen/credits.go @@ -106,7 +106,7 @@ func (v *Credits) OnLoad(loading d2screen.LoadingState) { v.creditsBackground.SetPosition(creditsX, creditsY) loading.Progress(twentyPercent) - v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateLabel(d2enum.ExitLabel)) + v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateString(d2enum.ExitLabel)) v.exitButton.SetPosition(charSelExitBtnX, charSelExitBtnY) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) loading.Progress(fourtyPercent) diff --git a/d2game/d2gamescreen/main_menu.go b/d2game/d2gamescreen/main_menu.go index 388275b9..238d073d 100644 --- a/d2game/d2gamescreen/main_menu.go +++ b/d2game/d2gamescreen/main_menu.go @@ -255,14 +255,14 @@ func (v *MainMenu) createMainMenuLabels(loading d2screen.LoadingState) { v.copyrightLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic) v.copyrightLabel.Alignment = d2ui.HorizontalAlignCenter - v.copyrightLabel.SetText(v.asset.TranslateLabel(d2enum.CopyrightLabel)) + v.copyrightLabel.SetText(v.asset.TranslateString(d2enum.CopyrightLabel)) v.copyrightLabel.Color[0] = d2util.Color(lightBrown) v.copyrightLabel.SetPosition(copyrightX, copyrightY) loading.Progress(thirtyPercent) v.copyrightLabel2 = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteStatic) v.copyrightLabel2.Alignment = d2ui.HorizontalAlignCenter - v.copyrightLabel2.SetText(v.asset.TranslateLabel(d2enum.AllRightsReservedLabel)) + v.copyrightLabel2.SetText(v.asset.TranslateString(d2enum.AllRightsReservedLabel)) v.copyrightLabel2.Color[0] = d2util.Color(lightBrown) v.copyrightLabel2.SetPosition(copyright2X, copyright2Y) @@ -284,24 +284,24 @@ func (v *MainMenu) createMultiplayerLabels() { v.tcpIPOptionsLabel = v.uiManager.NewLabel(d2resource.Font42, d2resource.PaletteUnits) v.tcpIPOptionsLabel.SetPosition(tcpOptionsX, tcpOptionsY) v.tcpIPOptionsLabel.Alignment = d2ui.HorizontalAlignCenter - v.tcpIPOptionsLabel.SetText(v.asset.TranslateLabel(d2enum.TCPIPOptionsLabel)) + v.tcpIPOptionsLabel.SetText(v.asset.TranslateString(d2enum.TCPIPOptionsLabel)) v.tcpJoinGameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits) v.tcpJoinGameLabel.Alignment = d2ui.HorizontalAlignCenter - v.tcpJoinGameLabel.SetText(strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateLabel(d2enum.TCPIPEnterHostIPLabel), 27), "\n")) + v.tcpJoinGameLabel.SetText(strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateString(d2enum.TCPIPEnterHostIPLabel), 27), "\n")) v.tcpJoinGameLabel.Color[0] = d2util.Color(gold) v.tcpJoinGameLabel.SetPosition(joinGameX, joinGameY) v.machineIP = v.uiManager.NewLabel(d2resource.Font24, d2resource.PaletteUnits) v.machineIP.Alignment = d2ui.HorizontalAlignCenter - v.machineIP.SetText(v.asset.TranslateLabel(d2enum.TCPIPYourIPLabel) + "\n" + v.getLocalIP()) + v.machineIP.SetText(v.asset.TranslateString(d2enum.TCPIPYourIPLabel) + "\n" + v.getLocalIP()) v.machineIP.Color[0] = d2util.Color(lightYellow) v.machineIP.SetPosition(machineIPX, machineIPY) v.hostTipLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteUnits) v.hostTipLabel.Alignment = d2ui.HorizontalAlignCenter v.hostTipLabel.SetText(d2ui.ColorTokenize(strings.Join(d2util.SplitIntoLinesWithMaxWidth( - v.asset.TranslateLabel(d2enum.TipHostLabel), 36), + v.asset.TranslateString(d2enum.TipHostLabel), 36), "\n"), d2ui.ColorTokenGold)) v.hostTipLabel.SetPosition(tipX, tipY) v.hostTipLabel.SetVisible(false) @@ -309,7 +309,7 @@ func (v *MainMenu) createMultiplayerLabels() { v.joinTipLabel = v.uiManager.NewLabel(d2resource.FontFormal12, d2resource.PaletteUnits) v.joinTipLabel.Alignment = d2ui.HorizontalAlignCenter v.joinTipLabel.SetText(d2ui.ColorTokenize(strings.Join(d2util.SplitIntoLinesWithMaxWidth( - v.asset.TranslateLabel(d2enum.TipJoinLabel), 36), + v.asset.TranslateString(d2enum.TipJoinLabel), 36), "\n"), d2ui.ColorTokenGold)) v.joinTipLabel.SetPosition(tipX, tipY) v.joinTipLabel.SetVisible(false) @@ -353,20 +353,20 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) { } func (v *MainMenu) createMainMenuButtons(loading d2screen.LoadingState) { - v.exitDiabloButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(d2enum.ExitGameLabel)) + v.exitDiabloButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateString(d2enum.ExitGameLabel)) v.exitDiabloButton.SetPosition(exitDiabloBtnX, exitDiabloBtnY) v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() }) - v.creditsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, v.asset.TranslateLabel(d2enum.CreditsLabel)) + v.creditsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, v.asset.TranslateString(d2enum.CreditsLabel)) v.creditsButton.SetPosition(creditBtnX, creditBtnY) v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() }) - v.cinematicsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, v.asset.TranslateLabel(d2enum.CinematicsLabel)) + v.cinematicsButton = v.uiManager.NewButton(d2ui.ButtonTypeShort, v.asset.TranslateString(d2enum.CinematicsLabel)) v.cinematicsButton.SetPosition(cineBtnX, cineBtnY) v.cinematicsButton.OnActivated(func() { v.onCinematicsButtonClicked() }) loading.Progress(seventyPercent) - v.singlePlayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(d2enum.SinglePlayerLabel)) + v.singlePlayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateString(d2enum.SinglePlayerLabel)) v.singlePlayerButton.SetPosition(singlePlayerBtnX, singlePlayerBtnY) v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() }) @@ -379,15 +379,15 @@ func (v *MainMenu) createMainMenuButtons(loading d2screen.LoadingState) { v.mapTestButton.OnActivated(func() { v.onMapTestClicked() }) v.btnTCPIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeMedium, - v.asset.TranslateLabel(d2enum.CancelLabel)) + v.asset.TranslateString(d2enum.CancelLabel)) v.btnTCPIPCancel.SetPosition(tcpBtnX, tcpBtnY) v.btnTCPIPCancel.OnActivated(func() { v.onTCPIPCancelClicked() }) - v.btnServerIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateLabel(d2enum.CancelLabel)) + v.btnServerIPCancel = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateString(d2enum.CancelLabel)) v.btnServerIPCancel.SetPosition(srvCancelBtnX, srvCancelBtnY) v.btnServerIPCancel.OnActivated(func() { v.onBtnTCPIPCancelClicked() }) - v.btnServerIPOk = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateLabel(d2enum.OKLabel)) + v.btnServerIPOk = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateString(d2enum.OKLabel)) v.btnServerIPOk.SetPosition(srvOkBtnX, srvOkBtnY) v.btnServerIPOk.OnActivated(func() { v.onBtnTCPIPOkClicked() }) loading.Progress(eightyPercent) @@ -395,26 +395,26 @@ func (v *MainMenu) createMainMenuButtons(loading d2screen.LoadingState) { func (v *MainMenu) createMultiplayerMenuButtons() { v.multiplayerButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, - v.asset.TranslateLabel(d2enum.OtherMultiplayerLabel)) + v.asset.TranslateString(d2enum.OtherMultiplayerLabel)) v.multiplayerButton.SetPosition(multiplayerBtnX, multiplayerBtnY) v.multiplayerButton.OnActivated(func() { v.onMultiplayerClicked() }) - v.networkTCPIPButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(d2enum.TCPIPGameLabel)) + v.networkTCPIPButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateString(d2enum.TCPIPGameLabel)) v.networkTCPIPButton.SetPosition(tcpNetBtnX, tcpNetBtnY) v.networkTCPIPButton.OnActivated(func() { v.onNetworkTCPIPClicked() }) v.networkCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeWide, - v.asset.TranslateLabel(d2enum.CancelLabel)) + v.asset.TranslateString(d2enum.CancelLabel)) v.networkCancelButton.SetPosition(networkCancelBtnX, networkCancelBtnY) v.networkCancelButton.OnActivated(func() { v.onNetworkCancelClicked() }) - v.btnTCPIPHostGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(d2enum.TCPIPHostGameLabel)) + v.btnTCPIPHostGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateString(d2enum.TCPIPHostGameLabel)) v.btnTCPIPHostGame.SetPosition(tcpHostBtnX, tcpHostBtnY) v.btnTCPIPHostGame.OnActivated(func() { v.onTCPIPHostGameClicked() }) v.btnTCPIPHostGame.OnHoverStart(func() { v.hostTipLabel.SetVisible(true) }) v.btnTCPIPHostGame.OnHoverEnd(func() { v.hostTipLabel.SetVisible(false) }) - v.btnTCPIPJoinGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateLabel(d2enum.TCPIPJoinGameLabel)) + v.btnTCPIPJoinGame = v.uiManager.NewButton(d2ui.ButtonTypeWide, v.asset.TranslateString(d2enum.TCPIPJoinGameLabel)) v.btnTCPIPJoinGame.SetPosition(tcpJoinBtnX, tcpJoinBtnY) v.btnTCPIPJoinGame.OnActivated(func() { v.onTCPIPJoinGameClicked() }) v.btnTCPIPJoinGame.OnHoverStart(func() { v.joinTipLabel.SetVisible(true) }) @@ -672,5 +672,5 @@ func (v *MainMenu) getLocalIP() string { v.Warning("no IPv4 Address could be found") - return v.asset.TranslateLabel(d2enum.IPNotFoundLabel) + return v.asset.TranslateString(d2enum.IPNotFoundLabel) } diff --git a/d2game/d2gamescreen/select_hero_class.go b/d2game/d2gamescreen/select_hero_class.go index 0f9efed6..c6591d5c 100644 --- a/d2game/d2gamescreen/select_hero_class.go +++ b/d2game/d2gamescreen/select_hero_class.go @@ -416,7 +416,7 @@ func (v *SelectHeroClass) createLabels() { halfFontWidth := fontWidth / half v.headingLabel.SetPosition(headingX-halfFontWidth, headingY) - v.headingLabel.SetText(v.asset.TranslateLabel(d2enum.SelectHeroClassLabel)) + v.headingLabel.SetText(v.asset.TranslateString(d2enum.SelectHeroClassLabel)) v.headingLabel.Alignment = d2ui.HorizontalAlignCenter v.heroClassLabel = v.uiManager.NewLabel(d2resource.Font30, d2resource.PaletteUnits) @@ -437,7 +437,7 @@ func (v *SelectHeroClass) createLabels() { v.heroNameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits) v.heroNameLabel.Alignment = d2ui.HorizontalAlignLeft - v.heroNameLabel.SetText(d2ui.ColorTokenize(v.asset.TranslateLabel(d2enum.CharNameLabel), d2ui.ColorTokenGold)) + v.heroNameLabel.SetText(d2ui.ColorTokenize(v.asset.TranslateString(d2enum.CharNameLabel), d2ui.ColorTokenGold)) v.heroNameLabel.SetPosition(heroNameLabelX, heroNameLabelY) v.expansionCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits) @@ -447,16 +447,16 @@ func (v *SelectHeroClass) createLabels() { v.hardcoreCharLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits) v.hardcoreCharLabel.Alignment = d2ui.HorizontalAlignLeft - v.hardcoreCharLabel.SetText(d2ui.ColorTokenize(v.asset.TranslateLabel(d2enum.HardCoreLabel), d2ui.ColorTokenGold)) + v.hardcoreCharLabel.SetText(d2ui.ColorTokenize(v.asset.TranslateString(d2enum.HardCoreLabel), d2ui.ColorTokenGold)) v.hardcoreCharLabel.SetPosition(hardcoreLabelX, hardcoreLabelY) } func (v *SelectHeroClass) createButtons() { - v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateLabel(d2enum.ExitLabel)) + v.exitButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateString(d2enum.ExitLabel)) v.exitButton.SetPosition(selHeroExitBtnX, selHeroExitBtnY) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) - v.okButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateLabel(d2enum.OKLabel)) + v.okButton = v.uiManager.NewButton(d2ui.ButtonTypeMedium, v.asset.TranslateString(d2enum.OKLabel)) v.okButton.SetPosition(selHeroOkBtnX, selHeroOkBtnY) v.okButton.OnActivated(func() { v.onOkButtonClicked() }) v.okButton.SetVisible(false) @@ -719,7 +719,7 @@ func (v *SelectHeroClass) setDescLabels(descKey int, key string) { if key != "" { heroDesc = v.asset.TranslateString(key) } else { - heroDesc = v.asset.TranslateLabel(descKey) + heroDesc = v.asset.TranslateString(descKey) } parts := d2util.SplitIntoLinesWithMaxWidth(heroDesc, heroDescCharWidth) From aea1d866905eafa815a2f4e068e6e1c19411f3e3 Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Tue, 2 Feb 2021 16:46:40 +0100 Subject: [PATCH 4/6] fixed lint error --- d2game/d2gamescreen/character_select.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/d2game/d2gamescreen/character_select.go b/d2game/d2gamescreen/character_select.go index 0ea37a7a..8a0ebc6f 100644 --- a/d2game/d2gamescreen/character_select.go +++ b/d2game/d2gamescreen/character_select.go @@ -288,7 +288,8 @@ func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) { loading.Progress(twentyPercent) - v.deleteCharCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, v.asset.TranslateString(d2enum.NoLabel)) + v.deleteCharCancelButton = v.uiManager.NewButton(d2ui.ButtonTypeOkCancel, + v.asset.TranslateString(d2enum.NoLabel)) v.deleteCharCancelButton.SetPosition(deleteCancelX, deleteCancelY) v.deleteCharCancelButton.SetVisible(false) v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() }) From ae77badd187c262ecacfdcd391ac783f90d26bff Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Tue, 2 Feb 2021 16:54:45 +0100 Subject: [PATCH 5/6] fixed lint error --- d2game/d2gamescreen/main_menu.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/d2game/d2gamescreen/main_menu.go b/d2game/d2gamescreen/main_menu.go index 238d073d..dcb1e2e2 100644 --- a/d2game/d2gamescreen/main_menu.go +++ b/d2game/d2gamescreen/main_menu.go @@ -288,7 +288,11 @@ func (v *MainMenu) createMultiplayerLabels() { v.tcpJoinGameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits) v.tcpJoinGameLabel.Alignment = d2ui.HorizontalAlignCenter - v.tcpJoinGameLabel.SetText(strings.Join(d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateString(d2enum.TCPIPEnterHostIPLabel), 27), "\n")) + v.tcpJoinGameLabel.SetText(strings.Join( + d2util.SplitIntoLinesWithMaxWidth(v.asset.TranslateString( + d2enum.TCPIPEnterHostIPLabel, + ), 27), "\n")) + v.tcpJoinGameLabel.Color[0] = d2util.Color(gold) v.tcpJoinGameLabel.SetPosition(joinGameX, joinGameY) From 9f9c882653bb2a796d487fcda3b1b9b17fff6542 Mon Sep 17 00:00:00 2001 From: "M. Sz" Date: Tue, 2 Feb 2021 19:25:27 +0100 Subject: [PATCH 6/6] data encoder: dt1 --- d2common/d2fileformats/d2dt1/block.go | 13 +- d2common/d2fileformats/d2dt1/dt1.go | 152 +++++++++++++++++---- d2common/d2fileformats/d2dt1/gfx_decode.go | 2 +- d2common/d2fileformats/d2dt1/material.go | 47 +++++++ d2common/d2fileformats/d2dt1/subtile.go | 39 ++++++ d2common/d2fileformats/d2dt1/tile.go | 4 + 6 files changed, 227 insertions(+), 30 deletions(-) diff --git a/d2common/d2fileformats/d2dt1/block.go b/d2common/d2fileformats/d2dt1/block.go index f463aae2..45e01917 100644 --- a/d2common/d2fileformats/d2dt1/block.go +++ b/d2common/d2fileformats/d2dt1/block.go @@ -2,12 +2,23 @@ package d2dt1 // Block represents a DT1 block type Block struct { + unknown1 []byte + unknown2 []byte X int16 Y int16 GridX byte GridY byte - Format BlockDataFormat + format int16 EncodedData []byte Length int32 FileOffset int32 } + +// Format returns block format +func (b *Block) Format() BlockDataFormat { + if b.format == 1 { + return BlockFormatIsometric + } + + return BlockFormatRLE +} diff --git a/d2common/d2fileformats/d2dt1/dt1.go b/d2common/d2fileformats/d2dt1/dt1.go index 3868f456..7dd5d218 100644 --- a/d2common/d2fileformats/d2dt1/dt1.go +++ b/d2common/d2fileformats/d2dt1/dt1.go @@ -2,15 +2,11 @@ package d2dt1 import ( "fmt" + "sort" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils" ) -// DT1 represents a DT1 file. -type DT1 struct { - Tiles []Tile -} - // BlockDataFormat represents the format of the block data type BlockDataFormat int16 @@ -32,6 +28,16 @@ const ( numUnknownTileBytes4 = 12 ) +// DT1 represents a DT1 file. +type DT1 struct { + majorVersion int32 + minorVersion int32 + unknownHeaderBytes []byte + numberOfTiles int32 + bodyPosition int32 + Tiles []Tile +} + // LoadDT1 loads a DT1 record //nolint:funlen,gocognit,gocyclo // Can't reduce func LoadDT1(fileData []byte) (*DT1, error) { @@ -40,36 +46,39 @@ func LoadDT1(fileData []byte) (*DT1, error) { var err error - majorVersion, err := br.ReadInt32() + result.majorVersion, err = br.ReadInt32() if err != nil { return nil, err } - minorVersion, err := br.ReadInt32() + result.minorVersion, err = br.ReadInt32() if err != nil { return nil, err } - if majorVersion != knownMajorVersion || minorVersion != knownMinorVersion { + if result.majorVersion != knownMajorVersion || result.minorVersion != knownMinorVersion { const fmtErr = "expected to have a version of 7.6, but got %d.%d instead" - return nil, fmt.Errorf(fmtErr, majorVersion, minorVersion) + return nil, fmt.Errorf(fmtErr, result.majorVersion, result.minorVersion) } - br.SkipBytes(numUnknownHeaderBytes) - - numberOfTiles, err := br.ReadInt32() + result.unknownHeaderBytes, err = br.ReadBytes(numUnknownHeaderBytes) if err != nil { return nil, err } - position, err := br.ReadInt32() + result.numberOfTiles, err = br.ReadInt32() if err != nil { return nil, err } - br.SetPosition(uint64(position)) + result.bodyPosition, err = br.ReadInt32() + if err != nil { + return nil, err + } - result.Tiles = make([]Tile, numberOfTiles) + br.SetPosition(uint64(result.bodyPosition)) + + result.Tiles = make([]Tile, result.numberOfTiles) for tileIdx := range result.Tiles { tile := Tile{} @@ -103,7 +112,10 @@ func LoadDT1(fileData []byte) (*DT1, error) { return nil, err } - br.SkipBytes(numUnknownTileBytes1) + tile.unknown1, err = br.ReadBytes(numUnknownTileBytes1) + if err != nil { + return nil, err + } tile.Type, err = br.ReadInt32() if err != nil { @@ -125,7 +137,10 @@ func LoadDT1(fileData []byte) (*DT1, error) { return nil, err } - br.SkipBytes(numUnknownTileBytes2) + tile.unknown2, err = br.ReadBytes(numUnknownTileBytes2) + if err != nil { + return nil, err + } for i := range tile.SubTileFlags { var subtileFlagBytes byte @@ -138,7 +153,10 @@ func LoadDT1(fileData []byte) (*DT1, error) { tile.SubTileFlags[i] = NewSubTileFlags(subtileFlagBytes) } - br.SkipBytes(numUnknownTileBytes3) + tile.unknown3, err = br.ReadBytes(numUnknownTileBytes3) + if err != nil { + return nil, err + } tile.blockHeaderPointer, err = br.ReadInt32() if err != nil { @@ -159,7 +177,10 @@ func LoadDT1(fileData []byte) (*DT1, error) { tile.Blocks = make([]Block, numBlocks) - br.SkipBytes(numUnknownTileBytes4) + tile.unknown4, err = br.ReadBytes(numUnknownTileBytes4) + if err != nil { + return nil, err + } result.Tiles[tileIdx] = tile } @@ -179,7 +200,11 @@ func LoadDT1(fileData []byte) (*DT1, error) { return nil, err } - br.SkipBytes(2) //nolint:gomnd // Unknown data + //nolint:gomnd // Unknown data + result.Tiles[tileIdx].Blocks[blockIdx].unknown1, err = br.ReadBytes(2) + if err != nil { + return nil, err + } result.Tiles[tileIdx].Blocks[blockIdx].GridX, err = br.ReadByte() if err != nil { @@ -191,23 +216,21 @@ func LoadDT1(fileData []byte) (*DT1, error) { return nil, err } - formatValue, err := br.ReadInt16() + result.Tiles[tileIdx].Blocks[blockIdx].format, err = br.ReadInt16() if err != nil { return nil, err } - if formatValue == 1 { - result.Tiles[tileIdx].Blocks[blockIdx].Format = BlockFormatIsometric - } else { - result.Tiles[tileIdx].Blocks[blockIdx].Format = BlockFormatRLE - } - result.Tiles[tileIdx].Blocks[blockIdx].Length, err = br.ReadInt32() if err != nil { return nil, err } - br.SkipBytes(2) //nolint:gomnd // Unknown data + //nolint:gomnd // Unknown data + result.Tiles[tileIdx].Blocks[blockIdx].unknown2, err = br.ReadBytes(2) + if err != nil { + return nil, err + } result.Tiles[tileIdx].Blocks[blockIdx].FileOffset, err = br.ReadInt32() if err != nil { @@ -229,3 +252,76 @@ func LoadDT1(fileData []byte) (*DT1, error) { return result, nil } + +// Marshal encodes dt1 data back to byte slice +func (d *DT1) Marshal() []byte { + sw := d2datautils.CreateStreamWriter() + + // header + sw.PushInt32(d.majorVersion) + sw.PushInt32(d.minorVersion) + sw.PushBytes(d.unknownHeaderBytes...) + sw.PushInt32(d.numberOfTiles) + sw.PushInt32(d.bodyPosition) + + // Step 1 - encoding tiles headers + for i := 0; i < len(d.Tiles); i++ { + sw.PushInt32(d.Tiles[i].Direction) + sw.PushInt16(d.Tiles[i].RoofHeight) + sw.PushUint16(d.Tiles[i].MaterialFlags.Encode()) + sw.PushInt32(d.Tiles[i].Height) + sw.PushInt32(d.Tiles[i].Width) + sw.PushBytes(d.Tiles[i].unknown1...) + sw.PushInt32(d.Tiles[i].Type) + sw.PushInt32(d.Tiles[i].Style) + sw.PushInt32(d.Tiles[i].Sequence) + sw.PushInt32(d.Tiles[i].RarityFrameIndex) + sw.PushBytes(d.Tiles[i].unknown2...) + + for _, j := range d.Tiles[i].SubTileFlags { + sw.PushBytes(j.Encode()) + } + + sw.PushBytes(d.Tiles[i].unknown3...) + sw.PushInt32(d.Tiles[i].blockHeaderPointer) + sw.PushInt32(d.Tiles[i].blockHeaderSize) + sw.PushInt32(int32(len(d.Tiles[i].Blocks))) + sw.PushBytes(d.Tiles[i].unknown4...) + } + + // we must sort blocks first + blocks := make(map[int][]Block) + for i := range d.Tiles { + blocks[int(d.Tiles[i].blockHeaderPointer)] = d.Tiles[i].Blocks + } + + keys := make([]int, 0, len(blocks)) + for i := range blocks { + keys = append(keys, i) + } + + sort.Ints(keys) + + // Step 2 - encoding blocks + for i := 0; i < len(keys); i++ { + // Step 2.1 - encoding blocks' header + for j := range blocks[keys[i]] { + sw.PushInt16(blocks[keys[i]][j].X) + sw.PushInt16(blocks[keys[i]][j].Y) + sw.PushBytes(blocks[keys[i]][j].unknown1...) + sw.PushBytes(blocks[keys[i]][j].GridX) + sw.PushBytes(blocks[keys[i]][j].GridY) + sw.PushInt16(blocks[keys[i]][j].format) + sw.PushInt32(blocks[keys[i]][j].Length) + sw.PushBytes(blocks[keys[i]][j].unknown2...) + sw.PushInt32(blocks[keys[i]][j].FileOffset) + } + + // Step 2.2 - encoding blocks' data + for j := range blocks[keys[i]] { + sw.PushBytes(blocks[keys[i]][j].EncodedData...) + } + } + + return sw.GetBytes() +} diff --git a/d2common/d2fileformats/d2dt1/gfx_decode.go b/d2common/d2fileformats/d2dt1/gfx_decode.go index 1e20d7b4..c88e1dab 100644 --- a/d2common/d2fileformats/d2dt1/gfx_decode.go +++ b/d2common/d2fileformats/d2dt1/gfx_decode.go @@ -7,7 +7,7 @@ const ( // DecodeTileGfxData decodes tile graphics data for a slice of dt1 blocks func DecodeTileGfxData(blocks []Block, pixels *[]byte, tileYOffset, tileWidth int32) { for _, block := range blocks { - if block.Format == BlockFormatIsometric { + if block.Format() == BlockFormatIsometric { // 3D isometric decoding xjump := []int32{14, 12, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 12, 14} nbpix := []int32{4, 8, 12, 16, 20, 24, 28, 32, 28, 24, 20, 16, 12, 8, 4} diff --git a/d2common/d2fileformats/d2dt1/material.go b/d2common/d2fileformats/d2dt1/material.go index 27da3394..b514aeb6 100644 --- a/d2common/d2fileformats/d2dt1/material.go +++ b/d2common/d2fileformats/d2dt1/material.go @@ -30,3 +30,50 @@ func NewMaterialFlags(data uint16) MaterialFlags { Snow: data&0x0400 == 0x0400, } } + +// Encode encodes MaterialFlags back to uint16 +func (m *MaterialFlags) Encode() uint16 { + var b uint16 = 0x000 + + if m.Other { + b |= 0x0001 + } + + if m.Water { + b |= 0x0002 + } + + if m.WoodObject { + b |= 0x0004 + } + + if m.InsideStone { + b |= 0x0008 + } + + if m.OutsideStone { + b |= 0x0010 + } + + if m.Dirt { + b |= 0x0020 + } + + if m.Sand { + b |= 0x0040 + } + + if m.Wood { + b |= 0x0080 + } + + if m.Lava { + b |= 0x0100 + } + + if m.Snow { + b |= 0x0400 + } + + return b +} diff --git a/d2common/d2fileformats/d2dt1/subtile.go b/d2common/d2fileformats/d2dt1/subtile.go index 981ee681..47d66e03 100644 --- a/d2common/d2fileformats/d2dt1/subtile.go +++ b/d2common/d2fileformats/d2dt1/subtile.go @@ -77,3 +77,42 @@ func NewSubTileFlags(data byte) SubTileFlags { Unknown3: data&128 == 128, } } + +// Encode encodes SubTileFlags back to byte +func (s *SubTileFlags) Encode() byte { + var b byte + + if s.BlockWalk { + b |= 1 + } + + if s.BlockLOS { + b |= 2 + } + + if s.BlockJump { + b |= 4 + } + + if s.BlockPlayerWalk { + b |= 8 + } + + if s.Unknown1 { + b |= 16 + } + + if s.BlockLight { + b |= 32 + } + + if s.Unknown2 { + b |= 64 + } + + if s.Unknown3 { + b |= 128 + } + + return b +} diff --git a/d2common/d2fileformats/d2dt1/tile.go b/d2common/d2fileformats/d2dt1/tile.go index f0b61c3a..7d1afdd0 100644 --- a/d2common/d2fileformats/d2dt1/tile.go +++ b/d2common/d2fileformats/d2dt1/tile.go @@ -2,6 +2,10 @@ package d2dt1 // Tile is a representation of a map tile type Tile struct { + unknown1 []byte + unknown2 []byte + unknown3 []byte + unknown4 []byte Direction int32 RoofHeight int16 MaterialFlags MaterialFlags