### BinaryReader Usage with Files and Buffers (TypeScript) Source: https://github.com/project-agonyl/agonyl-utils/blob/master/README.md Demonstrates how to use the BinaryReader class to read data from files or buffers. It covers initialization with a file path or a buffer, iterating through the data, and specifying custom offsets and byte orders (little endian default, big endian supported). ```typescript import { BinaryReader } from '@project-agonyl/agonyl-utils'; // From file const fileReader = new BinaryReader('path/to/file'); while (!fileReader.isEndOfBuffer()) { console.log(fileReader.readString(20)); } // From buffer const bufferReader = new BinaryReader(buffer); while (!bufferReader.isEndOfBuffer()) { console.log(bufferReader.readString(20)); } // From file with custom offset const fileReaderOffset = new BinaryReader('path/to/file', 100); while (!fileReaderOffset.isEndOfBuffer()) { console.log(fileReaderOffset.readString(20)); } // From file with big endian byte order const fileReaderBigEndian = new BinaryReader('path/to/file', 0, 'BE'); while (!fileReaderBigEndian.isEndOfBuffer()) { console.log(fileReaderBigEndian.readString(20)); } ``` -------------------------------- ### tsconfig.json Configuration for Experimental Decorators Source: https://github.com/project-agonyl/agonyl-utils/blob/master/README.md Configuration snippet for tsconfig.json to enable experimental decorators, which is a prerequisite for using the @meta decorator with Agonyl Utils' Serializable classes. ```json { "compilerOptions": { "experimentalDecorators": true } } ``` -------------------------------- ### Serialize and Deserialize Binary Data with Serializable Class (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Demonstrates how to use the `Serializable` class and `@meta` decorators to define custom binary structures for serialization and deserialization. Supports primitive types, fixed-width integers, byte arrays, and nested structures. Requires `experimentalDecorators` enabled in TypeScript. ```typescript import { Serializable, meta } from '@project-agonyl/agonyl-utils'; // Define nested serializable structure class PlayerInventory extends Serializable { @meta({ type: 'int16', order: 1 }) public itemId: number = 0; @meta({ type: 'byte', order: 2 }) public quantity: number = 0; @meta({ type: 'string', order: 3, length: 30 }) public itemName: string = ''; } // Define main packet structure class PlayerPacket extends Serializable { @meta({ type: 'int32', order: 1 }) public playerId: number = 0; @meta({ type: 'string', order: 2, length: 20 }) public playerName: string = ''; @meta({ type: 'int16', order: 3 }) public level: number = 1; @meta({ type: 'serializable', order: 4, length: 32 }) public inventory: PlayerInventory = new PlayerInventory(); @meta({ type: 'byte', order: 5, isArray: true, arraySize: 4 }) public stats: number[] = [0, 0, 0, 0]; } // Serialize to binary const packet = new PlayerPacket(); packet.playerId = 12345; packet.playerName = 'DragonSlayer'; packet.level = 99; packet.inventory.itemId = 1001; packet.inventory.quantity = 5; packet.inventory.itemName = 'Health Potion'; packet.stats = [100, 85, 120, 95]; const binaryData = packet.serialize(); console.log('Binary size:', binaryData.length); // Deserialize from binary const receivedPacket = new PlayerPacket(); receivedPacket.deserialize(binaryData); console.log('Player ID:', receivedPacket.playerId); console.log('Name:', receivedPacket.playerName); console.log('Level:', receivedPacket.level); console.log('Item:', receivedPacket.inventory.itemName); console.log('Stats:', receivedPacket.stats); ``` -------------------------------- ### Serializable Class Serialization and Deserialization in TypeScript Source: https://github.com/project-agonyl/agonyl-utils/blob/master/README.md Demonstrates how to use the Serializable class from Agonyl Utils to serialize and deserialize class instances to and from binary representations. It also shows how to convert to and from JSON arrays, preserving property order. Requires experimentalDecorators enabled in tsconfig.json. ```typescript import { Serializable, meta } from '@project-agonyl/agonyl-utils'; class MySubSerializable extends Serializable { @meta({ type: 'string', order: 1, length: 20 }) public mySubProperty: string = ''; } class MySerializable extends Serializable { @meta({ type: 'string', order: 1, length: 20 }) public myProperty: string = ''; @meta({ type: 'serializable', order: 2, length: 20 }) public mySubSerializable: MySubSerializable = new MySubSerializable(); @meta({ type: 'byte', order: 3, isArray: true, arraySize: 2, }) public myByteArray: number[] = []; } // Serialize const mySerializable = new MySerializable(); mySerializable.myProperty = 'Hello World!'; mySerializable.mySubSerializable.mySubProperty = 'Hello Sub World!'; mySerializable.myByteArray = [0x01, 0x02]; const serialized = mySerializable.serialize(); // Deserialize const deserializable = new MySerializable(); deserializable.deserialize(serialized); console.log(deserializable.myProperty); // 'Hello World!' console.log(deserializable.mySubSerializable.mySubProperty); // 'Hello Sub World!' console.log(deserializable.myByteArray); // [0x01, 0x02] // Convert to JSON array (preserves ordering) const jsonArray = mySerializable.toJson(); console.log(JSON.stringify(jsonArray, null, 2)); // Load from JSON array const loadedSerializable = new MySerializable(); loadedSerializable.fromJson(jsonArray); console.log(loadedSerializable.myProperty); // 'Hello World!' ``` -------------------------------- ### Format Bytes to Pretty Size (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Converts a byte count into a human-readable string with appropriate units like Bytes, KB, MB, GB, and TB. This function is useful for displaying file sizes, network transfer amounts, or memory usage in a user-friendly format. It takes a number (bytes) as input and returns a string. ```typescript import { getPrettySizeFromBytes } from '@project-agonyl/agonyl-utils'; // Various file sizes console.log(getPrettySizeFromBytes(0)); // Output: 0 Byte console.log(getPrettySizeFromBytes(523)); // Output: 523 Bytes console.log(getPrettySizeFromBytes(1024)); // Output: 1.0 KB console.log(getPrettySizeFromBytes(1536)); // Output: 1.5 KB console.log(getPrettySizeFromBytes(1048576)); // Output: 1.0 MB console.log(getPrettySizeFromBytes(5242880)); // Output: 5.0 MB console.log(getPrettySizeFromBytes(1073741824)); // Output: 1.0 GB console.log(getPrettySizeFromBytes(1099511627776)); // Output: 1.0 TB // Log packet sizes import { Serializable, meta } from '@project-agonyl/agonyl-utils'; class LargePacket extends Serializable { @meta({ type: 'byte', order: 1, isArray: true, arraySize: 1000 }) public data: number[] = new Array(1000).fill(0); } const packet = new LargePacket(); const serialized = packet.serialize(); const sizeInfo = getPrettySizeFromBytes(serialized.length); console.log(`Packet size: ${sizeInfo}`); // Output: Packet size: 1000 Bytes // Monitor memory usage const buffers = []; for (let i = 0; i < 100; i++) { buffers.push(Buffer.alloc(1024 * 1024)); // 1 MB each } const totalSize = buffers.length * 1024 * 1024; console.log(`Total memory: ${getPrettySizeFromBytes(totalSize)}`); // Output: Total memory: 100.0 MB ``` -------------------------------- ### TypeScript @meta Decorator for Binary Serialization Metadata Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Demonstrates the usage of the @meta decorator to define serialization properties for a TypeScript class. This includes various data types, array configurations, and nested serializable objects. It also shows the serialization and deserialization process. ```typescript import { Serializable, meta } from '@project-agonyl/agonyl-utils'; import 'reflect-metadata'; // Required for decorator support // Complete metadata example class ComplexPacket extends Serializable { // String field with fixed length @meta({ type: 'string', order: 1, length: 50 }) public username: string = ''; // Different integer types @meta({ type: 'byte', order: 2 }) // 1 byte (0-255) public flags: number = 0; @meta({ type: 'int16', order: 3 }) // 2 bytes public serverId: number = 0; @meta({ type: 'int32', order: 4 }) // 4 bytes public sessionToken: number = 0; // Boolean (1 byte: 0 or 1) @meta({ type: 'boolean', order: 5 }) public isAdmin: boolean = false; // Array of primitives @meta({ type: 'int16', order: 6, isArray: true, arraySize: 5 }) public inventory: number[] = []; // Nested serializable object @meta({ type: 'serializable', order: 7, length: 32 }) public metadata: MetadataBlock = new MetadataBlock(); } class MetadataBlock extends Serializable { @meta({ type: 'int32', order: 1 }) public timestamp: number = 0; @meta({ type: 'string', order: 2, length: 28 }) public description: string = ''; } // Usage with all features const packet = new ComplexPacket(); packet.username = 'GameMaster'; packet.flags = 0xFF; packet.serverId = 1; packet.sessionToken = 987654321; packet.isAdmin = true; packet.inventory = [101, 102, 103, 104, 105]; packet.metadata.timestamp = Date.now(); packet.metadata.description = 'Admin login event'; const binary = packet.serialize(); console.log('Total size:', binary.length); // Calculated from all fields const restored = new ComplexPacket(); restored.deserialize(binary); console.log('Username:', restored.username); // Output: GameMaster console.log('Is admin:', restored.isAdmin); // Output: true console.log('Inventory:', restored.inventory); // Output: [101, 102, 103, 104, 105] console.log('Metadata:', restored.metadata.description); // Output: Admin login event ``` -------------------------------- ### Convert Serializable Objects to/from JSON (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Illustrates converting `Serializable` objects to a JSON array format and back, preserving field order and metadata. This is useful for debugging, configuration, and human-readable storage of binary data structures. The `toJson` method outputs an array of objects, each describing a field's properties. ```typescript import { Serializable, meta } from '@project-agonyl/agonyl-utils'; class GameConfig extends Serializable { @meta({ type: 'string', order: 1, length: 50 }) public serverName: string = ''; @meta({ type: 'int16', order: 2 }) public port: number = 0; @meta({ type: 'int32', order: 3 }) public maxPlayers: number = 0; @meta({ type: 'boolean', order: 4 }) public pvpEnabled: boolean = false; } // Convert to JSON const config = new GameConfig(); config.serverName = 'Agonyl Main Server'; config.port = 7514; config.maxPlayers = 1000; config.pvpEnabled = true; const jsonArray = config.toJson(); console.log(JSON.stringify(jsonArray, null, 2)); // Load from JSON const loadedConfig = new GameConfig(); loadedConfig.fromJson(jsonArray); console.log('Server:', loadedConfig.serverName); console.log('Port:', loadedConfig.port); console.log('Max Players:', loadedConfig.maxPlayers); console.log('PVP:', loadedConfig.pvpEnabled); ``` -------------------------------- ### BinaryReader: Sequential Binary Reading (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt A stream-based reader for binary data (files and buffers) that tracks offsets automatically. Supports both little-endian and big-endian, making it versatile for parsing various binary formats and network protocols. ```typescript import { BinaryReader } from '@project-agonyl/agonyl-utils'; import * as fs from 'fs'; // Read from file with default little-endian const reader = new BinaryReader('./game_data.bin'); // Parse file header const magic = reader.readUInt32(); // 4 bytes const version = reader.readUInt16(); // 2 bytes const recordCount = reader.readUInt16(); // 2 bytes console.log(`File magic: 0x${magic.toString(16)}`); console.log(`Version: ${version}`); console.log(`Records: ${recordCount}`); // Read records sequentially const records = []; while (!reader.isEndOfBuffer()) { const record = { id: reader.readUInt32(), name: reader.readString(32), level: reader.readUInt16(), experience: reader.readUInt32(), flags: reader.readByte() }; records.push(record); } console.log('Parsed records:', records); // Read from buffer with custom offset and big-endian const buffer = Buffer.from([ 0x00, 0x01, 0x02, 0x03, // Skip first 4 bytes 0x00, 0x0A, // uint16: 10 (BE) 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x00 // "Hello" + null terminator ]); const beReader = new BinaryReader(buffer, 4, 'BE'); const value = beReader.readUInt16(); // Reads from offset 4 const text = beReader.readString(5); console.log('Value:', value); // Output: 10 console.log('Text:', text); // Output: Hello // Manual offset control reader.setCurrentOffset(100); const dataAt100 = reader.readUInt32(); reader.resetOffset(); const dataAt0 = reader.readByte(); console.log('Current position:', reader.getCurrentOffset()); ``` -------------------------------- ### SerializableWithAutoSetSize Class Serialization in TypeScript Source: https://github.com/project-agonyl/agonyl-utils/blob/master/README.md Illustrates the usage of SerializableWithAutoSetSize for automatic size setting during serialization. The 'size' property must be the first property in the serialization order and will be automatically updated. Requires experimentalDecorators enabled in tsconfig.json. ```typescript import { SerializableWithAutoSetSize, meta } from '@project-agonyl/agonyl-utils'; class MySerializable extends SerializableWithAutoSetSize { @meta({ type: 'int', order: 1 }) public size: number = 0; @meta({ type: 'string', order: 2, length: 20 }) public myProperty: string = ''; } // Serialize const mySerializable = new MySerializable(); mySerializable.myProperty = 'Hello World!'; const serialized = mySerializable.serialize(); // Deserialize const deserializable = new MySerializable(); deserializable.deserialize(serialized); console.log(deserializable.myProperty); // 'Hello World!' ``` -------------------------------- ### SerializableWithAutoSetSize: Network Packet Serialization (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Extends Serializable to automatically calculate and prepend the packet size. Requires a size field of type 'int' or 'int32' at order 1. Useful for network protocols needing length-prefixed messages. ```typescript import { SerializableWithAutoSetSize, meta } from '@project-agonyl/agonyl-utils'; class NetworkPacket extends SerializableWithAutoSetSize { @meta({ type: 'int32', order: 1 }) public size: number = 0; // Auto-calculated during serialization @meta({ type: 'int16', order: 2 }) public packetType: number = 0; @meta({ type: 'string', order: 3, length: 100 }) public message: string = ''; @meta({ type: 'int32', order: 4 }) public timestamp: number = 0; } // Size is automatically calculated const packet = new NetworkPacket(); packet.packetType = 101; packet.message = 'Player entered zone'; packet.timestamp = Date.now(); const serialized = packet.serialize(); console.log('Total packet size:', serialized.length); // Output: 110 bytes // Size field contains the actual length const sizeFromPacket = serialized.readUInt32LE(0); console.log('Size field value:', sizeFromPacket); // Output: 110 // Deserialize and verify const received = new NetworkPacket(); received.deserialize(serialized); console.log('Packet type:', received.packetType); // Output: 101 console.log('Message:', received.message); // Output: Player entered zone console.log('Size matches:', received.size === serialized.length); // Output: true ``` -------------------------------- ### Utility Functions for Byte and String Conversion (TypeScript) Source: https://github.com/project-agonyl/agonyl-utils/blob/master/README.md Provides utility functions for various data manipulations. These include converting numbers to little-endian byte arrays, strings to UTF-8 byte arrays (with optional fixed length), converting byte counts to human-readable sizes, validating JSON strings, and extracting strings from buffers. ```typescript /** * Returns a buffer with the specified number of bytes in little endian format. * @param num The number to convert. * @param bytes The number of bytes to use (default is 4). * @returns An array of numbers representing bytes. */ function getBytesFromNumberLE(num: number, bytes = 4): number[]; /** * Returns a buffer with the string in UTF-8 format. * @param str The string to convert. * @returns An array of numbers representing UTF-8 bytes. */ function getBytesFromString(str: string): number[]; /** * Returns a buffer with the string in UTF-8 format with the specified length. * Pads with null bytes if the string is shorter than the length. * @param str The string to convert. * @param length The desired length of the byte array. * @returns An array of numbers representing UTF-8 bytes. */ function getFixedLengthBytesFromString(str: string, length: number): number[]; /** * Returns a human readable string from the specified number of bytes. * e.g., 1024 bytes -> "1 KB" * @param bytes The number of bytes. * @returns A formatted string representing the size. */ function getPrettySizeFromBytes(bytes: number): string; /** * Returns true if the string is a valid JSON string. * @param str The string to validate. * @returns True if the string is valid JSON, false otherwise. */ function isValidJsonString(str: string): boolean; /** * Returns a string from the specified buffer. * @param buffer The buffer to read from. * @param start The starting offset in the buffer. * @param length The number of bytes to read. * @returns The extracted string. */ function getStringFromBuffer(buffer: Buffer, start: number, length: number): string; ``` -------------------------------- ### Extract String from Buffer (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Extracts strings from a buffer, supporting both null-terminated and fixed-length reads from a specified offset. This function is safe for parsing C-style strings and binary data, automatically handling null byte termination. It returns an empty string for invalid ranges. ```typescript import { getStringFromBuffer } from '@project-agonyl/agonyl-utils'; // Read null-terminated string const buffer1 = Buffer.from([72, 101, 108, 108, 111, 0, 87, 111, 114, 108, 100]); const str1 = getStringFromBuffer(buffer1, 0, 11); console.log('String:', str1); // Output: Hello (stops at null byte) // Read fixed-length string from offset const buffer2 = Buffer.from('HEADER___DATAPlayerName\x00\x00\x00\x00\x00'); const header = getStringFromBuffer(buffer2, 0, 6); const data = getStringFromBuffer(buffer2, 9, 10); console.log('Header:', header); // Output: HEADER console.log('Data:', data); // Output: PlayerName // Parse game packet const packet = Buffer.from([ 0x01, 0x00, 0x00, 0x00, // packet type // Player name (20 bytes) ...Buffer.from('Alice'), ...Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), 0x0A, 0x00, // level ]); const packetType = packet.readUInt32LE(0); const playerName = getStringFromBuffer(packet, 4, 20); const level = packet.readUInt16LE(24); console.log('Type:', packetType); // Output: 1 console.log('Player:', playerName); // Output: Alice console.log('Level:', level); // Output: 10 // Handle invalid ranges safely const invalid = getStringFromBuffer(buffer1, 100, 10); console.log('Invalid range:', invalid); // Output: "" (empty string) ``` -------------------------------- ### getBytesFromNumberLE: Number to Little-Endian Bytes (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Converts numbers into little-endian byte arrays, allowing for a configurable byte width. This utility is used internally by the Serializable class and is also valuable for manual construction of binary data. ```typescript import { getBytesFromNumberLE } from '@project-agonyl/agonyl-utils'; // Convert to different byte widths const byte = getBytesFromNumberLE(255, 1); console.log('1 byte:', byte); // Output: [255] const short = getBytesFromNumberLE(1000, 2); console.log('2 bytes:', short); // Output: [232, 3] (1000 = 0x03E8) const int = getBytesFromNumberLE(16777216, 4); console.log('4 bytes:', int); // Output: [0, 0, 0, 1] (16777216 = 0x01000000) // Default is 4 bytes const defaultInt = getBytesFromNumberLE(305419896); console.log('Default:', defaultInt); // Output: [120, 86, 52, 18] // Build custom packet manually const packetBytes = [ ...getBytesFromNumberLE(42, 4), // packet ID ...getBytesFromNumberLE(12345, 2), // player ID ...getBytesFromNumberLE(99, 1), // level ...getBytesFromNumberLE(1, 1) // status flag ]; const packet = Buffer.from(packetBytes); console.log('Manual packet:', packet); // 8 bytes total ``` -------------------------------- ### Convert String to Fixed-Length Byte Array (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Converts a string to a fixed-length byte array, padding with zeros or truncating as necessary. This is crucial for fields in binary protocols that require a specific byte size. The function accepts the string and the desired length, returning a new byte array. ```typescript import { getFixedLengthBytesFromString } from '@project-agonyl/agonyl-utils'; // Pad short strings with zeros const padded = getFixedLengthBytesFromString('Hi', 10); console.log('Padded:', padded); // Output: [72, 105, 0, 0, 0, 0, 0, 0, 0, 0] // Truncate long strings const truncated = getFixedLengthBytesFromString('This is a very long string', 10); console.log('Truncated:', truncated); // Output: [84, 104, 105, 115, 32, 105, 115, 32, 97, 32] // Exact fit const exact = getFixedLengthBytesFromString('Hello', 5); console.log('Exact:', exact); // Output: [72, 101, 108, 108, 111] // Build player name field (20 bytes fixed) const playerNames = ['Alice', 'BobTheGreat', 'X']; const nameFields = playerNames.map(name => getFixedLengthBytesFromString(name, 20) ); console.log('Alice field length:', nameFields[0].length); // Output: 20 console.log('BobTheGreat field length:', nameFields[1].length); // Output: 20 console.log('X field length:', nameFields[2].length); // Output: 20 // Create character database entry const characterEntry = Buffer.from([ ...getFixedLengthBytesFromString('DragonSlayer', 20), // name ...getFixedLengthBytesFromString('Warrior', 15), // class ...getFixedLengthBytesFromString('Guild Alpha', 30) // guild ]); console.log('Entry size:', characterEntry.length); // Output: 65 bytes ``` -------------------------------- ### Convert String to Character Codes (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Converts a string into an array of its character codes using single-byte encoding (ASCII/Unicode). Useful for building custom protocol messages or processing text data at a byte level. The function takes a string as input and returns an array of numbers representing character codes. ```typescript import { getBytesFromString } from '@project-agonyl/agonyl-utils'; const bytes = getBytesFromString('Hello'); console.log('Character codes:', bytes); // Output: [72, 101, 108, 108, 111] // Build custom protocol message const commandBytes = getBytesFromString('CMD:'); const paramBytes = getBytesFromString('MOVE'); const message = Buffer.from([...commandBytes, 0x00, ...paramBytes]); console.log('Protocol message:', message); // // Process game chat message const chatMessage = 'Hello World!'; const chatBytes = getBytesFromString(chatMessage); console.log('Length:', chatBytes.length); // Output: 12 console.log('First char code:', chatBytes[0]); // Output: 72 (H) ``` -------------------------------- ### Validate JSON String Safely (TypeScript) Source: https://context7.com/project-agonyl/agonyl-utils/llms.txt Checks if a given string is valid JSON without throwing an error. This is useful for validating user input, configuration files, or API responses where malformed JSON is expected. It returns a boolean indicating validity. Dependencies include standard JavaScript JSON parsing. ```typescript import { isValidJsonString } from '@project-agonyl/agonyl-utils'; // Valid JSON console.log(isValidJsonString('{"name":"Alice"}')); // Output: true console.log(isValidJsonString('[1,2,3]')); // Output: true console.log(isValidJsonString('"string"')); // Output: true console.log(isValidJsonString('123')); // Output: true console.log(isValidJsonString('true')); // Output: true // Invalid JSON console.log(isValidJsonString('{name:Alice}')); // Output: false (unquoted key) console.log(isValidJsonString('[1,2,3')); // Output: false (unclosed bracket) console.log(isValidJsonString('undefined')); // Output: false console.log(isValidJsonString('')); // Output: false (SyntaxError: Unexpected end of JSON input) // Safe config loading function loadConfig(configString: string): object | null { if (!isValidJsonString(configString)) { console.error('Invalid configuration format'); return null; } return JSON.parse(configString); } const userInput = '{"server":"localhost","port":7514}'; const config = loadConfig(userInput); console.log('Config:', config); // Output: { server: 'localhost', port: 7514 } // Validate API responses const responses = [ '{"status":"ok","data":[1,2,3]}', '{invalid json}', '{"status":"error"}' ]; responses.forEach((response, index) => { if (isValidJsonString(response)) { const parsed = JSON.parse(response); console.log(`Response ${index}:`, parsed.status); } else { console.log(`Response ${index}: Invalid JSON`); } }); // Output: // Response 0: ok // Response 1: Invalid JSON // Response 2: Invalid JSON ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.