138 lines
3.8 KiB
Go
138 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
)
|
|
|
|
const (
|
|
ConfigFile = "world_config.json"
|
|
Version = "0.1.0"
|
|
)
|
|
|
|
// printHeader displays the EQ2Emu banner and copyright info
|
|
func printHeader() {
|
|
fmt.Println("EQ2Emulator World Server")
|
|
fmt.Printf("Version: %s\n", Version)
|
|
fmt.Println()
|
|
fmt.Println("Copyright (C) 2007-2026 EQ2Emulator Development Team")
|
|
fmt.Println("https://www.eq2emu.com")
|
|
fmt.Println()
|
|
fmt.Println("EQ2Emulator is free software licensed under the GNU GPL v3")
|
|
fmt.Println("See LICENSE file for details")
|
|
fmt.Println()
|
|
}
|
|
|
|
// loadConfig loads configuration from JSON file with command line overrides
|
|
func loadConfig() (*WorldConfig, error) {
|
|
// Default configuration
|
|
config := &WorldConfig{
|
|
ListenAddr: "0.0.0.0",
|
|
ListenPort: 9000,
|
|
MaxClients: 1000,
|
|
BufferSize: 8192,
|
|
WebAddr: "0.0.0.0",
|
|
WebPort: 8080,
|
|
DatabasePath: "world.db",
|
|
XPRate: 1.0,
|
|
TSXPRate: 1.0,
|
|
VitalityRate: 1.0,
|
|
LogLevel: "info",
|
|
ThreadedLoad: true,
|
|
}
|
|
|
|
// Load from config file if it exists
|
|
if data, err := os.ReadFile(ConfigFile); err == nil {
|
|
if err := json.Unmarshal(data, config); err != nil {
|
|
return nil, fmt.Errorf("failed to parse config file: %w", err)
|
|
}
|
|
log.Printf("Loaded configuration from %s", ConfigFile)
|
|
} else {
|
|
log.Printf("Config file %s not found, using defaults", ConfigFile)
|
|
}
|
|
|
|
// Command line overrides
|
|
flag.StringVar(&config.ListenAddr, "listen-addr", config.ListenAddr, "UDP listen address")
|
|
flag.IntVar(&config.ListenPort, "listen-port", config.ListenPort, "UDP listen port")
|
|
flag.IntVar(&config.MaxClients, "max-clients", config.MaxClients, "Maximum client connections")
|
|
flag.StringVar(&config.WebAddr, "web-addr", config.WebAddr, "Web server address")
|
|
flag.IntVar(&config.WebPort, "web-port", config.WebPort, "Web server port")
|
|
flag.StringVar(&config.DatabasePath, "db-path", config.DatabasePath, "Database file path")
|
|
flag.StringVar(&config.LogLevel, "log-level", config.LogLevel, "Log level (debug, info, warn, error)")
|
|
flag.BoolVar(&config.ThreadedLoad, "threaded-load", config.ThreadedLoad, "Use threaded loading")
|
|
flag.Parse()
|
|
|
|
return config, nil
|
|
}
|
|
|
|
// saveConfig saves the current configuration to file
|
|
func saveConfig(config *WorldConfig) error {
|
|
data, err := json.MarshalIndent(config, "", " ")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal config: %w", err)
|
|
}
|
|
|
|
if err := os.WriteFile(ConfigFile, data, 0644); err != nil {
|
|
return fmt.Errorf("failed to write config file: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// setupSignalHandlers sets up graceful shutdown on SIGINT/SIGTERM
|
|
func setupSignalHandlers(world *World) <-chan os.Signal {
|
|
sigChan := make(chan os.Signal, 1)
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
go func() {
|
|
sig := <-sigChan
|
|
log.Printf("Received signal %v, initiating graceful shutdown...", sig)
|
|
world.Shutdown()
|
|
}()
|
|
|
|
return sigChan
|
|
}
|
|
|
|
func main() {
|
|
printHeader()
|
|
|
|
// Load configuration
|
|
config, err := loadConfig()
|
|
if err != nil {
|
|
log.Fatalf("Configuration error: %v", err)
|
|
}
|
|
|
|
// Save config file with any command line overrides
|
|
if err := saveConfig(config); err != nil {
|
|
log.Printf("Warning: failed to save config: %v", err)
|
|
}
|
|
|
|
// Create world server instance
|
|
world, err := NewWorld(config)
|
|
if err != nil {
|
|
log.Fatalf("Failed to create world server: %v", err)
|
|
}
|
|
|
|
// Initialize all components
|
|
log.Println("Initializing EQ2Emulator World Server...")
|
|
if err := world.Initialize(); err != nil {
|
|
log.Fatalf("Failed to initialize world server: %v", err)
|
|
}
|
|
|
|
// Setup signal handlers for graceful shutdown
|
|
setupSignalHandlers(world)
|
|
|
|
// Run the server
|
|
log.Println("Starting World Server...")
|
|
if err := world.Run(); err != nil {
|
|
log.Fatalf("World server error: %v", err)
|
|
}
|
|
|
|
log.Println("World Server stopped gracefully")
|
|
}
|