server uses existing heightmap
This commit is contained in:
parent
34bbc39595
commit
4484b381b8
@ -1,198 +0,0 @@
|
|||||||
#!/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);
|
|
||||||
}
|
|
||||||
96
packets.json
96
packets.json
@ -1,96 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "1.0.0",
|
|
||||||
"opcodes": {
|
|
||||||
"Login": {
|
|
||||||
"id": "0x01",
|
|
||||||
"fields": []
|
|
||||||
},
|
|
||||||
"Position": {
|
|
||||||
"id": "0x02",
|
|
||||||
"fields": [
|
|
||||||
{"name": "x", "type": "float32"},
|
|
||||||
{"name": "y", "type": "float32"},
|
|
||||||
{"name": "z", "type": "float32"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Spawn": {
|
|
||||||
"id": "0x03",
|
|
||||||
"fields": [
|
|
||||||
{"name": "playerId", "type": "uint32"},
|
|
||||||
{"name": "x", "type": "float32"},
|
|
||||||
{"name": "y", "type": "float32"},
|
|
||||||
{"name": "z", "type": "float32"},
|
|
||||||
{"name": "color", "type": "string"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Move": {
|
|
||||||
"id": "0x04",
|
|
||||||
"fields": [
|
|
||||||
{"name": "playerId", "type": "uint32"},
|
|
||||||
{"name": "dx", "type": "float32"},
|
|
||||||
{"name": "dy", "type": "float32"},
|
|
||||||
{"name": "dz", "type": "float32"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Update": {
|
|
||||||
"id": "0x05",
|
|
||||||
"fields": [
|
|
||||||
{"name": "playerId", "type": "uint32"},
|
|
||||||
{"name": "x", "type": "float32"},
|
|
||||||
{"name": "y", "type": "float32"},
|
|
||||||
{"name": "z", "type": "float32"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"PlayerJoined": {
|
|
||||||
"id": "0x06",
|
|
||||||
"fields": [
|
|
||||||
{"name": "playerId", "type": "uint32"},
|
|
||||||
{"name": "x", "type": "float32"},
|
|
||||||
{"name": "y", "type": "float32"},
|
|
||||||
{"name": "z", "type": "float32"},
|
|
||||||
{"name": "color", "type": "string"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"PlayerLeft": {
|
|
||||||
"id": "0x07",
|
|
||||||
"fields": [
|
|
||||||
{"name": "playerId", "type": "uint32"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"PlayerList": {
|
|
||||||
"id": "0x08",
|
|
||||||
"fields": [
|
|
||||||
{"name": "count", "type": "uint8"},
|
|
||||||
{"name": "players", "type": "array", "itemType": {
|
|
||||||
"fields": [
|
|
||||||
{"name": "playerId", "type": "uint32"},
|
|
||||||
{"name": "x", "type": "float32"},
|
|
||||||
{"name": "y", "type": "float32"},
|
|
||||||
{"name": "z", "type": "float32"},
|
|
||||||
{"name": "color", "type": "string"}
|
|
||||||
]
|
|
||||||
}}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ChangeColor": {
|
|
||||||
"id": "0x09",
|
|
||||||
"fields": [
|
|
||||||
{"name": "playerId", "type": "uint32"},
|
|
||||||
{"name": "color", "type": "string"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"ColorChanged": {
|
|
||||||
"id": "0x0A",
|
|
||||||
"fields": [
|
|
||||||
{"name": "playerId", "type": "uint32"},
|
|
||||||
{"name": "color", "type": "string"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"types": {
|
|
||||||
"uint8": {"size": 1, "encoding": "little-endian"},
|
|
||||||
"uint32": {"size": 4, "encoding": "little-endian"},
|
|
||||||
"float32": {"size": 4, "encoding": "little-endian"},
|
|
||||||
"string": {"encoding": "length-prefixed", "lengthType": "uint8"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -149,20 +149,37 @@ func main() {
|
|||||||
var (
|
var (
|
||||||
port = flag.String("port", "9999", "UDP port to listen on")
|
port = flag.String("port", "9999", "UDP port to listen on")
|
||||||
worldSize = flag.Int("size", WorldSize, "World size for heightmap generation")
|
worldSize = flag.Int("size", WorldSize, "World size for heightmap generation")
|
||||||
skipGen = flag.Bool("skip-gen", false, "Skip heightmap generation")
|
skipGen = flag.Bool("skip-gen", false, "Skip heightmap generation (fail if none exists)")
|
||||||
|
forceGen = flag.Bool("force-gen", false, "Force heightmap regeneration even if one exists")
|
||||||
assetsPath = flag.String("assets", "../assets", "Path to assets directory")
|
assetsPath = flag.String("assets", "../assets", "Path to assets directory")
|
||||||
)
|
)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Setup logging
|
// Setup logging
|
||||||
log.SetPrefix("[GameServer] ")
|
log.SetPrefix("[Game] ")
|
||||||
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
|
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
|
||||||
|
|
||||||
var heightmap [][]float32
|
var heightmap [][]float32
|
||||||
|
binPath := fmt.Sprintf("%s/heightmap.bin", *assetsPath)
|
||||||
|
|
||||||
if !*skipGen {
|
// Check if heightmap exists and should be loaded
|
||||||
// Generate and save heightmap
|
if _, err := os.Stat(binPath); err == nil && !*forceGen && !*skipGen {
|
||||||
log.Printf("Generating %dx%d heightmap...", *worldSize, *worldSize)
|
// Heightmap exists and we're not forcing regeneration
|
||||||
|
log.Printf("Found existing heightmap at %s, loading...", binPath)
|
||||||
|
heightmap, err = loadHeightmapBinary(binPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to load existing heightmap: %v, generating new one...", err)
|
||||||
|
heightmap = nil
|
||||||
|
} else {
|
||||||
|
log.Printf("Successfully loaded existing heightmap")
|
||||||
|
}
|
||||||
|
} else if *forceGen {
|
||||||
|
log.Printf("Force regeneration requested, ignoring existing heightmap")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate new heightmap if needed (not loaded, force generation, or doesn't exist)
|
||||||
|
if heightmap == nil && !*skipGen {
|
||||||
|
log.Printf("Generating new %dx%d heightmap...", *worldSize, *worldSize)
|
||||||
heightmap = generateHeightmap(*worldSize)
|
heightmap = generateHeightmap(*worldSize)
|
||||||
|
|
||||||
pngPath := fmt.Sprintf("%s/heightmap.png", *assetsPath)
|
pngPath := fmt.Sprintf("%s/heightmap.png", *assetsPath)
|
||||||
@ -172,20 +189,13 @@ func main() {
|
|||||||
log.Printf("Saved heightmap PNG to %s", pngPath)
|
log.Printf("Saved heightmap PNG to %s", pngPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
binPath := fmt.Sprintf("%s/heightmap.bin", *assetsPath)
|
|
||||||
if err := saveHeightmapBinary(heightmap, binPath); err != nil {
|
if err := saveHeightmapBinary(heightmap, binPath); err != nil {
|
||||||
log.Fatalf("Failed to save binary heightmap: %v", err)
|
log.Fatalf("Failed to save binary heightmap: %v", err)
|
||||||
}
|
}
|
||||||
log.Printf("Saved heightmap binary to %s", binPath)
|
log.Printf("Saved heightmap binary to %s", binPath)
|
||||||
} else {
|
} else if *skipGen && heightmap == nil {
|
||||||
// Load existing heightmap
|
// skip-gen was specified but no heightmap exists
|
||||||
binPath := fmt.Sprintf("%s/heightmap.bin", *assetsPath)
|
log.Fatalf("No existing heightmap found and generation was skipped (--skip-gen flag)")
|
||||||
log.Printf("Loading existing heightmap from %s", binPath)
|
|
||||||
var err error
|
|
||||||
heightmap, err = loadHeightmapBinary(binPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Failed to load heightmap: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server, err := net.NewServer(*port, heightmap)
|
server, err := net.NewServer(*port, heightmap)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user