Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Minecraft.Server.FourKit/Block/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,24 @@ public bool breakNaturally()
return NativeBridge.BreakBlock(_world.getDimensionId(), _x, _y, _z) != 0;
return false;
}

///<summary>
///Captures the current state of this block. You may then cast that state
///into any accepted type, such as Furnace or Sign.
///<para>The returned object will never be updated, and you are not guaranteed
///that(for example) a sign is still a sign after you capture its state.</para>
///</summary>
///<returns>BlockState with the current state of this block.</returns>
public BlockState getState()
{
Material material = getType();

switch (material)
{
case Material.SIGN:
return new Sign(this);
default:
return new BlockState(this);
}
}
}
264 changes: 264 additions & 0 deletions Minecraft.Server.FourKit/Block/BlockState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
namespace Minecraft.Server.FourKit.Block;


/// <Summary>
/// Represents a captured state of a block, which will not change automatically.
/// <para>
/// Unlike Block, which only one object can exist per coordinate, BlockState
/// can exist multiple times for any given Block.
/// </para>
/// <para>
/// Note that another plugin may change the state of the block and you will not know, or they may change the
/// block to another type entirely, causing your BlockState to become invalid.
/// </para>
/// </Summary>
public class BlockState
{
private readonly World _world;
private readonly int _x;
private readonly int _y;
private readonly int _z;
protected Material type;
protected byte data;

public BlockState(Block block)
{
_world = block.getWorld();
_x = block.getX();
_y = block.getY();
_z = block.getZ();
type = block.getType();
data = block.getData();
}

public static BlockState getBlockState(World world, int x, int y, int z)
{
return new BlockState(world.getBlockAt(x, y, z));
}

/// <summary>
/// Gets the world which contains this Block
/// </summary>
/// <returns>World containing this block</returns>
public World getWorld() => _world;

/// <summary>
/// Gets the x-coordinate of this block
/// </summary>
/// <returns>x-coordinate</returns>
public int getX() => _x;

/// <summary>
/// Gets the y-coordinate of this block
/// </summary>
/// <returns>y-coordinate</returns>
public int getY() => _y;

/// <summary>
/// Gets the z-coordinate of this block
/// </summary>
/// <returns>z-coordinate</returns>
public int getZ() => _z;

/// <summary>
/// Sets the data value for this block
/// </summary>
/// <param name="data">New block specific data</param>
public void setData(byte data)
{
this.data = data;
}

/// <summary>
/// Gets the data value for this block
/// </summary>
/// <returns>block specific data</returns>
public byte getData() => data;

/// <summary>
/// Sets the type of this block, resets block data to 0 if the block type changes
/// </summary>
/// <param name="type">Material to change this block to</param>
public void setType(Material type)
{
if (this.type != type)
{
this.type = type;
setData((byte)0);
}
}

/// <summary>
/// Sets the type-id of this block
/// </summary>
/// <param name="typeId">Type-Id to change this block to</param>
/// <returns>Whether the change was successful</returns>
public bool setTypeId(int typeId)
{
if (!Enum.IsDefined(typeof(Material), typeId))
{
return false;
}

setType((Material)typeId);
return true;
}

/// <summary>
/// Gets the type of this block
/// </summary>
/// <returns>block type</returns>
public Material getType() => type;

/// <summary>
/// Gets the type-id of this block
/// </summary>
/// <returns>block type-id</returns>
public int getTypeId() => (int)type;


/// <summary>
/// Gets the block represented by this BlockState
/// </summary>
/// <returns>Block that this BlockState represents</returns>
public Block getBlock() => _world.getBlockAt(_x, _y, _z);

/// <summary>
/// Gets the location of this block
/// </summary>
/// <returns>location</returns>
public Location getLocation()
{
return new Location(_world, _x, _y, _z);
}

/// <summary>
/// Stores the location of this block in the provided Location object.
/// <para>
/// If the provided Location is null this method does nothing and returns null.
/// </para>
/// </summary>
/// <param name="loc">Location object to modify</param>
/// <returns>The Location object provided or null</returns>
public Location getLocation(Location loc)
{
if (loc != null)
{
loc.setWorld(_world);
loc.setX(_x);
loc.setY(_y);
loc.setZ(_z);
loc.setYaw(0f);
loc.setPitch(0f);
}

return loc;
}

/// <summary>
/// Attempts to update the block represented by this state, setting it to
/// the new values as defined by this state.
/// <para>
/// This has the same effect as calling update(false). That is to say,
/// this will not modify the state of a block if it is no longer the same
/// type as it was when this state was taken.It will return false in this
/// eventuality.
/// </para>
/// </summary>
/// <returns>true if the update was successful, otherwise false</returns>
/// <see cref="update(bool)"/>
public bool update()
{
return update(false);
}

/// <summary>
/// Attempts to update the block represented by this state, setting it to
/// the new values as defined by this state.
/// <para>
/// NOT IMPLEMENTED This has the same effect as calling update(force, true). That is to
/// say, this will trigger a physics update to surrounding blocks.
/// </para>
/// </summary>
/// <param name="force">true to forcefully set the state</param>
/// <returns>true if the update was successful, otherwise false</returns>
public bool update(bool force)
{
return update(force, true);
}

/// <summary>
/// Attempts to update the block represented by this state, setting it to
/// the new values as defined by this state.
/// <para>
/// Unless force is true, this will not modify the state of a block if it
/// is no longer the same type as it was when this state was taken.It will
/// return false in this eventuality.
/// </para>
/// <para>
/// If force is true, it will set the type of the block to match the new
/// state, set the state data and then return true.
/// </para>
/// <para>
/// NOT IMPLEMENTED If applyPhysics is true, it will trigger a physics update on
/// surrounding blocks which could cause them to update or disappear.
/// </para>
/// </summary>
/// <param name="force">true to forcefully set the state</param>
/// <param name="applyPhysics">NOT IMPLEMENTED false to cancel updating physics on surrounding blocks</param>
/// <returns>true if the update was successful, otherwise false</returns>
public virtual bool update(bool force, bool applyPhysics)
{
Block block = getBlock();

if (block.getType() != getType())
{
if (force)
{
block.setType(type); //pass applyPhysics when implemented, fix docs for this func and related ones when implemented
} else
{
return false;
}
}

block.setData(data); //pass applyPhysics when implemented
//_world.getHandle.notify(_x, _y, _z); //when implemented

return true;
}

//TODO: implement World.Equals
//public override bool Equals(object? obj)
//{
// if (ReferenceEquals(this, obj))
// {
// return true;
// }

// if (obj is not BlockState other)
// {
// return false;
// }

// return (_world == other._world //|| _world.Equals(other._world))
// && _x == other._x
// && _y == other._y
// && _z == other._z
// && type == other.type
// && data == other.data;
//}

//TODO: implement World.GetHashCode
//public override int GetHashCode()
//{
// int hash = 7;
// hash = 73 * hash + _world.GetHashCode();
// hash = 73 * hash + _x;
// hash = 73 * hash + _y;
// hash = 73 * hash + _z;
// hash = 73 * hash + (int)type;
// hash = 73 * hash + data.GetHashCode();
// return hash;
//}
}
Loading