diff --git a/d2s.go b/d2s.go index 624f231..03b6625 100644 --- a/d2s.go +++ b/d2s.go @@ -7,8 +7,10 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils" + "github.com/gucio321/d2d2s/d2scorpse" + "github.com/gucio321/d2d2s/d2senums" + "github.com/gucio321/d2d2s/d2sitems" "github.com/gucio321/d2d2s/datautils" - "github.com/gucio321/d2d2s/enums" ) const ( @@ -35,7 +37,7 @@ type D2S struct { Status *Status Progression byte unknown2 uint16 - Class enums.CharacterClass + Class d2senums.CharacterClass unknown3 uint16 Level byte unknown4 uint32 @@ -57,8 +59,8 @@ type D2S struct { NPC *NPC Stats *Stats Skills [numSkills]SkillID - Items *Items - Corpse *Corpse + Items *d2sitems.Items + Corpse *d2scorpse.Corpse // necromancer only IronGolem *IronGolem } @@ -73,8 +75,8 @@ func New() *D2S { Waypoints: NewWaypoints(), NPC: &NPC{}, Stats: &Stats{}, - Items: &Items{}, - Corpse: &Corpse{}, + Items: &d2sitems.Items{}, + Corpse: d2scorpse.New(), IronGolem: &IronGolem{}, } @@ -125,7 +127,7 @@ func Unmarshal(data []byte) (*D2S, error) { result.unknown2 = sr.GetUInt16() class := sr.GetByte() - result.Class = enums.CharacterClass(class) + result.Class = d2senums.CharacterClass(class) result.unknown3 = sr.GetUInt16() @@ -230,16 +232,16 @@ func Unmarshal(data []byte) (*D2S, error) { numItems, err := result.Items.LoadHeader(sr) if err != nil { - return nil, err + return nil, fmt.Errorf("error loading items header: %w", err) } if err := result.Items.LoadList(sr, numItems); err != nil { - return nil, err + return nil, fmt.Errorf("error loading items list: %w", err) } // thanks to @nokka for figuring out these fields! if err := result.Corpse.Load(sr); err != nil { - return nil, err + return nil, fmt.Errorf("error loading corpse: %w", err) } if result.Status.Expansion { @@ -249,7 +251,7 @@ func Unmarshal(data []byte) (*D2S, error) { } // iron golem for necromancer - if result.Class == enums.CharacterClassNecromancer && result.Status.Expansion { + if result.Class == d2senums.CharacterClassNecromancer && result.Status.Expansion { if err := result.IronGolem.Load(sr); err != nil { return nil, err } @@ -340,12 +342,12 @@ func (d *D2S) Encode() ([]byte, error) { sw.PushBytes(d.Items.Encode()...) if err := d.Corpse.Encode(sw); err != nil { - return nil, err + return nil, fmt.Errorf("error encoding corpse: %w", err) } d.Mercenary.Encode(sw) - if d.Class == enums.CharacterClassNecromancer && d.Status.Expansion { + if d.Class == d2senums.CharacterClassNecromancer && d.Status.Expansion { d.IronGolem.Encode(sw) } diff --git a/corpse.go b/d2scorpse/corpse.go similarity index 81% rename from corpse.go rename to d2scorpse/corpse.go index 53746df..cde05ca 100644 --- a/corpse.go +++ b/d2scorpse/corpse.go @@ -1,4 +1,4 @@ -package d2d2s +package d2scorpse import ( "errors" @@ -6,15 +6,23 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils" + "github.com/gucio321/d2d2s/d2sitems" "github.com/gucio321/d2d2s/datautils" ) const corpseUnknownBytesCount = 12 +// New creates a new corpse data +func New() *Corpse { + result := &Corpse{} + + return result +} + // Corpse represents a ... corpse ?! type Corpse struct { unknown [corpseUnknownBytesCount]byte - Items *Items + Items *d2sitems.Items } // Load loads corpse @@ -33,11 +41,11 @@ func (c *Corpse) Load(sr *datautils.BitMuncher) error { unknown := sr.GetBytes(corpseUnknownBytesCount) copy(c.unknown[:], unknown[:corpseUnknownBytesCount]) - c.Items = &Items{} + c.Items = &d2sitems.Items{} numItems, err := c.Items.LoadHeader(sr) if err != nil { - return err + return fmt.Errorf("error loading items header: %w", err) } if err := c.Items.LoadList(sr, numItems); err != nil { diff --git a/d2scorpse/doc.go b/d2scorpse/doc.go new file mode 100644 index 0000000..afaeeca --- /dev/null +++ b/d2scorpse/doc.go @@ -0,0 +1,3 @@ +// Package d2scorpse contains Corpse structure for storing +// data about items in a character's corpse +package d2scorpse diff --git a/enums/class.go b/d2senums/class.go similarity index 95% rename from enums/class.go rename to d2senums/class.go index 0f78e8a..799828e 100644 --- a/enums/class.go +++ b/d2senums/class.go @@ -1,4 +1,4 @@ -package enums +package d2senums //go:generate stringer -type CharacterClass -trimprefix CharacterClass -linecomment -output class_string.go diff --git a/enums/class_string.go b/d2senums/class_string.go similarity index 98% rename from enums/class_string.go rename to d2senums/class_string.go index df18b9f..b6362cc 100644 --- a/enums/class_string.go +++ b/d2senums/class_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type CharacterClass -trimprefix CharacterClass -linecomment -output class_string.go"; DO NOT EDIT. -package enums +package d2senums import "strconv" diff --git a/enums/doc.go b/d2senums/doc.go similarity index 76% rename from enums/doc.go rename to d2senums/doc.go index 2f08a48..e15aac2 100644 --- a/enums/doc.go +++ b/d2senums/doc.go @@ -1,2 +1,2 @@ // Package enums contains enumerations used in project -package enums +package d2senums diff --git a/enums/equipped_place_string.go b/d2senums/equipped_place_string.go similarity index 98% rename from enums/equipped_place_string.go rename to d2senums/equipped_place_string.go index 74751b1..ae4b2ac 100644 --- a/enums/equipped_place_string.go +++ b/d2senums/equipped_place_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -linecomment -type ItemEquippedPlace -output equipped_place_string.go"; DO NOT EDIT. -package enums +package d2senums import "strconv" diff --git a/enums/item_quality.go b/d2senums/item_quality.go similarity index 98% rename from enums/item_quality.go rename to d2senums/item_quality.go index f827cbe..7ff06a0 100644 --- a/enums/item_quality.go +++ b/d2senums/item_quality.go @@ -1,4 +1,4 @@ -package enums +package d2senums //go:generate stringer -linecomment -type ItemQuality -output item_quality_string.go //go:generate stringer -linecomment -type LowQualityItemType -output low_quality_string.go diff --git a/enums/item_quality_string.go b/d2senums/item_quality_string.go similarity index 98% rename from enums/item_quality_string.go rename to d2senums/item_quality_string.go index dff2a8e..1fe4d3d 100644 --- a/enums/item_quality_string.go +++ b/d2senums/item_quality_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -linecomment -type ItemQuality -output item_quality_string.go"; DO NOT EDIT. -package enums +package d2senums import "strconv" diff --git a/enums/location.go b/d2senums/location.go similarity index 99% rename from enums/location.go rename to d2senums/location.go index a3cf03e..acc411e 100644 --- a/enums/location.go +++ b/d2senums/location.go @@ -1,4 +1,4 @@ -package enums +package d2senums //go:generate stringer -linecomment -type ItemLocationType -output location_type_string.go //go:generate stringer -linecomment -type StoragePlace -output storage_place_string.go diff --git a/enums/location_type_string.go b/d2senums/location_type_string.go similarity index 98% rename from enums/location_type_string.go rename to d2senums/location_type_string.go index dfb550d..f377181 100644 --- a/enums/location_type_string.go +++ b/d2senums/location_type_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -linecomment -type ItemLocationType -output location_type_string.go"; DO NOT EDIT. -package enums +package d2senums import "strconv" diff --git a/enums/low_quality_string.go b/d2senums/low_quality_string.go similarity index 98% rename from enums/low_quality_string.go rename to d2senums/low_quality_string.go index a1e1450..2bf42bb 100644 --- a/enums/low_quality_string.go +++ b/d2senums/low_quality_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -linecomment -type LowQualityItemType -output low_quality_string.go"; DO NOT EDIT. -package enums +package d2senums import "strconv" diff --git a/enums/storage_place_string.go b/d2senums/storage_place_string.go similarity index 98% rename from enums/storage_place_string.go rename to d2senums/storage_place_string.go index deee82b..0d08c4b 100644 --- a/enums/storage_place_string.go +++ b/d2senums/storage_place_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -linecomment -type StoragePlace -output storage_place_string.go"; DO NOT EDIT. -package enums +package d2senums import "strconv" diff --git a/d2sitems/d2smagicattributes/doc.go b/d2sitems/d2smagicattributes/doc.go new file mode 100644 index 0000000..ff5bac0 --- /dev/null +++ b/d2sitems/d2smagicattributes/doc.go @@ -0,0 +1,3 @@ +// Package d2smagicattributes contains MagicAttributes structure +// used for storing item's magic attributes +package d2smagicattributes diff --git a/magic_attributs.go b/d2sitems/d2smagicattributes/magic_attributs.go similarity index 95% rename from magic_attributs.go rename to d2sitems/d2smagicattributes/magic_attributs.go index 7e81788..dd4fe5a 100644 --- a/magic_attributs.go +++ b/d2sitems/d2smagicattributes/magic_attributs.go @@ -1,10 +1,10 @@ -package d2d2s +package d2smagicattributes import ( "errors" + "github.com/gucio321/d2d2s/d2sitems/itemdata" "github.com/gucio321/d2d2s/datautils" - "github.com/gucio321/d2d2s/itemdata" ) const endOfListMark = 0x1ff diff --git a/d2sitems/doc.go b/d2sitems/doc.go new file mode 100644 index 0000000..b0c42d7 --- /dev/null +++ b/d2sitems/doc.go @@ -0,0 +1,3 @@ +// Package d2sitems provides Items structure, where the main package +// stores Character's items data +package d2sitems diff --git a/itemdata/item.go b/d2sitems/itemdata/item.go similarity index 100% rename from itemdata/item.go rename to d2sitems/itemdata/item.go diff --git a/items.go b/d2sitems/items.go similarity index 88% rename from items.go rename to d2sitems/items.go index 2f4e112..41c2f37 100644 --- a/items.go +++ b/d2sitems/items.go @@ -1,4 +1,4 @@ -package d2d2s +package d2sitems import ( "errors" @@ -6,9 +6,10 @@ import ( "log" "strings" + "github.com/gucio321/d2d2s/d2senums" + "github.com/gucio321/d2d2s/d2sitems/d2smagicattributes" + "github.com/gucio321/d2d2s/d2sitems/itemdata" "github.com/gucio321/d2d2s/datautils" - "github.com/gucio321/d2d2s/enums" - "github.com/gucio321/d2d2s/itemdata" ) const ( @@ -145,16 +146,16 @@ type Item struct { Etheral bool Version byte // byte Location struct { - LocationID enums.ItemLocationType // 3 bits - EquippedID enums.ItemEquippedPlace // 4 bits - X byte // 4 bits - Y byte // 3 bits - StorageID enums.StoragePlace // 3 bits + LocationID d2senums.ItemLocationType // 3 bits + EquippedID d2senums.ItemEquippedPlace // 4 bits + X byte // 4 bits + Y byte // 3 bits + StorageID d2senums.StoragePlace // 3 bits } Ear struct { - Class enums.CharacterClass // 3 bits - Level byte // 7 bits - Name string // len(Name) * 7 bits + Class d2senums.CharacterClass // 3 bits + Level byte // 7 bits + Name string // len(Name) * 7 bits } Type string TypeID itemdata.ItemTypeID @@ -169,9 +170,9 @@ type Item struct { NumberOfItemsInSockets byte // 3 bits // Part 2; extended - ID uint32 // 32 bits (just uint32) - Level byte // 7 bits - Quality enums.ItemQuality // 4 bits + ID uint32 // 32 bits (just uint32) + Level byte // 7 bits + Quality d2senums.ItemQuality // 4 bits MultiplePicture struct { HasMultiplePicture bool // 1 bit ID byte // 7 bits @@ -197,7 +198,7 @@ type Item struct { SetName string SetListID byte // 5 bits SetListCount uint64 - SetAttributes []MagicAttributes + SetAttributes []d2smagicattributes.MagicAttributes UniqueID uint16 // 12 bits UniqueName string @@ -207,7 +208,7 @@ type Item struct { ID uint16 // 12 bits Name string unknown byte // 4 bits (brobably always value 5) - Attributes MagicAttributes + Attributes d2smagicattributes.MagicAttributes } Personalization struct { IsPersonalized bool @@ -227,7 +228,7 @@ type Item struct { TotalNumberOfSockets byte // 4 bits } - Attributes MagicAttributes + Attributes d2smagicattributes.MagicAttributes SocketedItems []Item } @@ -253,7 +254,7 @@ func (i *Item) Load(sr *datautils.BitMuncher) (err error) { func (i *Item) loadExtendedFields(sr *datautils.BitMuncher) (err error) { i.ID = sr.GetUInt32() // probably 4 * 8 chars i.Level = byte(sr.GetBits(levelLen)) - i.Quality = enums.ItemQuality(sr.GetBits(qualityLen)) + i.Quality = d2senums.ItemQuality(sr.GetBits(qualityLen)) // multiple picture i.MultiplePicture.HasMultiplePicture = sr.GetBit() == 1 @@ -269,13 +270,13 @@ func (i *Item) loadExtendedFields(sr *datautils.BitMuncher) (err error) { } switch i.Quality { - case enums.ItemQualityLow: + case d2senums.ItemQualityLow: i.QualityData.LowQualityID = byte(sr.GetBits(lowQualityIDLen)) - case enums.ItemQualityNormal: + case d2senums.ItemQualityNormal: // noop - case enums.ItemQualityHigh: + case d2senums.ItemQualityHigh: i.QualityData.HighQualityData = byte(sr.GetBits(highQualityDataLen)) - case enums.ItemQualityEnchanced: + case d2senums.ItemQualityEnchanced: i.QualityData.MagicPrefix = make([]MagicModifier, 1) id := uint16(sr.GetBits(magicModifierIDLen)) // helper variable (avoid noise with x.y.z.id ;-) i.QualityData.MagicPrefix[0].ID = id @@ -293,7 +294,7 @@ func (i *Item) loadExtendedFields(sr *datautils.BitMuncher) (err error) { if ok { i.QualityData.MagicSuffix[0].Name = suffixName } - case enums.ItemQualitySet: + case d2senums.ItemQualitySet: id := uint16(sr.GetBits(setIDLen)) i.QualityData.SetID = id setName, ok := itemdata.SetNames[id] @@ -301,7 +302,7 @@ func (i *Item) loadExtendedFields(sr *datautils.BitMuncher) (err error) { if ok { i.QualityData.SetName = setName } - case enums.ItemQualityRare, enums.ItemQualityCrafted: + case d2senums.ItemQualityRare, d2senums.ItemQualityCrafted: i.QualityData.RareNames = make([]MagicModifier, 2) for n := 0; n < 2; n++ { @@ -342,7 +343,7 @@ func (i *Item) loadExtendedFields(sr *datautils.BitMuncher) (err error) { } } } - case enums.ItemQualityUnique: + case d2senums.ItemQualityUnique: id := uint16(sr.GetBits(uniqueIDLen)) i.QualityData.UniqueID = id uniqueName, ok := itemdata.UniqueNames[id] @@ -410,7 +411,7 @@ func (i *Item) loadExtendedFields(sr *datautils.BitMuncher) (err error) { } var setListValue byte - if i.Quality == enums.ItemQualitySet { + if i.Quality == d2senums.ItemQualitySet { setListValue = byte(sr.GetBits(setListIDLen)) listCount, ok := itemdata.SetListMap[setListValue] i.QualityData.SetListID = setListValue @@ -423,15 +424,15 @@ func (i *Item) loadExtendedFields(sr *datautils.BitMuncher) (err error) { } if err := i.Attributes.Load(sr); err != nil { - return err + return fmt.Errorf("error loading item attributes: %w", err) } // nolint:wsl // note at the end of block if c := i.QualityData.SetListCount; c > 0 { for j := 0; j < int(c); j++ { - i.QualityData.SetAttributes = append(i.QualityData.SetAttributes, MagicAttributes{}) + i.QualityData.SetAttributes = append(i.QualityData.SetAttributes, d2smagicattributes.MagicAttributes{}) if err := i.QualityData.SetAttributes[len(i.QualityData.SetAttributes)-1].Load(sr); err != nil { - return err + return fmt.Errorf("error loading set attributes: %w", err) } } @@ -441,7 +442,7 @@ func (i *Item) loadExtendedFields(sr *datautils.BitMuncher) (err error) { if i.RuneWord.HasRuneWord { if err := i.RuneWord.Attributes.Load(sr); err != nil { - return err + return fmt.Errorf("error loading runeword attributes: %w", err) } } @@ -473,15 +474,15 @@ func (i *Item) loadSimpleFields(sr *datautils.BitMuncher) (err error) { i.unknown8 = byte(sr.GetBits(unknown8Len)) i.Version = sr.GetByte() i.unknown9 = byte(sr.GetBits(unknown9Len)) - i.Location.LocationID = enums.ItemLocationType(sr.GetBits(locationLocationIDLen)) - i.Location.EquippedID = enums.ItemEquippedPlace(sr.GetBits(locationEquippedIDLen)) + i.Location.LocationID = d2senums.ItemLocationType(sr.GetBits(locationLocationIDLen)) + i.Location.EquippedID = d2senums.ItemEquippedPlace(sr.GetBits(locationEquippedIDLen)) i.Location.X = byte(sr.GetBits(locationXLen)) i.Location.Y = byte(sr.GetBits(locationYLen)) i.unknown10 = sr.GetBit() == 1 - i.Location.StorageID = enums.StoragePlace(sr.GetBits(locationStorageIDLen)) + i.Location.StorageID = d2senums.StoragePlace(sr.GetBits(locationStorageIDLen)) if i.IsEar { - i.Ear.Class = enums.CharacterClass(sr.GetBits(earClassLen)) + i.Ear.Class = d2senums.CharacterClass(sr.GetBits(earClassLen)) i.Ear.Level = byte(sr.GetBits(earLevelLen)) var name []byte @@ -583,18 +584,18 @@ func (i *Item) encodeExtendedFields(sw *datautils.StreamWriter) (err error) { } switch i.Quality { - case enums.ItemQualityLow: + case d2senums.ItemQualityLow: sw.PushBits(i.QualityData.LowQualityID, lowQualityIDLen) - case enums.ItemQualityNormal: + case d2senums.ItemQualityNormal: // noop - case enums.ItemQualityHigh: + case d2senums.ItemQualityHigh: sw.PushBits(i.QualityData.HighQualityData, highQualityDataLen) - case enums.ItemQualityEnchanced: + case d2senums.ItemQualityEnchanced: sw.PushBits16(i.QualityData.MagicPrefix[0].ID, 11) sw.PushBits16(i.QualityData.MagicSuffix[0].ID, 11) - case enums.ItemQualitySet: + case d2senums.ItemQualitySet: sw.PushBits16(i.QualityData.SetID, setIDLen) - case enums.ItemQualityRare, enums.ItemQualityCrafted: + case d2senums.ItemQualityRare, d2senums.ItemQualityCrafted: for _, name := range i.QualityData.RareNames { sw.PushBits(byte(name.ID), 8) } @@ -616,7 +617,7 @@ func (i *Item) encodeExtendedFields(sw *datautils.StreamWriter) (err error) { sw.PushBits16(i.QualityData.MagicSuffix[n].ID, 11) } } - case enums.ItemQualityUnique: + case d2senums.ItemQualityUnique: sw.PushBits16(i.QualityData.UniqueID, uniqueIDLen) } @@ -664,24 +665,24 @@ func (i *Item) encodeExtendedFields(sw *datautils.StreamWriter) (err error) { sw.PushBits(i.Socketed.TotalNumberOfSockets, totalNSocketsLen) } - if i.Quality == enums.ItemQualitySet { + if i.Quality == d2senums.ItemQualitySet { sw.PushBits(i.QualityData.SetListID, setListIDLen) } if err := i.Attributes.Encode(sw); err != nil { - return err + return fmt.Errorf("error encoding item attributes: %w", err) } // OFC length of set attributes is > 0 fo sets for _, a := range i.QualityData.SetAttributes { if err := a.Encode(sw); err != nil { - return err + return fmt.Errorf("error encoding set attributes: %w", err) } } if i.RuneWord.HasRuneWord { if err := i.RuneWord.Attributes.Encode(sw); err != nil { - return err + return fmt.Errorf("error encoding runeword's attributes: %w", err) } } diff --git a/iron_golem.go b/iron_golem.go index 7056917..23f1af3 100644 --- a/iron_golem.go +++ b/iron_golem.go @@ -2,9 +2,11 @@ package d2d2s import ( "errors" + "fmt" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils" + "github.com/gucio321/d2d2s/d2sitems" "github.com/gucio321/d2d2s/datautils" ) @@ -12,7 +14,7 @@ const golemHeaderID = "kf" // IronGolem represents an iron golem type IronGolem struct { - Item *Item + Item *d2sitems.Item } // Load loads a golem's data @@ -28,9 +30,9 @@ func (i *IronGolem) Load(sr *datautils.BitMuncher) error { return nil // no golem } - item := &Items{} + item := &d2sitems.Items{} if err := item.LoadList(sr, 1); err != nil { - return err + return fmt.Errorf("error lading golem item: %w", err) } i.Item = &(*item)[0] diff --git a/merc_type.go b/merc_type.go index b0b3170..0f21eca 100644 --- a/merc_type.go +++ b/merc_type.go @@ -6,6 +6,7 @@ import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2datautils" + "github.com/gucio321/d2d2s/d2sitems" "github.com/gucio321/d2d2s/datautils" ) @@ -17,7 +18,7 @@ type mercenary struct { Code uint16 } Experience uint32 - Items *Items + Items *d2sitems.Items } // todo; see: https://user.xmission.com/~trevin/DiabloIIv1.09_Mercenaries.html#code @@ -40,11 +41,11 @@ func (m *mercenary) LoadMercItems(sr *datautils.BitMuncher) error { return nil // just no merc } - m.Items = &Items{} + m.Items = &d2sitems.Items{} numItems, err := m.Items.LoadHeader(sr) if err != nil { - return err + return fmt.Errorf("error loading mercenary items: %w", err) } if err := m.Items.LoadList(sr, numItems); err != nil {