1
0
Protocol/defs/gen/registration.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
}