summaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'src/battlemap/query')
-rw-r--r-- | src/battlemap/query/bm_character_turn.erl | 250 | ||||
-rw-r--r-- | src/battlemap/query/bm_load_state.erl | 111 |
2 files changed, 361 insertions, 0 deletions
diff --git a/src/battlemap/query/bm_character_turn.erl b/src/battlemap/query/bm_character_turn.erl new file mode 100644 index 0000000..26b8dce --- /dev/null +++ b/src/battlemap/query/bm_character_turn.erl @@ -0,0 +1,250 @@ +-module(bm_character_turn). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-include("../../../include/yaws_api.hrl"). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export([out/1]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%-spec send_to_database (list(database_diff:type()), character_turn_request:type()) -> 'ok'. + + +%%%% REQUEST DECODING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec decode_request (binary()) -> bm_character_turn_request:type(). +decode_request (BinaryRequest) -> + JSONMap = jiffy:decode(BinaryRequest, [return_maps]), + + bm_character_turn_request:decode(JSONMap). + +%%%% USER AUTHENTICATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec authenticate_user (bm_character_turn_request:type()) -> 'ok'. +authenticate_user (Request) -> + PlayerID = bm_character_turn_request:get_player_id(Request), + SessionToken = bm_character_turn_request:get_session_token(Request), + + bm_security:assert_identity(PlayerID, SessionToken), + bm_security:lock_queries(PlayerID), + + ok. + +%%%% MAIN LOGIC %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec fetch_data + ( + bm_character_turn_request:type() + ) + -> bm_character_turn_data:type(). +fetch_data (Request) -> + PlayerID = bm_character_turn_request:get_player_id(Request), + BattleID = bm_character_turn_request:get_battle_id(Request), + CharacterIX = bm_character_turn_request:get_character_ix(Request), + Battle = sh_timed_cache:fetch(battle_db, PlayerID, BattleID), + + bm_character_turn_data:new(Battle, CharacterIX). + +%%%% ASSERTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec assert_user_is_current_player + ( + bm_character_turn_data:type(), + bm_character_turn_request:type() + ) -> 'ok'. +assert_user_is_current_player (Data, Request) -> + PlayerID = bm_character_turn_request:get_player_id(Request), + Battle = bm_character_turn_data:get_battle(Data), + CurrentPlayerTurn = bm_battle:get_current_player_turn(Battle), + CurrentPlayerIX = bm_player_turn:get_player_ix(CurrentPlayerTurn), + CurrentPlayer = bm_battle:get_player(CurrentPlayerIX, Battle), + + true = (PlayerID == bm_player:get_id(CurrentPlayer)), + + ok. + +-spec assert_user_owns_played_character + ( + bm_character_turn_data:type(), + bm_character_turn_request:type() + ) -> 'ok'. +assert_user_owns_played_character (Data, Request) -> + PlayerID = bm_character_turn_request:get_player_id(Request), + Character = bm_character_turn_data:get_character(Data), + CharacterOwnerID = bm_character:get_owner_id(Character), + + true = (PlayerID == CharacterOwnerID), + + ok. + +-spec assert_character_can_be_played (bm_character_turn_data:type()) -> 'ok'. +assert_character_can_be_played (Data) -> + Character = bm_character_turn_data:get_character(Data), + + true = bm_character:get_is_active(Character), + + ok. + +-spec assert_user_permissions + ( + bm_character_turn_data:type(), + bm_character_turn_request:type() + ) -> 'ok'. +assert_user_permissions (Data, Request) -> + assert_user_is_current_player(Data, Request), + assert_user_owns_played_character(Data, Request), + assert_character_can_be_played(Data), + + ok. + +%%%% QUERY LOGIC HANDLING %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec finalize_character + ( + bm_character_turn_update:type() + ) + -> bm_character_turn_update:type(). +finalize_character (Update) -> + Data = bm_character_turn_update:get_data(Update), + Character = bm_character_turn_data:get_character(Data), + + DisabledCharacter = bm_character:set_is_active(false, Character), + UpdatedData = bm_character_turn_data:set_character(DisabledCharacter, Data), + FinalizedData = bm_character_turn_data:clean_battle(UpdatedData), + + bm_character_turn_update:set_data(FinalizedData, Update). + +-spec handle_actions + ( + bm_character_turn_data:type(), + bm_character_turn_request:type() + ) + -> bm_character_turn_update:type(). +handle_actions (Data, Request) -> + Actions = bm_character_turn_request:get_actions(Request), + + EmptyUpdate = bm_character_turn_update:new(Data), + PostActionsUpdate = + lists:foldl(fun bm_turn_actions:handle/2, EmptyUpdate, Actions), + + finalize_character(PostActionsUpdate). + +-spec update_timeline + ( + bm_character_turn_update:type() + ) + -> bm_character_turn_update:type(). +update_timeline (Update) -> + NewTimelineElements = bm_character_turn_update:get_timeline(Update), + Data = bm_character_turn_update:get_data(Update), + Battle = bm_character_turn_data:get_battle(Data), + PlayerTurn = bm_battle:get_current_player_turn(Battle), + PlayerIX = bm_player_turn:get_player_ix(PlayerTurn), + Player = bm_battle:get_player(PlayerIX, Battle), + + UpdatedPlayer = bm_player:add_to_timeline(NewTimelineElements, Player), + UpdatedBattle = bm_battle:set_player(PlayerIX, UpdatedPlayer, Battle), + UpdatedData = bm_character_turn_data:set_battle(UpdatedBattle, Data), + + bm_character_turn_update:set_data(UpdatedData, Update). + +-spec update_data + ( + bm_character_turn_data:type(), + bm_character_turn_request:type() + ) + -> bm_character_turn_update:type(). +update_data (Data, Request) -> + PostActionsUpdate = handle_actions(Data, Request), + PostCharacterTurnUpdate = update_timeline(PostActionsUpdate), + + bm_next_turn:update_if_needed(PostCharacterTurnUpdate). + +%%%% DATABASE UPDATES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec send_to_database + ( + bm_character_turn_update:type(), + bm_character_turn_request:type() + ) + -> 'ok'. +send_to_database (Update, Request) -> + PlayerID = bm_character_turn_request:get_player_id(Request), + BattleID = bm_character_turn_request:get_battle_id(Request), + Ops = bm_character_turn_update:get_db(Update), + Query = sh_db_query:new(battle_db, BattleID, {user, PlayerID}, Ops), + + % TODO: send queries to an actual DB... + + sh_database:commit(Query), + + ok. + +-spec send_to_cache + ( + bm_character_turn_update:type(), + bm_character_turn_request:type() + ) + -> 'ok'. +send_to_cache (Update, Request) -> + PlayerID = bm_character_turn_request:get_player_id(Request), + BattleID = bm_character_turn_request:get_battle_id(Request), + Data = bm_character_turn_update:get_data(Update), + Battle = bm_character_turn_data:get_battle(Data), + + sh_timed_cache:update(battle_db, PlayerID, BattleID, Battle), + + ok. + +-spec commit_update + ( + bm_character_turn_update:type(), + bm_character_turn_request:type() + ) + -> 'ok'. +commit_update (Update, Request) -> + send_to_database(Update, Request), + send_to_cache(Update, Request), + + ok. + +%%%% USER DISCONNECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec disconnect_user (bm_character_turn_request:type()) -> 'ok'. +disconnect_user (Request) -> + PlayerID = bm_character_turn_request:get_player_id(Request), + + bm_security:unlock_queries(PlayerID), + + ok. + +%%%% REPLY GENERATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate_reply (bm_character_turn_update:type()) -> binary(). +generate_reply (Update) -> + NewTimelineItems = bm_character_turn_update:get_timeline(Update), + + TurnResultReply = bm_turn_results:generate(NewTimelineItems), + + jiffy:encode([TurnResultReply]). + +%%%% MAIN LOGIC %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec handle (binary()) -> binary(). +handle (EncodedRequest) -> + Request = decode_request(EncodedRequest), + authenticate_user(Request), + Data = fetch_data(Request), + assert_user_permissions(Data, Request), + Update = update_data(Data, Request), + commit_update(Update, Request), + disconnect_user(Request), + generate_reply(Update). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +out(A) -> + { + content, + "application/json; charset=UTF-8", + handle(A#arg.clidata) + }. diff --git a/src/battlemap/query/bm_load_state.erl b/src/battlemap/query/bm_load_state.erl new file mode 100644 index 0000000..b580b9f --- /dev/null +++ b/src/battlemap/query/bm_load_state.erl @@ -0,0 +1,111 @@ +-module(bm_load_state). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-include("../../../include/yaws_api.hrl"). + +-record +( + input, + { + player_id :: bm_player:id(), + session_token :: binary(), + battle_id :: binary() + } +). + +-record +( + query_state, + { + battle :: bm_battle: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), + BattleID = maps:get(<<"bmi">>, JSONReqMap), + + #input + { + player_id = PlayerID, + session_token = SessionToken, + battle_id = BattleID + }. + +-spec fetch_data (input()) -> query_state(). +fetch_data (Input) -> + PlayerID = Input#input.player_id, + BattleID = Input#input.battle_id, + + Battle = timed_cache:fetch (battle_db, PlayerID, BattleID), + + #query_state + { + battle = Battle + }. + +-spec generate_reply(query_state(), input()) -> binary(). +generate_reply (QueryState, Input) -> + PlayerID = Input#input.player_id, + Battle = QueryState#query_state.battle, + + jiffy:encode + ( + [ + bm_set_timeline:generate + ( + bm_battle:get_encoded_last_turns_effects(Battle) + ), + bm_set_map:generate(bm_battle:get_battlemap(Battle)) + | + array:sparse_to_list + ( + array:map + ( + fun (IX, Character) -> + bm_add_char:generate(IX, Character, PlayerID) + end, + bm_battle:get_characters(Battle) + ) + ) + ] + ). + +-spec handle (binary()) -> binary(). +handle (Req) -> + Input = parse_input(Req), + bm_security:assert_identity + ( + Input#input.player_id, + Input#input.session_token + ), + bm_security:lock_queries(Input#input.player_id), + QueryState = fetch_data(Input), + bm_security:unlock_queries(Input#input.player_id), + generate_reply(QueryState, Input). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +out(A) -> + { + content, + "application/json; charset=UTF-8", + handle(A#arg.clidata) + }. |