Correct prev
parent
ad7e141ea5
commit
d24c9061a4
|
@ -0,0 +1,15 @@
|
|||
*.kpf
|
||||
*.beam
|
||||
*.o
|
||||
*.so
|
||||
build/*
|
||||
^build$
|
||||
Emakefile
|
||||
coverage
|
||||
coverage/*
|
||||
erl_crash.dump
|
||||
priv/
|
||||
test/logs/
|
||||
ebin/*.beam
|
||||
logs/*
|
||||
ebin/test.erl
|
|
@ -0,0 +1,16 @@
|
|||
Copyright (c) 2012 Alexander Markevych and individual contributors
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
|
@ -0,0 +1,41 @@
|
|||
ERL ?= erl
|
||||
ERLC = erlc
|
||||
EBIN_DIRS := $(wildcard deps/*/ebin)
|
||||
|
||||
.PHONY: rel deps
|
||||
|
||||
all: deps compile
|
||||
|
||||
compile: deps
|
||||
@./rebar compile
|
||||
|
||||
deps:
|
||||
@./rebar get-deps
|
||||
@./rebar check-deps
|
||||
|
||||
clean:
|
||||
@./rebar clean
|
||||
|
||||
realclean: clean
|
||||
@./rebar delete-deps
|
||||
|
||||
tests:
|
||||
@./rebar skip_deps=true eunit
|
||||
|
||||
rel: deps
|
||||
@./rebar compile generate
|
||||
|
||||
doc:
|
||||
rebar skip_deps=true doc
|
||||
|
||||
console:
|
||||
@erl -pa deps/*/ebin deps/*/include ebin include -boot start_sasl
|
||||
|
||||
analyze: checkplt
|
||||
@./rebar skip_deps=true dialyze
|
||||
|
||||
buildplt:
|
||||
@./rebar skip_deps=true build-plt
|
||||
|
||||
checkplt: buildplt
|
||||
@./rebar skip_deps=true check-plt
|
|
@ -0,0 +1,19 @@
|
|||
This project is to run a Minetest Server using Erlang, mainly hoping
|
||||
to improve server quality and stability.
|
||||
|
||||
In time this project will allow hundreds of players connected to one server,
|
||||
rather than the current technical limitations of the minetestserver program
|
||||
provided by celeron55's minetest GitHub repo.
|
||||
|
||||
This project should be under GPL V2 (or later.)
|
||||
|
||||
=======================================
|
||||
This project is still being worked out, until a working server module is completed.
|
||||
=======================================
|
||||
|
||||
The code is worked and created upon by Markevych (hummermania) Alexander.
|
||||
Look at https://github.com/hummermania/
|
||||
|
||||
The game, Minetest is worked and maintained by Celeron55, aka, Perttu Ahola.
|
||||
The repo for Minetest is https://github.com/celeron55/minetest and the
|
||||
extended version of it can be found here: http://github.com/celeron55/minetest_game
|
|
@ -0,0 +1,9 @@
|
|||
{application, erlmines,
|
||||
[{description, "Minetest server written on Erlang"},
|
||||
{vsn, "0.0.0"},
|
||||
{modules, [erlmines,erlmines_app,erlmines_sup,clientserver]},
|
||||
{registered, [erlmines]},
|
||||
{applications, [kernel, stdlib]},
|
||||
{mod, {erlmines_app, []}},
|
||||
{start_phases, []}
|
||||
]}.
|
|
@ -0,0 +1,521 @@
|
|||
%%
|
||||
%% erlmines - The minetest server written in Erlang
|
||||
%% Copyright (C) 2012 hummermania, Markevych Alexander <rabota.pmr@gmail.com>
|
||||
%%
|
||||
|
||||
-author('Alexander Markevych <rabota.pmr@gmail.com>').
|
||||
|
||||
-define(U8, 8/unsigned-little-integer).
|
||||
-define(U16, 16/unsigned-little-integer).
|
||||
-define(U32, 32/unsigned-little-integer).
|
||||
|
||||
-record(buffered_packet, {
|
||||
data, % Data of the packet, including headers
|
||||
time, % Seconds from buffering the packet or re-sending
|
||||
totaltime, % Seconds from buffering the packet
|
||||
address % Sender or destination
|
||||
}).
|
||||
|
||||
-record(original_packet, {
|
||||
data,
|
||||
address
|
||||
}).
|
||||
|
||||
-record(reliable_packet, {
|
||||
data
|
||||
}).
|
||||
|
||||
-record(incoming_split_packet, {
|
||||
% Key is chunk number, value is data without headers
|
||||
chunks,
|
||||
chunk_count,
|
||||
time, % Seconds from adding
|
||||
reliable % If true, isn't deleted on timeout
|
||||
}).
|
||||
|
||||
-define(PROTOCOL_VERSION, 7).
|
||||
-define(PROTOCOL_ID, 16#4f457403).
|
||||
-define(PASSWORD_SIZE,28). %% Maximum password length. Allows for base64-encoded SHA-1 (27+\0).
|
||||
-define(TEXTURENAME_ALLOWED_CHARS,"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.").
|
||||
|
||||
|
||||
%% === NOTES ===
|
||||
|
||||
%% A packet is sent through a channel to a peer with a basic header:
|
||||
%% TODO: Should we have a receiver_peer_id also?
|
||||
%% Header (7 bytes):
|
||||
%% [0] u32 protocol_id
|
||||
%% [4] u16 sender_peer_id
|
||||
%% [6] u8 channel
|
||||
%% sender_peer_id:
|
||||
%% Unique to each peer.
|
||||
%% value 0 is reserved for making new connections
|
||||
%% value 1 is reserved for server
|
||||
%% channel:
|
||||
%% The lower the number, the higher the priority is.
|
||||
%% Only channels 0, 1 and 2 exist.
|
||||
|
||||
-define(BASE_HEADER_SIZE, 7).
|
||||
-define(PEER_ID_INEXISTENT, 0).
|
||||
-define(PEER_ID_SERVER, 1).
|
||||
-define(CHANNEL_COUNT, 3).
|
||||
|
||||
|
||||
%% Packet types:
|
||||
|
||||
%% CONTROL: This is a packet used by the protocol.
|
||||
%% - When this is processed, nothing is handed to the user.
|
||||
%% Header (2 byte):
|
||||
%% [0] u8 type
|
||||
%% [1] u8 controltype
|
||||
%% controltype and data description:
|
||||
%% CONTROLTYPE_ACK
|
||||
%% [2] u16 seqnum
|
||||
%% CONTROLTYPE_SET_PEER_ID
|
||||
%% [2] u16 peer_id_new
|
||||
%% CONTROLTYPE_PING
|
||||
%% - There is no actual reply, but this can be sent in a reliable
|
||||
%% packet to get a reply
|
||||
%% CONTROLTYPE_DISCO
|
||||
|
||||
-define(TYPE_CONTROL, 0).
|
||||
-define(CONTROLTYPE_ACK, 0).
|
||||
-define(CONTROLTYPE_SET_PEER_ID, 1).
|
||||
-define(CONTROLTYPE_PING, 2).
|
||||
-define(CONTROLTYPE_DISCO, 3).
|
||||
|
||||
%% ORIGINAL: This is a plain packet with no control and no error checking at all.
|
||||
%% - When this is processed, it is directly handed to the user.
|
||||
%% Header (1 byte):
|
||||
%% [0] u8 type
|
||||
|
||||
-define(TYPE_ORIGINAL, 1).
|
||||
-define(ORIGINAL_HEADER_SIZE, 1).
|
||||
|
||||
|
||||
%% SPLIT: These are sequences of packets forming one bigger piece of data.
|
||||
%% - When processed and all the packet_nums 0...packet_count-1 are
|
||||
%% present (this should be buffered), the resulting data shall be
|
||||
%% directly handed to the user.
|
||||
%% - If the data fails to come up in a reasonable time, the buffer shall
|
||||
%% be silently discarded.
|
||||
%% - These can be sent as-is or atop of a RELIABLE packet stream.
|
||||
%% Header (7 bytes):
|
||||
%% [0] u8 type
|
||||
%% [1] u16 seqnum
|
||||
%% [3] u16 chunk_count
|
||||
%% [5] u16 chunk_num
|
||||
|
||||
-define(TYPE_SPLIT, 2).
|
||||
|
||||
%% RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs,
|
||||
%% and they shall be delivered in the same order as sent. This is done
|
||||
%% with a buffer in the receiving and transmitting end.
|
||||
%% - When this is processed, the contents of each packet is recursively
|
||||
%% processed as packets.
|
||||
%% Header (3 bytes):
|
||||
%% [0] u8 type
|
||||
%% [1] u16 seqnum
|
||||
|
||||
|
||||
-define(TYPE_RELIABLE, 3).
|
||||
-define(RELIABLE_HEADER_SIZE, 3).
|
||||
%%#define SEQNUM_INITIAL 0x10
|
||||
-define(SEQNUM_INITIAL, 65500).
|
||||
-define(SEQNUM_MAX, 65535).
|
||||
|
||||
|
||||
%% =================================
|
||||
%% TOSERVER command group
|
||||
%% =================================
|
||||
|
||||
-define(TOSERVER_INIT,16#10).
|
||||
|
||||
%% Sent first after connected.
|
||||
%%
|
||||
%% [0] u16 TOSERVER_INIT
|
||||
%% [2] u8 SER_FMT_VER_HIGHEST
|
||||
%% [3] u8[20] player_name
|
||||
%% [23] u8[28] password (new in some version)
|
||||
%% [51] u16 client network protocol version (new in some version)
|
||||
|
||||
|
||||
-define(TOSERVER_INIT2,16#11).
|
||||
|
||||
%% Sent as an ACK for TOCLIENT_INIT.
|
||||
%% After this, the server can send data.
|
||||
%%
|
||||
%% [0] u16 TOSERVER_INIT2
|
||||
|
||||
|
||||
-define(TOSERVER_GETBLOCK, 16#20). %% Obsolete
|
||||
-define(TOSERVER_ADDNODE, 16#21). %% Obsolete
|
||||
-define(TOSERVER_REMOVENODE, 16#22). %% Obsolete
|
||||
|
||||
-define(TOSERVER_PLAYERPOS, 16#23).
|
||||
|
||||
%% [0] u16 command
|
||||
%% [2] v3s32 position*100
|
||||
%% [2+12] v3s32 speed*100
|
||||
%% [2+12+12] s32 pitch*100
|
||||
%% [2+12+12+4] s32 yaw*100
|
||||
|
||||
|
||||
-define(TOSERVER_GOTBLOCKS,16#24).
|
||||
|
||||
%% [0] u16 command
|
||||
%% [2] u8 count
|
||||
%% [3] v3s16 pos_0
|
||||
%% [3+6] v3s16 pos_1
|
||||
%% ...
|
||||
|
||||
|
||||
-define(TOSERVER_DELETEDBLOCKS, 16#25).
|
||||
|
||||
%% [0] u16 command
|
||||
%% [2] u8 count
|
||||
%% [3] v3s16 pos_0
|
||||
%% [3+6] v3s16 pos_1
|
||||
%% ...
|
||||
|
||||
|
||||
-define(TOSERVER_ADDNODE_FROM_INVENTORY, 16#26). %% Obsolete
|
||||
|
||||
%% [0] u16 command
|
||||
%% [2] v3s16 pos
|
||||
%% [8] u16 i
|
||||
|
||||
|
||||
-define(TOSERVER_CLICK_OBJECT, 16#27). %% Obsolete
|
||||
|
||||
%% length: 13
|
||||
%% [0] u16 command
|
||||
%% [2] u8 button (0=left, 1=right)
|
||||
%% [3] v3s16 blockpos
|
||||
%% [9] s16 id
|
||||
%% [11] u16 item
|
||||
|
||||
|
||||
-define(TOSERVER_GROUND_ACTION, 16#28). %% Obsolete
|
||||
|
||||
%% length: 17
|
||||
%% [0] u16 command
|
||||
%% [2] u8 action
|
||||
%% [3] v3s16 nodepos_undersurface
|
||||
% [9] v3s16 nodepos_abovesurface
|
||||
% [15] u16 item
|
||||
% actions:
|
||||
% 0: start digging (from undersurface)
|
||||
% 1: place block (to abovesurface)
|
||||
% 2: stop digging (all parameters ignored)
|
||||
% 3: digging completed
|
||||
|
||||
|
||||
-define(TOSERVER_RELEASE, 16#29). %% Obsolete
|
||||
|
||||
% (oops, there is some gap here)
|
||||
|
||||
|
||||
-define(TOSERVER_SIGNTEXT, 16#30). %% Old signs, obsolete
|
||||
|
||||
% u16 command
|
||||
% v3s16 blockpos
|
||||
% s16 id
|
||||
% u16 textlen
|
||||
% textdata
|
||||
|
||||
|
||||
-define(TOSERVER_INVENTORY_ACTION, 16#31).
|
||||
|
||||
% See InventoryAction in inventory.h
|
||||
|
||||
|
||||
-define(TOSERVER_CHAT_MESSAGE, 16#32).
|
||||
|
||||
%% u16 command
|
||||
%% u16 length
|
||||
%% wstring message
|
||||
|
||||
|
||||
-define(TOSERVER_SIGNNODETEXT, 16#33).
|
||||
|
||||
%% u16 command
|
||||
%% v3s16 p
|
||||
%% u16 textlen
|
||||
%% textdata
|
||||
|
||||
|
||||
-define(TOSERVER_CLICK_ACTIVEOBJECT, 16#34). % Obsolete
|
||||
|
||||
%% length: 7
|
||||
%% [0] u16 command
|
||||
%% [2] u8 button (0=left, 1=right)
|
||||
%% [3] u16 id
|
||||
%% [5] u16 item
|
||||
|
||||
|
||||
-define(TOSERVER_DAMAGE, 16#35).
|
||||
|
||||
%% u16 command
|
||||
%% u8 amount
|
||||
|
||||
|
||||
-define(TOSERVER_PASSWORD, 16#36).
|
||||
|
||||
%% Sent to change password.
|
||||
|
||||
%% [0] u16 TOSERVER_PASSWORD
|
||||
%% [2] u8[28] old password
|
||||
%% [30] u8[28] new password
|
||||
|
||||
|
||||
-define(TOSERVER_PLAYERITEM, 16#37).
|
||||
|
||||
%% Sent to change selected item.
|
||||
%% [0] u16 TOSERVER_PLAYERITEM
|
||||
%% [2] u16 item
|
||||
|
||||
|
||||
-define(TOSERVER_RESPAWN,16#38).
|
||||
|
||||
%% u16 TOSERVER_RESPAWN
|
||||
|
||||
-define(TOSERVER_INTERACT, 16#39).
|
||||
|
||||
%% [0] u16 command
|
||||
%% [2] u8 action
|
||||
%% [3] u16 item
|
||||
%% [5] u32 length of the next item
|
||||
%% [9] serialized PointedThing
|
||||
%% actions:
|
||||
%% 0: start digging (from undersurface) or use
|
||||
%% 1: stop digging (all parameters ignored)
|
||||
%% 2: digging completed
|
||||
%% 3: place block or item (to abovesurface)
|
||||
%% 4: use item
|
||||
|
||||
%% (Obsoletes TOSERVER_GROUND_ACTION and TOSERVER_CLICK_ACTIVEOBJECT.)
|
||||
|
||||
|
||||
-define(TOSERVER_REQUEST_TEXTURES, 16#40).
|
||||
|
||||
%% u16 command
|
||||
%% u16 number of textures requested
|
||||
%% for each texture {
|
||||
%% u16 length of name
|
||||
%% string name
|
||||
%% }
|
||||
|
||||
|
||||
|
||||
|
||||
%% =================================
|
||||
%% TOCLIENT command group
|
||||
%% =================================
|
||||
|
||||
-define(TOCLIENT_INIT, 16#10).
|
||||
|
||||
%% Server's reply to TOSERVER_INIT.
|
||||
%% Sent second after connected.
|
||||
%%
|
||||
%% [0] u16 TOSERVER_INIT
|
||||
%% [2] u8 deployed version
|
||||
%% [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
|
||||
%% [12] u64 map seed (new as of 2011-02-27)
|
||||
%%
|
||||
%% NOTE: The position in here is deprecated; position is
|
||||
%% explicitly sent afterwards
|
||||
|
||||
|
||||
-define(TOCLIENT_BLOCKDATA, 16#20). %%TODO: Multiple blocks
|
||||
-define(TOCLIENT_ADDNODE, 16#21).
|
||||
-define(TOCLIENT_REMOVENODE, 16#22).
|
||||
|
||||
|
||||
-define(TOCLIENT_PLAYERPOS, 16#23). %% Obsolete
|
||||
|
||||
%% [0] u16 command
|
||||
%% // Followed by an arbitary number of these:
|
||||
%% // Number is determined from packet length.
|
||||
%% [N] u16 peer_id
|
||||
%% [N+2] v3s32 position*100
|
||||
%% [N+2+12] v3s32 speed*100
|
||||
%% [N+2+12+12] s32 pitch*100
|
||||
%% [N+2+12+12+4] s32 yaw*100
|
||||
|
||||
|
||||
-define(TOCLIENT_PLAYERINFO, 16#24). %% Obsolete
|
||||
|
||||
%% [0] u16 command
|
||||
%% // Followed by an arbitary number of these:
|
||||
%% // Number is determined from packet length.
|
||||
%% [N] u16 peer_id
|
||||
%% [N] char[20] name
|
||||
|
||||
|
||||
-define(TOCLIENT_OPT_BLOCK_NOT_FOUND, 16#25). %% Obsolete
|
||||
|
||||
-define(TOCLIENT_SECTORMETA, 16#26). %% Obsolete
|
||||
|
||||
%% [0] u16 command
|
||||
%% [2] u8 sector count
|
||||
%% [3...] v2s16 pos + sector metadata
|
||||
|
||||
|
||||
-define(TOCLIENT_INVENTORY, 16#27).
|
||||
|
||||
%% [0] u16 command
|
||||
%% [2] serialized inventory
|
||||
|
||||
|
||||
-define(TOCLIENT_OBJECTDATA, 16#28) %% Obsolete
|
||||
|
||||
%% Sent as unreliable.
|
||||
%%
|
||||
%% u16 command
|
||||
%% u16 number of player positions
|
||||
%% for each player:
|
||||
%% u16 peer_id
|
||||
%% v3s32 position*100
|
||||
%% v3s32 speed*100
|
||||
%% s32 pitch*100
|
||||
%% s32 yaw*100
|
||||
%% u16 count of blocks
|
||||
%% for each block:
|
||||
%% v3s16 blockpos
|
||||
%% block objects
|
||||
|
||||
|
||||
-define(TOCLIENT_TIME_OF_DAY, 16#29).
|
||||
|
||||
%% u16 command
|
||||
%% u16 time (0-23999)
|
||||
|
||||
|
||||
%% (oops, there is some gap here)
|
||||
|
||||
-define(TOCLIENT_CHAT_MESSAGE, 16#30).
|
||||
|
||||
%% u16 command
|
||||
%% u16 length
|
||||
%% wstring message
|
||||
|
||||
|
||||
-define(TOCLIENT_ACTIVE_OBJECT_REMOVE_ADD, 16#31).
|
||||
|
||||
%% u16 command
|
||||
%% u16 count of removed objects
|
||||
%% for all removed objects {
|
||||
%% u16 id
|
||||
%% }
|
||||
%% u16 count of added objects
|
||||
%% for all added objects {
|
||||
%% u16 id
|
||||
%% u8 type
|
||||
%% u32 initialization data length
|
||||
%% string initialization data
|
||||
%% }
|
||||
|
||||
|
||||
-define(TOCLIENT_ACTIVE_OBJECT_MESSAGES, 16#32).
|
||||
|
||||
%% u16 command
|
||||
%% for all objects
|
||||
%% {
|
||||
%% u16 id
|
||||
%% u16 message length
|
||||
%% string message
|
||||
%% }
|
||||
|
||||
|
||||
-define(TOCLIENT_HP, 16#33).
|
||||
|
||||
%% u16 command
|
||||
%% u8 hp
|
||||
|
||||
|
||||
-define(TOCLIENT_MOVE_PLAYER, 16#34).
|
||||
|
||||
%% u16 command
|
||||
%% v3f1000 player position
|
||||
%% f1000 player pitch
|
||||
%% f1000 player yaw
|
||||
|
||||
|
||||
-define(TOCLIENT_ACCESS_DENIED, 16#35).
|
||||
|
||||
%% u16 command
|
||||
%% u16 reason_length
|
||||
%% wstring reason
|
||||
|
||||
|
||||
-define(TOCLIENT_PLAYERITEM, 16#36)
|
||||
|
||||
%% u16 command
|
||||
%% u16 count of player items
|
||||
%% for all player items {
|
||||
%% u16 peer id
|
||||
%% u16 length of serialized item
|
||||
%% string serialized item
|
||||
%% }
|
||||
|
||||
|
||||
-define(TOCLIENT_DEATHSCREEN, 16#37).
|
||||
|
||||
%% u16 command
|
||||
%% u8 bool set camera point target
|
||||
%% v3f1000 camera point target (to point the death cause or whatever)
|
||||
|
||||
|
||||
-define(TOCLIENT_TEXTURES, 16#38).
|
||||
|
||||
%% u16 command
|
||||
%% u16 total number of texture bunches
|
||||
%% u16 index of this bunch
|
||||
%% u32 number of textures in this bunch
|
||||
%% for each texture {
|
||||
%% u16 length of name
|
||||
%% string name
|
||||
%% u32 length of data
|
||||
%% data
|
||||
%% }
|
||||
|
||||
|
||||
-define(TOCLIENT_TOOLDEF, 16#39).
|
||||
|
||||
%% u16 command
|
||||
%% u32 length of the next item
|
||||
%% serialized ToolDefManager
|
||||
|
||||
|
||||
-define(TOCLIENT_NODEDEF, 16#3a).
|
||||
|
||||
%% u16 command
|
||||
%% u32 length of the next item
|
||||
%% serialized NodeDefManager
|
||||
|
||||
|
||||
-define(TOCLIENT_CRAFTITEMDEF, 16#3b).
|
||||
|
||||
%% u16 command
|
||||
%% u32 length of the next item
|
||||
%% serialized CraftiItemDefManager
|
||||
|
||||
|
||||
-define(TOCLIENT_ANNOUNCE_TEXTURES, 16#3c).
|
||||
|
||||
%% u16 command
|
||||
%% u32 number of textures
|
||||
%% for each texture {
|
||||
%% u16 length of name
|
||||
%% string name
|
||||
%% u16 length of sha1_digest
|
||||
%% string sha1_digest
|
||||
%% }
|
||||
|
||||
|
||||
-define(TOCLIENT_ITEMDEF, 16#3d).
|
||||
|
||||
%% u16 command
|
||||
%% u32 length of next item
|
||||
%% serialized ItemDefManager
|
|
@ -0,0 +1,427 @@
|
|||
%%
|
||||
%% erlmines - The minetest server written in Erlang
|
||||
%% Copyright (C) 2012 hummermania, Markevych Alexander <rabota.pmr@gmail.com>
|
||||
%%
|
||||
|
||||
-module(clientserver).
|
||||
-author('Alexander Markevych <rabota.pmr@gmail.com>').
|
||||
-export([init/0]).
|
||||
|
||||
init() ->
|
||||
ToClientCommand = gb_sets:from_list([
|
||||
|
||||
{toclient_init, 16#10},
|
||||
%
|
||||
% Server's reply to TOSERVER_INIT.
|
||||
% Sent second after connected.
|
||||
%
|
||||
% [0] u16 TOSERVER_INIT
|
||||
% [2] u8 deployed version
|
||||
% [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
|
||||
% [12] u64 map seed (new as of 2011-02-27)
|
||||
%
|
||||
% NOTE: The position in here is deprecated; position is
|
||||
% explicitly sent afterwards
|
||||
|
||||
{ toclient_blockdata, 16#20}, % TODO: Multiple blocks
|
||||
{ toclient_addnode, 16#21},
|
||||
{ toclient_removenode, 16#22},
|
||||
{ toclient_playerpos, 16#23}, % Obsolete
|
||||
%
|
||||
% [0] u16 command
|
||||
% // Followed by an arbitary number of these:
|
||||
% // Number is determined from packet length.
|
||||
% [N] u16 peer_id
|
||||
% [N+2] v3s32 position*100
|
||||
% [N+2+12] v3s32 speed*100
|
||||
% [N+2+12+12] s32 pitch*100
|
||||
% [N+2+12+12+4] s32 yaw*100
|
||||
|
||||
{ toclient_playerinfo, 16#24}, % Obsolete
|
||||
%
|
||||
% [0] u16 command
|
||||
% // Followed by an arbitary number of these:
|
||||
% // Number is determined from packet length.
|
||||
% [N] u16 peer_id
|
||||
% [N] char[20] name
|
||||
%
|
||||
|
||||
{ toclient_opt_block_not_found, 16#25}, % Obsolete
|
||||
|
||||
{ toclient_sectormeta, 16#26}, % Obsolete
|
||||
%
|
||||
% [0] u16 command
|
||||
% [2] u8 sector count
|
||||
% [3...] v2s16 pos + sector metadata
|
||||
|
||||
{ toclient_inventory, 16#27},
|
||||
%
|
||||
% [0] u16 command
|
||||
% [2] serialized inventory
|
||||
%
|
||||
|
||||
{ toclient_objectdata, 16#28}, % Obsolete
|
||||
%
|
||||
% Sent as unreliable.
|
||||
%
|
||||
% u16 command
|
||||
% u16 number of player positions
|
||||
% for each player:
|
||||
% u16 peer_id
|
||||
% v3s32 position*100
|
||||
% v3s32 speed*100
|
||||
% s32 pitch*100
|
||||
% s32 yaw*100
|
||||
% u16 count of blocks
|
||||
% for each block:
|
||||
% v3s16 blockpos
|
||||
% block objects
|
||||
%
|
||||
|
||||
{ toclient_time_of_day, 16#29},
|
||||
%
|
||||
% u16 command
|
||||
% u16 time (0-23999)
|
||||
% Added in a later version:
|
||||
% f1000 time_speed
|
||||
%
|
||||
|
||||
% (oops, there is some gap here)
|
||||
|
||||
{ toclient_chat_message, 16#30},
|
||||
%
|
||||
% u16 command
|
||||
% u16 length
|
||||
% wstring message
|
||||
%
|
||||
|
||||
{ toclient_active_object_remove_add, 16#31},
|
||||
%
|
||||
% u16 command
|
||||
% u16 count of removed objects
|
||||
% for all removed objects {
|
||||
% u16 id
|
||||
% }
|
||||
% u16 count of added objects
|
||||
% for all added objects {
|
||||
% u16 id
|
||||
% u8 type
|
||||
% u32 initialization data length
|
||||
% string initialization data
|
||||
% }
|
||||
|
||||
|
||||
{ toclient_active_object_messages, 16#32},
|
||||
%
|
||||
% u16 command
|
||||
% for all objects
|
||||
% {
|
||||
% u16 id
|
||||
% u16 message length
|
||||
% string message
|
||||
% }
|
||||
%
|
||||
|
||||
{ toclient_hp, 16#33},
|
||||
%
|
||||
% u16 command
|
||||
% u8 hp
|
||||
%
|
||||
|
||||
{ toclient_move_player, 16#34},
|
||||
%
|
||||
% u16 command
|
||||
% v3f1000 player position
|
||||
% f1000 player pitch
|
||||
% f1000 player yaw
|
||||
%
|
||||
|
||||
{ toclient_access_denied, 16#35},
|
||||
%
|
||||
% u16 command
|
||||
% u16 reason_length
|
||||
% wstring reason
|
||||
%
|
||||
|
||||
{ toclient_playeritem, 16#36},
|
||||
%
|
||||
% u16 command
|
||||
% u16 count of player items
|
||||
% for all player items {
|
||||
% u16 peer id
|
||||
% u16 length of serialized item
|
||||
% string serialized item
|
||||
% }
|
||||
%
|
||||
|
||||
{ toclient_deathscreen, 16#37},
|
||||
%
|
||||
% u16 command
|
||||
% u8 bool set camera point target
|
||||
% v3f1000 camera point target (to point the death cause or whatever)
|
||||
%
|
||||
|
||||
{ toclient_media, 16#38},
|
||||
%
|
||||
% u16 command
|
||||
% u16 total number of texture bunches
|
||||
% u16 index of this bunch
|
||||
% u32 number of files in this bunch
|
||||
% for each file {
|
||||
% u16 length of name
|
||||
% string name
|
||||
% u32 length of data
|
||||
% data
|
||||
% }
|
||||
%
|
||||
|
||||
{ toclient_tooldef, 16#39},
|
||||
%
|
||||
% u16 command
|
||||
% u32 length of the next item
|
||||
% serialized ToolDefManager
|
||||
%
|
||||
|
||||
{ toclient_nodedef, 16#3a},
|
||||
%
|
||||
% u16 command
|
||||
% u32 length of the next item
|
||||
% serialized NodeDefManager
|
||||
%
|
||||
|
||||
{ toclient_craftitemdef, 16#3b},
|
||||
%
|
||||
% u16 command
|
||||
% u32 length of the next item
|
||||
% serialized CraftiItemDefManager
|
||||
%
|
||||
|
||||
{ toclient_announce_media, 16#3c},
|
||||
%
|
||||
% u16 command
|
||||
% u32 number of files
|
||||
% for each texture {
|
||||
% u16 length of name
|
||||
% string name
|
||||
% u16 length of sha1_digest
|
||||
% string sha1_digest
|
||||
% }
|
||||
%
|
||||
|
||||
{ toclient_itemdef, 16#3d},
|
||||
%
|
||||
% u16 command
|
||||
% u32 length of next item
|
||||
% serialized ItemDefManager
|
||||
%
|
||||
|
||||
{ toclient_play_sound, 16#3f},
|
||||
%
|
||||
% u16 command
|
||||
% s32 sound_id
|
||||
% u16 len
|
||||
% u8[len] sound name
|
||||
% s32 gain*1000
|
||||
% u8 type (0=local, 1=positional, 2=object)
|
||||
% s32[3] pos_nodes*10000
|
||||
% u16 object_id
|
||||
% u8 loop (bool)
|
||||
%
|
||||
|
||||
{ toclient_stop_sound, 16#40}
|
||||
%
|
||||
% u16 command
|
||||
% s32 sound_id
|
||||
%
|
||||
]),
|
||||
|
||||
ToServerCommand = gb_sets:from_list([
|
||||
|
||||
{ toserver_init, 16#10},
|
||||
%
|
||||
% Sent first after connected.
|
||||
%
|
||||
% [0] u16 TOSERVER_INIT
|
||||
% [2] u8 SER_FMT_VER_HIGHEST
|
||||
% [3] u8[20] player_name
|
||||
% [23] u8[28] password (new in some version)
|
||||
% [51] u16 client network protocol version (new in some version)
|
||||
%
|
||||
|
||||
{ toserver_init2, 16#11},
|
||||
%
|
||||
% Sent as an ACK for TOCLIENT_INIT.
|
||||
% After this, the server can send data.
|
||||
%
|
||||
% [0] u16 TOSERVER_INIT2
|
||||
%
|
||||
|
||||
{ toserver_getblock, 16#20}, % Obsolete
|
||||
{ toserver_addnode, 16#21}, % Obsolete
|
||||
{ toserver_removenode, 16#22}, % Obsolete
|
||||
|
||||
{ toserver_playerpos, 16#23},
|
||||
%
|
||||
% [0] u16 command
|
||||
% [2] v3s32 position*100
|
||||
% [2+12] v3s32 speed*100
|
||||
% [2+12+12] s32 pitch*100
|
||||
% [2+12+12+4] s32 yaw*100
|
||||
%
|
||||
|
||||
{ toserver_gotblocks, 16#24},
|
||||
%
|
||||
% [0] u16 command
|
||||
% [2] u8 count
|
||||
% [3] v3s16 pos_0
|
||||
% [3+6] v3s16 pos_1
|
||||
% ...
|
||||
%
|
||||
|
||||
{ toserver_deletedblocks, 16#25},
|
||||
%
|
||||
% [0] u16 command
|
||||
% [2] u8 count
|
||||
% [3] v3s16 pos_0
|
||||
% [3+6] v3s16 pos_1
|
||||
% ...
|
||||
%
|
||||
|
||||
{ toserver_addnode_from_inventory, 16#26}, % Obsolete
|
||||
%
|
||||
% [0] u16 command
|
||||
% [2] v3s16 pos
|
||||
% [8] u16 i
|
||||
%
|
||||
|
||||
{ toserver_click_object, 16#27}, % Obsolete
|
||||
%
|
||||
% length: 13
|
||||
% [0] u16 command
|
||||
% [2] u8 button (0=left, 1=right)
|
||||
% [3] v3s16 blockpos
|
||||
% [9] s16 id
|
||||
% [11] u16 item
|
||||
%
|
||||
|
||||
{ toserver_ground_action, 16#28}, % Obsolete
|
||||
%
|
||||
% length: 17
|
||||
% [0] u16 command
|
||||
% [2] u8 action
|
||||
% [3] v3s16 nodepos_undersurface
|
||||
% [9] v3s16 nodepos_abovesurface
|
||||
% [15] u16 item
|
||||
% actions:
|
||||
% 0: start digging (from undersurface)
|
||||
% 1: place block (to abovesurface)
|
||||
% 2: stop digging (all parameters ignored)
|
||||
% 3: digging completed
|
||||
%
|
||||
|
||||
{ toserver_release, 16#29}, % Obsolete
|
||||
|
||||
% (oops, there is some gap here)
|
||||
|
||||
{ toserver_signtext, 16#30}, % Old signs, obsolete
|
||||
%
|
||||
% u16 command
|
||||
% v3s16 blockpos
|
||||
% s16 id
|
||||
% u16 textlen
|
||||
% textdata
|
||||
%
|
||||
|
||||
{ toserver_inventory_action, 16#31},
|
||||
%
|
||||
% See InventoryAction in inventory.h
|
||||
%
|
||||
|
||||
{ toserver_chat_message, 16#32},
|
||||
%
|
||||
% u16 command
|
||||
% u16 length
|
||||
% wstring message
|
||||
%
|
||||
|
||||
{ toserver_signnodetext, 16#33},
|
||||
%
|
||||
% u16 command
|
||||
% v3s16 p
|
||||
% u16 textlen
|
||||
% textdata
|
||||
%
|
||||
|
||||
{ toserver_click_activeobject, 16#34}, % Obsolete
|
||||
%
|
||||
% length: 7
|
||||
% [0] u16 command
|
||||
% [2] u8 button (0=left, 1=right)
|
||||
% [3] u16 id
|
||||
% [5] u16 item
|
||||
%
|
||||
|
||||
{ toserver_damage, 16#35},
|
||||
%
|
||||
% u16 command
|
||||
% u8 amount
|
||||
%
|
||||
|
||||
{ toserver_password, 16#36},
|
||||
%
|
||||
% Sent to change password.
|
||||
%
|
||||
% [0] u16 TOSERVER_PASSWORD
|
||||
% [2] u8[28] old password
|
||||
% [30] u8[28] new password
|
||||
%
|
||||
|
||||
{ toserver_playeritem, 16#37},
|
||||
%
|
||||
% Sent to change selected item.
|
||||
%
|
||||
% [0] u16 TOSERVER_PLAYERITEM
|
||||
% [2] u16 item
|
||||
%
|
||||
|
||||
{ toserver_respawn, 16#38},
|
||||
%
|
||||
% u16 TOSERVER_RESPAWN
|
||||
%
|
||||
|
||||
{ toserver_interact, 16#39},
|
||||
%
|
||||
% [0] u16 command
|
||||
% [2] u8 action
|
||||
% [3] u16 item
|
||||
% [5] u32 length of the next item
|
||||
% [9] serialized PointedThing
|
||||
% actions:
|
||||
% 0: start digging (from undersurface) or use
|
||||
% 1: stop digging (all parameters ignored)
|
||||
% 2: digging completed
|
||||
% 3: place block or item (to abovesurface)
|
||||
% 4: use item
|
||||
%
|
||||
% (Obsoletes TOSERVER_GROUND_ACTION and TOSERVER_CLICK_ACTIVEOBJECT.)
|
||||
%
|
||||
|
||||
{ toserver_removed_sounds, 16#3a},
|
||||
%
|
||||
% u16 command
|
||||
% u16 len
|
||||
% s32[len] sound_id
|
||||
%
|
||||
|
||||
{ toserver_request_media, 16#40}
|
||||
%
|
||||
% u16 command
|
||||
% u16 number of files requested
|
||||
% for each file {
|
||||
% u16 length of name
|
||||
% string name
|
||||
% }
|
||||
%
|
||||
]),
|
||||
[ToClientCommand, ToServerCommand].
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
%%
|
||||
%% erlmines - The minetest server written in Erlang
|
||||
%% Copyright (C) 2012 hummermania, Markevych Alexander <rabota.pmr@gmail.com>
|
||||
%%
|
||||
|
||||
-module(connection).
|
||||
-author('Alexander Markevych <rabota.pmr@gmail.com>').
|
||||
-include("connection.hrl").
|
||||
|
||||
-export([makePacket/5, makeSplitPacket/3, test/0]).
|
||||
|
||||
ceiling(X) ->
|
||||
T = trunc(X),
|
||||
case X - T == 0 of
|
||||
true -> T;
|
||||
false -> T + 1
|
||||
end.
|
||||
|
||||
readPeerId(PacketData) ->
|
||||
<<_P:?U32,SenderPeerId:?U16,_Other/binary>> = PacketData,
|
||||
SenderPeerId.
|
||||
|
||||
readChannel(PacketData) ->
|
||||
<<_P:?U32,_S:?U16,Channel:?U8,_Other/binary>> = PacketData,
|
||||
Channel.
|
||||
|
||||
% This adds the base headers to the data and makes a packet out of it
|
||||
makePacket(Address, Data, ProtocolId,SenderPeerId,Channel)->
|
||||
#buffered_packet{
|
||||
address=Address,
|
||||
data = <<ProtocolId:?U32,SenderPeerId:?U16,Channel:?U8,Data/binary>>
|
||||
}.
|
||||
% Add the TYPE_ORIGINAL header to the data
|
||||
makeOriginalPacket(Data) ->
|
||||
#original_packet{ data = <<?TYPE_ORIGINAL:?U8,Data/binary>> }.
|
||||
|
||||
% Split data in chunks and add TYPE_SPLIT headers to them
|
||||
makeSplitPacket(Data,ChunkSizeMax,SeqNum) ->
|
||||
ChunkHeaderSize = 7,
|
||||
MaxDataSize = ChunkSizeMax - ChunkHeaderSize,
|
||||
ChunkCount=ceiling(byte_size(Data)/MaxDataSize),
|
||||
Chunks = makeSplitPacketList(MaxDataSize, SeqNum, ChunkCount, 0, Data),
|
||||
Chunks.
|
||||
|
||||
makeSplitPacketList(MaxDataSize, SeqNum, ChunkCount, ChunkCount, Data) ->[];
|
||||
makeSplitPacketList(MaxDataSize, SeqNum, ChunkCount, ChunkNum, Data) ->
|
||||
DataSize = byte_size(Data),
|
||||
ChunkDataSize = case MaxDataSize - DataSize < 0 of
|
||||
true -> MaxDataSize;
|
||||
false -> DataSize
|
||||
end,
|
||||
<<ChunkData:ChunkDataSize/binary,Tile/binary>> = Data,
|
||||
%%ChunkNum1 = ChunkNum+1,
|
||||
[<<?TYPE_SPLIT:?U8, SeqNum:?U16, ChunkCount:?U16, ChunkNum:?U16,ChunkData/binary>>|makeSplitPacketList(MaxDataSize,SeqNum,ChunkCount,ChunkNum+1,Tile)].
|
||||
|
||||
test() ->
|
||||
makeSplitPacket(list_to_binary([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22]),9,65500).
|
||||
|
||||
% Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet
|
||||
% Increments split_seqnum if a split packet is made
|
||||
makeAutoSplitPacket(Data,ChunkSizeMax,SplitSeqNum) ->
|
||||
todo.
|
||||
|
||||
% core::list<SharedBuffer<u8> > makeAutoSplitPacket(
|
||||
% SharedBuffer<u8> data,
|
||||
% u32 chunksize_max,
|
||||
% u16 &split_seqnum)
|
||||
%{
|
||||
% u32 original_header_size = 1;
|
||||
% core::list<SharedBuffer<u8> > list;
|
||||
% if(data.getSize() + original_header_size > chunksize_max)
|
||||
% {
|
||||
% list = makeSplitPacket(data, chunksize_max, split_seqnum);
|
||||
% split_seqnum++;
|
||||
% return list;
|
||||
% }
|
||||
% else
|
||||
% {
|
||||
% list.push_back(makeOriginalPacket(data));
|
||||
% }
|
||||
% return list;
|
||||
%}
|
||||
%
|
||||
|
||||
% Add the TYPE_RELIABLE header to the data
|
||||
makeReliablePacket(Data, SeqNum) ->
|
||||
#reliable_packet{ data = <<?TYPE_RELIABLE:?U8,SeqNum:?U16,Data/binary>> }.
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
%%
|
||||
%% erlmines - The minetest server written in Erlang
|
||||
%% Copyright (C) 2012 hummermania, Markevych Alexander <rabota.pmr@gmail.com>
|
||||
%%
|
||||
-module(connection_channel).
|
||||
-author('Alexander Markevych <rabota.pmr@gmail.com>').
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
-define(RPB, connection_reliable_packet_buffer).
|
||||
-define(ISB, connection_incoming_split_buffer).
|
||||
|
||||
init(ChannelID) ->
|
||||
ets:new(channels,[public, named_table]),
|
||||
?RPB:init(list_to_atom(atom_to_list(incoming_reliables_) ++ integer_to_list(ChannelID))),
|
||||
?RPB:init(list_to_atom(atom_to_list(outgoing_reliables_) ++ integer_to_list(ChannelID))),
|
||||
?ISB:init(list_to_atom(atom_to_list(incoming_splits_) ++ integer_to_list(ChannelID))).
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
%%
|
||||
%% erlmines - The minetest server written in Erlang
|
||||
%% Copyright (C) 2012 hummermania, Markevych Alexander <rabota.pmr@gmail.com>
|
||||
%%
|
||||
|
||||
-module(connection_incoming_split_buffer).
|
||||
-author('Alexander Markevych <rabota.pmr@gmail.com>').
|
||||
|
||||
-export([insert/2, removeUnreliableTimedOuts/2]).
|
||||
|
||||
%-define(TABLE_ID, ?MODULE).
|
||||
|
||||
init(Table) ->
|
||||
ets:new(Table, [public, named_table]),
|
||||
ok.
|
||||
|
||||
insert(Table, BufferedPacket, Reliable) ->
|
||||
HeaderSize = ?BASE_HEADER_SIZE+7,
|
||||
<<_Header:?BASE_HEADER_SIZE, Type:?U8, SeqNum:?U16, ChunkCount:?U16, ChunkNum:?U16, _Other/binary>> = BufferedPacket,
|
||||
case ets:lookup(Table, SeqNum) ->
|
||||
[{SeqNum, FindPacket}] -> io:format("IncomingSplitPacket with SeqNum=~p is found in ReliablePacketBuffer~n",[SeqNum]);
|
||||
[] -> ets:insert(Table, {SeqNum, BufferedPacket}).
|
||||
%
|
||||
% This will throw a GotSplitPacketException when a full
|
||||
% split packet is constructed.
|
||||
%
|
||||
% SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
|
||||
%{
|
||||
% u32 headersize = BASE_HEADER_SIZE + 7;
|
||||
% assert(p.data.getSize() >= headersize);
|
||||
% u8 type = readU8(&p.data[BASE_HEADER_SIZE+0]);
|
||||
% assert(type == TYPE_SPLIT);
|
||||
% u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE+1]);
|
||||
% u16 chunk_count = readU16(&p.data[BASE_HEADER_SIZE+3]);
|
||||
% u16 chunk_num = readU16(&p.data[BASE_HEADER_SIZE+5]);
|
||||
%
|
||||
% // Add if doesn't exist
|
||||
% if(m_buf.find(seqnum) == NULL)
|
||||
% {
|
||||
% IncomingSplitPacket *sp = new IncomingSplitPacket();
|
||||
% sp->chunk_count = chunk_count;
|
||||
% sp->reliable = reliable;
|
||||
% m_buf[seqnum] = sp;
|
||||
% }
|
||||
%
|
||||
% IncomingSplitPacket *sp = m_buf[seqnum];
|
||||
%
|
||||
% // TODO: These errors should be thrown or something? Dunno.
|
||||
% if(chunk_count != sp->chunk_count)
|
||||
% derr_con<<"Connection: WARNING: chunk_count="<<chunk_count
|
||||
% <<" != sp->chunk_count="<<sp->chunk_count
|
||||
% <<std::endl;
|
||||
% if(reliable != sp->reliable)
|
||||
% derr_con<<"Connection: WARNING: reliable="<<reliable
|
||||
% <<" != sp->reliable="<<sp->reliable
|
||||
% <<std::endl;
|
||||
%
|
||||
% // If chunk already exists, cancel
|
||||
% if(sp->chunks.find(chunk_num) != NULL)
|
||||
% throw AlreadyExistsException("Chunk already in buffer");
|
||||
%
|
||||
% // Cut chunk data out of packet
|
||||
% u32 chunkdatasize = p.data.getSize() - headersize;
|
||||
% SharedBuffer<u8> chunkdata(chunkdatasize);
|
||||
% memcpy(*chunkdata, &(p.data[headersize]), chunkdatasize);
|
||||
%
|
||||
% // Set chunk data in buffer
|
||||
% sp->chunks[chunk_num] = chunkdata;
|
||||
%
|
||||
% // If not all chunks are received, return empty buffer
|
||||
% if(sp->allReceived() == false)
|
||||
% return SharedBuffer<u8>();
|
||||
%
|
||||
% // Calculate total size
|
||||
% u32 totalsize = 0;
|
||||
% core::map<u16, SharedBuffer<u8> >::Iterator i;
|
||||
% i = sp->chunks.getIterator();
|
||||
% for(; i.atEnd() == false; i++)
|
||||
% {
|
||||
% totalsize += i.getNode()->getValue().getSize();
|
||||
% }
|
||||
%
|
||||
% SharedBuffer<u8> fulldata(totalsize);
|
||||
%
|
||||
% // Copy chunks to data buffer
|
||||
% u32 start = 0;
|
||||
% for(u32 chunk_i=0; chunk_i<sp->chunk_count;
|
||||
% chunk_i++)
|
||||
% {
|
||||
% SharedBuffer<u8> buf = sp->chunks[chunk_i];
|
||||
% u16 chunkdatasize = buf.getSize();
|
||||
% memcpy(&fulldata[start], *buf, chunkdatasize);
|
||||
% start += chunkdatasize;;
|
||||
% }
|
||||
%
|
||||
% // Remove sp from buffer
|
||||
% m_buf.remove(seqnum);
|
||||
% delete sp;
|
||||
%
|
||||
% return fulldata;
|
||||
% }
|
||||
|
||||
removeUnreliableTimedOuts(Table) -> ok.
|
||||
|
||||
% void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout)
|
||||
% {
|
||||
% core::list<u16> remove_queue;
|
||||
% core::map<u16, IncomingSplitPacket*>::Iterator i;
|
||||
% i = m_buf.getIterator();
|
||||
% for(; i.atEnd() == false; i++)
|
||||
% {
|
||||
% IncomingSplitPacket *p = i.getNode()->getValue();
|
||||
% // Reliable ones are not removed by timeout
|
||||
% if(p->reliable == true)
|
||||
% continue;
|
||||
% p->time += dtime;
|
||||
% if(p->time >= timeout)
|
||||
% remove_queue.push_back(i.getNode()->getKey());
|
||||
% }
|
||||
% core::list<u16>::Iterator j;
|
||||
% j = remove_queue.begin();
|
||||
% for(; j != remove_queue.end(); j++)
|
||||
% {
|
||||
% dout_con<<"NOTE: Removing timed out unreliable split packet"
|
||||
% <<std::endl;
|
||||
% delete m_buf[*j];
|
||||
% m_buf.remove(*j);
|
||||
% }
|
||||
% }
|
|
@ -0,0 +1,148 @@
|
|||
%%
|
||||
%% erlmines - The minetest server written in Erlang
|
||||
%% Copyright (C) 2012 hummermania, Markevych Alexander <rabota.pmr@gmail.com>
|
||||
%%
|
||||
-module(connection_reliable_packet_buffer).
|
||||
-author('Alexander Markevych <rabota.pmr@gmail.com>').
|
||||
-include("connection.hrl").
|
||||
-compile(export_all).
|
||||
|
||||
%-define(TABLE_ID, ?MODULE).
|
||||
|
||||
init(Table) ->
|
||||
ets:new(Table, [public, named_table]).
|
||||
|
||||
insert(Table, #buffered_packet{data=BufferedPacket, time=_Time, totaltime=_TotalTime, address = _Address} = BPrec) ->
|
||||
<<_Header:?BASE_HEADER_SIZE/binary, Type:?U8, SeqNum:?U16,_Other/binary>> = BufferedPacket,
|
||||
io:format("Type=~p, SeqNum=~p~n",[Type,SeqNum]),
|
||||
case ets:lookup(Table, SeqNum) of
|
||||
[{SeqNum, FindPacket}] ->
|
||||
io:format("Reliable packet with SeqNum=~p is found in ReliablePacketBuffer~n",[SeqNum]),
|
||||
{exists,FindPacket};
|
||||
[] -> ets:insert(Table, {SeqNum, BPrec}),
|
||||
{ok,BPrec}
|
||||
end.
|
||||
|
||||
test_insert(Table) ->
|
||||
insert(Table, #buffered_packet{data=list_to_binary([1,2,3,4,5,6,7,33,00,34,77,77,77,77]), time=0, totaltime=0}),
|
||||
insert(Table, #buffered_packet{data=list_to_binary([1,2,3,4,5,6,7,33,01,11,77,77,77,77]), time=0, totaltime=0}),
|
||||
insert(Table, #buffered_packet{data=list_to_binary([1,2,3,4,5,6,7,33,02,62,77,77,77,77]), time=0, totaltime=0}),
|
||||
insert(Table, #buffered_packet{data=list_to_binary([1,2,3,4,5,6,7,33,67,02,77,77,77,77]), time=0, totaltime=0}),
|
||||
insert(Table, #buffered_packet{data=list_to_binary([1,2,3,4,5,6,7,33,00,10,77,77,77,77]), time=0, totaltime=0}).
|
||||
|
||||
|
||||
findPacket(Table, SeqNum) ->
|
||||
case ets:lookup(Table, SeqNum) of
|
||||
[{SeqNum, FindPacket}] -> {ok, FindPacket};
|
||||
[]-> {error, not_found}
|
||||
end.
|
||||
|
||||
test_findPacket(Table)->
|
||||
findPacket(Table, 15874). % 8704, 2817, 579
|
||||
|
||||
print(Table) ->
|
||||
ets:foldl(fun({SeqNum, Packet},AccIn) ->
|
||||
io:format("SeqNum=~p: ~p ~n", [SeqNum,Packet]),
|
||||
AccIn
|
||||
end, end_list, Table).
|
||||
|
||||
empty(Table) ->
|
||||
Size = ets:info(Table, size),
|
||||
case Size of
|
||||
0 -> true;
|
||||
_ -> Size
|
||||
end.
|
||||
|
||||
size(Table) ->
|
||||
ets:info(Table, size).
|
||||
|
||||
% TODO Check the returning value
|
||||
notFound(Table) ->
|
||||
ets:last(Table).
|
||||
|
||||
%RPBSearchResult ReliablePacketBuffer::notFound()
|
||||
%{
|
||||
% return m_list.end();
|
||||
%}
|
||||
|
||||
getFirstSeqnum(Table) ->
|
||||
ets:first(Table).
|
||||
|
||||
popFirst(Table) ->
|
||||
FirstSeqNum = ets:first(Table),
|
||||
#buffered_packet{data=FirstPacket} = ets:lookup(Table, FirstSeqNum),
|
||||
<<_Header:?BASE_HEADER_SIZE,_Type:?U8,SeqNum:?U16,_Other/binary>> = FirstPacket,
|
||||
ets:delete(Table, SeqNum),
|
||||
#buffered_packet{data=FirstPacket}.
|
||||
|
||||
popSeqnum(Table, SeqNum) ->
|
||||
FindPacket = ets:lookup(Table, SeqNum),
|
||||
ets:delete(Table, SeqNum),
|
||||
FindPacket.
|
||||
|
||||
incrementTimeouts(Table, Dtime) ->
|
||||
ets:foldl(fun({SeqNum, Packet},AccIn) ->
|
||||
#buffered_packet{data = Data, time = Time, totaltime = TotalTime, address = Address} = Packet,
|
||||
ets:update_element(Table, SeqNum,
|
||||
{2,#buffered_packet{data=Data,time = Time + Dtime, totaltime = TotalTime + Dtime, address = Address}}),
|
||||
AccIn
|
||||
end, end_list, Table).
|
||||
|
||||
test_increment()->
|
||||
init(rpb_test),
|
||||
test_insert(rpb_test),
|
||||
print(rpb_test),
|
||||
incrementTimeouts(rpb_test, 35),
|
||||
print(rpb_test).
|
||||
|
||||
resetTimedOuts(Table, Timeout) ->
|
||||
ets:foldl(fun({SeqNum, Packet},AccIn) ->
|
||||
#buffered_packet{data = Data, time = Time, totaltime = TotalTime, address = Address} = Packet,
|
||||
if Time >= Timeout ->
|
||||
ets:update_element(Table, SeqNum,
|
||||
{2,#buffered_packet{data=Data,time = 0, totaltime = TotalTime, address = Address}});
|
||||
true -> ok
|
||||
end,
|
||||
AccIn
|
||||
end, end_list, Table).
|
||||
|
||||
|
||||
anyTotaltimeReached(Table, Timeout) ->
|
||||
%ets:select(Table, ets:fun2ms(fun({SeqNum,#buffered_packet{totaltime = TotalTime}}) when TotalTime >= Timeout -> true end)).
|
||||
%ets:select(Table,
|
||||
% ets:fun2ms(fun({Seq,#buffered_packet{data = _, time = _, totaltime = TotalTime, address = _}}) -> TotalTime end)).
|
||||
|
||||
%TODO This construction need to refactoring
|
||||
case ets:select(Table, [{{'_',#buffered_packet{data='_',time='_',totaltime='$1',address='_'}},[{'>=','$1',Timeout}],['$1']}]) of
|
||||
[] -> false;
|
||||
_ -> true % or we must check list size
|
||||
end.
|
||||
|
||||
%bool ReliablePacketBuffer::anyTotaltimeReached(float timeout)
|
||||
%{
|
||||
% core::list<BufferedPacket>::Iterator i;
|
||||
% i = m_list.begin();
|
||||
% for(; i != m_list.end(); i++){
|
||||
% if(i->totaltime >= timeout)
|
||||
% return true;
|
||||
% }
|
||||
% return false;
|
||||
%}
|
||||
|
||||
|
||||
getTimedOuts(Table, Timeout) ->
|
||||
% TODO - Check the returning value: list of buffered_packet, or SeqNum
|
||||
ets:select(Table, [{{'$1',#buffered_packet{data='_',time='$2',totaltime='_',address='_'}},[{'>=','$2',Timeout}],['$1']}]).
|
||||
|
||||
% core::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout)
|
||||
%{
|
||||
% core::list<BufferedPacket> timed_outs;
|
||||
% core::list<BufferedPacket>::Iterator i;
|
||||
% i = m_list.begin();
|
||||
% for(; i != m_list.end(); i++)
|
||||
% {
|
||||
% if(i->time >= timeout)
|
||||
% timed_outs.push_back(*i);
|
||||
% }
|
||||
% return timed_outs;
|
||||
%}
|
|
@ -0,0 +1,50 @@
|
|||
-module(erlmines).
|
||||
|
||||
%%-behaviour(gen_server).
|
||||
-include("erlmines.hrl").
|
||||
|
||||
-export([server/1]).
|
||||
|
||||
server(Port) ->
|
||||
{ok,Socket} = gen_udp:open(Port,[binary]),
|
||||
listen(Socket).
|
||||
|
||||
listen(Socket) ->
|
||||
receive
|
||||
%%{udp,Socket,Host,Port,Bin} = Message ->
|
||||
{udp,Socket,_,_,Bin} ->
|
||||
io:format("========================================~n",[]),
|
||||
io:format("Data= ~p~n",[Bin]),
|
||||
process_packet(Bin),
|
||||
listen(Socket)
|
||||
after 10000 ->
|
||||
gen_udp:close(Socket),
|
||||
{exit,timeout}
|
||||
end.
|
||||
|
||||
|
||||
process_packet(<<ProtocolId:?U32, SenderPeerId:?U16, Channel:?U8, PacketType:?U8, Data/binary>>) ->
|
||||
case PacketType of
|
||||
?TYPE_CONTROL -> Type = "TYPE_CONTROL (0)",
|
||||
type_control(Data);
|
||||
?TYPE_ORIGINAL -> Type = "TYPE_ORIGINAL(1)",
|
||||
type_original(Data);
|
||||
?TYPE_SPLIT -> Type = "TYPE_SPLIT(2)",
|
||||
type_split(Data);
|
||||
?TYPE_RELIABLE -> Type = "TYPE_RELIABLE(2)",
|
||||
type_reliable(Data)
|
||||
end,
|
||||
io:format("ProtocolId: ~p, SenderPeerId:~p, Channel:~p, PacketType: ~p, Data:~p~n",[ProtocolId,SenderPeerId,Channel,Type,Data]).
|
||||
|
||||
type_control(<<ControlType:?U8,Data/binary>>)-> ok.
|
||||
|
||||
type_original(Data)-> ok.
|
||||
type_split(<<SeqNum:?U16,ChunkCount:?U16,ChunkNum:?U16,Data/binary>>)-> ok.
|
||||
type_reliable(<<SeqNum:?U16,Data/binary>>)-> ok.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
%%
|
||||
%% erlmines - The minetest server written in Erlang
|
||||
%% Copyright (C) 2012 hummermania, Markevych Alexander <rabota.pmr@gmail.com>
|
||||
%%
|
||||
-module(erlmines_app).
|
||||
-author('Alexander Markevych <rabota.pmr@gmail.com>').
|
||||
-behaviour(application).
|
||||
-export([start/2, stop/1]).
|
||||
|
||||
start(_Type, StartArgs) ->
|
||||
erlmines_sup:start_link(StartArgs).
|
||||
|
||||
stop(_State) ->
|
||||
ok.
|
|
@ -0,0 +1,31 @@
|
|||
%%
|
||||
%% erlmines - The minetest server written in Erlang
|
||||
%% Copyright (C) 2012 hummermania, Markevych Alexander <rabota.pmr@gmail.com>
|
||||
%%
|
||||
-module(erlmines_sup).
|
||||
-author('Alexander Markevych <rabota.pmr@gmail.com>').
|
||||
-behaviour(supervisor).
|
||||
|
||||
-export([start/0, start_link/1, init/1]).
|
||||
|
||||
start() ->
|
||||
spawn(fun() ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, _Arg = [])
|
||||
end).
|
||||
|
||||
start_link(Args) ->
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, Args).
|
||||
|
||||
init([]) ->
|
||||
case application:get_env(pidfile) of
|
||||
{ok, Location} ->
|
||||
Pid = os:getpid(),
|
||||
ok = file:write_file(Location, list_to_binary(Pid));
|
||||
undefined -> ok
|
||||
end,
|
||||
|
||||
{ok, {{one_for_one, 100, 300},
|
||||
[{erlmines,
|
||||
{erlmines, start_link, []},
|
||||
permanent, 10000, worker, [erlmines]}
|
||||
]}}.
|
Loading…
Reference in New Issue