Hucaru / Valhalla

A Golang MapleStory (v28) server
MIT License
274 stars 71 forks source link

Building out useable items #35

Open ErwinsExpertise opened 4 years ago

ErwinsExpertise commented 4 years ago

Currently I am in the process of building out useable items. Currently there is not really a process in the code that builds out useable items other than what is in the info node. For most useable items the important information is actually in spec which is not iterated over.

I am trying to figure out the best way to structure this. While we could always created a nested struct it does not seem necessary

type Item struct {
         Info Info
         Spec Spec
}

type Info struct {
         // Everything in info
}

type Spec struct {
         // Everything in spec
}

This seems like it would be rather tedious and not have any real advantages. The way I am currently experimenting with is by iterating over a slice of subSearches and creating items to map[int]Item . Once the iteration has finished the structs are merged.

                for j := uint32(0); j < uint32(itemGroupNode.ChildCount); j++ {
                    itemNode := nodes[itemGroupNode.ChildID+j]
                    name := textLookup[itemNode.NameID]

                    var item Item
                    itemMap := make(map[int]Item)

                    subSearches := []string{"/info", "/spec"}
                    for i, subSrch := range subSearches {
                        subSearch := search + "/" + groupName + "/" + name + subSrch

                        valid := gonx.FindNode(subSearch, nodes, textLookup, func(node *gonx.Node) {
                            itemMap[i] = getItem(node, nodes, textLookup)
                        })

                        if !valid {
                            log.Println("Invalid node search:", subSearch)
                        }

                    }
                    item = itemMap[0]

                    mergo.Merge(&item, itemMap[1])

                    name = strings.TrimSuffix(name, filepath.Ext(name))
                    itemID, err := strconv.Atoi(name)

                    if err != nil {
                        log.Println(err)
                        continue
                    }

                    item.InvTabID = byte(itemID / 1e6)
                    items[int32(itemID)] = item
                }

This method is using the following package at the cost of reflection: https://github.com/imdario/mergo

Any ideas that might be more efficient or should this suffice?

Hucaru commented 4 years ago

Unless I am missing something I think the following would work best as there is less copying being done:

                for j := uint32(0); j < uint32(itemGroupNode.ChildCount); j++ {
                    itemNode := nodes[itemGroupNode.ChildID+j]
                    name := textLookup[itemNode.NameID]

                    subSearches := []string{search + "/" + groupName + "/" + name + "/info",
                        search + "/" + groupName + "/" + name + "/spec"}

                    var item Item

                    for _, subSearch := range subSearches {
                        valid := gonx.FindNode(subSearch, nodes, textLookup, func(node *gonx.Node) {
                            getItem(node, nodes, textLookup, &item)
                        })

                        if !valid {
                            log.Println("Invalid node search:", subSearch)
                        }
                    }

                    name = strings.TrimSuffix(name, filepath.Ext(name))
                    itemID, err := strconv.Atoi(name)

                    if err != nil {
                        log.Println(err)
                        continue
                    }

                    item.InvTabID = byte(itemID / 1e6)
                    items[int32(itemID)] = item
                }

where getItem is now:

func getItem(node *gonx.Node, nodes []gonx.Node, textLookup []string, item *Item) {
    for i := uint32(0); i < uint32(node.ChildCount); i++ {
        option := nodes[node.ChildID+i]
        optionName := textLookup[option.NameID]

        switch optionName {
        ...
        default:
            log.Println("Unsupported NX item option:", optionName, "->", option.Data)
        }

    }
}

You can just extend the item struct to add the missing fields and then add the spec names in the switch statement