package config import ( "fmt" "os" "time" "gopkg.in/yaml.v3" ) type Config struct { Server ServerConfig `yaml:"server"` Database DatabaseConfig `yaml:"database"` World WorldConfig `yaml:"world"` Network NetworkConfig `yaml:"network"` Log LogConfig `yaml:"log"` } type DatabaseConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` User string `yaml:"user"` Password string `yaml:"password"` DBName string `yaml:"dbname"` MaxConns int32 `yaml:"max_conns"` MinConns int32 `yaml:"min_conns"` SaveInterval time.Duration `yaml:"save_interval"` } func (d *DatabaseConfig) DSN() string { return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", d.User, d.Password, d.Host, d.Port, d.DBName) } type ServerConfig struct { Host string `yaml:"host"` Port int `yaml:"port"` } type WorldConfig struct { TickRate int `yaml:"tick_rate"` AOI AOIConfig `yaml:"aoi"` MaxPlayers int `yaml:"max_players"` } type AOIConfig struct { Enabled bool `yaml:"enabled"` CellSize float32 `yaml:"cell_size"` ViewRange int `yaml:"view_range"` } type NetworkConfig struct { WriteBufferSize int `yaml:"write_buffer_size"` ReadBufferSize int `yaml:"read_buffer_size"` SendChannelSize int `yaml:"send_channel_size"` HeartbeatInterval time.Duration `yaml:"heartbeat_interval"` HeartbeatTimeout time.Duration `yaml:"heartbeat_timeout"` MaxMessageSize int64 `yaml:"max_message_size"` } type LogConfig struct { Level string `yaml:"level"` } func (c *Config) TickInterval() time.Duration { return time.Second / time.Duration(c.World.TickRate) } func (c *ServerConfig) Address() string { return fmt.Sprintf("%s:%d", c.Host, c.Port) } func Load(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read config file: %w", err) } cfg := defaultConfig() if err := yaml.Unmarshal(data, cfg); err != nil { return nil, fmt.Errorf("parse config file: %w", err) } // 환경변수로 DB 접속 정보 오버라이드 (Docker 환경용) if v := os.Getenv("DB_HOST"); v != "" { cfg.Database.Host = v } if v := os.Getenv("DB_PORT"); v != "" { fmt.Sscanf(v, "%d", &cfg.Database.Port) } if v := os.Getenv("DB_USER"); v != "" { cfg.Database.User = v } if v := os.Getenv("DB_PASSWORD"); v != "" { cfg.Database.Password = v } if v := os.Getenv("DB_NAME"); v != "" { cfg.Database.DBName = v } return cfg, nil } func defaultConfig() *Config { return &Config{ Server: ServerConfig{ Host: "0.0.0.0", Port: 8080, }, World: WorldConfig{ TickRate: 20, MaxPlayers: 5000, AOI: AOIConfig{ Enabled: true, CellSize: 50.0, ViewRange: 2, }, }, Database: DatabaseConfig{ Host: "localhost", Port: 5432, User: "postgres", Password: "postgres", DBName: "mmorpg", MaxConns: 50, MinConns: 5, SaveInterval: 60 * time.Second, }, Network: NetworkConfig{ WriteBufferSize: 4096, ReadBufferSize: 4096, SendChannelSize: 256, HeartbeatInterval: 5 * time.Second, HeartbeatTimeout: 15 * time.Second, MaxMessageSize: 8192, }, Log: LogConfig{ Level: "info", }, } }