defmodule Odinsea.Admin.Handler do @moduledoc """ Main admin command handler. Ported from Java handling.admin.AdminHandler Parses chat messages starting with '!' as admin commands and routes them to the appropriate command implementation. """ require Logger alias Odinsea.Admin.Commands alias Odinsea.Channel.Packets @doc """ Parses and executes an admin command from chat message. Commands start with '!' followed by the command name and arguments. Example: "!warp PlayerName 100000000" Returns: - {:ok, result_message} - Command executed successfully - {:error, reason} - Command failed - :not_command - Message is not an admin command """ def handle_command(message, client_state) when is_binary(message) do # Check if message is a command (starts with !) if String.starts_with?(message, "!") do parse_and_execute(message, client_state) else :not_command end end @doc """ Parses command string and executes. """ def parse_and_execute(message, client_state) do # Remove leading '!' and split into command and arguments command_str = String.slice(message, 1..-1//-1) parts = String.split(command_str) case parts do [] -> {:error, "Empty command"} [command | args] -> command = String.downcase(command) char_id = if client_state.character_id, do: client_state.character_id, else: "unknown" Logger.info("Admin command from #{char_id}: #{command} #{inspect(args)}") # Get admin state (character info with GM level) admin_state = build_admin_state(client_state) case Commands.execute(command, args, admin_state) do {:ok, result} -> # Send success message back to admin notify_admin(client_state, result) {:ok, result} {:error, reason} -> # Send error message back to admin notify_admin(client_state, "Error: #{reason}") {:error, reason} end end end @doc """ Checks if a message is an admin command. """ def admin_command?(message) do String.starts_with?(message, "!") end @doc """ Gets the command name from a message (for logging). """ def extract_command_name(message) do case String.split(message) do [first | _] -> String.downcase(String.trim_leading(first, "!")) _ -> "unknown" end end @doc """ Sends help information to the admin. """ def send_help(client_state) do commands = Commands.list_commands() help_text = [ "=== Admin Commands ===", "" | Enum.map(commands, fn {cmd, args, desc} -> "!#{cmd} #{args} - #{desc}" end) ] |> Enum.join("\n") notify_admin(client_state, help_text) end # ============================================================================ # Private Functions # ============================================================================ defp build_admin_state(client_state) do # Get character information including GM level gm_level = get_gm_level(client_state) %{ character_id: client_state.character_id, channel_id: client_state.channel_id, gm_level: gm_level, client_pid: self() } end defp get_gm_level(client_state) do # Try to get GM level from character case client_state.character_id do nil -> 0 character_id -> # In a full implementation, this would query the character state # For now, use a default or check player storage case Odinsea.Channel.Players.get_player(character_id) do nil -> 0 player_data -> Map.get(player_data, :gm, 0) end end end defp notify_admin(client_state, message) do case client_state.character_id do nil -> :ok character_id -> case Odinsea.Channel.Players.get_player(character_id) do nil -> :ok %{client_pid: pid} when is_pid(pid) -> packet = Packets.drop_message(5, message) send(pid, {:send_packet, packet}) :ok _ -> :ok end end end end