199 lines
5.4 KiB
PHP
Executable File
199 lines
5.4 KiB
PHP
Executable File
#!/usr/bin/env php
|
|
<?php
|
|
|
|
/**
|
|
* Generate packet definitions for C++ client and Go server from packets.json
|
|
*/
|
|
|
|
/**
|
|
* Load packet definitions from JSON file
|
|
*/
|
|
function load_packet_definitions($filename = 'packets.json') {
|
|
if (!file_exists($filename)) {
|
|
throw new Exception("Could not open $filename");
|
|
}
|
|
|
|
$content = file_get_contents($filename);
|
|
$packets = json_decode($content, true);
|
|
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
throw new Exception("JSON decode error: " . json_last_error_msg());
|
|
}
|
|
|
|
return $packets;
|
|
}
|
|
|
|
/**
|
|
* Convert PascalCase to SNAKE_CASE
|
|
*/
|
|
function to_snake_case($str) {
|
|
$result = preg_replace('/([A-Z])/', '_$1', $str);
|
|
return strtoupper(ltrim($result, '_'));
|
|
}
|
|
|
|
/**
|
|
* Generate C++ header file with packet definitions
|
|
*/
|
|
function generate_cpp_header($packets) {
|
|
$header = <<<CPP
|
|
// Auto-generated packet definitions from packets.json
|
|
// DO NOT EDIT MANUALLY
|
|
|
|
#pragma once
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
CPP;
|
|
|
|
// Generate enum
|
|
$header .= "enum class MessageType : uint8_t {\n";
|
|
|
|
// Sort keys for consistent output
|
|
$names = array_keys($packets['opcodes']);
|
|
sort($names);
|
|
|
|
foreach ($names as $i => $name) {
|
|
$packet = $packets['opcodes'][$name];
|
|
$header .= sprintf(" %s = %s", $name, $packet['id']);
|
|
if ($i < count($names) - 1) {
|
|
$header .= ",";
|
|
}
|
|
$header .= "\n";
|
|
}
|
|
$header .= "};\n\n";
|
|
|
|
// Generate packet structures
|
|
$header .= "// Packet structure definitions\n";
|
|
$header .= "namespace Packets {\n\n";
|
|
|
|
foreach ($names as $name) {
|
|
$packet = $packets['opcodes'][$name];
|
|
if (!empty($packet['fields'])) {
|
|
$header .= sprintf("struct %s {\n", $name);
|
|
$header .= sprintf(" static constexpr MessageType TYPE = MessageType::%s;\n", $name);
|
|
|
|
foreach ($packet['fields'] as $field) {
|
|
$cpp_type = '';
|
|
|
|
switch ($field['type']) {
|
|
case 'string':
|
|
$cpp_type = 'std::string';
|
|
break;
|
|
case 'uint8':
|
|
$cpp_type = 'uint8_t';
|
|
break;
|
|
case 'uint32':
|
|
$cpp_type = 'uint32_t';
|
|
break;
|
|
case 'float32':
|
|
$cpp_type = 'float';
|
|
break;
|
|
case 'array':
|
|
$header .= sprintf(" // Array field: %s - requires custom handling\n", $field['name']);
|
|
continue 2;
|
|
}
|
|
|
|
$header .= sprintf(" %s %s;\n", $cpp_type, $field['name']);
|
|
}
|
|
|
|
$header .= "};\n\n";
|
|
}
|
|
}
|
|
|
|
$header .= "} // namespace Packets\n";
|
|
|
|
return $header;
|
|
}
|
|
|
|
/**
|
|
* Generate Go file with packet definitions
|
|
*/
|
|
function generate_go_file($packets) {
|
|
$go_file = <<<GO
|
|
// Auto-generated packet definitions from packets.json
|
|
// DO NOT EDIT MANUALLY
|
|
|
|
package main
|
|
|
|
// Message type constants
|
|
const (
|
|
GO;
|
|
$go_file .= "\n";
|
|
|
|
// Sort keys for consistent output
|
|
$names = array_keys($packets['opcodes']);
|
|
sort($names);
|
|
|
|
// Generate constants
|
|
foreach ($names as $name) {
|
|
$packet = $packets['opcodes'][$name];
|
|
$const_name = 'MSG_' . to_snake_case($name);
|
|
$go_file .= sprintf("\t%s = %s\n", $const_name, $packet['id']);
|
|
}
|
|
|
|
$go_file .= ")\n\n";
|
|
|
|
// Generate packet structures
|
|
$go_file .= "// Packet structure definitions\n\n";
|
|
|
|
foreach ($names as $name) {
|
|
$packet = $packets['opcodes'][$name];
|
|
if (!empty($packet['fields'])) {
|
|
$struct_name = "Packet $name";
|
|
$go_file .= sprintf("type %s struct {\n", $struct_name);
|
|
|
|
foreach ($packet['fields'] as $field) {
|
|
$field_name = ucfirst($field['name']);
|
|
$go_type = '';
|
|
|
|
switch ($field['type']) {
|
|
case 'string':
|
|
$go_type = 'string';
|
|
break;
|
|
case 'uint8':
|
|
$go_type = 'uint8';
|
|
break;
|
|
case 'uint32':
|
|
$go_type = 'uint32';
|
|
break;
|
|
case 'float32':
|
|
$go_type = 'float32';
|
|
break;
|
|
case 'array':
|
|
$go_file .= sprintf("\t// Array field: %s - requires custom handling\n", $field_name);
|
|
continue 2;
|
|
}
|
|
|
|
$go_file .= sprintf("\t%s %s\n", $field_name, $go_type);
|
|
}
|
|
|
|
$go_file .= "}\n\n";
|
|
}
|
|
}
|
|
|
|
return $go_file;
|
|
}
|
|
|
|
try {
|
|
// Load packet definitions
|
|
$packets = load_packet_definitions();
|
|
|
|
// Generate C++ header
|
|
$cpp_header = generate_cpp_header($packets);
|
|
$cpp_path = 'client/net/PacketDefinitions.hpp';
|
|
file_put_contents($cpp_path, $cpp_header);
|
|
echo "Generated $cpp_path\n";
|
|
|
|
// Generate Go file
|
|
$go_file = generate_go_file($packets);
|
|
$go_path = 'server/packet_definitions.go';
|
|
file_put_contents($go_path, $go_file);
|
|
echo "Generated $go_path\n";
|
|
|
|
echo sprintf("Successfully generated packet definitions for protocol version %s\n", $packets['version']);
|
|
|
|
} catch (Exception $e) {
|
|
echo "Error: " . $e->getMessage() . "\n";
|
|
exit(1);
|
|
}
|