Skip to content

Commit

Permalink
Add world handling (and fall to ground)
Browse files Browse the repository at this point in the history
- World is now properly parsed and stored from chunk data
- Block changes are also handled and world updated accordingly
- Added ground checking, the player will move down to reach the ground
- Performance tweaking in Protocol18, using lists instead of arrays
- Fix player look not properly skipped causing invalid location after
teleport
  • Loading branch information
ORelio committed Nov 30, 2015
1 parent 2e4544f commit cb00c28
Show file tree
Hide file tree
Showing 10 changed files with 661 additions and 91 deletions.
99 changes: 99 additions & 0 deletions MinecraftClient/Mapping/Block.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MinecraftClient.Mapping
{
/// <summary>
/// Represents a Minecraft Block
/// </summary>
public struct Block
{
/// <summary>
/// Storage for block ID and metadata
/// </summary>
private ushort blockIdAndMeta;

/// <summary>
/// Id of the block
/// </summary>
public short BlockId
{
get
{
return (short)(blockIdAndMeta >> 4);
}
set
{
blockIdAndMeta = (ushort)(value << 4 | BlockMeta);
}
}

/// <summary>
/// Metadata of the block
/// </summary>
public byte BlockMeta
{
get
{
return (byte)(blockIdAndMeta & 0x0F);
}
set
{
blockIdAndMeta = (ushort)((blockIdAndMeta & ~0x0F) | (value & 0x0F));
}
}

/// <summary>
/// Check if the block can be passed through or not
/// </summary>
public bool Solid
{
get
{
return BlockId != 0;
}
}

/// <summary>
/// Get a block of the specified type and metadata
/// </summary>
/// <param name="type">Block type</param>
/// <param name="metadata">Block metadata</param>
public Block(short type, byte metadata = 0)
{
this.blockIdAndMeta = 0;
this.BlockId = type;
this.BlockMeta = metadata;
}

/// <summary>
/// Get a block of the specified type and metadata
/// </summary>
/// <param name="typeAndMeta"></param>
public Block(ushort typeAndMeta)
{
this.blockIdAndMeta = typeAndMeta;
}

/// <summary>
/// Represents an empty block
/// </summary>
public static Block Air
{
get
{
return new Block(0);
}
}

/// <summary>
/// String representation of the block
/// </summary>
public override string ToString()
{
return BlockId.ToString() + (BlockMeta != 0 ? ":" + BlockMeta.ToString() : "");
}
}
}
63 changes: 63 additions & 0 deletions MinecraftClient/Mapping/Chunk.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MinecraftClient.Mapping
{
/// <summary>
/// Represent a chunk of terrain in a Minecraft world
/// </summary>
public class Chunk
{
public const int SizeX = 16;
public const int SizeY = 16;
public const int SizeZ = 16;

/// <summary>
/// Blocks contained into the chunk
/// </summary>
private readonly Block[,,] blocks = new Block[SizeX, SizeY, SizeZ];

/// <summary>
/// Read, or set the specified block
/// </summary>
/// <param name="blockX">Block X</param>
/// <param name="blockY">Block Y</param>
/// <param name="blockZ">Block Z</param>
/// <returns>chunk at the given location</returns>
public Block this[int blockX, int blockY, int blockZ]
{
get
{
if (blockX < 0 || blockX >= SizeX)
throw new ArgumentOutOfRangeException("blockX", "Must be between 0 and " + (SizeX - 1) + " (inclusive)");
if (blockY < 0 || blockY >= SizeY)
throw new ArgumentOutOfRangeException("blockY", "Must be between 0 and " + (SizeY - 1) + " (inclusive)");
if (blockZ < 0 || blockZ >= SizeZ)
throw new ArgumentOutOfRangeException("blockZ", "Must be between 0 and " + (SizeZ - 1) + " (inclusive)");
return blocks[blockX, blockY, blockZ];
}
set
{
if (blockX < 0 || blockX >= SizeX)
throw new ArgumentOutOfRangeException("blockX", "Must be between 0 and " + (SizeX - 1) + " (inclusive)");
if (blockY < 0 || blockY >= SizeY)
throw new ArgumentOutOfRangeException("blockY", "Must be between 0 and " + (SizeY - 1) + " (inclusive)");
if (blockZ < 0 || blockZ >= SizeZ)
throw new ArgumentOutOfRangeException("blockZ", "Must be between 0 and " + (SizeZ - 1) + " (inclusive)");
blocks[blockX, blockY, blockZ] = value;
}
}

/// <summary>
/// Get block at the specified location
/// </summary>
/// <param name="location">Location, a modulo will be applied</param>
/// <returns>The block</returns>
public Block GetBlock(Location location)
{
return this[((int)location.X) % Chunk.SizeX, ((int)location.Y) % Chunk.SizeY, ((int)location.Z) % Chunk.SizeZ];
}
}
}
48 changes: 48 additions & 0 deletions MinecraftClient/Mapping/ChunkColumn.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MinecraftClient.Mapping
{
/// <summary>
/// Represent a column of chunks of terrain in a Minecraft world
/// </summary>
public class ChunkColumn
{
public const int ColumnSize = 16;

/// <summary>
/// Blocks contained into the chunk
/// </summary>
private readonly Chunk[] chunks = new Chunk[ColumnSize];

/// <summary>
/// Get or set the specified chunk column
/// </summary>
/// <param name="chunkX">ChunkColumn X</param>
/// <param name="chunkY">ChunkColumn Y</param>
/// <returns>chunk at the given location</returns>
public Chunk this[int chunkY]
{
get
{
return chunks[chunkY];
}
set
{
chunks[chunkY] = value;
}
}

/// <summary>
/// Get chunk at the specified location
/// </summary>
/// <param name="location">Location, a modulo will be applied</param>
/// <returns>The chunk, or null if not loaded</returns>
public Chunk GetChunk(Location location)
{
return this[location.ChunkY];
}
}
}
75 changes: 75 additions & 0 deletions MinecraftClient/Mapping/Location.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,72 @@ public Location(double x, double y, double z)
Z = z;
}

