submit world server skeleton

This commit is contained in:
Sky Johnson 2025-08-07 20:01:51 -05:00
parent 68479a5f0c
commit fe1a74aa7f
2 changed files with 216 additions and 3 deletions

6
.gitignore vendored
View File

@ -19,6 +19,6 @@
go.work
# Test builds
./world_config.json
./world_server
./world.db
/world_config.json
/world_server
/world.db

213
cmd/world_server/main.go Normal file
View File

@ -0,0 +1,213 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"eq2emu/internal/world"
)
const defaultConfigFile = "world_config.json"
var (
configFile = flag.String("config", defaultConfigFile, "Path to configuration file")
listenAddr = flag.String("listen-addr", "", "Override listen address")
listenPort = flag.Int("listen-port", 0, "Override listen port")
webPort = flag.Int("web-port", 0, "Override web interface port")
dbPath = flag.String("db", "", "Override database path")
logLevel = flag.String("log-level", "", "Override log level (debug, info, warn, error)")
serverName = flag.String("name", "", "Override server name")
xpRate = flag.Float64("xp-rate", 0, "Override XP rate")
showVersion = flag.Bool("version", false, "Show version and exit")
)
// Version information (set at build time)
var (
Version = "1.0.0-dev"
BuildTime = "unknown"
GitCommit = "unknown"
)
func main() {
flag.Parse()
if *showVersion {
fmt.Printf("EQ2Go World Server\n")
fmt.Printf("Version: %s\n", Version)
fmt.Printf("Build Time: %s\n", BuildTime)
fmt.Printf("Git Commit: %s\n", GitCommit)
os.Exit(0)
}
// Load configuration
config, err := loadConfig(*configFile)
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
// Apply command-line overrides
applyOverrides(config)
// Print startup banner
printBanner(config)
// Create world server
worldServer, err := world.NewWorld(config)
if err != nil {
log.Fatalf("Failed to create world server: %v", err)
}
// Start world server
if err := worldServer.Start(); err != nil {
log.Fatalf("Failed to start world server: %v", err)
}
// Setup signal handlers
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
// Run server in background
go worldServer.Process()
// Wait for shutdown signal
sig := <-sigChan
fmt.Printf("\nReceived signal: %v\n", sig)
// Graceful shutdown
if err := worldServer.Stop(); err != nil {
log.Printf("Error during shutdown: %v", err)
}
}
// loadConfig loads the configuration from file
func loadConfig(filename string) (*world.WorldConfig, error) {
// Check if config file exists
if _, err := os.Stat(filename); os.IsNotExist(err) {
// Create default configuration
config := createDefaultConfig()
// Save default configuration
if err := saveConfig(filename, config); err != nil {
return nil, fmt.Errorf("failed to save default config: %w", err)
}
fmt.Printf("Created default configuration file: %s\n", filename)
return config, nil
}
// Load existing configuration
file, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("failed to open config file: %w", err)
}
defer file.Close()
var config world.WorldConfig
decoder := json.NewDecoder(file)
if err := decoder.Decode(&config); err != nil {
return nil, fmt.Errorf("failed to decode config: %w", err)
}
return &config, nil
}
// saveConfig saves the configuration to file
func saveConfig(filename string, config *world.WorldConfig) error {
file, err := os.Create(filename)
if err != nil {
return fmt.Errorf("failed to create config file: %w", err)
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
if err := encoder.Encode(config); err != nil {
return fmt.Errorf("failed to encode config: %w", err)
}
return nil
}
// createDefaultConfig creates a default configuration
func createDefaultConfig() *world.WorldConfig {
return &world.WorldConfig{
// Network settings
ListenAddr: "0.0.0.0",
ListenPort: 9000,
MaxClients: 1000,
// Web interface settings
WebAddr: "0.0.0.0",
WebPort: 8080,
WebCertFile: "",
WebKeyFile: "",
WebKeyPassword: "",
// Database settings
DatabasePath: "world.db",
// Server settings
ServerName: "EQ2Go World Server",
ServerMOTD: "Welcome to EQ2Go!",
LogLevel: "info",
// Game settings
XPRate: 1.0,
TSXPRate: 1.0,
CoinRate: 1.0,
LootRate: 1.0,
// Login server settings
LoginServerAddr: "127.0.0.1",
LoginServerPort: 5999,
LoginServerKey: "",
}
}
// applyOverrides applies command-line overrides to the configuration
func applyOverrides(config *world.WorldConfig) {
if *listenAddr != "" {
config.ListenAddr = *listenAddr
}
if *listenPort > 0 {
config.ListenPort = *listenPort
}
if *webPort > 0 {
config.WebPort = *webPort
}
if *dbPath != "" {
config.DatabasePath = *dbPath
}
if *logLevel != "" {
config.LogLevel = *logLevel
}
if *serverName != "" {
config.ServerName = *serverName
}
if *xpRate > 0 {
config.XPRate = float32(*xpRate)
}
}
// printBanner prints the server startup banner
func printBanner(config *world.WorldConfig) {
fmt.Println("================================================================================")
fmt.Println(" EQ2Go World Server")
fmt.Println("================================================================================")
fmt.Printf("Version: %s\n", Version)
fmt.Printf("Server Name: %s\n", config.ServerName)
fmt.Printf("Listen Address: %s:%d\n", config.ListenAddr, config.ListenPort)
fmt.Printf("Web Interface: %s:%d\n", config.WebAddr, config.WebPort)
fmt.Printf("Database: %s\n", config.DatabasePath)
fmt.Printf("Log Level: %s\n", config.LogLevel)
fmt.Printf("XP Rate: %.1fx\n", config.XPRate)
fmt.Printf("TS XP Rate: %.1fx\n", config.TSXPRate)
fmt.Printf("Coin Rate: %.1fx\n", config.CoinRate)
fmt.Printf("Loot Rate: %.1fx\n", config.LootRate)
fmt.Println("================================================================================")
}