summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/character')
-rw-r--r--src/character/chr_handler.erl40
-rw-r--r--src/character/chr_shim.erl25
-rw-r--r--src/character/query/chr_load.erl111
-rw-r--r--src/character/reply/chr_add_char.erl39
-rw-r--r--src/character/struct/chr_character.erl151
-rw-r--r--src/character/struct/chr_roster.erl127
6 files changed, 493 insertions, 0 deletions
diff --git a/src/character/chr_handler.erl b/src/character/chr_handler.erl
new file mode 100644
index 0000000..7697bcd
--- /dev/null
+++ b/src/character/chr_handler.erl
@@ -0,0 +1,40 @@
+-module(chr_handler).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-export([start/1]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec start (pid()) -> 'ok'.
+start (TimedCachesManagerPid) ->
+ case shr_database:fetch(char_roster_db, <<"0">>, admin) of
+ {ok, _} -> ok;
+ not_found ->
+ shr_database:insert_at
+ (
+ char_roster_db,
+ <<"0">>,
+ any,
+ any,
+ chr_shim:generate_random_character_roster()
+ )
+ end,
+ shr_timed_caches_manager:new_cache
+ (
+ TimedCachesManagerPid,
+ char_roster_db,
+ none
+ ),
+
+ ok.
diff --git a/src/character/chr_shim.erl b/src/character/chr_shim.erl
new file mode 100644
index 0000000..d7e688f
--- /dev/null
+++ b/src/character/chr_shim.erl
@@ -0,0 +1,25 @@
+-module(chr_shim).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-export([generate_random_character_roster/0]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec generate_random_character_roster () -> chr_roster:type().
+generate_random_character_roster () ->
+ Result = chr_roster:new(<<"0">>, <<"0">>),
+
+ %% TODO: unimplemented.
+
+ Result.
diff --git a/src/character/query/chr_load.erl b/src/character/query/chr_load.erl
new file mode 100644
index 0000000..290ea37
--- /dev/null
+++ b/src/character/query/chr_load.erl
@@ -0,0 +1,111 @@
+-module(chr_load).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-include("../../../include/yaws_api.hrl").
+
+-record
+(
+ input,
+ {
+ player_id :: binary(),
+ session_token :: binary()
+ }
+).
+
+-record
+(
+ query_state,
+ {
+ player :: shr_player:type(),
+ inventory :: shr_inventory:type(),
+ roster :: chr_roster:type()
+ }
+).
+
+-type input() :: #input{}.
+-type query_state() :: #query_state{}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-export([out/1]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec parse_input (binary()) -> input().
+parse_input (Req) ->
+ JSONReqMap = jiffy:decode(Req, [return_maps]),
+ PlayerID = maps:get(<<"pid">>, JSONReqMap),
+ SessionToken = maps:get(<<"stk">>, JSONReqMap),
+
+ #input
+ {
+ player_id = PlayerID,
+ session_token = SessionToken
+ }.
+
+-spec authenticate_user (input()) -> {'ok', shr_player:type()}.
+authenticate_user (Input) ->
+ PlayerID = Input#input.player_id,
+ SessionToken = Input#input.session_token,
+
+ Player = shr_timed_cache:fetch(player_db, any, PlayerID),
+
+ shr_security:assert_identity(SessionToken, Player),
+
+ {ok, Player}.
+
+-spec fetch_data (shr_player:type(), input()) -> query_state().
+fetch_data (Player, Input) ->
+ PlayerID = Input#input.player_id,
+ RosterID = shr_player:get_roster_id(Player),
+ InventoryID = shr_player:get_inventory_id(Player),
+
+ Roster = shr_timed_cache:fetch(char_roster_db, PlayerID, RosterID),
+ Inventory = shr_timed_cache:fetch(char_roster_db, PlayerID, InventoryID),
+
+ #query_state
+ {
+ player = Player,
+ roster = Roster,
+ inventory = Inventory
+ }.
+
+-spec generate_reply(query_state()) -> binary().
+generate_reply (QueryState) ->
+ Roster = QueryState#query_state.roster,
+ Inventory = QueryState#query_state.inventory,
+
+ RosterCharacters = chr_roster:get_characters(Roster),
+ SetInventory = shr_set_inventory:generate(Inventory),
+ EncodedRoster =
+ array:to_list
+ (
+ array:sparse_map(fun chr_add_char:generate/2, RosterCharacters)
+ ),
+
+ Output = jiffy:encode([SetInventory|EncodedRoster]),
+
+ Output.
+
+-spec handle (binary()) -> binary().
+handle (Req) ->
+ Input = parse_input(Req),
+ {ok, Player} = authenticate_user(Input),
+ shr_security:lock_queries(Input#input.player_id),
+ QueryState = fetch_data(Player, Input),
+ shr_security:unlock_queries(Input#input.player_id),
+ generate_reply(QueryState).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+out(A) ->
+ {
+ content,
+ "application/json; charset=UTF-8",
+ handle(A#arg.clidata)
+ }.
diff --git a/src/character/reply/chr_add_char.erl b/src/character/reply/chr_add_char.erl
new file mode 100644
index 0000000..53a62d6
--- /dev/null
+++ b/src/character/reply/chr_add_char.erl
@@ -0,0 +1,39 @@
+-module(chr_add_char).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-export([generate/2]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec generate
+ (
+ non_neg_integer(),
+ chr_character:type()
+ )
+ -> {list(any())}.
+generate (IX, Character) ->
+ {ActiveWeapon, SecondaryWeapon} = chr_character:get_weapon_ids(Character),
+
+ {
+ [
+ {<<"msg">>, <<"add_char">>},
+ {<<"ix">>, IX},
+ {<<"nam">>, chr_character:get_name(Character)},
+ {<<"awp">>, ActiveWeapon},
+ {<<"swp">>, SecondaryWeapon},
+ {<<"ar">>, chr_character:get_armor_id(Character)},
+ {<<"gls">>, array:to_list(chr_character:get_glyph_ids(Character))},
+ {<<"gb">>, chr_character:get_glyph_board_id(Character)}
+ ]
+ }.
diff --git a/src/character/struct/chr_character.erl b/src/character/struct/chr_character.erl
new file mode 100644
index 0000000..a9ef52d
--- /dev/null
+++ b/src/character/struct/chr_character.erl
@@ -0,0 +1,151 @@
+-module(chr_character).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-record
+(
+ character,
+ {
+ name :: binary(),
+ portrait :: binary(),
+ weapon_ids :: {shr_weapon:id(), shr_weapon:id()},
+ armor_id :: shr_armor:id(),
+ glyph_ids :: array:array(shr_glyph:id()),
+ glyph_board_id :: shr_glyph_board:id()
+ }
+).
+
+-opaque type() :: #character{}.
+
+-export_type([type/0]).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% Accessors
+-export
+(
+ [
+ get_name/1,
+ get_portrait/1,
+ get_weapon_ids/1,
+ get_armor_id/1,
+ get_glyph_ids/1,
+ get_glyph_board_id/1,
+
+ set_name/2,
+ set_portrait/2,
+ set_weapon_ids/2,
+ set_armor_id/2,
+ set_glyph_ids/2,
+ set_glyph_board_id/2,
+
+ get_name_field/0,
+ get_portrait_field/0,
+ get_weapon_ids_field/0,
+ get_armor_id_field/0,
+ get_glyph_ids_field/0,
+ get_glyph_board_id_field/0
+ ]
+).
+
+-export
+(
+ [
+ random/0
+ ]
+).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% Accessors
+-spec get_name (type()) -> binary().
+get_name (Char) -> Char#character.name.
+
+-spec get_portrait (type()) -> binary().
+get_portrait (Char) -> Char#character.portrait.
+
+-spec get_weapon_ids (type()) -> {shr_weapon:id(), shr_weapon:id()}.
+get_weapon_ids (Char) -> Char#character.weapon_ids.
+
+-spec get_armor_id (type()) -> shr_armor:id().
+get_armor_id (Char) -> Char#character.armor_id.
+
+-spec get_glyph_ids (type()) -> array:array(shr_glyph:id()).
+get_glyph_ids (Char) -> Char#character.glyph_ids.
+
+-spec get_glyph_board_id (type()) -> shr_glyph_board:id().
+get_glyph_board_id (Char) -> Char#character.glyph_board_id.
+
+
+-spec set_name (binary(), type()) -> type().
+set_name (Name, Char) ->
+ Char#character
+ {
+ name = Name
+ }.
+
+-spec set_portrait (binary(), type()) -> type().
+set_portrait (PortraitID, Char) ->
+ Char#character
+ {
+ portrait = PortraitID
+ }.
+
+-spec set_armor_id (shr_armor:id(), type()) -> type().
+set_armor_id (ArmorID, Char) ->
+ Char#character
+ {
+ armor_id = ArmorID
+ }.
+
+-spec set_weapon_ids ({shr_weapon:id(), shr_weapon:id()}, type()) -> type().
+set_weapon_ids (WeaponIDs, Char) ->
+ Char#character
+ {
+ weapon_ids = WeaponIDs
+ }.
+
+-spec set_glyph_ids (array:array(shr_glyph:id()), type()) -> type().
+set_glyph_ids (GlyphIDs, Char) ->
+ Char#character
+ {
+ glyph_ids = GlyphIDs
+ }.
+
+-spec set_glyph_board_id (shr_glyph_board:id(), type()) -> type().
+set_glyph_board_id (GlyphBoardID, Char) ->
+ Char#character
+ {
+ glyph_board_id = GlyphBoardID
+ }.
+
+-spec random () -> type().
+random () ->
+ #character
+ {
+ name = <<"">>,
+ portrait = <<"0">>,
+ weapon_ids = {0, 0},
+ armor_id = 0,
+ glyph_ids = array:new(),
+ glyph_board_id = <<"0">>
+ }.
+
+-spec get_name_field () -> non_neg_integer().
+get_name_field () -> #character.name.
+-spec get_portrait_field () -> non_neg_integer().
+get_portrait_field () -> #character.portrait.
+-spec get_armor_id_field () -> non_neg_integer().
+get_armor_id_field () -> #character.armor_id.
+-spec get_weapon_ids_field () -> non_neg_integer().
+get_weapon_ids_field () -> #character.weapon_ids.
+-spec get_glyph_ids_field () -> non_neg_integer().
+get_glyph_ids_field () -> #character.glyph_ids.
+-spec get_glyph_board_id_field () -> non_neg_integer().
+get_glyph_board_id_field () -> #character.glyph_board_id.
diff --git a/src/character/struct/chr_roster.erl b/src/character/struct/chr_roster.erl
new file mode 100644
index 0000000..99a82fc
--- /dev/null
+++ b/src/character/struct/chr_roster.erl
@@ -0,0 +1,127 @@
+-module(chr_roster).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-type id() :: binary().
+
+-record
+(
+ roster,
+ {
+ id :: id(),
+ owner :: binary(),
+ characters :: array:array(chr_character:type())
+ }
+).
+
+-opaque type() :: #roster{}.
+
+-export_type([type/0, id/0]).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% Accessors
+-export
+(
+ [
+ get_id/1,
+ get_owner/1,
+ get_characters/1,
+ get_character/2,
+
+ set_characters/2,
+ set_character/3,
+
+ add_character/2,
+ remove_character/2
+ ]
+).
+
+-export
+(
+ [
+ get_characters_field/0
+ ]
+).
+
+-export
+(
+ [
+ new/2
+ ]
+).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% Accessors
+-spec get_id (type()) -> id().
+get_id (Roster) -> Roster#roster.id.
+
+-spec get_owner (type()) -> binary().
+get_owner (Roster) -> Roster#roster.owner.
+
+-spec get_characters (type()) -> array:array(chr_character:type()).
+get_characters (Roster) -> Roster#roster.characters.
+
+-spec get_character (non_neg_integer(), type()) -> chr_character:type().
+get_character (IX, Roster) -> array:get(IX, Roster#roster.characters).
+
+-spec set_characters (array:array(chr_character:type()), type()) -> type().
+set_characters (Characters, Roster) -> Roster#roster{ characters = Characters }.
+
+-spec set_character
+ (
+ non_neg_integer(),
+ chr_character:type(),
+ type()
+ )
+ -> type().
+set_character (IX, Character, Roster) ->
+ Roster#roster
+ {
+ characters = array:set(IX, Character, Roster#roster.characters)
+ }.
+
+-spec add_character (chr_character:type(), type()) -> type().
+add_character (Character, Roster) ->
+ CurrentCharacters = Roster#roster.characters,
+ CurrentSize = array:size(CurrentCharacters),
+
+ Roster#roster
+ {
+ characters = array:set(CurrentSize, Character, CurrentCharacters)
+ }.
+
+-spec remove_character (non_neg_integer(), type()) -> type().
+remove_character (IX, Roster) ->
+ CurrentCharacters = Roster#roster.characters,
+ CurrentSize = array:size(CurrentCharacters),
+ NewSize = (CurrentSize - 1),
+ LastCharacter = array:get(NewSize, CurrentCharacters),
+
+ S0Characters = array:set(IX, LastCharacter, CurrentCharacters),
+ S1Characters = array:resize(NewSize, S0Characters),
+
+ Roster#roster
+ {
+ characters = S1Characters
+ }.
+
+-spec get_characters_field () -> non_neg_integer().
+get_characters_field () -> #roster.characters.
+
+-spec new (binary(), binary()) -> type().
+new (ID, Owner) ->
+ #roster
+ {
+ id = ID,
+ owner = Owner,
+ characters = array:new()
+ }.