defmodule Odinsea.Application do @moduledoc """ Main application supervisor for Odinsea. Ported from Java Program.java and ServerStart.java. """ use Application require Logger @impl true def start(_type, _args) do Logger.info("Starting Odinsea Server v#{version()}") # Log server configuration log_configuration() children = [ # Database repository Odinsea.Repo, # Redis connection pool {Redix, name: :redix, host: redis_config()[:host], port: redis_config()[:port]}, # Game data providers (load before servers) Odinsea.Game.ItemInfo, Odinsea.Game.MapFactory, Odinsea.Game.LifeFactory, Odinsea.Game.DropTable, Odinsea.Game.SkillFactory, Odinsea.Game.ReactorFactory, Odinsea.Game.Quest, # Cash Shop data provider Odinsea.Shop.CashItemFactory, # MTS (Maple Trading System) Odinsea.Shop.MTS, # Scripting system (must be before game servers) Odinsea.Scripting.Supervisor, # Timer system (before game servers) Odinsea.Game.Timer.WorldTimer, Odinsea.Game.Timer.MapTimer, Odinsea.Game.Timer.BuffTimer, Odinsea.Game.Timer.EventTimer, Odinsea.Game.Timer.CloneTimer, Odinsea.Game.Timer.EtcTimer, Odinsea.Game.Timer.CheatTimer, Odinsea.Game.Timer.PingTimer, Odinsea.Game.Timer.RedisTimer, Odinsea.Game.Timer.EMTimer, Odinsea.Game.Timer.GlobalTimer, # Registry for player lookups {Registry, keys: :unique, name: Odinsea.PlayerRegistry}, # Registry for channel lookups {Registry, keys: :unique, name: Odinsea.Channel.Registry}, # Registry for character processes (in-game players) {Registry, keys: :unique, name: Odinsea.CharacterRegistry}, # Registry for map instances {map_id, channel_id} => pid {Registry, keys: :unique, name: Odinsea.MapRegistry}, # Dynamic supervisor for client connections {DynamicSupervisor, strategy: :one_for_one, name: Odinsea.ClientSupervisor}, # Dynamic supervisor for map instances {DynamicSupervisor, strategy: :one_for_one, name: Odinsea.MapSupervisor}, # Game world supervisor Odinsea.World.Supervisor, # Login server Odinsea.Login.Listener, # Channel servers (dynamic based on config) {Odinsea.Channel.Supervisor, game_config()[:channels]}, # Cash shop server Odinsea.Shop.Listener ] opts = [strategy: :one_for_one, name: Odinsea.Supervisor] Supervisor.start_link(children, opts) end @impl true def prep_stop(state) do Logger.info("Odinsea server shutting down...") # Perform graceful shutdown tasks :ok end @doc """ Returns the server version. """ def version do "0.1.0-#{Odinsea.Constants.Server.server_revision()}" end @doc """ Returns the current unix timestamp in milliseconds. """ def current_time do System.system_time(:millisecond) end @doc """ Returns uptime in milliseconds. """ def uptime do current_time() - Application.get_env(:odinsea, :start_time, current_time()) end defp log_configuration do server = server_config() rates = Application.get_env(:odinsea, :rates, []) Logger.info(""" Server Configuration: Name: #{server[:name]} Host: #{server[:host]} Revision: #{server[:revision]} EXP Rate: #{rates[:exp]}x Meso Rate: #{rates[:meso]}x """) login = login_config() Logger.info("Login Server: port=#{login[:port]}, limit=#{login[:user_limit]}") game = game_config() Logger.info("Game Channels: count=#{game[:channels]}") shop = shop_config() Logger.info("Cash Shop: port=#{shop[:port]}") end defp server_config, do: Application.get_env(:odinsea, :server, []) defp login_config, do: Application.get_env(:odinsea, :login, []) defp game_config, do: Application.get_env(:odinsea, :game, []) defp shop_config, do: Application.get_env(:odinsea, :shop, []) defp redis_config, do: Application.get_env(:odinsea, :redis, []) end