142 lines
2.8 KiB
Elixir
142 lines
2.8 KiB
Elixir
defmodule Odinsea.Channel.Players do
|
|
@moduledoc """
|
|
Player storage for channel server.
|
|
Manages online player state and lookups.
|
|
|
|
Ported from Java handling.channel.PlayerStorage
|
|
|
|
Uses ETS for fast in-memory lookups.
|
|
"""
|
|
|
|
require Logger
|
|
|
|
@table :channel_players
|
|
|
|
@doc """
|
|
Starts the player storage (creates ETS table).
|
|
"""
|
|
def start_link do
|
|
:ets.new(@table, [
|
|
:set,
|
|
:public,
|
|
:named_table,
|
|
read_concurrency: true,
|
|
write_concurrency: true
|
|
])
|
|
|
|
{:ok, self()}
|
|
end
|
|
|
|
@doc """
|
|
Adds a player to the channel storage.
|
|
"""
|
|
def add_player(character_id, player_data) do
|
|
:ets.insert(@table, {character_id, player_data})
|
|
:ok
|
|
end
|
|
|
|
@doc """
|
|
Adds a player with full character state.
|
|
Extracts relevant fields from character state.
|
|
"""
|
|
def add_character(character_id, %{} = character_state) do
|
|
player_data = %{
|
|
character_id: character_id,
|
|
name: character_state.name,
|
|
map_id: character_state.map_id,
|
|
level: character_state.level,
|
|
job: character_state.job,
|
|
gm: Map.get(character_state, :gm, 0),
|
|
client_pid: character_state.client_pid
|
|
}
|
|
|
|
:ets.insert(@table, {character_id, player_data})
|
|
:ok
|
|
end
|
|
|
|
@doc """
|
|
Removes a player from the channel storage.
|
|
"""
|
|
def remove_player(character_id) do
|
|
:ets.delete(@table, character_id)
|
|
:ok
|
|
end
|
|
|
|
@doc """
|
|
Gets player data by character ID.
|
|
Returns nil if not found.
|
|
"""
|
|
def get_player(character_id) do
|
|
case :ets.lookup(@table, character_id) do
|
|
[{^character_id, data}] -> data
|
|
[] -> nil
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Checks if a character is online in this channel.
|
|
"""
|
|
def is_online?(character_id) do
|
|
:ets.member(@table, character_id)
|
|
end
|
|
|
|
@doc """
|
|
Gets all online players.
|
|
"""
|
|
def get_all_players do
|
|
:ets.tab2list(@table)
|
|
|> Enum.map(fn {_id, data} -> data end)
|
|
end
|
|
|
|
@doc """
|
|
Gets player count.
|
|
"""
|
|
def count do
|
|
:ets.info(@table, :size)
|
|
end
|
|
|
|
@doc """
|
|
Gets a player by name.
|
|
"""
|
|
def get_player_by_name(name) do
|
|
@table
|
|
|> :ets.tab2list()
|
|
|> Enum.find(fn {_id, data} -> data.name == name end)
|
|
|> case do
|
|
nil -> nil
|
|
{_, data} -> data
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Finds a player by name in the channel.
|
|
Returns the player data or nil if not found.
|
|
|
|
This is the public API for player lookup by name.
|
|
"""
|
|
def find_by_name(name, _channel_id \\ nil) do
|
|
get_player_by_name(name)
|
|
end
|
|
|
|
@doc """
|
|
Updates player data.
|
|
"""
|
|
def update_player(character_id, updates) do
|
|
case get_player(character_id) do
|
|
nil -> :error
|
|
data ->
|
|
updated = Map.merge(data, updates)
|
|
:ets.insert(@table, {character_id, updated})
|
|
:ok
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Clears all players (e.g., during shutdown).
|
|
"""
|
|
def clear do
|
|
:ets.delete_all_objects(@table)
|
|
:ok
|
|
end
|
|
end
|