Skip to content

Commit

Permalink
* Blocks can now be Spawned and Removed. Used when it's placed/destro…
Browse files Browse the repository at this point in the history
…yed by the server, not by the player.

* Added basic block physics features - falling sand and gravel. See #52, #94
  • Loading branch information
Gremlin13 authored and Gremlin13 committed Oct 10, 2011
1 parent 6db76bc commit b02aa64
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 16 deletions.
3 changes: 3 additions & 0 deletions Chraft/Chraft.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@
<Compile Include="World\Blocks\BlockPistonHead.cs" />
<Compile Include="World\Blocks\BlockSponge.cs" />
<Compile Include="World\Blocks\BlockStickyPiston.cs" />
<Compile Include="World\Blocks\Physics\BlockBasePhysics.cs" />
<Compile Include="World\Blocks\Physics\FallingSand.cs" />
<Compile Include="World\Blocks\Physics\FallingGravel.cs" />
<Compile Include="World\ChunkLightUpdate.cs" />
<Compile Include="World\Location.cs" />
<Compile Include="Entity\Mob.cs" />
Expand Down
19 changes: 19 additions & 0 deletions Chraft/World/Blocks/BlockBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,25 @@ public virtual void Destroy(EntityBase entity, StructBlock block)
NotifyNearbyBlocks(entity, block);
}

/// <summary>
/// Removes the block from the world. Don't drop anything.
/// </summary>
/// <param name="block">block that is being removed</param>
public virtual void Remove(StructBlock block)
{
UpdateOnDestroy(block);
NotifyNearbyBlocks(null, block);
}

/// <summary>
/// Spawns the block in the world (not placed by the player)
/// </summary>
/// <param name="block">block that is being spawned</param>
public virtual void Spawn(StructBlock block)
{
UpdateOnPlace(block);
}

/// <summary>
/// Notifies the nearby block that the current block has been destroyed
/// May be used by recipient block to start the physic simulation etc
Expand Down
37 changes: 37 additions & 0 deletions Chraft/World/Blocks/BlockGravel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Chraft.Entity;
using Chraft.Interfaces;
using Chraft.Plugins.Events.Args;
using Chraft.World.Blocks.Physics;

namespace Chraft.World.Blocks
{
Expand Down Expand Up @@ -39,5 +40,41 @@ protected override void DropItems(EntityBase entity, StructBlock block)
}
base.DropItems(entity, block);
}

public override void NotifyDestroy(EntityBase entity, StructBlock sourceBlock, StructBlock targetBlock)
{
if ((targetBlock.Coords.WorldY - sourceBlock.Coords.WorldY) == 1 &&
targetBlock.Coords.WorldX == sourceBlock.Coords.WorldX &&
targetBlock.Coords.WorldZ == sourceBlock.Coords.WorldZ)
{
StartPhysics(targetBlock);
}
base.NotifyDestroy(entity, sourceBlock, targetBlock);
}

public override void Place(EntityBase entity, StructBlock block, StructBlock targetBlock, BlockFace face)
{
if (!CanBePlacedOn(entity, block, targetBlock, face))
return;

if (!RaisePlaceEvent(entity, block))
return;

UpdateOnPlace(block);

RemoveItem(entity);

if (block.Coords.WorldY > 1)
if (block.World.GetBlockId(block.Coords.WorldX, block.Coords.WorldY - 1, block.Coords.WorldZ) == (byte)BlockData.Blocks.Air)
StartPhysics(block);
}

protected void StartPhysics(StructBlock block)
{
Remove(block);
FallingGravel fgBlock = new FallingGravel(block.World, new Location(block.Coords.WorldX + 0.5, block.Coords.WorldY + 0.5, block.Coords.WorldZ + 0.5));
fgBlock.Start();
block.World.PhysicsBlocks.TryAdd(fgBlock.EntityId, fgBlock);
}
}
}
37 changes: 37 additions & 0 deletions Chraft/World/Blocks/BlockSand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Chraft.Entity;
using Chraft.Interfaces;
using Chraft.Plugins.Events.Args;
using Chraft.World.Blocks.Physics;

namespace Chraft.World.Blocks
{
Expand All @@ -17,5 +18,41 @@ public BlockSand()
IsSolid = true;
LootTable.Add(new ItemStack((short)Type, 1));
}

