mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-02 14:46:28 -05:00
Lint error cleanup1 (#779)
* fixed lint error in d2app/app.go * go fmt entire project * adding doc.go for d2records * fixed lint issues in d2core/d2map * fixed lint error in d2interface/palette.go * fixed lint error in d2core/d2hero/hero_state_factory.go * adding dov.go to d2common/d2geom * fixing lint errors in d2common/d2loader * adding doc.go to d2common/d2cache * adding doc files for d2datautils, d2util, d2path * adding package doc strings for mapgen, in-geam help screen, and tcp client connection * removed all cuddling lint errors * changed stamina equality check to '<=' instead of '<'
This commit is contained in:
parent
30b6f0cb4e
commit
783993470e
@ -636,8 +636,8 @@ func (a *App) ToCharacterSelect(connType d2clientconnectiontype.ClientConnection
|
||||
func (a *App) ToMapEngineTest(region, level int) {
|
||||
met, err := d2gamescreen.CreateMapEngineTest(region, level, a.asset, a.terminal, a.renderer, a.inputManager, a.audio, a.screen)
|
||||
if err != nil {
|
||||
return
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
a.screen.SetNextScreen(met)
|
||||
|
2
d2common/d2cache/doc.go
Normal file
2
d2common/d2cache/doc.go
Normal file
@ -0,0 +1,2 @@
|
||||
// Package d2cache provides a generic caching implementation
|
||||
package d2cache
|
3
d2common/d2datautils/doc.go
Normal file
3
d2common/d2datautils/doc.go
Normal file
@ -0,0 +1,3 @@
|
||||
// Package d2datautils is a utility package that provides helper functions/classes
|
||||
// for parsing the original diablo2 files. (eg. parsers for binary files that aren't byte-aligned)
|
||||
package d2datautils
|
@ -216,6 +216,7 @@ func (v *MPQ) loadBlockTable() {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
blockData[i] = binary.LittleEndian.Uint32(hash)
|
||||
}
|
||||
|
||||
|
@ -166,10 +166,12 @@ func (v *Stream) bufferData() {
|
||||
|
||||
func (v *Stream) loadSingleUnit() {
|
||||
fileData := make([]byte, v.BlockSize)
|
||||
|
||||
_, err := v.MPQData.file.Seek(int64(v.MPQData.data.HeaderSize), 0)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
_, err = v.MPQData.file.Read(fileData)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -204,6 +206,7 @@ func (v *Stream) loadBlock(blockIndex, expectedLength uint32) []byte {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
_, err = v.MPQData.file.Read(data)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -294,14 +297,13 @@ func deflate(data []byte) []byte {
|
||||
}
|
||||
|
||||
buffer := new(bytes.Buffer)
|
||||
_, err = buffer.ReadFrom(r)
|
||||
|
||||
_, err = buffer.ReadFrom(r)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
|
||||
err = r.Close()
|
||||
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
@ -318,14 +320,13 @@ func pkDecompress(data []byte) []byte {
|
||||
}
|
||||
|
||||
buffer := new(bytes.Buffer)
|
||||
_, err = buffer.ReadFrom(r)
|
||||
|
||||
_, err = buffer.ReadFrom(r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = r.Close()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
2
d2common/d2geom/doc.go
Normal file
2
d2common/d2geom/doc.go
Normal file
@ -0,0 +1,2 @@
|
||||
// Package d2geom is a utility package for anything related to geometry
|
||||
package d2geom
|
@ -17,6 +17,6 @@ type Color interface {
|
||||
// Palette is a color palette
|
||||
type Palette interface {
|
||||
NumColors() int
|
||||
GetColors() [256]Color
|
||||
GetColors() [numColors]Color
|
||||
GetColor(idx int) (Color, error)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package asset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader/asset/types"
|
||||
)
|
||||
|
||||
|
@ -81,6 +81,7 @@ func TestLoader_AddSource(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// nolint:gocyclo // this is just a test, not a big deal if we ignore linter here
|
||||
func TestLoader_Load(t *testing.T) {
|
||||
loader := NewLoader(nil)
|
||||
|
||||
@ -89,21 +90,25 @@ func TestLoader_Load(t *testing.T) {
|
||||
t.Fail()
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
_, err = loader.AddSource(sourcePathD)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
_, err = loader.AddSource(sourcePathA)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
_, err = loader.AddSource(sourcePathC)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
entryCommon, errCommon := loader.Load(commonFile) // common file exists in all three Sources
|
||||
|
||||
entryA, errA := loader.Load(exclusiveA) // each source has a file exclusive to itself
|
||||
|
2
d2common/d2path/doc.go
Normal file
2
d2common/d2path/doc.go
Normal file
@ -0,0 +1,2 @@
|
||||
// Package d2path is a utility package for functionality related to map entity pathing
|
||||
package d2path
|
@ -92,9 +92,11 @@ func (p *GlyphPrinter) drawDebugText(target *ebiten.Image, str string, ox, oy in
|
||||
|
||||
op.CompositeMode = ebiten.CompositeModeLighter
|
||||
err := target.DrawImage(s, op)
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
x += cw
|
||||
}
|
||||
}
|
||||
|
3
d2common/d2util/doc.go
Normal file
3
d2common/d2util/doc.go
Normal file
@ -0,0 +1,3 @@
|
||||
// Package d2util is a utility package for general-purpose functions used frequently throughout the
|
||||
// codebase.
|
||||
package d2util
|
@ -20,6 +20,7 @@ func ImgIndexToRGBA(indexData []byte, palette d2interface.Palette) []byte {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
colorData[i*bytesPerPixel] = c.R()
|
||||
colorData[i*bytesPerPixel+1] = c.G()
|
||||
colorData[i*bytesPerPixel+2] = c.B()
|
||||
|
@ -238,6 +238,7 @@ func (a *Animation) GetCurrentFrameSize() (width, height int) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
return width, height
|
||||
}
|
||||
|
||||
|
@ -28,16 +28,19 @@ type Button struct {
|
||||
|
||||
func (b *Button) onMouseButtonDown(_ d2interface.MouseEvent) bool {
|
||||
b.state = buttonStatePressed
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *Button) onMouseButtonUp(_ d2interface.MouseEvent) bool {
|
||||
b.state = buttonStateDefault
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *Button) onMouseLeave(_ d2interface.MouseMoveEvent) bool {
|
||||
b.state = buttonStateDefault
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ func createLabel(renderer d2interface.Renderer, text string, font *d2asset.Font)
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
label.SetVisible(true)
|
||||
|
||||
return label
|
||||
|
@ -54,6 +54,7 @@ func (f *HeroStateFactory) CreateHeroState(
|
||||
|
||||
defaultStats := f.asset.Records.Character.Stats[hero]
|
||||
skillState, err := f.CreateHeroSkillsState(defaultStats)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -109,7 +110,7 @@ func (f *HeroStateFactory) CreateHeroSkillsState(classStats *d2records.CharStats
|
||||
for idx := range classStats.BaseSkill {
|
||||
skillName := &classStats.BaseSkill[idx]
|
||||
|
||||
if len(*skillName) == 0 {
|
||||
if *skillName == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -149,6 +149,7 @@ func (f *ItemFactory) NewItem(codes ...string) (*Item, error) {
|
||||
}
|
||||
|
||||
item.factory = f
|
||||
|
||||
return item.init(), nil
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,7 @@ func (m *MapEngine) addDT1(fileName string) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
m.dt1TileData = append(m.dt1TileData, dt1.Tiles...)
|
||||
m.dt1Files = append(m.dt1Files, fileName)
|
||||
}
|
||||
|
@ -192,9 +192,11 @@ func (f *MapEntityFactory) NewNPC(x, y int, monstat *d2records.MonStatsRecord, d
|
||||
|
||||
composite, err := f.asset.LoadComposite(d2enum.ObjectTypeCharacter, monstat.AnimationDirectoryToken,
|
||||
d2resource.PaletteUnits)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.composite = composite
|
||||
|
||||
if err := composite.SetMode(d2enum.MonsterAnimationModeNeutral,
|
||||
|
@ -2,6 +2,7 @@ package d2mapentity
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
|
||||
@ -109,7 +110,7 @@ func (p *Player) Advance(tickTime float64) {
|
||||
// Drain and regenerate Stamina
|
||||
if p.IsRunning() && !p.atTarget() && !p.IsInTown() {
|
||||
p.Stats.Stamina -= float64(p.composite.AssetManager.Records.Character.Stats[p.Class].StaminaRunDrain) * tickTime / 5
|
||||
if p.Stats.Stamina < 0 {
|
||||
if p.Stats.Stamina <= 0 {
|
||||
p.SetSpeed(baseWalkSpeed)
|
||||
p.Stats.Stamina = 0
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// Package d2wilderness provides an enumeration of wilderness types
|
||||
package d2wilderness
|
||||
|
||||
// nolint: golint // these probably don't require individual explanations.
|
||||
|
@ -130,6 +130,7 @@ func (mr *MapRenderer) Render(target d2interface.Surface) {
|
||||
if mr.mapEngine.IsLoading {
|
||||
return
|
||||
}
|
||||
|
||||
mapSize := mr.mapEngine.Size()
|
||||
|
||||
stxf, styf := mr.viewport.ScreenToWorld(screenMiddleX, -200)
|
||||
|
@ -3,17 +3,17 @@ package d2maprenderer
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
)
|
||||
|
||||
func (mr *MapRenderer) generateTileCache() {
|
||||
var err error
|
||||
mr.palette, err = mr.loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
@ -88,6 +88,7 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord) {
|
||||
tileYOffset := d2math.AbsInt32(tileYMinimum)
|
||||
tileHeight := d2math.AbsInt32(tileData[i].Height)
|
||||
image, err := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight), d2enum.FilterNearest)
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
@ -100,6 +101,7 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
mr.setImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex, image)
|
||||
}
|
||||
}
|
||||
|
@ -13,16 +13,20 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||
)
|
||||
|
||||
// NewStampFactory creates a MapStamp factory instance
|
||||
func NewStampFactory(asset *d2asset.AssetManager, entity *d2mapentity.MapEntityFactory) *StampFactory {
|
||||
return &StampFactory{asset, entity}
|
||||
}
|
||||
|
||||
// StampFactory is responsible for loading map stamps. A stamp can be thought of like a
|
||||
// preset map configuration, like the various configurations of Act 1 town.
|
||||
type StampFactory struct {
|
||||
asset *d2asset.AssetManager
|
||||
entity *d2mapentity.MapEntityFactory
|
||||
}
|
||||
|
||||
// LoadStamp loads the Stamp data from file.
|
||||
// LoadStamp loads the Stamp data from file, using the given level type, level preset index, and
|
||||
// level file index.
|
||||
func (f *StampFactory) LoadStamp(levelType d2enum.RegionIdType, levelPreset, fileIndex int) *Stamp {
|
||||
stamp := &Stamp{
|
||||
factory: f,
|
||||
@ -33,7 +37,10 @@ func (f *StampFactory) LoadStamp(levelType d2enum.RegionIdType, levelPreset, fil
|
||||
}
|
||||
|
||||
for _, levelTypeDt1 := range &stamp.levelType.Files {
|
||||
if levelTypeDt1 != "" && levelTypeDt1 != "0" {
|
||||
if levelTypeDt1 == "" || levelTypeDt1 == "0" {
|
||||
continue
|
||||
}
|
||||
|
||||
fileData, err := f.asset.LoadFile("/data/global/tiles/" + levelTypeDt1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -47,7 +54,6 @@ func (f *StampFactory) LoadStamp(levelType d2enum.RegionIdType, levelPreset, fil
|
||||
|
||||
stamp.tiles = append(stamp.tiles, dt1.Tiles...)
|
||||
}
|
||||
}
|
||||
|
||||
var levelFilesToPick []string
|
||||
|
||||
|
8
d2core/d2records/doc.go
Normal file
8
d2core/d2records/doc.go
Normal file
@ -0,0 +1,8 @@
|
||||
// d2records provides a RecordManager implementation which is used to parse
|
||||
// the various txt files from the d2 mpq archives. Each data dictionary (txt file) is
|
||||
// parsed into slices or maps of structs. There is a struct type defined for each txt file.
|
||||
//
|
||||
// The RecordManager is a singleton that loads all of the txt files and export them as
|
||||
// data members. The RecordManager is meant to be used a a singleton member, exported by the
|
||||
// AssetManager in d2core/d2asset.
|
||||
package d2records
|
@ -277,7 +277,6 @@ func skillDetailsLoader(r *RecordManager, d *d2txt.DataDictionary) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
func animToEnum(anim string) d2enum.PlayerAnimationMode {
|
||||
switch anim {
|
||||
case "SC":
|
||||
|
@ -220,6 +220,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
btn.width += w
|
||||
}
|
||||
|
||||
@ -251,6 +252,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
|
||||
|
||||
func (v *Button) renderFrames(btnSprite *Sprite, btnLayout *ButtonLayout, label *Label) {
|
||||
var err error
|
||||
|
||||
totalButtonTypes := btnSprite.GetFrameCount() / (btnLayout.XSegments * btnLayout.YSegments)
|
||||
|
||||
err = btnSprite.RenderSegmented(v.normalSurface, btnLayout.XSegments, btnLayout.YSegments, btnLayout.BaseFrame)
|
||||
|
@ -26,6 +26,7 @@ type Checkbox struct {
|
||||
// NewCheckbox creates a new instance of a checkbox
|
||||
func (ui *UIManager) NewCheckbox(checkState bool) *Checkbox {
|
||||
var err error
|
||||
|
||||
result := &Checkbox{
|
||||
checkState: checkState,
|
||||
visible: true,
|
||||
@ -45,6 +46,7 @@ func (ui *UIManager) NewCheckbox(checkState bool) *Checkbox {
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
checkboxSprite.SetPosition(0, 0)
|
||||
|
||||
result.Image, err = ui.renderer.NewSurface(result.width, result.height, d2enum.FilterNearest)
|
||||
@ -84,6 +86,7 @@ func (v *Checkbox) bindManager(manager *UIManager) {
|
||||
// Render renders the checkbox
|
||||
func (v *Checkbox) Render(target d2interface.Surface) error {
|
||||
var err error
|
||||
|
||||
target.PushTranslation(v.x, v.y)
|
||||
defer target.Pop()
|
||||
|
||||
|
@ -53,6 +53,7 @@ func (ui *UIManager) addWidget(widget Widget) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
ui.widgets = append(ui.widgets, widget)
|
||||
|
||||
widget.bindManager(ui)
|
||||
|
@ -143,6 +143,7 @@ const (
|
||||
// OnLoad loads the resources for the Character Select screen
|
||||
func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
|
||||
var err error
|
||||
|
||||
v.audioProvider.PlayBGM(d2resource.BGMTitle)
|
||||
|
||||
if err := v.inputManager.BindHandler(v); err != nil {
|
||||
@ -152,10 +153,12 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
|
||||
loading.Progress(tenPercent)
|
||||
|
||||
bgX, bgY := 0, 0
|
||||
|
||||
v.background, err = v.uiManager.NewSprite(d2resource.CharacterSelectionBackground, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.background.SetPosition(bgX, bgY)
|
||||
|
||||
v.createButtons(loading)
|
||||
@ -178,6 +181,7 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
selBoxX, selBoxY := 37, 86
|
||||
v.selectionBox.SetPosition(selBoxX, selBoxY)
|
||||
|
||||
@ -185,6 +189,7 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
okCancelX, okCancelY := 270, 175
|
||||
v.okCancelBox.SetPosition(okCancelX, okCancelY)
|
||||
|
||||
@ -196,6 +201,7 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
offsetX, offsetY := rootLabelOffsetX, rootLabelOffsetY+((i/2)*95)
|
||||
|
||||
if i&1 > 0 {
|
||||
offsetX = 385
|
||||
}
|
||||
@ -205,10 +211,12 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
|
||||
v.characterNameLabel[i].Color[0] = rgbaColor(lightBrown)
|
||||
|
||||
offsetY += labelHeight
|
||||
|
||||
v.characterStatsLabel[i] = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.characterStatsLabel[i].SetPosition(offsetX, offsetY)
|
||||
|
||||
offsetY += labelHeight
|
||||
|
||||
v.characterExpLabel[i] = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteStatic)
|
||||
v.characterExpLabel[i].SetPosition(offsetX, offsetY)
|
||||
v.characterExpLabel[i].Color[0] = rgbaColor(lightGreen)
|
||||
@ -287,6 +295,7 @@ func (v *CharacterSelect) updateCharacterBoxes() {
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
idx := i + (v.charScrollbar.GetCurrentOffset() * 2)
|
||||
|
||||
if idx >= len(v.gameStates) {
|
||||
v.characterNameLabel[i].SetText("")
|
||||
v.characterStatsLabel[i].SetText("")
|
||||
@ -455,6 +464,7 @@ func (v *CharacterSelect) onDeleteCharacterConfirmClicked() {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.charScrollbar.SetCurrentOffset(0)
|
||||
v.refreshGameStates()
|
||||
v.toggleDeleteCharacterDialog(false)
|
||||
|
@ -90,10 +90,12 @@ func (v *Credits) LoadContributors() []string {
|
||||
// OnLoad is called to load the resources for the credits screen
|
||||
func (v *Credits) OnLoad(loading d2screen.LoadingState) {
|
||||
var err error
|
||||
|
||||
v.creditsBackground, err = v.uiManager.NewSprite(d2resource.CreditsBackground, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.creditsBackground.SetPosition(creditsX, creditsY)
|
||||
loading.Progress(twentyPercent)
|
||||
|
||||
|
@ -208,6 +208,7 @@ func (v *Game) Render(screen d2interface.Surface) error {
|
||||
// When help overlay is open, put transparent black screen. Magic noumber is hex for RGBA.
|
||||
screen.DrawRect(800, 600, d2util.Color(0x0000007f))
|
||||
}
|
||||
|
||||
if err := v.gameControls.Render(screen); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -183,28 +183,33 @@ func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
|
||||
|
||||
func (v *MainMenu) loadBackgroundSprites() {
|
||||
var err error
|
||||
|
||||
v.background, err = v.uiManager.NewSprite(d2resource.GameSelectScreen, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.background.SetPosition(backgroundX, backgroundY)
|
||||
|
||||
v.trademarkBackground, err = v.uiManager.NewSprite(d2resource.TrademarkScreen, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.trademarkBackground.SetPosition(backgroundX, backgroundY)
|
||||
|
||||
v.tcpIPBackground, err = v.uiManager.NewSprite(d2resource.TCPIPBackground, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.tcpIPBackground.SetPosition(backgroundX, backgroundY)
|
||||
|
||||
v.serverIPBackground, err = v.uiManager.NewSprite(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.serverIPBackground.SetPosition(serverIPbackgroundX, serverIPbackgroundY)
|
||||
}
|
||||
|
||||
@ -248,18 +253,22 @@ func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
||||
|
||||
v.tcpJoinGameLabel = v.uiManager.NewLabel(d2resource.Font16, d2resource.PaletteUnits)
|
||||
v.tcpJoinGameLabel.Alignment = d2gui.HorizontalAlignCenter
|
||||
|
||||
v.tcpJoinGameLabel.SetText("Enter Host IP Address\nto Join Game")
|
||||
|
||||
v.tcpJoinGameLabel.Color[0] = rgbaColor(gold)
|
||||
|
||||
v.tcpJoinGameLabel.SetPosition(joinGameX, joinGameY)
|
||||
}
|
||||
|
||||
func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
|
||||
var err error
|
||||
|
||||
v.diabloLogoLeft, err = v.uiManager.NewSprite(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.diabloLogoLeft.SetEffect(d2enum.DrawEffectModulate)
|
||||
v.diabloLogoLeft.PlayForward()
|
||||
v.diabloLogoLeft.SetPosition(diabloLogoX, diabloLogoY)
|
||||
@ -269,6 +278,7 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.diabloLogoRight.SetEffect(d2enum.DrawEffectModulate)
|
||||
v.diabloLogoRight.PlayForward()
|
||||
v.diabloLogoRight.SetPosition(diabloLogoX, diabloLogoY)
|
||||
@ -277,12 +287,14 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.diabloLogoLeftBack.SetPosition(diabloLogoX, diabloLogoY)
|
||||
|
||||
v.diabloLogoRightBack, err = v.uiManager.NewSprite(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
v.diabloLogoRightBack.SetPosition(diabloLogoX, diabloLogoY)
|
||||
}
|
||||
|
||||
|
@ -229,6 +229,7 @@ func (m *EscapeMenu) wrapLayout(fn func(*layout)) *layout {
|
||||
left := center.AddLayout(d2gui.PositionTypeVertical)
|
||||
left.SetSize(sidePanelsSize, pentSize)
|
||||
leftPent, err := left.AddAnimatedSprite(d2resource.PentSpin, d2resource.PaletteUnits, d2gui.DirectionBackward)
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
@ -248,6 +249,7 @@ func (m *EscapeMenu) wrapLayout(fn func(*layout)) *layout {
|
||||
right.AddSpacerStatic(sidePanelsSize-pentSize, 0)
|
||||
right.SetSize(sidePanelsSize, pentSize)
|
||||
rightPent, err := right.AddAnimatedSprite(d2resource.PentSpin, d2resource.PaletteUnits, d2gui.DirectionForward)
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
@ -290,12 +292,14 @@ func (m *EscapeMenu) addBigSelectionLabel(l *layout, text string, targetLayout l
|
||||
label.SetMouseEnterHandler(func(_ d2interface.MouseMoveEvent) {
|
||||
m.onHoverElement(elID)
|
||||
})
|
||||
|
||||
l.AddSpacerStatic(spacerWidth, labelGutter)
|
||||
l.actionableElements = append(l.actionableElements, label)
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) addPreviousMenuLabel(l *layout) {
|
||||
l.AddSpacerStatic(spacerWidth, labelGutter)
|
||||
|
||||
guiLabel, err := l.AddLabel("PREVIOUS MENU", d2gui.FontStyle30Units)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -330,7 +334,9 @@ func (m *EscapeMenu) addEnumLabel(l *layout, optID optionID, text string, values
|
||||
layout.SetMouseEnterHandler(func(_ d2interface.MouseMoveEvent) {
|
||||
m.onHoverElement(elID)
|
||||
})
|
||||
|
||||
layout.AddSpacerDynamic()
|
||||
|
||||
guiLabel, err := layout.AddLabel(values[0], d2gui.FontStyle30Units)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -350,11 +356,13 @@ func (m *EscapeMenu) addEnumLabel(l *layout, optID optionID, text string, values
|
||||
label.Trigger()
|
||||
})
|
||||
l.AddSpacerStatic(spacerWidth, labelGutter)
|
||||
|
||||
l.actionableElements = append(l.actionableElements, label)
|
||||
}
|
||||
|
||||
func (m *EscapeMenu) OnLoad() {
|
||||
var err error
|
||||
|
||||
m.selectSound, err = m.audioProvider.LoadSound(d2resource.SFXCursorSelect, false, false)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -415,6 +423,7 @@ func (m *EscapeMenu) onHoverElement(id int) {
|
||||
|
||||
x, _ := m.leftPent.GetPosition()
|
||||
m.leftPent.SetPosition(x, y+spacerWidth)
|
||||
|
||||
x, _ = m.rightPent.GetPosition()
|
||||
m.rightPent.SetPosition(x, y+spacerWidth)
|
||||
}
|
||||
@ -428,6 +437,7 @@ func (m *EscapeMenu) setLayout(id layoutID) {
|
||||
m.rightPent = m.layouts[id].rightPent
|
||||
m.currentLayout = id
|
||||
m.layouts[id].currentEl = len(m.layouts[id].actionableElements) - 1 // default to Previous Menu
|
||||
|
||||
m.guiManager.SetLayout(m.layouts[id].Layout)
|
||||
|
||||
// when first rendering a layout, widgets don't have offsets so we hide pentagrams for a frame
|
||||
@ -435,6 +445,7 @@ func (m *EscapeMenu) setLayout(id layoutID) {
|
||||
m.layouts[id].rendered = true
|
||||
m.leftPent.SetVisible(false)
|
||||
m.rightPent.SetVisible(false)
|
||||
|
||||
go func() {
|
||||
time.Sleep(16 * time.Millisecond)
|
||||
m.onHoverElement(m.layouts[id].currentEl)
|
||||
@ -454,6 +465,7 @@ func (m *EscapeMenu) onUpKey() {
|
||||
if m.layouts[m.currentLayout].currentEl == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
m.layouts[m.currentLayout].currentEl--
|
||||
m.onHoverElement(m.layouts[m.currentLayout].currentEl)
|
||||
}
|
||||
@ -466,6 +478,7 @@ func (m *EscapeMenu) onDownKey() {
|
||||
if m.layouts[m.currentLayout].currentEl == len(m.layouts[m.currentLayout].actionableElements)-1 {
|
||||
return
|
||||
}
|
||||
|
||||
m.layouts[m.currentLayout].currentEl++
|
||||
m.onHoverElement(m.layouts[m.currentLayout].currentEl)
|
||||
}
|
||||
|
@ -334,23 +334,28 @@ func (g *GameControls) OnKeyUp(event d2interface.KeyEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *GameControls) onEscKey() {
|
||||
// When escape is pressed:
|
||||
// 1. If there was some overlay or panel open, close it
|
||||
// 2. Otherwise, if the Escape Menu was open, let the Escape Menu handle it
|
||||
// 3. If nothing was open, open the Escape Menu
|
||||
|
||||
func (g *GameControls) onEscKey() {
|
||||
escHandled := false
|
||||
|
||||
if g.inventory.IsOpen() {
|
||||
g.inventory.Close()
|
||||
|
||||
escHandled = true
|
||||
}
|
||||
|
||||
if g.heroStatsPanel.IsOpen() {
|
||||
g.heroStatsPanel.Close()
|
||||
|
||||
escHandled = true
|
||||
}
|
||||
|
||||
if g.HelpOverlay.IsOpen() {
|
||||
g.HelpOverlay.Toggle()
|
||||
|
||||
escHandled = true
|
||||
}
|
||||
|
||||
@ -476,6 +481,7 @@ func (g *GameControls) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
||||
// Load the resources required for the GameControls
|
||||
func (g *GameControls) Load() {
|
||||
var err error
|
||||
|
||||
g.globeSprite, err = g.ui.NewSprite(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -495,6 +501,7 @@ func (g *GameControls) Load() {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
err = g.menuButton.SetCurrentFrame(2)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@ -1010,6 +1017,7 @@ func (g *GameControls) Render(target d2interface.Surface) error {
|
||||
g.nameLabel.SetPosition(255, 535)
|
||||
g.nameLabel.Render(target)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// Package help contains the in-game diablo2 help panel
|
||||
package help
|
||||
|
||||
import (
|
||||
@ -58,6 +59,7 @@ func NewHelpOverlay(
|
||||
|
||||
func (h *Overlay) Toggle() {
|
||||
fmt.Print("Help overlay toggled\n")
|
||||
|
||||
if h.isOpen {
|
||||
h.close()
|
||||
} else {
|
||||
@ -95,6 +97,7 @@ func (h *Overlay) IsInRect(px, py int) bool {
|
||||
if px >= x && px <= x+ww && py >= y && py <= y+hh {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@ -106,6 +109,7 @@ func (h *Overlay) Load() {
|
||||
prevX = 0
|
||||
prevY = 0
|
||||
)
|
||||
|
||||
for frameIndex := 0; frameIndex < 7; frameIndex++ {
|
||||
f, err := h.uiManager.NewSprite(d2resource.HelpBorder, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
@ -176,6 +180,7 @@ func (h *Overlay) Load() {
|
||||
// Bullets
|
||||
|
||||
yOffset := 59
|
||||
|
||||
h.createBullet(callout{
|
||||
LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp2"), "Ctrl"), // TODO "Ctrl" should be hotkey // "Hold Down <%s> to Run"
|
||||
LabelX: 100,
|
||||
@ -185,6 +190,7 @@ func (h *Overlay) Load() {
|
||||
})
|
||||
|
||||
yOffset += 20
|
||||
|
||||
h.createBullet(callout{
|
||||
LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp3"), "Alt"), // TODO "Alt" should be hotkey // "Hold down <%s> to highlight items on the ground"
|
||||
LabelX: 100,
|
||||
@ -194,6 +200,7 @@ func (h *Overlay) Load() {
|
||||
})
|
||||
|
||||
yOffset += 20
|
||||
|
||||
h.createBullet(callout{
|
||||
LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp4"), "Shift"), // TODO "Shift" should be hotkey // "Hold down <%s> to attack while standing still"
|
||||
LabelX: 100,
|
||||
@ -203,6 +210,7 @@ func (h *Overlay) Load() {
|
||||
})
|
||||
|
||||
yOffset += 20
|
||||
|
||||
h.createBullet(callout{
|
||||
LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp5"), "Tab"), // TODO "Tab" should be hotkey // "Hit <%s> to toggle the automap on and off"
|
||||
LabelX: 100,
|
||||
@ -212,6 +220,7 @@ func (h *Overlay) Load() {
|
||||
})
|
||||
|
||||
yOffset += 20
|
||||
|
||||
h.createBullet(callout{
|
||||
LabelText: d2tbl.TranslateString("StrHelp6"), // "Hit <Esc> to bring up the Game Menu"
|
||||
LabelX: 100,
|
||||
@ -221,6 +230,7 @@ func (h *Overlay) Load() {
|
||||
})
|
||||
|
||||
yOffset += 20
|
||||
|
||||
h.createBullet(callout{
|
||||
LabelText: d2tbl.TranslateString("StrHelp7"), // "Hit <Enter> to go into chat mode"
|
||||
LabelX: 100,
|
||||
@ -230,6 +240,7 @@ func (h *Overlay) Load() {
|
||||
})
|
||||
|
||||
yOffset += 20
|
||||
|
||||
h.createBullet(callout{
|
||||
LabelText: d2tbl.TranslateString("StrHelp8"), // "Hit F1-F8 to set your Left or Right Mouse Buttton Skills."
|
||||
LabelX: 100,
|
||||
@ -239,6 +250,7 @@ func (h *Overlay) Load() {
|
||||
})
|
||||
|
||||
yOffset += 20
|
||||
|
||||
h.createBullet(callout{
|
||||
LabelText: fmt.Sprintf(d2tbl.TranslateString("StrHelp8a"), "H"), // TODO "H" should be hotkey
|
||||
LabelX: 100,
|
||||
@ -391,7 +403,6 @@ func (h *Overlay) Load() {
|
||||
DotX: 530,
|
||||
DotY: 568,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
type line struct {
|
||||
@ -426,6 +437,7 @@ func (h *Overlay) createBullet(c callout) {
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
newDot.SetPosition(c.DotX, c.DotY+14)
|
||||
h.frames = append(h.frames, newDot)
|
||||
}
|
||||
@ -456,6 +468,7 @@ func (h *Overlay) createCallout(c callout) {
|
||||
MoveY: c.DotY - c.LabelY - hh - 5,
|
||||
Color: color.White,
|
||||
}
|
||||
|
||||
h.lines = append(h.lines, l)
|
||||
|
||||
newDot, err := h.uiManager.NewSprite(d2resource.HelpWhiteBullet, d2resource.PaletteSky)
|
||||
|
@ -80,6 +80,7 @@ func NewHeroStatsPanel(asset *d2asset.AssetManager, ui *d2ui.UIManager, heroName
|
||||
// Load the data for the hero status panel
|
||||
func (s *HeroStatsPanel) Load() {
|
||||
var err error
|
||||
|
||||
s.frame, err = s.uiManager.NewSprite(d2resource.Frame, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -123,6 +123,7 @@ func (g *ItemGrid) loadItem(item InventoryItem) {
|
||||
|
||||
// TODO: Put the pattern into D2Shared
|
||||
imgPath := fmt.Sprintf("/data/global/items/inv%s.dc6", item.GetItemCode())
|
||||
|
||||
itemSprite, err := g.uiManager.NewSprite(imgPath, d2resource.PaletteSky)
|
||||
if err != nil {
|
||||
log.Printf("Failed to load sprite, error: " + err.Error())
|
||||
@ -223,6 +224,7 @@ func (g *ItemGrid) renderItem(item InventoryItem, target d2interface.Surface, x,
|
||||
if itemSprite != nil {
|
||||
itemSprite.SetPosition(x, y)
|
||||
itemSprite.GetCurrentFrameSize()
|
||||
|
||||
err := itemSprite.Render(target)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -198,6 +198,7 @@ func (r *RemoteClientConnection) decodeToPacket(t d2netpackettype.NetPacketType,
|
||||
if err = json.Unmarshal([]byte(data), &p); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
np = d2netpacket.NetPacket{PacketType: t, PacketData: d2netpacket.MarshalPacket(p)}
|
||||
|
||||
case d2netpackettype.CastSkill:
|
||||
|
@ -279,6 +279,7 @@ func (g *GameClient) handleCastSkillPacket(packet d2netpacket.NetPacket) error {
|
||||
player.SetDirection(direction)
|
||||
|
||||
skillRecord := g.asset.Records.Skill.Details[playerCast.SkillID]
|
||||
|
||||
missileEntity, err := g.createMissileEntity(skillRecord, player, castX, castY)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -38,6 +38,7 @@ func CreateAddPlayerPacket(id, name string, x, y int, heroType d2enum.Hero,
|
||||
Stats: stats,
|
||||
Skills: skills,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(addPlayerPacket)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -21,6 +21,7 @@ func CreateGenerateMapPacket(regionType d2enum.RegionIdType) NetPacket {
|
||||
generateMapPacket := GenerateMapPacket{
|
||||
RegionType: regionType,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(generateMapPacket)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -22,6 +22,7 @@ func CreateSpawnItemPacket(x, y int, codes ...string) NetPacket {
|
||||
Y: y,
|
||||
Codes: codes,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(spawnItemPacket)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -28,6 +28,7 @@ func CreateMovePlayerPacket(playerID string, startX, startY, destX, destY float6
|
||||
DestX: destX,
|
||||
DestY: destY,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(movePlayerPacket)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -20,6 +20,7 @@ func CreatePingPacket() NetPacket {
|
||||
ping := PingPacket{
|
||||
TS: time.Now(),
|
||||
}
|
||||
|
||||
b, err := json.Marshal(ping)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -29,6 +29,7 @@ func CreateCastPacket(entityID string, skillID int, targetX, targetY float64) Ne
|
||||
TargetY: targetY,
|
||||
TargetEntityID: "", // TODO implement targeting entities
|
||||
}
|
||||
|
||||
b, err := json.Marshal(castPacket)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -23,6 +23,7 @@ func CreatePlayerConnectionRequestPacket(id string, playerState *d2hero.HeroStat
|
||||
ID: id,
|
||||
PlayerState: playerState,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(playerConnectionRequest)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -22,6 +22,7 @@ func CreatePlayerDisconnectRequestPacket(id string) NetPacket {
|
||||
playerDisconnectRequest := PlayerDisconnectRequestPacket{
|
||||
ID: id,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(playerDisconnectRequest)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -22,6 +22,7 @@ func CreatePongPacket(id string) NetPacket {
|
||||
ID: id,
|
||||
TS: time.Now(),
|
||||
}
|
||||
|
||||
b, err := json.Marshal(pong)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -20,6 +20,7 @@ func CreateServerClosedPacket() NetPacket {
|
||||
serverClosed := ServerClosedPacket{
|
||||
TS: time.Now(),
|
||||
}
|
||||
|
||||
b, err := json.Marshal(serverClosed)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -21,6 +21,7 @@ func CreateUpdateServerInfoPacket(seed int64, playerID string) NetPacket {
|
||||
Seed: seed,
|
||||
PlayerID: playerID,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(updateServerInfo)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
|
@ -1,3 +1,4 @@
|
||||
// Package d2tcpclientconnection provides a TCP protocol implementation of a client connection
|
||||
package d2tcpclientconnection
|
||||
|
||||
import (
|
||||
|
@ -3,12 +3,13 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2mpq"
|
||||
)
|
||||
|
||||
@ -17,6 +18,7 @@ func main() {
|
||||
outPath string
|
||||
verbose bool
|
||||
)
|
||||
|
||||
flag.StringVar(&outPath, "o", "./output/", "output directory")
|
||||
flag.BoolVar(&verbose, "v", false, "verbose output")
|
||||
flag.Parse()
|
||||
@ -28,6 +30,7 @@ func main() {
|
||||
|
||||
filename := flag.Arg(0)
|
||||
mpq, err := d2mpq.Load(filename)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -38,6 +41,7 @@ func main() {
|
||||
}
|
||||
|
||||
_, mpqFile := filepath.Split(strings.Replace(filename, "\\", "/", -1))
|
||||
|
||||
for _, filename := range list {
|
||||
extractFile(mpq, mpqFile, filename, outPath)
|
||||
|
||||
@ -67,6 +71,7 @@ func extractFile(mpq d2interface.Archive, mpqFile string, filename string, outPa
|
||||
log.Printf("failed to create file: %s, %v", filename, err)
|
||||
return
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
buf, err := mpq.ReadFile(filename)
|
||||
@ -74,6 +79,6 @@ func extractFile(mpq d2interface.Archive, mpqFile string, filename string, outPa
|
||||
log.Printf("failed to read file: %s, %v", filename, err)
|
||||
return
|
||||
}
|
||||
f.Write(buf)
|
||||
|
||||
f.Write(buf)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user