### Install and Import agonyl-utils-go Crypto Package Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/crypto.md Instructions for installing the agonyl-utils-go library using go get and importing the crypto package into your Go source files. ```bash go get github.com/project-agonyl/agonyl-utils-go ``` ```go import "github.com/project-agonyl/agonyl-utils-go/crypto" ``` -------------------------------- ### Install and Import questfile Package Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/questfile.md This snippet shows how to install the agonyl-utils-go library using go get and how to import the questfile package into your Go project. This is the standard way to begin using the package's functionalities. ```bash go get github.com/project-agonyl/agonyl-utils-go ``` ```go import "github.com/project-agonyl/agonyl-utils-go/questfile" ``` -------------------------------- ### Go Installation and Import for Spawnlist Package Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/spawnlist.md Demonstrates how to install the spawnlist package using go get and how to import it into your Go code for use. ```bash go get github.com/project-agonyl/agonyl-utils-go ``` ```go import "github.com/project-agonyl/agonyl-utils-go/spawnlist" ``` -------------------------------- ### Usage Examples Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Provides practical code examples for reading, writing, and manipulating map bin data using the mapbin package. ```APIDOC ## Usage Examples ### Reading a map bin from a file ```go import ( "log" "os" "github.com/project-agonyl/agonyl-utils-go/mapbin" ) f, err := os.Open("map.bin") if err != nil { log.Fatal(err) } defer f.Close() data, err := mapbin.Read(f) if err != nil { log.Fatal(err) } for i := range data { name := data[i].GetName() log.Printf("Map %d: ID=%d Name=%q", i, data[i].ID, name) } ``` ### Writing a map bin ```go import ( "log" "os" "github.com/project-agonyl/agonyl-utils-go/mapbin" ) data := mapbin.MapBin{ {ID: 1, Unknown1: 0, Name: [0x20]byte{'F', 'o', 'r', 'e', 's', 't'}}, {ID: 2, Name: [0x20]byte{'D', 'u', 'n', 'g', 'e', 'o', 'n'}}, } f, _ := os.Create("map.bin") defer f.Close() if err := mapbin.Write(f, data); err != nil { log.Fatal(err) } ``` ### Round-trip (read, modify, write) ```go import ( "bytes" "log" "github.com/project-agonyl/agonyl-utils-go/mapbin" ) // Assume 'data' is an existing MapBin buf := &bytes.Buffer{} if err := mapbin.Write(buf, data); err != nil { log.Fatal(err) } readBack, err := mapbin.Read(buf) if err != nil { log.Fatal(err) } // readBack now contains the same data as 'data' ``` ### Building items with copy (recommended for names) ```go import "github.com/project-agonyl/agonyl-utils-go/mapbin" item := mapbin.MapBinItem{ID: 100, Unknown1: 1, Unknown2: 2} copy(item.Name[:], "Town Center") data := mapbin.MapBin{item} ``` ``` -------------------------------- ### Install and Import Monsterbin Package (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/monsterbin.md Demonstrates how to install the agonyl-utils-go package using `go get` and how to import the monsterbin package into your Go project. ```bash go get github.com/project-agonyl/agonyl-utils-go ``` ```go import "github.com/project-agonyl/agonyl-utils-go/monsterbin" ``` -------------------------------- ### Write Map Bin Data Example (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Shows how to create a MapBin slice with sample data and write it to a file named 'map.bin' using the mapbin.Write function. This example illustrates the process of serializing map data. ```go data := mapbin.MapBin{ {ID: 1, Unknown1: 0, Name: [0x20]byte{'F', 'o', 'r', 'e', 's', 't'}}, // rest zero {ID: 2, Name: [0x20]byte{'D', 'u', 'n', 'g', 'e', 'o', 'n'}}, } f, _ := os.Create("map.bin") defer f.Close() if err := mapbin.Write(f, data); err != nil { log.Fatal(err) } ``` -------------------------------- ### Install and Import mapbin Package (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Instructions for installing the agonyl-utils-go library and importing the mapbin package into your Go project. This is the first step to using the package's functionalities. ```bash go get github.com/project-agonyl/agonyl-utils-go ``` ```go import "github.com/project-agonyl/agonyl-utils-go/mapbin" ``` -------------------------------- ### Install and Import Agonyl Utils Go Npcfile Package Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/npcfile.md This snippet shows how to install the agonyl-utils-go library using go get and how to import the npcfile package into your Go project for use. ```bash go get github.com/project-agonyl/agonyl-utils-go import "github.com/project-agonyl/agonyl-utils-go/npcfile" ``` -------------------------------- ### Read Map Bin File Example (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Demonstrates how to open a map bin file, read its contents using mapbin.Read, and iterate through the decoded map entries to print their IDs and names. ```go f, err := os.Open("map.bin") if err != nil { log.Fatal(err) } defer f.Close() data, err := mapbin.Read(f) if err != nil { log.Fatal(err) } for i := range data { name := data[i].GetName() log.Printf("Map %d: ID=%d Name=%q", i, data[i].ID, name) } ``` -------------------------------- ### Write Monsterbin to File (Go Usage) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/monsterbin.md Example showing how to create a `MonsterBin` slice with sample data and write it to a file using the `monsterbin.Write` function. ```go data := monsterbin.MonsterBin{ {ID: 1, Name: [0x1F]byte{'G', 'o', 'b', 'l', 'i', 'n'}}, {ID: 2, Name: [0x1F]byte{'O', 'r', 'c'}}, } f, _ := os.Create("monster.bin") defer f.Close() if err := monsterbin.Write(f, data); err != nil { log.Fatal(err) } ``` -------------------------------- ### Basic Encrypt/Decrypt Round-Trip Example Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/crypto.md Demonstrates the basic usage of the crypto package: creating a Crypto instance, encrypting a byte slice in place, and then decrypting it back to its original state using the same instance. ```go c := crypto.NewCrypto562(0x1234) payload := []byte{/* at least 16 bytes for one block */} // ... fill payload ... c.EncryptInPlace(payload) // payload is now encrypted in place c.DecryptInPlace(payload) // payload is back to plaintext ``` -------------------------------- ### Read Monsterbin from File (Go Usage) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/monsterbin.md Example demonstrating how to open a file, read monster bin data using the `monsterbin.Read` function, and iterate through the loaded monster entries. ```go f, err := os.Open("monster.bin") if err != nil { log.Fatal(err) } defer f.Close() data, err := monsterbin.Read(f) if err != nil { log.Fatal(err) } for i := range data { name := data[i].GetName() log.Printf("Monster %d: ID=%d Name=%q", i, data[i].ID, name) } ``` -------------------------------- ### Go Usage: Reading a Spawnlist from a File Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/spawnlist.md Provides a practical example of how to open a binary file, read its contents as a spawn list using the `spawnlist.Read` function, and then iterate through the loaded spawn items. ```go f, err := os.Open("spawnlist.bin") if err != nil { log.Fatal(err) } defer f.Close() data, err := spawnlist.Read(f) if err != nil { log.Fatal(err) } for i := range data { item := &data[i] log.Printf("Spawn %d: ID=%d at (%d,%d) orientation=%d", i, item.Id, item.X, item.Y, item.Orientation) } ``` -------------------------------- ### Map Bin Round-trip Example (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Illustrates a round-trip operation: writing map data to a bytes.Buffer, then reading it back using mapbin.Read. This verifies that the write and read operations are consistent. ```go buf := &bytes.Buffer{} if err := mapbin.Write(buf, data); err != nil { log.Fatal(err) } readBack, err := mapbin.Read(buf) if err != nil { log.Fatal(err) } // readBack has the same count and items as data ``` -------------------------------- ### Create and Use Login Messages in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Shows how to create various login-related messages for client-server communication using the protocol package. It includes examples for client login, server selection, gate server login, and character login. These messages are essential for establishing a connection and authenticating with the game server. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/protocol" ) func main() { // Client to Server login message loginMsg := protocol.NewMsgC2SLogin("myaccount", "mypassword") fmt.Printf("Login - Size: %d, Ctrl: %x, Cmd: %x\n", loginMsg.Size, loginMsg.Ctrl, loginMsg.Cmd) // Server selection message selectMsg := protocol.NewMsgC2SSelectServer(1) fmt.Printf("Select Server - ServerID: %d\n", selectMsg.ServerID) // Gate login message (after server selection) pcId := uint32(12345) gateLoginMsg := protocol.NewMsgC2SGateLogin(pcId, "myaccount", "mypassword") fmt.Printf("Gate Login - PcId: %d, Size: %d\n", gateLoginMsg.PcId, gateLoginMsg.Size) // Character login message charLoginMsg := protocol.NewMsgC2SCharacterLogin(pcId, "MyCharacter", 562) fmt.Printf("Character Login - Protocol: %x\n", charLoginMsg.Protocol) // World login message worldLoginMsg := protocol.NewMsgC2SWorldLogin(pcId, "MyCharacter") fmt.Printf("World Login - Protocol: %x\n", worldLoginMsg.Protocol) // Character logout message logoutMsg := protocol.NewMsgC2SCharacterLogout(pcId) fmt.Printf("Logout - Protocol: %x\n", logoutMsg.Protocol) } ``` -------------------------------- ### Handle Character List Messages in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Demonstrates how to create and manage character lists for game accounts using the protocol package. It includes examples for creating an empty character list for new accounts, populating a list with character information (including class, nation, and level), and sending a request to delete a character. This is crucial for character selection and management features. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/protocol" ) func main() { pcId := uint32(12345) // Create empty character list (new account) emptyList := protocol.NewMsgS2CCharacterListEmpty(pcId) fmt.Printf("Empty list size: %d\n", emptyList.Size) // Create character list with characters characters := []protocol.CharacterInfo{ { SlotUsed: 1, Class: 0, // Warrior Nation: 0, // Temoz Level: 50, }, { SlotUsed: 1, Class: 1, // Holy Knight Nation: 1, // Quanato Level: 75, }, } copy(characters[0].Name[:], "Warrior01") copy(characters[1].Name[:], "Knight02") charList := protocol.NewMsgS2CCharacterList(pcId, characters) fmt.Printf("Character list with %d characters\n", len(characters)) fmt.Printf("Protocol: %x, Size: %d\n", charList.Protocol, charList.Size) // Delete character request deleteMsg := protocol.NewMsgC2SAskDeletePlayer(pcId, "OldCharacter") fmt.Printf("Delete request - Protocol: %x\n", deleteMsg.Protocol) } ``` -------------------------------- ### Handle Server Errors and Notifications in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Illustrates how to create and process server error responses and level-up notifications using the protocol package. It also includes an example of a ping/keep-alive message. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/protocol" ) func main() { pcId := uint32(12345) // Server error message errorMsg := protocol.NewMsgS2CError(pcId, 1001, "Invalid credentials") fmt.Printf("Error - Code: %d, Protocol: %x\n", errorMsg.Code, errorMsg.Protocol) // Level up notification levelUpMsg := protocol.NewMsgS2CLevelUp(100) fmt.Printf("Level Up - New Level: %d, Protocol: %x\n", levelUpMsg.Level, levelUpMsg.Protocol) // Ping/keep-alive message pingMsg := protocol.NewMsgZACLChkTimeTick(pcId, 1000, 500) fmt.Printf("Ping - TickCount: %d, TickSvr: %d\n", pingMsg.TickCount, pingMsg.TickSvr) } ``` -------------------------------- ### Manage Gate Server Communication in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Provides examples of various gate server messages for communication between login server, zone agent, and zone server components. This includes connection, logout, and information exchange messages. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/protocol" ) func main() { // Gate server registering with login server connectMsg := protocol.NewMsgGate2LsConnect( 1, // Server ID 1, // Agent ID "192.168.1.10", // IP Address 7000, // Port "Server-01", // Server Name ) fmt.Printf("Gate Connect - ServerId: %d, Port: %d\n", connectMsg.ServerId, connectMsg.Port) // Account logout notification to login server logoutMsg := protocol.NewMsgGate2LsAccLogout(0, "player_account") fmt.Printf("Account Logout - Reason: %d\n", logoutMsg.Reason) // Prepared account login notification preparedMsg := protocol.NewMsgGate2LsPreparedAccLogin("player_account") fmt.Printf("Prepared Login - Cmd: %x\n", preparedMsg.Cmd) // Gate to Zone Server connection gateZsMsg := protocol.NewMsgGate2ZsConnect(1) fmt.Printf("Gate-ZS Connect - AgentID: %d\n", gateZsMsg.AgentID) // Zone Agent to Zone Server logout zaLogoutMsg := protocol.NewMsgZa2ZsAccLogout(12345, 1) fmt.Printf("ZA Logout - PcId: %d, Reason: %d\n", zaLogoutMsg.PcId, zaLogoutMsg.Reason) // Server to client gate info (zone server connection details) gateInfoMsg := protocol.NewMsgS2CGateInfo(12345, "192.168.1.20", 8000) fmt.Printf("Gate Info - ZaIP, ZaPort: %d\n", gateInfoMsg.ZaPort) // Login server say message (announcements) sayMsg := protocol.NewMsgLs2ClSay("Welcome to the server!") fmt.Printf("LS Say - Type: %d\n", sayMsg.Type) // Disconnect notification disconnectMsg := protocol.NewMsgLs2ZaDisconnect(1, "player_account", 12345) fmt.Printf("Disconnect - Reason: %d\n", disconnectMsg.Reason) } ``` -------------------------------- ### Character and Nation Name Helpers in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Utilizes the utils package to convert numerical IDs for character classes and nations into human-readable display names. It includes examples for valid IDs and demonstrates the default fallback behavior for invalid IDs. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/utils" ) func main() { // Get character class names fmt.Println("Class 0:", utils.GetClassName(0)) // Output: Warrior fmt.Println("Class 1:", utils.GetClassName(1)) // Output: Holy Knight fmt.Println("Class 2:", utils.GetClassName(2)) // Output: Mage fmt.Println("Class 3:", utils.GetClassName(3)) // Output: Archer fmt.Println("Class 99:", utils.GetClassName(99)) // Output: Warrior (default) // Get nation names fmt.Println("Nation 0:", utils.GetNationName(0)) // Output: Temoz fmt.Println("Nation 1:", utils.GetNationName(1)) // Output: Quanato fmt.Println("Nation 99:", utils.GetNationName(99)) // Output: Temoz (default) } ``` -------------------------------- ### Message to Bytes and Back Round-trip Example (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/protocol.md Demonstrates a complete round-trip process: serializing a Go struct message to bytes using GetBytesFromMsg and then deserializing those bytes back into a Go struct using ReadMsgFromBytes. ```Go // Encode: message → bytes msg := protocol.MsgHead{ /* ... */ } data, err := protocol.GetBytesFromMsg(msg) if err != nil { return err } // Decode: bytes → message var decoded protocol.MsgHead err = protocol.ReadMsgFromBytes(data, &decoded) if err != nil { return err } // decoded now holds the same values as msg (for the bytes that were written) ``` -------------------------------- ### Encrypt/Decrypt Data with A3 v562 Cipher in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Demonstrates in-place encryption and decryption of byte slices using the A3 client v562 cipher algorithm. Requires a dynamic key derived from session context and operates on data starting from offset 0x0C. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/crypto" ) func main() { // Create a new crypto instance with a session-specific dynamic key dynamicKey := 0x12345678 cipher := crypto.NewCrypto562(dynamicKey) // Sample packet data (minimum 16 bytes to process at least one block) data := []byte{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, } // Make a copy for demonstration original := make([]byte, len(data)) copy(original, data) // Encrypt in place (modifies data starting at offset 0x0C) cipher.EncryptInPlace(data) fmt.Printf("Encrypted: %x\n", data) // Decrypt in place (restores original data) cipher.DecryptInPlace(data) fmt.Printf("Decrypted: %x\n", data) // Output: Decrypted matches original for bytes at offset 0x0C onward } ``` -------------------------------- ### Write Quest File - Go Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/questfile.md Illustrates the process of creating and writing a quest file. It shows how to populate the header, objectives, and continuation fields before writing the data to a file. Errors during writing are logged. ```go var q questfile.QuestFile q.Header.SetQuestID(100) q.Header.SetGivenNPCID(200) q.Header.EXP = 5000 q.Continuation[0] = 2001 q.Continuation[1] = questfile.UnusedContinuation q.Continuation[2] = questfile.UnusedContinuation // Set q.Objectives[0..6].Block and optional Name for each f, _ := os.Create("quest.dat") deferr f.Close() if err := questfile.Write(f, q); err != nil { log.Fatal(err) } ``` -------------------------------- ### Get Monster Name (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/monsterbin.md Provides the `GetName` method for `MonsterBinItem`. This method interprets the fixed-size `Name` field as a null-padded string and returns the trimmed version. ```go func (m *MonsterBinItem) GetName() string ``` -------------------------------- ### Go Usage: Writing a Spawnlist to a File Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/spawnlist.md Illustrates how to create a SpawnList slice with sample data and then write this data to a file named 'spawnlist.bin' using the `spawnlist.Write` function. ```go data := spawnlist.SpawnList{ {Id: 1, X: 10, Y: 20, Orientation: 0, SpwanStep: 1}, {Id: 2, X: 30, Y: 40, Orientation: 2, SpwanStep: 0}, } f, _ := os.Create("spawnlist.bin") defer f.Close() if err := spawnlist.Write(f, data); err != nil { log.Fatal(err) } ``` -------------------------------- ### Get Map Name from MapBinItem (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md The GetName method on MapBinItem extracts the map name as a string. It interprets the fixed-size Name field as a null-padded string and trims it to the first null character or the end of the buffer. ```go func (m *MapBinItem) GetName() string ``` -------------------------------- ### Get NPC Name String from NPCFileData in Go Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/npcfile.md A method on the NPCFileData struct that extracts and returns the NPC's display name. It interprets the fixed-size Name field as a null-padded string and trims any padding. ```go func (n *NPCFileData) GetName() string ``` -------------------------------- ### Run Monsterbin Package Tests (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/monsterbin.md Instructions on how to run the tests for the `monsterbin` package using the standard Go testing command. ```bash go test ./monsterbin/... ``` -------------------------------- ### Run Go Tests Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/questfile.md Commands to execute tests and benchmarks for the questfile package in Go. The first command runs standard tests, while the second runs benchmarks, including minimal and maximal file sizes. ```bash go test ./questfile/... ``` ```bash go test -bench=. ./questfile/... ``` -------------------------------- ### Get Character Class Name (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/utils.md Maps a character class ID (byte) to its display name string. Handles known IDs (Holy Knight, Mage, Archer) and defaults to 'Warrior' for unknown or reserved IDs. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/utils" ) func main() { classID := byte(2) nationID := byte(1) className := utils.GetClassName(classID) // "Mage" nationName := utils.GetNationName(nationID) // "Quanato" fmt.Printf("Character: %s from %s\n", className, nationName) // Default for unknown IDs name := utils.GetClassName(255) // "Warrior" nation := utils.GetNationName(0) // "Temoz" fmt.Printf("Unknown Class: %s, Unknown Nation: %s\n", name, nation) } ``` -------------------------------- ### Handle Empty Spawn Lists in Go Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/spawnlist.md Demonstrates how writing a nil or empty slice to a spawn list results in zero bytes being written. It also shows that reading from an empty stream correctly returns a non-nil empty slice without errors. ```go // Writing nil or empty slice produces zero bytes var list spawnlist.SpawnList _ = spawnlist.Write(w, list) // Reading an empty stream returns a non-nil empty slice and no error data, err := spawnlist.Read(bytes.NewReader(nil)) // err == nil, len(data) == 0 ``` -------------------------------- ### Decrypt Packet Payload in Go Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/crypto.md Decrypts a received packet payload using a session key. The decryption is performed in-place, and subsequent processing is done on the decrypted data starting from offset 0x0C. Requires a crypto.NewCrypto562 instance initialized with the session key. ```go raw := receive() c := crypto.NewCrypto562(sessionKey) c.DecryptInPlace(raw) processPayload(raw[0x0C:]) ``` -------------------------------- ### ULL File Encoding and Decoding in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Demonstrates the encoding and decoding of ULL (A3 client data) files using the utils package. It shows how to encode a byte slice in place and then decode it back to its original state, verifying the integrity of the round-trip process. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/utils" ) func main() { // Sample data buffer data := []byte("Hello, A3 World! This is test data for ULL encoding.") size := len(data) // Make a copy for comparison original := make([]byte, size) copy(original, data) // Encode the data in place utils.EncodeULL(data, size) fmt.Printf("Encoded data (first 20 bytes): %x\n", data[:20]) // Decode the data back utils.DecodeULL(data, size) fmt.Printf("Decoded data: %s\n", string(data)) // Verify round-trip match := true for i := range data { if data[i] != original[i] { match = false break } } fmt.Printf("Round-trip successful: %v\n", match) // Output: true } ``` -------------------------------- ### Test Spawnlist Package in Go Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/spawnlist.md Instructions for testing the spawnlist package using the Go testing framework. It outlines recommended test cases to ensure the package functions correctly under various conditions, including empty streams, valid data, truncated streams, and failing readers/writers. ```bash go test ./spawnlist/... ``` -------------------------------- ### Read and Write NPC Configuration Data in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Handles reading and writing of NPC configuration binary files. It parses detailed NPC stats, attack, defense, and display information. Requires the 'npcfile' package. ```go package main import ( "bytes" "fmt" "os" "github.com/project-agonyl/agonyl-utils-go/npcfile" ) func main() { // Reading NPC data file, err := os.Open("npc001.dat") if err != nil { panic(err) } defer file.Close() npc, err := npcfile.Read(file) if err != nil { panic(err) } fmt.Printf("NPC: %s (ID: %d)\n", npc.GetName(), npc.Id) fmt.Printf("Level: %d, HP: %d\n", npc.Level, npc.HP) fmt.Printf("Defense: %d, Movement Speed: %d\n", npc.Defense, npc.MovementSpeed) fmt.Printf("Player EXP: %d, Mercenary EXP: %d\n", npc.PlayerExp, npc.MercenaryExp) // Print attack info for i, attack := range npc.Attacks { fmt.Printf("Attack %d - Range: %d, Area: %d, Damage: %d\n", i+1, attack.Range, attack.Area, attack.Damage) } // Creating NPC data newNPC := npcfile.NPCFileData{ Id: 500, Level: 25, HP: 5000, Defense: 50, MovementSpeed: 100, PlayerExp: 250, RespawnRate: 30, Attacks: [3]npcfile.NPCAttack{ {Range: 10, Area: 1, Damage: 100, AdditionalDamage: 20}, {Range: 5, Area: 3, Damage: 150, AdditionalDamage: 30}, {Range: 15, Area: 1, Damage: 80, AdditionalDamage: 10}, }, } copy(newNPC.Name[:], "Elite Guard") var buf bytes.Buffer if err := npcfile.Write(&buf, newNPC); err != nil { panic(err) } } ``` -------------------------------- ### Run Go Tests Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/crypto.md Command to run the tests for the crypto package within the agonyl-utils-go project. This command utilizes the standard Go testing tools. ```bash go test ./crypto/... ``` -------------------------------- ### Create and Send Chat Messages in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Demonstrates creating and sending different types of chat messages (general, whisper, party, clan, system) using the protocol package. It shows how to instantiate message objects and retrieve their byte representations for transmission. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/protocol" ) func main() { pcId := uint32(12345) // General chat message (client to server) generalChat := protocol.NewMsgC2SSay(pcId, protocol.General, "Player1", "Hello everyone!") fmt.Printf("General Chat - Type: %d\n", generalChat.SayType) // Whisper message whisper := protocol.NewMsgC2SSay(pcId, protocol.Whisper, "TargetPlayer", "Private message") fmt.Printf("Whisper - Type: %d\n", whisper.SayType) // Party chat partyChat := protocol.NewMsgC2SSay(pcId, protocol.Party, "Player1", "Party members only") fmt.Printf("Party Chat - Type: %d\n", partyChat.SayType) // Clan/Knighthood chat clanChat := protocol.NewMsgC2SSay(pcId, protocol.Knighthood, "Player1", "Clan announcement") fmt.Printf("Clan Chat - Type: %d\n", clanChat.SayType) // Server to client chat message (with sender PcId) serverMsg := protocol.NewMsgS2CSay(pcId, protocol.System, "System", "Server maintenance in 10 minutes") fmt.Printf("Server Message - SayPcId: %d\n", serverMsg.SayPcId) // Get message bytes for transmission msgBytes := generalChat.GetBytes() fmt.Printf("Message bytes length: %d\n", len(msgBytes)) } ``` -------------------------------- ### Run Mapbin Package Tests (Bash) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Command to execute the tests for the mapbin package using Go's built-in testing framework. This is essential for verifying the package's correctness and ensuring changes do not introduce regressions. ```bash go test ./mapbin/... ``` -------------------------------- ### Questfile Binary Format Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/questfile.md Details the structure and encoding of the A3 binary quest file format, including header, objectives, continuation, and size constraints. ```APIDOC ## Binary Format - **Little-endian** throughout. - **Header**: 96 bytes (see documentation PDF for offset table). Quest ID and Given NPC use lower 16 bits of 4-byte fields; Target NPC is 24 bytes; reward slots are 4 bytes each (2-byte item code + 2 padding); counts are 1 byte in 4-byte fields; EXP/Woonz/Lore are uint32; tail 4 bytes padding. - **Objectives**: Exactly 7. Each is 96 bytes then, if **NameLength** (offset 92) > 0, exactly **NameLength** bytes of name. For types 0 (KILL), 1 (QUESTITEM), 2 (BRINGNPC), **NameLength** must be 0. For 3 (DROP) and 4 (FIND), name is optional. - **Continuation**: 12 bytes (3× uint32). **0xFFFFFFFF** means no continuation in that slot. - **Trailing**: No bytes may follow the continuation; otherwise **Read** returns **ErrTrailingBytes**. Minimum file size: 780 bytes. Maximum: 780 + 7×255 name bytes. ``` -------------------------------- ### Read Quest File - Go Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/questfile.md Demonstrates how to open and read a quest data file. It handles potential file opening errors and quest file parsing errors, then logs the quest ID and details of each objective. ```go f, err := os.Open("quest.dat") if err != nil { log.Fatal(err) } deferr f.Close() q, err := questfile.Read(f) if err != nil { log.Fatal(err) } log.Printf("Quest ID=%d", q.Header.QuestID()) for i, obj := range q.Objectives { log.Printf("Objective %d type=%d nameLen=%d", i+1, obj.ObjectiveType(), obj.NameLength()) } ``` -------------------------------- ### Read and Write Spawn List Data in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Manages spawn point binary files, including NPC/monster spawn positions, orientations, and step data. Requires the 'spawnlist' package. ```go package main import ( "bytes" "fmt" "os" "github.com/project-agonyl/agonyl-utils-go/spawnlist" ) func main() { // Reading spawn list file, err := os.Open("spawn_map01.dat") if err != nil { panic(err) } defer file.Close() spawns, err := spawnlist.Read(file) if err != nil { panic(err) } fmt.Printf("Total spawn points: %d\n", len(spawns)) for i, spawn := range spawns { fmt.Printf("Spawn %d: ID=%d, Position=(%d,%d), Orientation=%d, Step=%d\n", i+1, spawn.Id, spawn.X, spawn.Y, spawn.Orientation, spawn.SpwanStep) } // Creating spawn list newSpawns := spawnlist.SpawnList{ {Id: 100, X: 50, Y: 75, Orientation: 0, SpwanStep: 1}, {Id: 100, X: 52, Y: 78, Orientation: 2, SpwanStep: 1}, {Id: 101, X: 100, Y: 120, Orientation: 4, SpwanStep: 2}, } var buf bytes.Buffer if err := spawnlist.Write(&buf, newSpawns); err != nil { panic(err) } fmt.Printf("Written %d spawn entries\n", len(newSpawns)) } ``` -------------------------------- ### Read and Write Quest Data in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Parses and serializes the A3 binary quest file format, including a 96-byte header and multiple objective types (KILL, QUESTITEM, BRINGNPC, DROP, FIND). Requires the 'questfile' package. ```go package main import ( "bytes" "fmt" "os" "github.com/project-agonyl/agonyl-utils-go/questfile" ) func main() { // Reading quest data file, err := os.Open("quest001.dat") if err != nil { panic(err) } defer file.Close() quest, err := questfile.Read(file) if err != nil { panic(err) } fmt.Printf("Quest ID: %d\n", quest.Header.QuestID()) fmt.Printf("Given NPC ID: %d\n", quest.Header.GivenNPCID()) fmt.Printf("Level Range: %d - %d\n", quest.Header.MinLevel, quest.Header.MaxLevel) fmt.Printf("Rewards - EXP: %d, Woonz: %d, Lore: %d\n", quest.Header.EXP, quest.Header.Woonz, quest.Header.Lore) // Check objectives for i, obj := range quest.Objectives { objType := obj.ObjectiveType() switch objType { case questfile.TypeKILL: fmt.Printf("Objective %d: KILL type\n", i+1) case questfile.TypeQUESTITEM: fmt.Printf("Objective %d: QUESTITEM type\n", i+1) case questfile.TypeDROP: fmt.Printf("Objective %d: DROP type (name len: %d)\n", i+1, obj.NameLength()) case questfile.TypeFIND: fmt.Printf("Objective %d: FIND type (name len: %d)\n", i+1, obj.NameLength()) } } // Check continuation quests for i, cont := range quest.Continuation { if cont != questfile.UnusedContinuation { fmt.Printf("Continuation %d: Quest ID %d\n", i+1, cont) } } // Writing quest data var buf bytes.Buffer if err := questfile.Write(&buf, quest); err != nil { panic(err) } } ``` -------------------------------- ### Run NPC File Tests (Bash) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/npcfile.md Command to execute the unit tests for the npcfile package using Go's standard testing library. This command should be run from the project's root directory. ```bash go test ./npcfile/... ``` -------------------------------- ### Consistent Key Usage for Multiple Packets Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/crypto.md Shows how to reuse a single Crypto instance for multiple packets within a session. This ensures that the same dynamic key is consistently applied for encryption or decryption across different data segments. ```go sessionKey := deriveKeyFromSession(sessionID) c := crypto.NewCrypto562(sessionKey) for _, packet := range packets { c.DecryptInPlace(packet.Payload) // or EncryptInPlace for sending } ``` -------------------------------- ### Clan Message Protocol Handling in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Demonstrates creating and inspecting clan information request and response messages using the protocol package. It shows how to generate a clan info request and how to handle the structure of a clan info response, including clan name and member details. ```go package main import ( "fmt" "github.com/project-agonyl/agonyl-utils-go/protocol" ) func main() { pcId := uint32(12345) // Request clan information clanInfoReq := protocol.NewMsgC2SReqClanInfo(pcId) fmt.Printf("Clan Info Request - Protocol: %x\n", clanInfoReq.Protocol) // Clan info response structure (populated by server) var clanInfo protocol.MsgS2CClanInfo clanInfo.SetSize() fmt.Printf("Clan Info Response - Size: %d\n", clanInfo.GetSize()) // ClanInfo contains: ClanName, ClanMates (up to 13 members) // Each ClanMate has: CharacterName, Class, and reserved fields } ``` -------------------------------- ### Map Bin Binary Format Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Details the structure of the map bin binary file format, including the entry count and the layout of individual map records. ```APIDOC ## Binary Format ### Description The map bin file format consists of a header followed by a sequence of map records. ### Structure 1. **Entry Count**: A `uint32` value in little-endian format, indicating the total number of map items that follow. 2. **Map Items**: A sequence of `MapBinItem` structures. Each item has a fixed size: - `ID` (`uint32`): 4 bytes. - `Unknown1` to `Unknown5` (`uint32`): 5 fields * 4 bytes/field = 20 bytes. - `Name` (`[0x20]byte`): 32 bytes (0x20). The total size of each `MapBinItem` is 4 + 20 + 32 = 56 bytes. ``` -------------------------------- ### Create MapBinItem with Copied Name (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Demonstrates the recommended way to set the Name field of a MapBinItem by copying a string into the fixed-size byte array. This ensures correct handling of the name data. ```go item := mapbin.MapBinItem{ID: 100, Unknown1: 1, Unknown2: 2} copy(item.Name[:], "Town Center") data := mapbin.MapBin{item} ``` -------------------------------- ### Read MapBin from io.Reader Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Reads a map bin file from an io.Reader, decoding the entry count and subsequent map records. ```APIDOC ## Function: `Read` ### Description Reads a map bin from an `io.Reader`. It first reads a little-endian `uint32` representing the entry count, followed by that many `MapBinItem` records. ### Parameters - **r** (`io.Reader`): The source of the binary data (e.g., a file or a buffer). ### Returns - **`MapBin`**: A slice of `MapBinItem` representing the decoded map data. - **`error`**: `nil` on success, or a non-nil error if the stream is truncated or a read operation fails. ``` -------------------------------- ### Write NPC File Data (Go) Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/npcfile.md Creates an NPCFileData struct, populates it with NPC details including ID, level, HP, respawn rate, and attack information. It then writes this data to a new file named 'npc.dat'. Errors during file creation or writing are logged. ```go data := npcfile.NPCFileData{ Id: 42, Level: 5, HP: 1000, RespawnRate: 30, } copy(data.Name[:], "Guard") data.Attacks[0] = npcfile.NPCAttack{Range: 50, Area: 10, Damage: 100, AdditionalDamage: 20} f, _ := os.Create("npc.dat") defer f.Close() if err := npcfile.Write(f, data); err != nil { log.Fatal(err) } ``` -------------------------------- ### Mapbin Package Overview Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Provides functions to read and write map bin files, including a MapBinItem struct for individual map records and a MapBin type for slices of these records. ```APIDOC ## Mapbin Package ### Description The `mapbin` package provides functionality to read and write the A3 client map bin binary format. It supports reading a map bin from an `io.Reader` and writing a `MapBin` to an `io.Writer`. The format consists of a little-endian uint32 entry count followed by fixed-size map records. ### Key Components - **`MapBinItem`**: Represents a single map record with ID, reserved fields, and a name. - **`MapBin`**: A slice of `MapBinItem` used for in-memory representation and I/O operations. - **`Read(r io.Reader)`**: Reads a map bin from a given reader. - **`Write(w io.Writer, data MapBin)`**: Writes a `MapBin` to a given writer. - **`MapBinItem.GetName()`**: Retrieves the trimmed string name from a `MapBinItem`. ``` -------------------------------- ### NewCrypto562 Constructor Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/crypto.md Function to create a new Crypto instance using the 562 variant stream cipher. It requires a dynamic key for seeding the cipher state, which must be consistent for both encryption and decryption. ```go func NewCrypto562(dynamicKey int) Crypto ``` -------------------------------- ### Write MapBin to io.Writer Source: https://github.com/project-agonyl/agonyl-utils-go/blob/master/docs/mapbin.md Writes a MapBin data structure to an io.Writer in the specified map bin binary format. ```APIDOC ## Function: `Write` ### Description Writes the provided `MapBin` data to an `io.Writer` in the map bin format. It first writes a little-endian `uint32` count equal to the length of the data, followed by each `MapBinItem` in sequence. ### Parameters - **w** (`io.Writer`): The destination for the binary data. - **data** (`MapBin`): The slice of map entries to write. ### Returns - **`error`**: `nil` on success, or a non-nil error if a write operation fails. ``` -------------------------------- ### Read/Write A3 Map Binary Files in Go Source: https://context7.com/project-agonyl/agonyl-utils-go/llms.txt Handles reading and writing A3 client map binary files. These files consist of a count header followed by fixed-size map entries, each containing an ID and a 32-byte name. Uses little-endian encoding. ```go package main import ( "bytes" "fmt" "os" "github.com/project-agonyl/agonyl-utils-go/mapbin" ) func main() { // Reading map data from file file, err := os.Open("map.bin") if err != nil { panic(err) } defer file.Close() maps, err := mapbin.Read(file) if err != nil { panic(err) } // Iterate through map entries for _, m := range maps { fmt.Printf("Map ID: %d, Name: %s\n", m.ID, m.GetName()) } // Creating and writing map data newMaps := mapbin.MapBin{ {ID: 1, Name: [0x20]byte{'T', 'o', 'w', 'n', ' ', 'S', 'q', 'u', 'a', 'r', 'e'}}, {ID: 2, Name: [0x20]byte{'F', 'o', 'r', 'e', 's', 't', ' ', 'Z', 'o', 'n', 'e'}}, } var buf bytes.Buffer if err := mapbin.Write(&buf, newMaps); err != nil { panic(err) } fmt.Printf("Written %d bytes\n", buf.Len()) } ```