public override void NotifyDestroy(EntityBase entity, StructBlock sourceBlock, StructBlock targetBlock)
{
if ((targetBlock.Coords.WorldY - sourceBlock.Coords.WorldY) == 1 &&
targetBlock.Coords.WorldX == sourceBlock.Coords.WorldX &&
targetBlock.Coords.WorldZ == sourceBlock.Coords.WorldZ)
{
StartPhysics(targetBlock);
}
base.NotifyDestroy(entity, sourceBlock, targetBlock);
}

public override void Place(EntityBase entity, StructBlock block, StructBlock targetBlock, BlockFace face)
{
if (!CanBePlacedOn(entity, block, targetBlock, face))
return;

if (!RaisePlaceEvent(entity, block))
return;

UpdateOnPlace(block);

RemoveItem(entity);

if (block.Coords.WorldY > 1)
if (block.World.GetBlockId(block.Coords.WorldX, block.Coords.WorldY - 1, block.Coords.WorldZ) == (byte)BlockData.Blocks.Air)
StartPhysics(block);
}

protected void StartPhysics(StructBlock block)
{
Remove(block);
FallingSand fsBlock = new FallingSand(block.World, new Location(block.Coords.WorldX + 0.5, block.Coords.WorldY + 0.5, block.Coords.WorldZ + 0.5));
fsBlock.Start();
block.World.PhysicsBlocks.TryAdd(fsBlock.EntityId, fsBlock);
}
}
}
73 changes: 73 additions & 0 deletions Chraft/World/Blocks/Physics/BlockBasePhysics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chraft.Net.Packets;
using Chraft.Utils;

namespace Chraft.World.Blocks.Physics
{
public abstract class BlockBasePhysics
{
public int EntityId { get; protected set; }
public WorldManager World { get; protected set; }
public Location Position { get; protected set; }
public bool IsPlaying { get; protected set; }
public Vector3 Velocity { get; protected set; }
public AddObjectVehiclePacket.ObjectType Type;

protected BlockBasePhysics(WorldManager world, Location pos)
{
World = world;
Position = pos;
EntityId = world.Server.AllocateEntity();

CreateEntityPacket entity = new CreateEntityPacket { EntityId = EntityId };
foreach (var nearbyPlayer in World.Server.GetNearbyPlayers(World, new AbsWorldCoords(Position.X, Position.Y, Position.Z)))
{
nearbyPlayer.SendPacket(entity);
}
}

public virtual void Start()
{
if (IsPlaying)
return;
AddObjectVehiclePacket obj = new AddObjectVehiclePacket
{
EntityId = EntityId,
Type = Type,
UnknownFlag = 0,
X = Position.X,
Y = Position.Y,
Z = Position.Z
};
foreach (var nearbyPlayer in World.Server.GetNearbyPlayers(World, new AbsWorldCoords(Position.X, Position.Y, Position.Z)))
{
nearbyPlayer.SendPacket(obj);
}
IsPlaying = true;
}

public virtual void Simulate()
{
}

public virtual void Stop()
{
IsPlaying = false;
BlockBasePhysics unused = null;
World.PhysicsBlocks.TryRemove(EntityId, out unused);
DestroyEntityPacket entity = new DestroyEntityPacket { EntityId = EntityId };
foreach (var nearbyPlayer in World.Server.GetNearbyPlayers(World, new AbsWorldCoords(Position.X, Position.Y, Position.Z)))
{
nearbyPlayer.SendPacket(entity);
}
OnStop();
}

protected virtual void OnStop()
{
}
}
}
17 changes: 17 additions & 0 deletions Chraft/World/Blocks/Physics/FallingGravel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chraft.Utils;

namespace Chraft.World.Blocks.Physics
{
public class FallingGravel : FallingSand
{
public FallingGravel(WorldManager world, Location pos) : base(world, pos)
{
Type = Net.Packets.AddObjectVehiclePacket.ObjectType.FallingGravel;
BlockId = (byte) BlockData.Blocks.Gravel;
}
}
}
49 changes: 49 additions & 0 deletions Chraft/World/Blocks/Physics/FallingSand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Chraft.Utils;

