Skip to content

Commit

Permalink
Block digging working, and updating ets with world changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ScottBrooks committed Sep 10, 2010
1 parent 8d616bc commit d805e48
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 12 deletions.
11 changes: 11 additions & 0 deletions src/mc.erl
Expand Up @@ -191,6 +191,17 @@ handle_packet(Client, {kick, Message}) ->
gen_server:cast(Client, {kick, Message}),
none;

handle_packet(_Client, {arm_animation, _EntityID, _Unknown}) ->
none;

handle_packet(Client, {block_dig, Stage, X, Y, Z, Direction}) ->
case mc_world:block_dig(Stage, X, Y, Z, Direction, Client) of
{block_change, X, Y, Z, Type, Meta} ->
mc_reply:block_change(X, Y, Z, Type, Meta);
_ ->
none
end;

handle_packet(_State, Unknown) ->
io:format("Unknown Packet: ~p~n", [Unknown]),
<<"">>.
Expand Down
6 changes: 5 additions & 1 deletion src/mc_reply.erl
Expand Up @@ -31,8 +31,12 @@ entity_add_mob(EntityID, Type, X, Y, Z, R, P) ->
chat(Message) ->
mc_util:write_packet(16#03, [{string, Message}]).

block_change(X, Y, Z, Type, Meta) ->
mc_util:write_packet(16#35, [{int, X}, {byte,Y}, {int, Z}, {byte, Type}, {byte, Meta}]).

fake_world(Pid, BlockCount, LocX, LocY, LocZ) ->


fake_world(Pid, BlockCount, LocX, _LocY, LocZ) ->
Width = math:sqrt(BlockCount),
erlcraft_client_fsm:send_packet(Pid, mc_reply:chat("Hello world")),
lists:map(
Expand Down
95 changes: 84 additions & 11 deletions src/mc_world.erl
Expand Up @@ -4,20 +4,77 @@

-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-record(state, {world_path, world}).
-record(state, {world_path, world, chunk_store}).

%% External API
-export([start_link/1, get_chunk/3, get_spawn/0, load_chunk/4, dbg_chunk/3]).
-export([start_link/1, get_chunk/3, get_spawn/0, load_chunk/5, dbg_chunk/3, block_dig/6]).

generate_pre_chunk(X,Z, Update) ->
mc_util:write_packet(16#32, [{int, X}, {int, Z}, {bool, Update}]).

block_from_bin(Binary, Offset) ->
<<_:Offset/binary, Block:8/integer, _/binary>> = Binary,
Block.
block_from_bin_packed(Binary, Offset) ->
AdjOffset = Offset * 4,
<<_:AdjOffset/bits, Block:8/integer, _/bits>> = Binary,
Block bsr 4.

%generate_chunk(X, Y, Z, SizeX, SizeY, SizeZ) ->
% Data = mc_util:chunk_data(SizeX * SizeY * SizeX),
% Compressed = zlib:compress(mc_util:encode_list(Data)),
% mc_util:write_packet(16#33, lists:flatten([{int, X*16}, {short, Y}, {int, Z*16}, {byte, SizeX-1}, {byte, SizeY-1}, {byte, SizeZ-1}, {int, size(Compressed)}, {binary, Compressed}])).
block_dig(State, _X, _Y, _Z, _Direction, _Client, _ChunkStore) when State =:= 0 ->
ok;
block_dig(State, _X, _Y, _Z, _Direction, _Client, _ChunkStore) when State =:= 1 ->
ok;
block_dig(State, _X, _Y, _Z, _Direction, _Client, _ChunkStore) when State =:= 2 ->
ok;
block_dig(State, X, Y, Z, Direction, _Client, ChunkStore) when State =:= 3 ->
io:format("Dig: S: ~p [~p,~p,~p], D: ~p~n", [State, X, Y, Z, Direction]),
Key = {X, Z},
case ets:lookup(ChunkStore, Key) of
[] ->
io:format("Key: ~p not found[~p,~p,~p]~n", [Key, X, Y, Z]);
[{Key, BD, MD, WL}] ->
Offset = Y,
HalfOffset = trunc(Y/2),
Block = block_from_bin(BD, Offset),
Meta = block_from_bin_packed(MD, HalfOffset),
io:format("B: ~p M: ~p~n", [Block, Meta]),
<<Before:Offset/binary, Block:8/integer, After/binary>> = BD,
NBD = <<Before/binary, 0:8/integer, After/binary>>,
ets:insert(ChunkStore, {Key, NBD, MD, WL}),
{block_change, X, Y, Z, 0, 8};
Else ->
io:format("unknown: ~p key: ~p~n", [Else, Key]),
ok
end.

load_chunk(X, Y, Z, Root, ChunkStore) ->
SizeX = 16, SizeY = 128, SizeZ = 16,
[BlockData, MetaData, LightData] = try ets:member(ChunkStore, {X*16, Z*16}) of
true -> load_chunk_ets(X, Y, Z, ChunkStore);
false-> load_chunk_disk(X, Y, Z, Root, ChunkStore)
catch _:_ ->
load_chunk_disk(X, Y, Z, Root, ChunkStore)
end,
Compressed = zlib:compress(<<BlockData/binary, MetaData/binary, MetaData/binary, LightData/binary>>),
mc_util:write_packet(16#33, lists:flatten([{int, X*16}, {short, Y}, {int, Z*16}, {byte, SizeX-1}, {byte, SizeY-1}, {byte, SizeZ-1}, {int, size(Compressed)}, {binary, Compressed}])).

load_chunk(X,Y,Z, Root) ->

load_chunk_ets(X, _Y, Z, ChunkStore) ->
lists:foldl(fun(Idx, [Blocks, Meta, Light]) ->
OZ = Idx rem 16,
OX = trunc(Idx/16),
case ets:lookup(ChunkStore, {X * 16 + OX, Z * 16 + OZ}) of
[{{_,_}, BD, MD, WL}] ->
[<<Blocks/binary, BD/binary>>, <<Meta/binary, MD/binary>>, <<Light/binary, WL/binary>>];
_ -> io:format("Could not find key: [~p,~p]", [X*16 + OX, Z*16 + OZ])
end
end, [<<>>, <<>>, <<>>], lists:seq(0, 255)).

load_chunk_disk(X, _Y, Z, Root, ChunkStore) ->
F1 = string:to_lower(case X of
PosX when PosX >= 0 ->
erlang:integer_to_list(X rem 64, 36);
Expand All @@ -38,11 +95,19 @@ load_chunk(X,Y,Z, Root) ->
{tag_byte_array, <<"BlockLight">>, BlockLight} = lists:keyfind(<<"BlockLight">>, 2, LevelData),
{tag_byte_array, <<"SkyLight">>, SkyLight} = lists:keyfind(<<"SkyLight">>, 2, LevelData),
{tag_byte_array, <<"Data">>, MetaData} = lists:keyfind(<<"Data">>, 2, LevelData),
SizeX = 16, SizeY = 128, SizeZ = 16,
%MetaInfo = mc_util:expand_4_to_8(MetaData),
WorldLight = mc_util:or_binaries(BlockLight, SkyLight),
Compressed = zlib:compress(<<Blocks/binary, MetaData/binary, MetaData/binary, WorldLight/binary>>),
mc_util:write_packet(16#33, lists:flatten([{int, X*16}, {short, Y}, {int, Z*16}, {byte, SizeX-1}, {byte, SizeY-1}, {byte, SizeZ-1}, {int, size(Compressed)}, {binary, Compressed}])).
lists:foreach(fun(Idx) ->
BlockIdx = Idx * 128,
MetaIdx = Idx * 64,
OZ = Idx rem 16,
OX = trunc(Idx/16),
<<_:BlockIdx/binary, BD:128/binary, _/binary>> = Blocks,
<<_:MetaIdx/binary, MD:64/binary, _/binary>> = MetaData,
<<_:MetaIdx/binary, WL:64/binary, _/binary>> = WorldLight,
true = ets:insert(ChunkStore, {{X * 16 + OX,Z * 16 + OZ}, BD, MD, WL})
end, lists:seq(0, 255)),
io:format("Wrote [~p,~p] to [~p, ~p]~n", [X*16, Z*16, X*16+16, Z*16+16]),
[Blocks, MetaData, WorldLight].

dbg_chunk(<<>>, <<>>, <<>>) ->
ok;
Expand All @@ -64,6 +129,9 @@ dbg_chunk(Blocks, MetaData, LightData) ->
end,
dbg_chunk(RestBlocks, RestMeta, RestLight).

block_dig(Stage, X, Y, Z, Direction, Client) ->
gen_server:call(?MODULE, {block_dig, Stage, X, Y, Z, Direction, Client}).

get_spawn() ->
gen_server:call(?MODULE, {get_spawn}).

Expand All @@ -82,13 +150,14 @@ init([MapName]) ->
Path = string:join([Cwd, MapName] , "/"),
LevelPath = string:join([Path, "level.dat"], "/"),
World = nbt:load_file(LevelPath),
{ok, #state{world_path = Path, world = World}}.
ChunkStore = ets:new(world, []),
{ok, #state{world_path = Path, world = World, chunk_store = ChunkStore}}.

handle_call({get_chunk, X, Y, Z}, _From, #state{world_path = WorldPath} = State) when is_integer(X), is_integer(Z) ->
handle_call({get_chunk, X, Y, Z}, _From, #state{world_path = WorldPath, chunk_store = ChunkStore} = State) when is_integer(X), is_integer(Z) ->
io:format("Chunk Request: [~p, ~p, ~p]~n", [X, Y, Z]),
PreChunk = generate_pre_chunk(X, Z, 1),
% ChunkData = generate_chunk(X, Y, Z, 16, 128, 16),
ChunkData = load_chunk(X, Y, Z, WorldPath),
ChunkData = load_chunk(X, Y, Z, WorldPath, ChunkStore),
{reply, {chunk, PreChunk, ChunkData}, State};

handle_call({get_spawn}, _From, #state{world = World} = State) ->
Expand All @@ -114,7 +183,11 @@ handle_call({get_spawn}, _From, #state{world = World} = State) ->
end,
io:format("Spawning player at: [~p, ~p, ~p]~n", [SpawnX, SpawnY, SpawnZ]),
{reply, {loc, SX, SY, SZ, SY - 1.5, 0.0, 0.0}, State};


handle_call({block_dig, Stage, X, Y, Z, Direction, Client}, _From, #state{chunk_store = ChunkStore} = _State) ->
BlockChange = block_dig(Stage, X, Y, Z, Direction, Client, ChunkStore),
{reply, BlockChange, _State};

handle_call(_Request, _From, _State) ->
io:format("Call: ~p~n", [_Request]),
{reply, none, _State}.
Expand Down

0 comments on commit d805e48

Please sign in to comment.