/// <summary>
/// The X index of the corresponding chunk in the world
/// </summary>
public int ChunkX
{
get
{
return ((int)X) / Chunk.SizeX;
}
}

/// <summary>
/// The Y index of the corresponding chunk in the world
/// </summary>
public int ChunkY
{
get
{
return ((int)Y) / Chunk.SizeY;
}
}

/// <summary>
/// The Z index of the corresponding chunk in the world
/// </summary>
public int ChunkZ
{
get
{
return ((int)Z) / Chunk.SizeY;
}
}

/// <summary>
/// The X index of the corresponding block in the corresponding chunk of the world
/// </summary>
public int ChunkBlockX
{
get
{
return ((int)X) % Chunk.SizeX;
}
}

/// <summary>
/// The Y index of the corresponding block in the corresponding chunk of the world
/// </summary>
public int ChunkBlockY
{
get
{
return ((int)Y) % Chunk.SizeY;
}
}

/// <summary>
/// The Z index of the corresponding block in the corresponding chunk of the world
/// </summary>
public int ChunkBlockZ
{
get
{
return ((int)Z) % Chunk.SizeZ;
}
}

/// <summary>
/// Compare two locations. Locations are equals if the integer part of their coordinates are equals.
/// </summary>
Expand Down Expand Up @@ -155,5 +221,14 @@ public override int GetHashCode()
| (((int)Y) & ~((~0) << 13)) << 13
| (((int)Z) & ~((~0) << 06)) << 00;
}

/// <summary>
/// Convert the location into a string representation
/// </summary>
/// <returns>String representation of the location</returns>
public override string ToString()
{
return String.Format("X:{0} Y:{1} Z:{2}", X, Y, Z);
}
}
}

0 comments on commit cb00c28

Please sign in to comment.