namespace Chraft.World.Blocks.Physics
{
public class FallingSand : BlockBasePhysics
{
protected byte BlockId;

public FallingSand(WorldManager world, Location pos) : base(world, pos)
{
Type = Net.Packets.AddObjectVehiclePacket.ObjectType.FallingSand;
BlockId = (byte) BlockData.Blocks.Sand;
Velocity = new Vector3(0, -0.4D, 0);
}

public override void Simulate()
{
int x = MathHelper.floor_double(Position.X);
int y = MathHelper.floor_double(Position.Y);
int z = MathHelper.floor_double(Position.Z);
byte blockId = World.GetBlockId(x, y, z);
if (blockId != (byte)BlockData.Blocks.Air)
{
Stop();
return;
}

if (Position.Y <= 1)
{
Stop();
return;
}

Position.Vector += Velocity;
}

protected override void OnStop()
{
UniversalCoords uc = UniversalCoords.FromWorld(MathHelper.floor_double(Position.X), MathHelper.floor_double(Position.Y) + 1, MathHelper.floor_double(Position.Z));
StructBlock block = new StructBlock(uc, BlockId, 0, World);
BlockHelper.Instance(BlockId).Spawn(block);
base.OnStop();
}
}
}
36 changes: 20 additions & 16 deletions Chraft/World/WorldManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Chraft.Net;
Expand All @@ -7,6 +8,7 @@
using System.IO;
using Chraft.Entity;
using Chraft.World.Blocks;
using Chraft.World.Blocks.Physics;
using Chraft.World.Weather;
using Chraft.Plugins.Events.Args;
using System.Threading.Tasks;
Expand Down Expand Up @@ -40,6 +42,9 @@ public partial class WorldManager : IDisposable

public ConcurrentQueue<ChunkLightUpdate> ChunksToRecalculate;

public ConcurrentDictionary<int, BlockBasePhysics> PhysicsBlocks;
private Task _PhysicsSimulationTask;

private readonly object ChunkLightUpdateLock = new object();
private Task _GrowStuffTask;
private Task _CollectTask;
Expand Down Expand Up @@ -175,6 +180,7 @@ public bool Load()
_ChunkProvider = new ChunkProvider(this);
Generator = _ChunkProvider.GetNewGenerator(GeneratorType.Custom, GetSeed());
ChunkManager = new WorldChunkManager(this);
PhysicsBlocks = new ConcurrentDictionary<int, BlockBasePhysics>();

InitializeSpawn();
InitializeThreads();
Expand Down Expand Up @@ -354,7 +360,12 @@ private void GlobalTickProc(object state)
}
}


if (_PhysicsSimulationTask == null || _PhysicsSimulationTask.IsCompleted)
{
_PhysicsSimulationTask = new Task(PhysicsProc);
_PhysicsSimulationTask.Start();
}

}

public Chunk GetChunkFromPosition(int x, int z)
Expand Down Expand Up @@ -421,6 +432,14 @@ private void GrowProc()
}
}

private void PhysicsProc()
{
foreach (var physicsBlock in PhysicsBlocks)
{
physicsBlock.Value.Simulate();
}
}

private void EntityMoverStart()
{
Thread thread = new Thread(MovementThread);
Expand Down Expand Up @@ -705,21 +724,6 @@ private void UpdatePhysics(UniversalCoords coords, bool updateClients = true)
{
BlockData.Blocks type = (BlockData.Blocks)GetBlockId(coords);
UniversalCoords oneDown = UniversalCoords.FromWorld(coords.WorldX, coords.WorldY - 1, coords.WorldZ);
if (type == BlockData.Blocks.Sand && coords.WorldY > 0 && GetBlockId(oneDown) == 0)
{
SetBlockAndData(coords, 0, 0);
SetBlockAndData(oneDown, (byte)BlockData.Blocks.Sand, 0);
Update(oneDown, updateClients);
return;
}

if (type == BlockData.Blocks.Gravel && coords.WorldY > 0 && GetBlockId(UniversalCoords.FromWorld(coords.WorldX, coords.WorldY - 1, coords.WorldZ)) == 0)
{
SetBlockAndData(coords, 0, 0);
SetBlockAndData(oneDown, (byte)BlockData.Blocks.Gravel, 0);
Update(oneDown, updateClients);
return;
}

if (type == BlockData.Blocks.Water)
{
Expand Down

0 comments on commit b02aa64

Please sign in to comment.