175 lines
4.3 KiB
Go
175 lines
4.3 KiB
Go
//go:build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
// XMLDefinition represents the root element containing structs
|
|
type XMLDefinition struct {
|
|
XMLName xml.Name `xml:"structs"`
|
|
Structs []XMLStruct `xml:"struct"`
|
|
}
|
|
|
|
// XMLStruct represents a packet structure definition
|
|
type XMLStruct struct {
|
|
Name string `xml:"name,attr"`
|
|
ClientVersion string `xml:"clientVersion,attr"`
|
|
OpcodeName string `xml:"opcodeName,attr"`
|
|
}
|
|
|
|
// Registration represents a packet registration entry
|
|
type Registration struct {
|
|
StructName string
|
|
TypeName string
|
|
Version uint16
|
|
OpcodeName string
|
|
}
|
|
|
|
// RegistrationData holds all registration data for template
|
|
type RegistrationData struct {
|
|
PackageName string
|
|
Registrations []Registration
|
|
}
|
|
|
|
const registrationTemplate = `// Code generated by go generate; DO NOT EDIT.
|
|
// This file was generated from XML packet definitions
|
|
|
|
package {{.PackageName}}
|
|
|
|
import (
|
|
"reflect"
|
|
"git.sharkk.net/EQ2/Protocol/defs/generated"
|
|
)
|
|
|
|
// initializePacketMappings loads all packet structure definitions
|
|
func (pm *PacketManager) initializePacketMappings() {
|
|
{{range .Registrations}} pm.registerStruct("{{.StructName}}", {{.Version}}, "{{.OpcodeName}}", reflect.TypeOf(generated.{{.TypeName}}{}))
|
|
{{end}}}
|
|
`
|
|
|
|
func main() {
|
|
// Process all XML files
|
|
xmlDir := filepath.Join(".", "xml")
|
|
outputFile := "registrations_generated.go"
|
|
|
|
registrations := []Registration{}
|
|
|
|
// Process common.xml
|
|
commonFile := filepath.Join(xmlDir, "common.xml")
|
|
if regs, err := processXMLFile(commonFile); err == nil {
|
|
registrations = append(registrations, regs...)
|
|
} else {
|
|
log.Printf("Warning: Could not process common.xml: %v", err)
|
|
}
|
|
|
|
// Process login.xml
|
|
loginFile := filepath.Join(xmlDir, "login.xml")
|
|
if regs, err := processXMLFile(loginFile); err == nil {
|
|
registrations = append(registrations, regs...)
|
|
} else {
|
|
log.Printf("Warning: Could not process login.xml: %v", err)
|
|
}
|
|
|
|
// Sort registrations by struct name, then version
|
|
sort.Slice(registrations, func(i, j int) bool {
|
|
if registrations[i].StructName != registrations[j].StructName {
|
|
return registrations[i].StructName < registrations[j].StructName
|
|
}
|
|
return registrations[i].Version < registrations[j].Version
|
|
})
|
|
|
|
// Generate the registration code
|
|
if err := generateRegistrationCode(registrations, outputFile); err != nil {
|
|
log.Fatalf("Failed to generate registration code: %v", err)
|
|
}
|
|
|
|
log.Printf("Generated %s with %d registrations", outputFile, len(registrations))
|
|
}
|
|
|
|
func processXMLFile(filename string) ([]Registration, error) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
data, err := io.ReadAll(file)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Wrap in root element if needed
|
|
xmlContent := string(data)
|
|
if !strings.Contains(xmlContent, "<structs>") {
|
|
xmlContent = "<structs>\n" + xmlContent + "\n</structs>"
|
|
}
|
|
|
|
var def XMLDefinition
|
|
if err := xml.Unmarshal([]byte(xmlContent), &def); err != nil {
|
|
return nil, fmt.Errorf("failed to parse XML: %v", err)
|
|
}
|
|
|
|
registrations := []Registration{}
|
|
|
|
for _, s := range def.Structs {
|
|
if s.OpcodeName == "" {
|
|
continue // Skip structs without opcodes
|
|
}
|
|
|
|
version, err := strconv.ParseUint(s.ClientVersion, 10, 16)
|
|
if err != nil {
|
|
log.Printf("Warning: Invalid version %s for %s", s.ClientVersion, s.Name)
|
|
continue
|
|
}
|
|
|
|
// Determine the Go type name (remove underscores from struct names)
|
|
typeName := strings.ReplaceAll(s.Name, "_", "")
|
|
if version > 1 {
|
|
typeName = fmt.Sprintf("%sV%d", typeName, version)
|
|
}
|
|
|
|
registrations = append(registrations, Registration{
|
|
StructName: s.Name,
|
|
TypeName: typeName,
|
|
Version: uint16(version),
|
|
OpcodeName: s.OpcodeName,
|
|
})
|
|
}
|
|
|
|
return registrations, nil
|
|
}
|
|
|
|
func generateRegistrationCode(registrations []Registration, outputFile string) error {
|
|
tmpl, err := template.New("registration").Parse(registrationTemplate)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to parse template: %v", err)
|
|
}
|
|
|
|
out, err := os.Create(outputFile)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create output file: %v", err)
|
|
}
|
|
defer out.Close()
|
|
|
|
data := RegistrationData{
|
|
PackageName: "defs",
|
|
Registrations: registrations,
|
|
}
|
|
|
|
if err := tmpl.Execute(out, data); err != nil {
|
|
return fmt.Errorf("failed to execute template: %v", err)
|
|
}
|
|
|
|
return nil
|
|
} |