diff --git a/include/records.hrl b/include/records.hrl index 211f620..5e3e2fc 100644 --- a/include/records.hrl +++ b/include/records.hrl @@ -18,4 +18,4 @@ %% EGS database schema. --record(users, {gid, pid, socket, auth, charnumber, charname}). +-record(users, {gid, pid, socket, auth, folder, charnumber, charname}). diff --git a/src/egs_game.erl b/src/egs_game.erl index 448ab4e..b7b0672 100644 --- a/src/egs_game.erl +++ b/src/egs_game.erl @@ -74,7 +74,7 @@ process_handle(16#020d, CSocket, Version, Packet) -> case User#users.auth of Auth -> log(GID, "good auth, proceed"), - egs_db:users_insert(#users{gid=GID, pid=self(), socket=CSocket, auth= << 0:32 >>}), + egs_db:users_insert(#users{gid=GID, pid=self(), socket=CSocket, auth= << 0:32 >>, folder=User#users.folder}), egs_proto:send_flags(CSocket, GID), ?MODULE:char_select(CSocket, GID, Version); _ -> @@ -123,16 +123,23 @@ char_select_handle(16#020b, CSocket, GID, Version, Packet) -> char_select_handle(16#0d02, CSocket, GID, Version, Packet) -> log(GID, "character creation"), + User = egs_db:users_select(GID), [{number, Number}, {char, Char}] = egs_proto:parse_character_create(Packet), - file:write_file(io_lib:format("save/~b-character", [Number]), Char), - file:write_file(io_lib:format("save/~b-character.options", [Number]), << 0:192 >>), + _ = file:make_dir(io_lib:format("save/~s", [User#users.folder])), + file:write_file(io_lib:format("save/~s/~b-character", [User#users.folder, Number]), Char), + file:write_file(io_lib:format("save/~s/~b-character.options", [User#users.folder, Number]), << 0:192 >>), char_select_load(CSocket, GID, Version, Number); %% @doc Character selection screen request. char_select_handle(16#0d06, CSocket, GID, Version, _) -> log(GID, "send character selection screen"), - egs_proto:send_character_list(CSocket, GID, char_load(0), char_load(1), char_load(2), char_load(3)), + User = egs_db:users_select(GID), + egs_proto:send_character_list(CSocket, GID, + char_load(User#users.folder, 0), + char_load(User#users.folder, 1), + char_load(User#users.folder, 2), + char_load(User#users.folder, 3)), ?MODULE:char_select(CSocket, GID, Version); %% @doc Unknown command handler. Do nothing. @@ -143,8 +150,8 @@ char_select_handle(Command, CSocket, GID, Version, _) -> %% @doc Load the given character's data. -char_load(Number) -> - Filename = io_lib:format("save/~b-character", [Number]), +char_load(Folder, Number) -> + Filename = io_lib:format("save/~s/~b-character", [Folder, Number]), case file:read_file(Filename) of {ok, Char} -> {ok, Options} = file:read_file(io_lib:format("~s.options", [Filename])), @@ -156,8 +163,8 @@ char_load(Number) -> %% @doc Load the selected character and start the main game's loop. char_select_load(CSocket, GID, Version, Number) -> - [{status, _}, {char, << Name:512/bits, _/bits >>}|_] = char_load(Number), User = egs_db:users_select(GID), + [{status, _}, {char, << Name:512/bits, _/bits >>}|_] = char_load(User#users.folder, Number), NewRow = User#users{charnumber=Number, charname=Name}, egs_db:users_insert(NewRow), ?MODULE:lobby_load(CSocket, GID, 16#0100, 16#0100), @@ -168,7 +175,7 @@ char_select_load(CSocket, GID, Version, Number) -> lobby_load(CSocket, GID, Map, Entry) -> User = egs_db:users_select(GID), - [{status, 1}, {char, Char}, {options, Options}] = char_load(User#users.charnumber), + [{status, 1}, {char, Char}, {options, Options}] = char_load(User#users.folder, User#users.charnumber), [{quest, Quest}, {zone, Zone}] = proplists:get_value(Map, ?MAPS, [{quest, "p/quest.gc1.nbl"}, {zone, "p/zone.gc1.nbl"}]), try egs_proto:send_character_selected(CSocket, GID, Char, Options), @@ -297,7 +304,7 @@ handle(Command, _, GID, _, Packet) when Command =:= 16#0d07 -> log(GID, "options changes"), [{options, Options}] = egs_proto:parse_options_change(Packet), User = egs_db:users_select(GID), - file:write_file(io_lib:format("save/~b-character.options", [User#users.charnumber]), Options); + file:write_file(io_lib:format("save/~s/~b-character.options", [User#users.folder, User#users.charnumber]), Options); %% @doc Unknown command handler. Do nothing. diff --git a/src/egs_login.erl b/src/egs_login.erl index e214670..c9f3f4b 100644 --- a/src/egs_login.erl +++ b/src/egs_login.erl @@ -90,12 +90,16 @@ handle(16#0217, CSocket, SessionID, _) -> %% @doc Authentication request handler. Currently always succeed. %% Use the temporary session ID as the GID for now. +%% Use username and password as a folder name for saving character data. %% @todo Handle real GIDs whenever there's real authentication. -handle(16#0219, CSocket, SessionID, _) -> - log(SessionID, "auth success"), +handle(16#0219, CSocket, SessionID, Packet) -> + [{username, Username}, {password, Password}] = egs_proto:parse_auth_request(Packet), + log(SessionID, io_lib:format("auth success for ~s ~s", [Username, Password])), Auth = crypto:rand_bytes(4), - egs_db:users_insert(#users{gid=SessionID, pid=self(), socket=CSocket, auth=Auth}), + Folder = << Username/binary, "-", Password/binary >>, + log(SessionID, Folder), + egs_db:users_insert(#users{gid=SessionID, pid=self(), socket=CSocket, auth=Auth, folder=Folder}), egs_proto:send_auth_success(CSocket, SessionID, SessionID, Auth); %% @doc MOTD request handler. Handles both forms of MOTD requests, US and JP. diff --git a/src/egs_proto.erl b/src/egs_proto.erl index 4cf1bd0..b5f5008 100644 --- a/src/egs_proto.erl +++ b/src/egs_proto.erl @@ -111,6 +111,13 @@ packet_split(Packet) -> [ Split | packet_split(Rest) ] end. +%% @doc Parse a login authentication command. Return the username and password. + +parse_auth_request(Packet) -> + << _:352, Username:192/bits, Password:192/bits, _/bits >> = Packet, + [{username, re:replace(Username, "\\0+", "", [global, {return, binary}])}, + {password, re:replace(Password, "\\0+", "", [global, {return, binary}])}]. + %% @doc Parse a character creation command. Return the character number and data. parse_character_create(Packet) ->