Packages

SDK for GameServer hooks development. Provides type specs, documentation, and IDE autocomplete for GameServer modules without requiring the full server.

Current section

Files

Jump to
game_server_sdk lib game_server leaderboards.ex
Raw

lib/game_server/leaderboards.ex

defmodule GameServer.Leaderboards do
@moduledoc ~S"""
The Leaderboards context.
Provides server-authoritative leaderboard management. Scores can only be
submitted via server-side code — there is no public API for score submission.
## Usage
# Create a leaderboard
{:ok, lb} = Leaderboards.create_leaderboard(%{
slug: "weekly_kills",
title: "Weekly Kills",
sort_order: :desc,
operator: :incr
})
# Submit score (server-only): resolve the active leaderboard first and submit by ID
leaderboard = Leaderboards.get_active_leaderboard_by_slug("weekly_kills")
{:ok, record} = Leaderboards.submit_score(leaderboard.id, user_id, 10)
# List records with rank (use leaderboard id)
records = Leaderboards.list_records(leaderboard.id, page: 1, limit: 25)
# Get user's record (use leaderboard id)
{:ok, record} = Leaderboards.get_user_record(leaderboard.id, user_id)
**Note:** This is an SDK stub. Calling these functions will raise an error.
The actual implementation runs on the GameServer.
"""
@doc ~S"""
Returns a changeset for a leaderboard (used in forms).
"""
@spec change_leaderboard(GameServer.Leaderboards.Leaderboard.t()) :: Ecto.Changeset.t()
def change_leaderboard(_leaderboard) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Leaderboards.change_leaderboard/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Returns a changeset for a leaderboard (used in forms).
"""
@spec change_leaderboard(GameServer.Leaderboards.Leaderboard.t(), map()) :: Ecto.Changeset.t()
def change_leaderboard(_leaderboard, _attrs) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Leaderboards.change_leaderboard/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Returns a changeset for a record (used in admin forms).
"""
@spec change_record(GameServer.Leaderboards.Record.t()) :: Ecto.Changeset.t()
def change_record(_record) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Leaderboards.change_record/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Returns a changeset for a record (used in admin forms).
"""
@spec change_record(GameServer.Leaderboards.Record.t(), map()) :: Ecto.Changeset.t()
def change_record(_record, _attrs) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Leaderboards.change_record/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Count all leaderboard records across all leaderboards.
"""
@spec count_all_records() :: non_neg_integer()
def count_all_records() do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Leaderboards.count_all_records/0 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Counts unique leaderboard slugs.
"""
@spec count_leaderboard_groups() :: non_neg_integer()
def count_leaderboard_groups() do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Leaderboards.count_leaderboard_groups/0 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Counts leaderboards matching the given filters.
Accepts the same filter options as `list_leaderboards/1`.
"""
@spec count_leaderboards() :: non_neg_integer()
def count_leaderboards() do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Leaderboards.count_leaderboards/0 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Counts leaderboards matching the given filters.
Accepts the same filter options as `list_leaderboards/1`.
"""
@spec count_leaderboards(keyword()) :: non_neg_integer()
def count_leaderboards(_opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Leaderboards.count_leaderboards/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Counts records for a leaderboard.
"""
@spec count_records(Ecto.UUID.t()) :: non_neg_integer()
def count_records(_leaderboard_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Leaderboards.count_records/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Counts records for a leaderboard.
"""
@spec count_records(
Ecto.UUID.t(),
keyword()
) :: non_neg_integer()
def count_records(_leaderboard_id, _opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
0
_ ->
raise "GameServer.Leaderboards.count_records/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Creates a new leaderboard.
## Attributes
See `t:GameServer.Types.leaderboard_create_attrs/0` for available fields.
## Examples
iex> create_leaderboard(%{slug: "my_lb", title: "My Leaderboard"})
{:ok, %Leaderboard{}}
iex> create_leaderboard(%{slug: "", title: ""})
{:error, %Ecto.Changeset{}}
"""
@spec create_leaderboard(GameServer.Types.leaderboard_create_attrs()) ::
{:ok, GameServer.Leaderboards.Leaderboard.t()} | {:error, Ecto.Changeset.t()}
def create_leaderboard(_attrs) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Leaderboard{id: 0, slug: "", title: "", description: nil, sort_order: :desc, operator: :set, starts_at: nil, ends_at: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.create_leaderboard/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Deletes a leaderboard and all its records.
"""
@spec delete_leaderboard(GameServer.Leaderboards.Leaderboard.t()) ::
{:ok, GameServer.Leaderboards.Leaderboard.t()} | {:error, Ecto.Changeset.t()}
def delete_leaderboard(_leaderboard) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Leaderboard{id: 0, slug: "", title: "", description: nil, sort_order: :desc, operator: :set, starts_at: nil, ends_at: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.delete_leaderboard/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Deletes a record.
"""
@spec delete_record(GameServer.Leaderboards.Record.t()) ::
{:ok, GameServer.Leaderboards.Record.t()} | {:error, Ecto.Changeset.t()}
def delete_record(_record) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.delete_record/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Deletes a user's record from a leaderboard.
Accepts either leaderboard ID or slug (both strings).
"""
@spec delete_user_record(String.t(), Ecto.UUID.t()) ::
{:ok, GameServer.Leaderboards.Record.t()} | {:error, :not_found}
def delete_user_record(_id_or_slug, _user_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.delete_user_record/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Ends a leaderboard by setting `ends_at` to the current time.
"""
@spec end_leaderboard(GameServer.Leaderboards.Leaderboard.t() | String.t()) ::
{:ok, GameServer.Leaderboards.Leaderboard.t()} | {:error, Ecto.Changeset.t() | :not_found}
def end_leaderboard(_leaderboard) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Leaderboard{id: 0, slug: "", title: "", description: nil, sort_order: :desc, operator: :set, starts_at: nil, ends_at: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.end_leaderboard/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Gets the currently active leaderboard with the given slug.
Returns `nil` if no active leaderboard exists.
An active leaderboard is one that:
- Has not ended (`ends_at` is nil or in the future)
- Has started (`starts_at` is nil or in the past)
If multiple active leaderboards exist with the same slug,
returns the most recently created one.
"""
@spec get_active_leaderboard_by_slug(String.t()) :: GameServer.Leaderboards.Leaderboard.t() | nil
def get_active_leaderboard_by_slug(_slug) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
if :erlang.phash2(make_ref(), 2) == 0, do: nil, else: %GameServer.Leaderboards.Leaderboard{id: 0, slug: "", title: "", description: nil, sort_order: :desc, operator: :set, starts_at: nil, ends_at: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}
_ ->
raise "GameServer.Leaderboards.get_active_leaderboard_by_slug/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Gets a single record by leaderboard ID and label.
"""
@spec get_label_record(Ecto.UUID.t(), String.t()) :: GameServer.Leaderboards.Record.t() | nil
def get_label_record(_leaderboard_id, _label) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
if :erlang.phash2(make_ref(), 2) == 0, do: nil, else: %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}
_ ->
raise "GameServer.Leaderboards.get_label_record/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Gets a leaderboard by its UUID, or the active leaderboard by slug.
## Examples
iex> get_leaderboard("0198c0de-...")
%Leaderboard{}
iex> get_leaderboard(Ecto.UUID.generate())
nil
"""
@spec get_leaderboard(String.t()) :: GameServer.Leaderboards.Leaderboard.t() | nil
def get_leaderboard(_id_or_slug) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
if :erlang.phash2(make_ref(), 2) == 0, do: nil, else: %GameServer.Leaderboards.Leaderboard{id: 0, slug: "", title: "", description: nil, sort_order: :desc, operator: :set, starts_at: nil, ends_at: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}
_ ->
raise "GameServer.Leaderboards.get_leaderboard/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Gets a leaderboard by its ID. Raises if not found.
"""
@spec get_leaderboard!(String.t()) :: GameServer.Leaderboards.Leaderboard.t()
def get_leaderboard!(_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Leaderboards.get_leaderboard!/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Gets a single record by leaderboard ID and user ID.
"""
@spec get_record(Ecto.UUID.t(), Ecto.UUID.t()) :: GameServer.Leaderboards.Record.t() | nil
def get_record(_leaderboard_id, _user_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
if :erlang.phash2(make_ref(), 2) == 0, do: nil, else: %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}
_ ->
raise "GameServer.Leaderboards.get_record/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Gets a record by its ID. Raises if not found.
Intended for internal/admin usage.
"""
@spec get_record!(Ecto.UUID.t()) :: GameServer.Leaderboards.Record.t()
def get_record!(_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
nil
_ ->
raise "GameServer.Leaderboards.get_record!/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Gets a user's record with their rank.
Returns `{:ok, record_with_rank}` or `{:error, :not_found}`.
"""
@spec get_user_record(Ecto.UUID.t(), Ecto.UUID.t()) ::
{:ok, GameServer.Leaderboards.Record.t()} | {:error, :not_found}
def get_user_record(_leaderboard_id, _user_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.get_user_record/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists unique leaderboard slugs with summary info.
Returns a list of maps with:
- `:slug` - the leaderboard slug
- `:title` - title from the latest leaderboard
- `:description` - description from the latest leaderboard
- `:active_id` - ID of the currently active leaderboard (or nil)
- `:latest_id` - ID of the most recent leaderboard
- `:season_count` - total number of leaderboards with this slug
"""
@spec list_leaderboard_groups() :: [map()]
def list_leaderboard_groups() do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
%{}
_ ->
raise "GameServer.Leaderboards.list_leaderboard_groups/0 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists unique leaderboard slugs with summary info.
Returns a list of maps with:
- `:slug` - the leaderboard slug
- `:title` - title from the latest leaderboard
- `:description` - description from the latest leaderboard
- `:active_id` - ID of the currently active leaderboard (or nil)
- `:latest_id` - ID of the most recent leaderboard
- `:season_count` - total number of leaderboards with this slug
"""
@spec list_leaderboard_groups(keyword()) :: [map()]
def list_leaderboard_groups(_opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
%{}
_ ->
raise "GameServer.Leaderboards.list_leaderboard_groups/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists leaderboards with optional filters.
## Options
* `:slug` - Filter by slug (returns all seasons of that leaderboard)
* `:active` - If `true`, only active leaderboards. If `false`, only ended.
* `:order_by` - Order by field: `:ends_at` or `:inserted_at` (default)
* `:starts_after` - Only leaderboards that started after this DateTime
* `:starts_before` - Only leaderboards that started before this DateTime
* `:ends_after` - Only leaderboards that end after this DateTime
* `:ends_before` - Only leaderboards that end before this DateTime
* `:page` - Page number (default 1)
* `:page_size` - Page size (default 25)
## Examples
iex> list_leaderboards(active: true)
[%Leaderboard{}, ...]
iex> list_leaderboards(slug: "weekly_kills")
[%Leaderboard{}, ...]
iex> list_leaderboards(starts_after: ~U[2025-01-01 00:00:00Z])
[%Leaderboard{}, ...]
"""
@spec list_leaderboards() :: [GameServer.Leaderboards.Leaderboard.t()]
def list_leaderboards() do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Leaderboards.list_leaderboards/0 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists leaderboards with optional filters.
## Options
* `:slug` - Filter by slug (returns all seasons of that leaderboard)
* `:active` - If `true`, only active leaderboards. If `false`, only ended.
* `:order_by` - Order by field: `:ends_at` or `:inserted_at` (default)
* `:starts_after` - Only leaderboards that started after this DateTime
* `:starts_before` - Only leaderboards that started before this DateTime
* `:ends_after` - Only leaderboards that end after this DateTime
* `:ends_before` - Only leaderboards that end before this DateTime
* `:page` - Page number (default 1)
* `:page_size` - Page size (default 25)
## Examples
iex> list_leaderboards(active: true)
[%Leaderboard{}, ...]
iex> list_leaderboards(slug: "weekly_kills")
[%Leaderboard{}, ...]
iex> list_leaderboards(starts_after: ~U[2025-01-01 00:00:00Z])
[%Leaderboard{}, ...]
"""
@spec list_leaderboards(keyword()) :: [GameServer.Leaderboards.Leaderboard.t()]
def list_leaderboards(_opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Leaderboards.list_leaderboards/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists all leaderboards with the given slug (all seasons), ordered by end date.
"""
@spec list_leaderboards_by_slug(String.t()) :: [GameServer.Leaderboards.Leaderboard.t()]
def list_leaderboards_by_slug(_slug) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Leaderboards.list_leaderboards_by_slug/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists all leaderboards with the given slug (all seasons), ordered by end date.
"""
@spec list_leaderboards_by_slug(
String.t(),
keyword()
) :: [GameServer.Leaderboards.Leaderboard.t()]
def list_leaderboards_by_slug(_slug, _opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Leaderboards.list_leaderboards_by_slug/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists records for a leaderboard, ordered by rank.
## Options
See `t:GameServer.Types.pagination_opts/0` for available options.
Returns records with `rank` field populated.
"""
@spec list_records(String.t()) :: [GameServer.Leaderboards.Record.t()]
def list_records(_leaderboard_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Leaderboards.list_records/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists records for a leaderboard, ordered by rank.
## Options
See `t:GameServer.Types.pagination_opts/0` for available options.
Returns records with `rank` field populated.
"""
@spec list_records(String.t(), GameServer.Types.pagination_opts()) :: [
GameServer.Leaderboards.Record.t()
]
def list_records(_leaderboard_id, _opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Leaderboards.list_records/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists records around a specific user (centered on their position).
Returns records above and below the user's rank.
## Options
* `:limit` - Total number of records to return (default 11, centered on user)
"""
@spec list_records_around_user(String.t(), Ecto.UUID.t()) :: [GameServer.Leaderboards.Record.t()]
def list_records_around_user(_leaderboard_id, _user_id) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Leaderboards.list_records_around_user/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Lists records around a specific user (centered on their position).
Returns records above and below the user's rank.
## Options
* `:limit` - Total number of records to return (default 11, centered on user)
"""
@spec list_records_around_user(String.t(), Ecto.UUID.t(), keyword()) :: [
GameServer.Leaderboards.Record.t()
]
def list_records_around_user(_leaderboard_id, _user_id, _opts) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
[]
_ ->
raise "GameServer.Leaderboards.list_records_around_user/3 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Resolves multiple slugs to their currently active leaderboards in a single query.
Returns a map of `slug => %Leaderboard{}` for each slug that has an active
leaderboard. Slugs with no active leaderboard are omitted from the result.
## Examples
iex> resolve_slugs(["weekly_kills", "monthly_score", "nonexistent"])
%{
"weekly_kills" => %Leaderboard{id: 1, slug: "weekly_kills", ...},
"monthly_score" => %Leaderboard{id: 5, slug: "monthly_score", ...}
}
"""
@spec resolve_slugs([String.t()]) :: %{required(String.t()) => GameServer.Leaderboards.Leaderboard.t()}
def resolve_slugs(_slugs) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
""
_ ->
raise "GameServer.Leaderboards.resolve_slugs/1 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Submit a score for a label-based (non-user) record.
Works just like `submit_score/4` but uses a string label instead of a user ID.
This is useful for statistics, rankings by category, etc.
## Examples
iex> submit_label_score(leaderboard_id, "English", 42)
{:ok, %Record{label: "English", score: 42}}
"""
@spec submit_label_score(String.t(), String.t(), integer(), map()) ::
{:ok, GameServer.Leaderboards.Record.t()} | {:error, term()}
def submit_label_score(_leaderboard_id, _label, _score, _metadata) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.submit_label_score/4 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Submits a score for a user on a leaderboard.
This is a server-only function — there is no public API for score submission.
The score is processed according to the leaderboard's operator:
* `:set` — Always replace with new score
* `:best` — Only update if new score is better (respects sort_order)
* `:incr` — Add to existing score
* `:decr` — Subtract from existing score
To submit to a leaderboard by slug, first get the active leaderboard ID:
leaderboard = Leaderboards.get_active_leaderboard_by_slug("weekly_kills")
Leaderboards.submit_score(leaderboard.id, user_id, 10)
## Examples
iex> submit_score(123, user_id, 10)
{:ok, %Record{score: 10}}
iex> submit_score(123, user_id, 5, %{weapon: "sword"})
{:ok, %Record{score: 15, metadata: %{weapon: "sword"}}}
"""
@spec submit_score(String.t(), Ecto.UUID.t(), integer()) ::
{:ok, GameServer.Leaderboards.Record.t()} | {:error, term()}
def submit_score(_leaderboard_id, _user_id, _score) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.submit_score/3 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Submits a score for a user on a leaderboard.
This is a server-only function — there is no public API for score submission.
The score is processed according to the leaderboard's operator:
* `:set` — Always replace with new score
* `:best` — Only update if new score is better (respects sort_order)
* `:incr` — Add to existing score
* `:decr` — Subtract from existing score
To submit to a leaderboard by slug, first get the active leaderboard ID:
leaderboard = Leaderboards.get_active_leaderboard_by_slug("weekly_kills")
Leaderboards.submit_score(leaderboard.id, user_id, 10)
## Examples
iex> submit_score(123, user_id, 10)
{:ok, %Record{score: 10}}
iex> submit_score(123, user_id, 5, %{weapon: "sword"})
{:ok, %Record{score: 15, metadata: %{weapon: "sword"}}}
"""
@spec submit_score(String.t(), Ecto.UUID.t(), integer(), map()) ::
{:ok, GameServer.Leaderboards.Record.t()} | {:error, term()}
def submit_score(_leaderboard_id, _user_id, _score, _metadata) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.submit_score/4 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Updates an existing leaderboard.
Note: `slug`, `sort_order`, and `operator` cannot be changed after creation.
## Attributes
See `t:GameServer.Types.leaderboard_update_attrs/0` for available fields.
"""
@spec update_leaderboard(
GameServer.Leaderboards.Leaderboard.t(),
GameServer.Types.leaderboard_update_attrs()
) :: {:ok, GameServer.Leaderboards.Leaderboard.t()} | {:error, Ecto.Changeset.t()}
def update_leaderboard(_leaderboard, _attrs) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Leaderboard{id: 0, slug: "", title: "", description: nil, sort_order: :desc, operator: :set, starts_at: nil, ends_at: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.update_leaderboard/2 is a stub - only available at runtime on GameServer"
end
end
@doc ~S"""
Updates an existing record.
Intended for internal/admin usage.
"""
@spec update_record(GameServer.Leaderboards.Record.t(), map()) ::
{:ok, GameServer.Leaderboards.Record.t()} | {:error, Ecto.Changeset.t()}
def update_record(_record, _attrs) do
case Application.get_env(:game_server_sdk, :stub_mode, :raise) do
:placeholder ->
{:ok, %GameServer.Leaderboards.Record{id: 0, leaderboard_id: 0, user_id: 0, label: nil, score: 0, rank: nil, metadata: %{}, inserted_at: ~U[1970-01-01 00:00:00Z], updated_at: ~U[1970-01-01 00:00:00Z]}}
_ ->
raise "GameServer.Leaderboards.update_record/2 is a stub - only available at runtime on GameServer"
end
end
end