| summaryrefslogtreecommitdiff | 
diff options
| author | nsensfel <SpamShield0@noot-noot.org> | 2018-06-06 15:54:18 +0200 | 
|---|---|---|
| committer | nsensfel <SpamShield0@noot-noot.org> | 2018-06-06 15:54:18 +0200 | 
| commit | ee9c2ac044cc77b80f30420c8f0788cad4281084 (patch) | |
| tree | 6ce9c45b6c0f0c556839b6f462f84eab06e26594 /src/shared | |
| parent | 97f7511e61cebae3676a83aa9c0dc2efb15d8d8c (diff) | |
Figuring out how to organize the src folder(s)...
Diffstat (limited to 'src/shared')
| -rw-r--r-- | src/shared/include/db_item.hrl | 15 | ||||
| -rw-r--r-- | src/shared/include/db_query.hrl | 63 | ||||
| -rw-r--r-- | src/shared/include/db_user.hrl | 7 | ||||
| -rw-r--r-- | src/shared/io/sh_database.erl | 137 | ||||
| -rw-r--r-- | src/shared/io/sh_timed_cache.erl | 130 | ||||
| -rw-r--r-- | src/shared/io/sh_timed_caches_manager.erl | 152 | ||||
| -rw-r--r-- | src/shared/struct/sh_attributes.erl | 108 | ||||
| -rw-r--r-- | src/shared/struct/sh_db_item.erl | 70 | ||||
| -rw-r--r-- | src/shared/struct/sh_db_query.erl | 59 | ||||
| -rw-r--r-- | src/shared/struct/sh_db_user.erl | 28 | ||||
| -rw-r--r-- | src/shared/struct/sh_statistics.erl | 193 | 
11 files changed, 962 insertions, 0 deletions
| diff --git a/src/shared/include/db_item.hrl b/src/shared/include/db_item.hrl new file mode 100644 index 0000000..86d5863 --- /dev/null +++ b/src/shared/include/db_item.hrl @@ -0,0 +1,15 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   db_item, +   { +      id :: any(), +      perm :: db_user:permission(), +      val :: any() +   } +). + +-type db_item() :: #db_item{}. + diff --git a/src/shared/include/db_query.hrl b/src/shared/include/db_query.hrl new file mode 100644 index 0000000..7e5a5b0 --- /dev/null +++ b/src/shared/include/db_query.hrl @@ -0,0 +1,63 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   set_field, +   { +      field :: non_neg_integer(), +      value :: any() +   } +). + +-record +( +   add_to_field, +   { +      field :: non_neg_integer(), +      values :: list(any()), +      head :: boolean() +   } +). + +-record +( +   update_indexed, +   { +      field :: non_neg_integer(), +      ix :: non_neg_integer(), +      ops :: list(db_query_op()) +   } +). + +-record +( +   set_perm, +   { +      perm :: db_user:permission() +   } +). + +-record +( +   set_val, +   { +      val :: any() +   } +). + +-record +( +   db_query, +   { +      db :: atom(), +      id :: any(), +      user :: db_user:user(), +      ops :: list(db_query_master_op()) +   } +). + +-type db_query_op() :: (#set_field{} | #add_to_field{} | #update_indexed{}). +-type db_query_master_op() :: (db_query_op() | #set_perm{} | #set_val{}). +-type db_query() :: #db_query{}. + diff --git a/src/shared/include/db_user.hrl b/src/shared/include/db_user.hrl new file mode 100644 index 0000000..c5b033e --- /dev/null +++ b/src/shared/include/db_user.hrl @@ -0,0 +1,7 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type db_named_user() :: {'user', any()}. +-type db_user() :: (db_named_user() | 'admin' | 'any'). +-type db_permission() :: (list(db_named_user()) | 'any'). + diff --git a/src/shared/io/sh_database.erl b/src/shared/io/sh_database.erl new file mode 100644 index 0000000..a65b784 --- /dev/null +++ b/src/shared/io/sh_database.erl @@ -0,0 +1,137 @@ +-module(sh_database). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      generate_db/0, +      fetch/2, +      commit/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_db_node () -> +   list_to_atom("db_node@" ++ net_adm:localhost()). + +-spec generate_random_characters +   ( +      non_neg_integer(), +      non_neg_integer(), +      non_neg_integer(), +      non_neg_integer(), +      bm_battlemap:type(), +      list(bm_location:type()), +      list(bm_character:type()) +   ) +   -> list(bm_character:type()). +generate_random_characters +( +   0, +   0, +   _CharactersPerPlayer, +   _TotalCharacterCount, +   _Battlemap, +   _ForbiddenLocations, +   Result +) -> +   Result; +generate_random_characters +( +   MaxPlayerID, +   0, +   CharactersPerPlayer, +   TotalCharacterCount, +   Battlemap, +   ForbiddenLocations, +   Result +) -> +   generate_random_characters +   ( +      (MaxPlayerID - 1), +      CharactersPerPlayer, +      CharactersPerPlayer, +      TotalCharacterCount, +      Battlemap, +      ForbiddenLocations, +      Result +   ); +generate_random_characters +( +   MaxPlayerID, +   PlayerCharacterCount, +   CharactersPerPlayer, +   TotalCharacterCount, +   Battlemap, +   ForbiddenLocations, +   Result +) -> +   NewCharacter = +      bm_character:random +      ( +         TotalCharacterCount, +         list_to_binary(integer_to_list(MaxPlayerID)), +         bm_battlemap:get_width(Battlemap), +         bm_battlemap:get_height(Battlemap), +         ForbiddenLocations +      ), +   Character = +      case MaxPlayerID of +         0 -> bm_character:set_is_active(true, NewCharacter); +         _ -> NewCharacter +      end, + +   generate_random_characters +   ( +      MaxPlayerID, +      (PlayerCharacterCount - 1), +      CharactersPerPlayer, +      (TotalCharacterCount + 1), +      Battlemap, +      [bm_character:get_location(Character)|ForbiddenLocations], +      [Character|Result] +   ). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate_db () -> 'ok'. +generate_db () -> +   BattlemapWidth = sh_roll:between(16, 64), +   BattlemapHeight = sh_roll:between(16, 64), +   Battlemap = bm_battlemap:random(0, BattlemapWidth, BattlemapHeight), +   Characters = generate_random_characters(1, 8, 8, 0, Battlemap, [], []), +   PlayersAsList = [bm_player:new(<<"0">>), bm_player:new(<<"1">>)], +   Battle = bm_battle:new(<<"0">>, PlayersAsList, Battlemap, Characters), + +   {atomic, ok} = +      rpc:call +      ( +         get_db_node(), +         storage_access, +         insert, +         [battle_db, <<"0">>, any, Battle] +      ), + +   ok. + +-spec fetch (atom(), any()) -> ({'ok', any()} | 'not_found'). +fetch (DB, ObjectID) -> +   {atomic, Reply} = +      rpc:call(get_db_node(), storage_access, read, [DB, ObjectID]), +   io:format("~ndb_shim:fetch(~p) -> ~p.~n", [{DB, ObjectID}, Reply]), +   Reply. + +-spec commit (db_query:type()) -> 'ok'. +commit (Query) -> +   {atomic, ok} = rpc:call(get_db_node(), storage_access, query, [Query]), +   io:format("~ndb_shim:commit(~p) -> ok.~n", [Query]), +   ok. diff --git a/src/shared/io/sh_timed_cache.erl b/src/shared/io/sh_timed_cache.erl new file mode 100644 index 0000000..1839992 --- /dev/null +++ b/src/shared/io/sh_timed_cache.erl @@ -0,0 +1,130 @@ +-module(sh_timed_cache). +-behavior(gen_server). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% 'gen_server' Exports +-export +( +   [ +      init/1, +      handle_cast/2, +      handle_call/3, %% No reply will ever be given. +      terminate/2, +      code_change/3, +      format_status/2, +      handle_info/2 +   ] +). + +%%%% Actual Interface +-export +( +   [ +      fetch/3, +      update/4, +      invalidate/3 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec add_to_cache (atom(), any(), any()) -> any(). +add_to_cache (DB, Owner, ObjectID) -> +   {ok, TimerPID} = sh_gen_server:start(?MODULE, {DB, {Owner, ObjectID}}, []), +   {ok, Data} = sh_database:fetch(DB, ObjectID), +   ets:insert(DB, {{Owner, ObjectID}, TimerPID, Data}), +   Data. + +-spec add_update_to_cache (atom(), any(), any(), any()) -> 'ok'. +add_update_to_cache (DB, Owner, ObjectID, Data) -> +   {ok, TimerPID} = gen_server:start(?MODULE, {DB, {Owner, ObjectID}}, []), +   ets:insert(DB, {{Owner, ObjectID}, TimerPID, Data}), +   ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% 'gen_server' functions +init ({DB, ObjectID}) -> +   io:format("~nCache entry added: ~p.~n", [{DB, ObjectID}]), +   {ok, {DB, ObjectID}, sh_timed_caches_manager:get_timeout()}. + +handle_call (invalidate, _, State) -> +   {stop, normal, State}; +handle_call (ping, _, State) -> +   {noreply, State, sh_timed_caches_manager:get_timeout()}. + +handle_cast (invalidate, State) -> +   {stop, normal, State}; +handle_cast (ping, State) -> +   {noreply, State, sh_timed_caches_manager:get_timeout()}. + +terminate (_, {DB, ObjectID}) -> +   io:format +   ( +      "~nCache entry timed out or was invalidated: ~p.~n", +      [{DB, ObjectID}] +   ), +   ets:delete(DB, ObjectID). + +code_change (_, State, _) -> +   {ok, State}. + +format_status (_, [_, State]) -> +   [{data, [{"State", State}]}]. + +handle_info(timeout, State) -> +   {stop, normal, State}; +handle_info(_, {DB, ObjectID}) -> +   {noreply, {DB, ObjectID}, timed_caches_manager:get_timeout()}. + +%%%% Interface Functions +-spec fetch (atom(), any(), any()) -> any(). +fetch (DB, Owner, ObjectID) -> +   io:format("~nfetch from cache: ~p.~n", [{DB, {Owner, ObjectID}}]), +   case ets:lookup(DB, {Owner, ObjectID}) of +      [] -> add_to_cache(DB, Owner, ObjectID); + +      [{_, TimerPID, Data}] -> +         gen_server:cast(TimerPID, ping), +         Data +   end. + +-spec update (atom(), any(), any(), any()) -> 'ok'. +update (DB, Owner, ObjectID, Data) -> +   io:format("~nUpdating cache: ~p.~n", [{DB, {Owner, ObjectID}}]), +   case ets:lookup(DB, {Owner, ObjectID}) of +      [] -> ok; + +      [{_OwnerID, TimerPID, _Data}] -> +         gen_server:stop(TimerPID) +   end, +   add_update_to_cache(DB, Owner, ObjectID, Data). + +-spec invalidate (atom(), any(), any()) -> 'ok'. +invalidate (DB, Owner, ObjectID) -> +   case ets:lookup(DB, {Owner, ObjectID}) of +      [] -> +         io:format +         ( +            "~nInvalidation request on non-stored entry: ~p.~n", +            [{DB, Owner, ObjectID}] +         ), +         ok; + +      [{_, TimerPID, _}] -> +         io:format +         ( +            "~nInvalidation request on stored entry: ~p.~n", +            [{DB, Owner, ObjectID}] +         ), +         gen_server:stop(TimerPID), +         ok +   end. diff --git a/src/shared/io/sh_timed_caches_manager.erl b/src/shared/io/sh_timed_caches_manager.erl new file mode 100644 index 0000000..7921552 --- /dev/null +++ b/src/shared/io/sh_timed_caches_manager.erl @@ -0,0 +1,152 @@ +-module(sh_timed_caches_manager). +-behavior(gen_server). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% 'gen_server' Exports +-export( +   [ +      init/1, +      handle_cast/2, +      handle_call/3, +      terminate/2, +      code_change/3, +      format_status/2, +      handle_info/2 +   ] +). + +%%%% Actual Interface +-export( +   [ +      start/0, +      new_cache/3, +      delete_cache/2, +      get_timeout/0 +   ] +) +. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +remove_cache (DB) -> +   ets:delete(DB). + +add_cache (DB, none) -> +   io:format("~nTimed Caches Manager added a new cache. ~n"), +   ets:new( +      DB, +      [ +         set, +         public, +         named_table, +         {keypos, 1}, +         {read_concurrency, true}, +         {heir, none} +      ] +   ); +add_cache (DB, Heir) -> +   io:format("~nTimed Caches Manager added a new cache. ~n"), +   ets:new( +      DB, +      [ +         set, +         public, +         named_table, +         {keypos, 1}, +         {read_concurrency, true}, +         {heir, Heir, DB} +      ] +   ). + +inherit_cache (CacheList, DB, Heir) -> +   case lists:member(DB, CacheList) of +      true -> +         ets:setopts(DB, {heir, Heir, DB}), +         CacheList; + +      false -> +         [DB|CacheList] +   end. + +remove_cache (CacheList, DB) -> +   case lists:member(DB, CacheList) of +      true -> +         remove_cache(DB), +         lists:delete(DB, CacheList); +      false -> +         CacheList +   end. + +add_cache (CacheList, DB, Heir) -> +   case lists:member(DB, CacheList) of +      true when (Heir =:= none) -> +         CacheList; + +      true -> +         ets:setopts(DB, {heir, Heir, DB}), +         CacheList; + +      false -> +         add_cache(DB, Heir), +         [DB|CacheList] +   end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% 'gen_server' functions +init (CacheList) -> +   io:format("~nStarting Timed Caches Manager..."), +   {ok, CacheList}. + +handle_call ({remove, CacheName}, _Caller, State) -> +   {noreply, remove_cache(State, CacheName)}; +handle_call ({add, CacheName, Heir}, _Caller, State)-> +   {noreply, add_cache(State, CacheName, Heir)}; +handle_call ({inherit, CacheName, Heir}, _Caller, State)-> +   {noreply, inherit_cache(State, CacheName, Heir)}; +handle_call (terminate, _, State) -> +   {stop, normal, State}. + +handle_cast ({remove, CacheName}, State) -> +   {noreply, remove_cache(State, CacheName)}; +handle_cast ({add, CacheName, Heir}, State)-> +   {noreply, add_cache(State, CacheName, Heir)}; +handle_cast ({inherit, CacheName, Heir}, State)-> +   {noreply, inherit_cache(State, CacheName, Heir)}; +handle_cast (terminate, State) -> +   {stop, normal, State}. + +terminate (_Reason, []) -> +   ok; +terminate (Reason, [CacheName|OtherCaches]) -> +   remove_cache(CacheName), +   terminate(Reason, OtherCaches). + +code_change (_, State, _) -> +   {ok, State}. + +format_status (_, [_, State]) -> +   [{data, [{"State", State}]}]. + +handle_info(_, State) -> +   {noreply, State}. + +%%%% Interface Functions +start () -> +   gen_server:start(timed_caches_manager, [], []). + +new_cache (ManagerPid, DB, Heir) -> +   gen_server:cast(ManagerPid, {add, DB, Heir}). + +delete_cache (ManagerPid, DB) -> +   gen_server:cast(ManagerPid, {remove, DB}). + +get_timeout () -> +   120000. % 2min. diff --git a/src/shared/struct/sh_attributes.erl b/src/shared/struct/sh_attributes.erl new file mode 100644 index 0000000..93dcfc6 --- /dev/null +++ b/src/shared/struct/sh_attributes.erl @@ -0,0 +1,108 @@ +-module(sh_attributes). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   attributes, +   { +      constitution :: integer(), +      dexterity :: integer(), +      intelligence :: integer(), +      mind :: integer(), +      speed :: integer(), +      strength :: integer() +   } +). + +-opaque type() :: #attributes{}. + +-export_type([type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-export +( +   [ +      get_constitution/1, +      get_dexterity/1, +      get_intelligence/1, +      get_mind/1, +      get_speed/1, +      get_strength/1, + +      set_constitution/2, +      set_dexterity/2, +      set_intelligence/2, +      set_mind/2, +      set_speed/2, +      set_strength/2 +   ] +). + +%%%% Accessors +-export +( +   [ +      random/0 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-spec get_constitution (type()) -> integer(). +get_constitution (Att) -> Att#attributes.constitution. + +-spec get_dexterity (type()) -> integer(). +get_dexterity (Att) -> Att#attributes.dexterity. + +-spec get_intelligence (type()) -> integer(). +get_intelligence (Att) -> Att#attributes.intelligence. + +-spec get_mind (type()) -> integer(). +get_mind (Att) -> Att#attributes.mind. + +-spec get_speed (type()) -> integer(). +get_speed (Att) -> Att#attributes.speed. + +-spec get_strength (type()) -> integer(). +get_strength (Att) -> Att#attributes.strength. + +-spec set_constitution (integer(), type()) -> type(). +set_constitution (Val, Att) -> Att#attributes{ constitution = Val }. + +-spec set_dexterity (integer(), type()) -> type(). +set_dexterity (Val, Att) -> Att#attributes{ dexterity = Val }. + +-spec set_intelligence (integer(), type()) -> type(). +set_intelligence (Val, Att) -> Att#attributes{ intelligence = Val }. + +-spec set_mind (integer(), type()) -> type(). +set_mind (Val, Att) -> Att#attributes{ mind = Val }. + +-spec set_speed (integer(), type()) -> type(). +set_speed (Val, Att) -> Att#attributes{ speed = Val }. + +-spec set_strength (integer(), type()) -> type(). +set_strength (Val, Att) -> Att#attributes{ strength = Val }. + +-spec random () -> type(). +random () -> +   #attributes +   { +      constitution = sh_roll:percentage(), +      dexterity = sh_roll:percentage(), +      intelligence = sh_roll:percentage(), +      mind = sh_roll:percentage(), +      speed = sh_roll:percentage(), +      strength = sh_roll:percentage() +   }. diff --git a/src/shared/struct/sh_db_item.erl b/src/shared/struct/sh_db_item.erl new file mode 100644 index 0000000..e499634 --- /dev/null +++ b/src/shared/struct/sh_db_item.erl @@ -0,0 +1,70 @@ +-module(sh_db_item). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-include("../include/db_item.hrl"). + +-type type() :: db_item(). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([type/0]). + +-export +( +   [ +      new/3, + +      get_id/1, +      get_permission/1, +      get_value/1, + +      set_permission/2, +      set_value/2, + +      get_id_field/0, +      get_record_info/0, +      get_record_name/0 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec new (any(), db_user:permission(), any()) -> type(). +new (ID, Permission, Value) -> +   #db_item +   { +      id = ID, +      perm = Permission, +      val = Value +   }. + +-spec get_id (type()) -> any(). +get_id (#db_item { id = Result }) -> Result. + +-spec get_permission (type()) -> db_user:permission(). +get_permission (#db_item { perm = Result }) -> Result. + +-spec get_value (type()) -> any(). +get_value (#db_item { val = Result }) -> Result. + +-spec set_permission (db_user:permission(), type()) -> type(). +set_permission (Perm, Item) -> Item#db_item{ perm = Perm }. + +-spec set_value (any(), type()) -> type(). +set_value (Value, Item) -> Item#db_item{ val = Value }. + +-spec get_id_field () -> non_neg_integer(). +get_id_field () -> #db_item.id. + +get_record_info () -> record_info(fields, db_item). + +get_record_name () -> db_item. + diff --git a/src/shared/struct/sh_db_query.erl b/src/shared/struct/sh_db_query.erl new file mode 100644 index 0000000..998568e --- /dev/null +++ b/src/shared/struct/sh_db_query.erl @@ -0,0 +1,59 @@ +-module(sh_db_query). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-include("../include/db_query.hrl"). + +-opaque op() :: db_query_op(). +-opaque type() :: db_query(). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([type/0, op/0]). + +-export +( +   [ +      new/4, +      set_field/2, +      add_to_field/2, +      update_indexed/3 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec new (atom(), any(), sh_db_user:user(), list(op())) -> type(). +new (DBName, ObjectID, User, Ops) -> +   #db_query +   { +      db = DBName, +      id = ObjectID, +      user = User, +      ops = Ops +   }. + +-spec set_field (non_neg_integer(), any()) -> op(). +set_field (Field, Value) -> +   #set_field { field = Field, value = Value }. + +-spec add_to_field (non_neg_integer(), list(any())) -> op(). +add_to_field (Field, Values) -> +   #add_to_field { field = Field, values = Values }. + +-spec update_indexed +   ( +      non_neg_integer(), +      non_neg_integer(), +      list(op()) +   ) +   -> op(). +update_indexed (Field, IX, Updates) -> +   #update_indexed { field = Field, ix = IX, ops = Updates}. diff --git a/src/shared/struct/sh_db_user.erl b/src/shared/struct/sh_db_user.erl new file mode 100644 index 0000000..40a46d3 --- /dev/null +++ b/src/shared/struct/sh_db_user.erl @@ -0,0 +1,28 @@ +-module(sh_db_user). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-include("../include/db_user.hrl"). + +-type user() :: db_user(). +-type permission() :: db_permission(). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([user/0, permission/0]). + +-export([can_access/2]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec can_access (permission(), user()) -> boolean(). +can_access (_, admin) -> true; +can_access (any, _) -> true; +can_access (List, {'user', User}) -> +   lists:member(User, List). diff --git a/src/shared/struct/sh_statistics.erl b/src/shared/struct/sh_statistics.erl new file mode 100644 index 0000000..7cf2b06 --- /dev/null +++ b/src/shared/struct/sh_statistics.erl @@ -0,0 +1,193 @@ +-module(sh_statistics). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   statistics, +   { +      movement_points :: non_neg_integer(), +      health :: non_neg_integer(), +      dodges :: non_neg_integer(), +      parries :: non_neg_integer(), +      damage_min :: non_neg_integer(), +      damage_max :: non_neg_integer(), +      accuracy :: non_neg_integer(), +      double_hits :: non_neg_integer(), +      critical_hits :: non_neg_integer() +   } +). + +-opaque type() :: #statistics{}. + +-export_type([type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-export +( +   [ +      get_movement_points/1, +      get_health/1, +      get_dodges/1, +      get_parries/1, +      get_damage_min/1, +      get_damage_max/1, +      get_accuracy/1, +      get_double_hits/1, +      get_critical_hits/1, + +      get_damages/1 +   ] +). + +-export +( +   [ +      new/2 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec ceil (float()) -> integer(). +ceil (F) -> +   I = trunc(F), +   case (F > I) of +      true -> (I + 1); +      _ -> I +   end. + +-spec float_to_int (float()) -> integer(). +float_to_int (F) -> ceil(F). + +-spec min_max (number(), number(), number()) -> number(). +min_max (Min, Max, V) -> min(Max, max(Min, V)). + +-spec average (list(number())) -> number(). +%average ([]) -> 0; +average (L) -> lists:sum(L) / length(L). + +% V | 010 | 030 | 050 | 070 | 100 | +% F | 004 | 023 | 058 | 104 | 200 | +-spec gentle_squared_growth (number()) -> non_neg_integer(). +gentle_squared_growth (V) -> float_to_int(math:pow(V, 1.8) / 20). + +% V | 010 | 030 | 050 | 070 | 100 | +% F | 001 | 005 | 018 | 041 | 100 | +-spec sudden_squared_growth (number()) -> non_neg_integer(). +sudden_squared_growth (V) -> float_to_int(math:pow(V, 2.5) / 1000). + +% V | 010 | 030 | 050 | 070 | 100 | +% F | 002 | 006 | 016 | 049 | 256 | +-spec sudden_exp_growth (number()) -> non_neg_integer(). +sudden_exp_growth (V) -> float_to_int(math:pow(4, V / 25)). + +% V | 010 | 030 | 050 | 070 | 100 | +% F | 040 | 066 | 079 | 088 | 099 | +% Seems too generous, values for attributes below 50 should dip faster and +% lower. +%-spec already_high_slow_growth (non_neg_integer()) -> non_neg_integer(). +%already_high_slow_growth (V) -> float_to_int(30 * math:log((V + 5)/4)). + +-spec damage_base_modifier (non_neg_integer()) -> float(). +damage_base_modifier (Strength) -> ((math:pow(Strength, 1.8) / 2000.0) - 0.75). + +-spec apply_damage_base_modifier +   ( +      float(), +      non_neg_integer() +   ) +   -> non_neg_integer(). +apply_damage_base_modifier (Modifier, BaseValue) -> +   max(0, float_to_int(BaseValue + (BaseValue * Modifier))). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-spec get_movement_points (type()) -> non_neg_integer(). +get_movement_points (Stats) -> Stats#statistics.movement_points. + +-spec get_health (type()) -> non_neg_integer(). +get_health (Stats) -> Stats#statistics.health. + +-spec get_dodges (type()) -> non_neg_integer(). +get_dodges (Stats) -> Stats#statistics.dodges. + +-spec get_parries (type()) -> non_neg_integer(). +get_parries (Stats) -> Stats#statistics.parries. + +-spec get_damage_min (type()) -> non_neg_integer(). +get_damage_min (Stats) -> Stats#statistics.damage_min. + +-spec get_damage_max (type()) -> non_neg_integer(). +get_damage_max (Stats) -> Stats#statistics.damage_max. + +-spec get_accuracy (type()) -> non_neg_integer(). +get_accuracy (Stats) -> Stats#statistics.accuracy. + +-spec get_double_hits (type()) -> non_neg_integer(). +get_double_hits (Stats) -> Stats#statistics.double_hits. + +-spec get_critical_hits (type()) -> non_neg_integer(). +get_critical_hits (Stats) -> Stats#statistics.critical_hits. + +-spec get_damages (type()) -> {non_neg_integer(), non_neg_integer()}. +get_damages (Stats) -> +   { +      Stats#statistics.damage_min, +      Stats#statistics.damage_max +   }. + +-spec new +   ( +      attributes:type(), +      {weapon:id(), weapon:id()} +   ) +   -> type(). +new (BaseAttributes, WeaponIDs) -> +   {ActiveWeaponID, _} = WeaponIDs, +   ActiveWeapon = weapon:from_id(ActiveWeaponID), +   {MinDamage, MaxDamage} = weapon:get_damages(ActiveWeapon), +   Attributes = weapon:apply_to_attributes(BaseAttributes, ActiveWeapon), +   Constitution = attributes:get_constitution(Attributes), +   Dexterity = attributes:get_dexterity(Attributes), +   Intelligence = attributes:get_intelligence(Attributes), +   Mind = attributes:get_mind(Attributes), +   Speed = attributes:get_speed(Attributes), +   Strength = attributes:get_strength(Attributes), +   DamageBaseModifier = damage_base_modifier(Strength), + +   #statistics +   { +      movement_points = +         gentle_squared_growth +         ( +            average([Mind, Constitution, Constitution, Speed, Speed, Speed]) +         ), +      health = +         gentle_squared_growth(average([Mind, Constitution, Constitution])), +      dodges = +         min_max(0, 100, sudden_exp_growth(average([Dexterity, Mind, Speed]))), +      parries = +         min_max +         ( +            0, +            75, +            sudden_exp_growth +            ( +               average([Dexterity, Intelligence, Speed, Strength]) +            ) +         ), +      damage_min = apply_damage_base_modifier(DamageBaseModifier, MinDamage), +      damage_max = apply_damage_base_modifier(DamageBaseModifier, MaxDamage), +      accuracy = min_max(0, 100, sudden_squared_growth(Dexterity)), +      double_hits = +         min_max(0, 100, sudden_squared_growth(average([Mind, Speed]))), +      critical_hits = min_max(0, 100, sudden_squared_growth(Intelligence)) +   }. | 


