From b521233125d24f14c33a115c35782c426b89414f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Fri, 14 May 2010 23:45:03 +0200 Subject: [PATCH] Handle other players and their movements. This does not include making a player appear right after spawning, making a player disappear after logoff and most lobby actions. This probably isn't even correct or complete but it works for now. --- include/records.hrl | 3 +- p/packet0200.bin | Bin 92 -> 92 bytes p/packet0201.bin | Bin 836 -> 836 bytes p/packet1005.bin | Bin 1748 -> 1748 bytes p/player.bin | Bin 0 -> 716 bytes src/egs_db.erl | 12 +++++++ src/egs_game.erl | 76 ++++++++++++++++++++++++++++++++++++++++---- 7 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 p/player.bin diff --git a/include/records.hrl b/include/records.hrl index 5e3e2fc..eb060fe 100644 --- a/include/records.hrl +++ b/include/records.hrl @@ -18,4 +18,5 @@ %% EGS database schema. --record(users, {gid, pid, socket, auth, folder, charnumber, charname}). +-record(ids, {type, id}). +-record(users, {gid, pid, socket, auth, folder, charnumber, charname, lid}). diff --git a/p/packet0200.bin b/p/packet0200.bin index 7b17e4242b5e0a202d6a54fa5e6fcf7d29f9d1ed..30c5832cd0c367c62621d2d8bf2a1be9675d2209 100644 GIT binary patch delta 12 Tcma!vnV`VZIBf>QL=_7F8)gIv delta 12 Scma!vnV`Tj69^`%SO5SXi3Gj? diff --git a/p/packet0201.bin b/p/packet0201.bin index bda432c8977b1800f01021bbb42a805c430220fd..d0e6f250ea49ddebfc972b351505a5165e4b4edf 100644 GIT binary patch literal 836 zcmdUtyGsK>5XOJIckvPvKN6g`i*x6(pcw8?Z8U8j0Ye6znZi zh-hIYh(*8`Hdb1Q+IZgNxCGM$D+gxg+nN3Ln`Jj|fK~>YN(lNfs|kf~YT);}qwlx| zj&pxuHyPTE;z1sr^=B)4vmeQ23TtQnasED65)qkWg$Z!ekj<4&Z!CQCn2(q!dRk z7vu!^Xne}`xNaoLea#D`XS|tOp_fh5VpRv2R$&gu8rQI@_tFtd0@&9AxbbHorvB&g&UO8P#Rc2s#7Rq%p X@HFK8MZb1D;nlpCY(7I<`j6-b^d(Dr literal 836 zcmZ=^W?*1q1QK8%#88=G$Oz>yFfaGB(SQs8Ku>$#w%&bgoAc?gp3=A?2EDZna z8Ne8(?f-u!2DgU{45?`>3~#&`7)~-WGJOBf$PoC0f#J+g28M-Tg^=)BGT|8$hgMyxF007iSJa_;A diff --git a/p/packet1005.bin b/p/packet1005.bin index fdcdf2e1bd93dad7353530a733b77741865f9dce..55363b9019b4b55a339d535d80fa4adc3421788c 100644 GIT binary patch delta 47 ncmcb@dxdv`f=c7G84L)(2xk5Vf`;RHWeki$3?TW9E)&=QFlY_C delta 47 ncmcb@dxdv`f{L5IAtM7EK$!o5py7C483Usb14w?O%LFz60Za?4 diff --git a/p/player.bin b/p/player.bin new file mode 100644 index 0000000000000000000000000000000000000000..437f69cfb0ff37f4706c67417d131a6b18c0af91 GIT binary patch literal 716 zcmZQz5Msz!XUNC^2SDck|NkGH5CDsSB)EZ?k>MPJ!oQ793=A0-&l(txz?7q_b7d$7 z!c>Mlm;w@MCPrS}{~$eFLLkft#7qoI0?b@20xS&sg;;^^VP)WFWd$kes$pPQ_m7$3 ze?8F2Knw!*dJGKDezP$2RxmK+y@7b^KG5|qr5PC}EM;I=Wz4`Z0j!c4Od2I|GJzNy zHeF@dS<42|0G2@zTnsOm5%`llH-nl6NTCSBfmjfRu|YHpi!c;Sfw46|2r&Kp#KLqP z7?4w0MH#DDXEAUB!-$RXCft$+APeL!ba{{-5FR?9!5-mOQrQTd3=GJ6k;QSb85sZp C!awK$ literal 0 HcmV?d00001 diff --git a/src/egs_db.erl b/src/egs_db.erl index 1c16cdb..5d71312 100644 --- a/src/egs_db.erl +++ b/src/egs_db.erl @@ -36,8 +36,15 @@ do(Q) -> create() -> mnesia:create_schema([node()]), mnesia:start(), + mnesia:create_table(ids, [{attributes, record_info(fields, ids)}]), + mnesia:dirty_update_counter(ids, lobby, 0), mnesia:create_table(users, [{attributes, record_info(fields, users)}]). +%% @doc Retrieve the next unique ID. + +next(Type) -> + mnesia:dirty_update_counter(ids, Type, 1). + %% @doc Select exactly one user by its GID. Return an #users record. users_select(GID) -> @@ -49,6 +56,11 @@ users_select(GID) -> users_select_all() -> do(qlc:q([X || X <- mnesia:table(users)])). +%% @doc Select all other users. Return a list of #users records. + +users_select_others(GID) -> + do(qlc:q([X || X <- mnesia:table(users), X#users.gid /= GID, X#users.charnumber /= undefined])). + %% @doc Insert or update an user. users_insert(User) -> diff --git a/src/egs_game.erl b/src/egs_game.erl index b7b0672..a3d22c3 100644 --- a/src/egs_game.erl +++ b/src/egs_game.erl @@ -74,7 +74,8 @@ 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 >>, folder=User#users.folder}), + LID = egs_db:next(lobby), + egs_db:users_insert(#users{gid=GID, pid=self(), socket=CSocket, auth= << 0:32 >>, folder=User#users.folder, lid=LID}), egs_proto:send_flags(CSocket, GID), ?MODULE:char_select(CSocket, GID, Version); _ -> @@ -196,6 +197,8 @@ lobby_load(CSocket, GID, Map, Entry) -> egs_proto:send_load_quest(CSocket, GID), send_packet_201(CSocket, GID, Map, Entry, Char), % 0a06, (0233, other chars?) + Users = egs_db:users_select_others(GID), + send_packet_233(CSocket, GID, Users), egs_proto:send_loading_end(CSocket, GID), egs_proto:send_camera_center(CSocket, GID) catch @@ -206,9 +209,30 @@ lobby_load(CSocket, GID, Map, Entry) -> %% @doc Game's main loop. %% @todo Have some kind of clock process for keepalive packets. +%% @todo Handle 0102 and 0503 broadcasts correctly. loop(CSocket, GID, Version) -> receive + {psu_broadcast_0102, Data} -> + << _:96, SrcGID:32/little-unsigned-integer, _:256, After/bits >> = Data, + % TODO: assign the LID correctly when sending the character info for the player's character, not when broadcasting + User = egs_db:users_select(SrcGID), + LID = User#users.lid, + Send = << 16#01020101:32, 0:32, 16#00011300:32, SrcGID:32/little-unsigned-integer, 0:64, + 16#00011300:32, GID:32/little-unsigned-integer, 0:64, SrcGID:32/little-unsigned-integer, + LID:32/little-unsigned-integer, After/binary >>, + egs_proto:packet_send(CSocket, Send), + ?MODULE:loop(CSocket, GID, Version); + {psu_broadcast_0503, Data} -> + << _:96, SrcGID:32/little-unsigned-integer, _:256, After/bits >> = Data, + % TODO: assign the LID correctly when sending the character info for the player's character, not when broadcasting + User = egs_db:users_select(SrcGID), + LID = User#users.lid, + Send = << 16#05030101:32, 0:32, 16#00011300:32, SrcGID:32/little-unsigned-integer, 0:64, + 16#00011300:32, GID:32/little-unsigned-integer, 0:64, SrcGID:32/little-unsigned-integer, + LID:32/little-unsigned-integer, After/binary >>, + egs_proto:packet_send(CSocket, Send), + ?MODULE:loop(CSocket, GID, Version); {psu_chat, ChatGID, ChatName, ChatMessage} -> egs_proto:send_chat(CSocket, Version, ChatGID, ChatName, ChatMessage), ?MODULE:loop(CSocket, GID, Version); @@ -279,7 +303,7 @@ handle(16#0302, _, GID, _, _) -> %% We must take extra precautions to handle different versions of the game correctly. %% @todo Only broadcast to people in the same map. -handle(Command, _, GID, Version, Packet) when Command =:= 16#0304 -> +handle(16#0304, _, GID, Version, Packet) -> log(GID, "broadcast chat"), [{gid, _}, {name, ChatName}, {message, ChatMessage}] = egs_proto:parse_chat(Version, Packet), case ChatName of @@ -291,16 +315,28 @@ handle(Command, _, GID, Version, Packet) when Command =:= 16#0304 -> end, lists:foreach(fun(User) -> User#users.pid ! {psu_chat, GID, ActualName, ChatMessage} end, egs_db:users_select_all()); +%% @doc Movements handler. Broadcast to all other players. + +handle(16#0102, _, GID, _, Packet) -> + << _:32, Data/bits >> = Packet, + lists:foreach(fun(User) -> User#users.pid ! {psu_broadcast_0102, Data} end, egs_db:users_select_others(GID)); + +%% @doc Position change handler. Broadcast to all other players. + +handle(16#0503, _, GID, _, Packet) -> + << _:32, Data/bits >> = Packet, + lists:foreach(fun(User) -> User#users.pid ! {psu_broadcast_0503, Data} end, egs_db:users_select_others(GID)); + %% @doc Lobby change handler. -handle(Command, CSocket, GID, _, Packet) when Command =:= 16#0807 -> +handle(16#0807, CSocket, GID, _, Packet) -> [{map, Map}, {entry, Entry}] = egs_proto:parse_lobby_change(Packet), log(GID, io_lib:format("lobby change (~4.16.0b,~4.16.0b)", [Map, Entry])), lobby_load(CSocket, GID, Map, Entry); %% @doc Options changes handler. -handle(Command, _, GID, _, Packet) when Command =:= 16#0d07 -> +handle(16#0d07, _, GID, _, Packet) -> log(GID, "options changes"), [{options, Options}] = egs_proto:parse_options_change(Packet), User = egs_db:users_select(GID), @@ -325,10 +361,38 @@ send_packet_201(CSocket, GID, Map, Entry, Char) -> {ok, File} = file:read_file("p/packet0201.bin"), << _:96, A:32/bits, _:96, B:32/bits, _:96, C:32/bits, _:128, D:96/bits, _:2592, After/bits >> = File, Packet = << 16#0201:16, 0:48, A/binary, GID:32/little-unsigned-integer, 0:64, B/binary, GID:32/little-unsigned-integer, - 0:64, C/binary, GID:32/little-unsigned-integer, 0:96, D/binary, Map:16/unsigned-integer, 0:16, Entry:16/unsigned-integer, - 0:16, 0:320, Char/binary, After/binary >>, + 0:64, C/binary, GID:32/little-unsigned-integer, 0:96, D/binary, Map:16/unsigned-integer, + 0:16, Entry:16/unsigned-integer, 0:16, 0:320, Char/binary, After/binary >>, egs_proto:packet_send(CSocket, Packet). +%% @todo Figure out what the other things are. + +send_packet_233(CSocket, GID, Users) -> + NbUsers = length(Users), + case NbUsers of + 0 -> + ignore; + _ -> + Header = << 16#02330300:32, 0:32, 16#00001200:32, GID:32/little-unsigned-integer, 0:64, 16#00011300:32, + GID:32/little-unsigned-integer, 0:64, NbUsers:32/little-unsigned-integer >>, + Contents = build_packet_233_contents(Users), + Packet = << Header/binary, Contents/binary >>, + egs_proto:packet_send(CSocket, Packet) + end. + +build_packet_233_contents([]) -> + << >>; +build_packet_233_contents(Users) -> + [User|Rest] = Users, + {ok, File} = file:read_file("p/player.bin"), + << A:32/bits, _:32, B:64/bits, _:32, C:480/bits, _:2208, D/bits >> = File, + {ok, CharFile} = file:read_file(io_lib:format("save/~s/~b-character", [User#users.folder, User#users.charnumber])), + CharGID = User#users.gid, + LID = User#users.lid, + Chunk = << A/binary, CharGID:32/little-unsigned-integer, B/binary, LID:16/little-unsigned-integer, 16#0100:16, C/binary, CharFile/binary, D/binary >>, + Next = build_packet_233_contents(Rest), + << Chunk/binary, Next/binary >>. + %% @todo Figure out what the packet is. send_packet_1005(CSocket, GID, Char) ->