diff --git a/TrueCraft.API/Coordinates3D.cs b/TrueCraft.API/Coordinates3D.cs
index b835465..f5150a0 100644
--- a/TrueCraft.API/Coordinates3D.cs
+++ b/TrueCraft.API/Coordinates3D.cs
@@ -14,7 +14,7 @@ namespace TrueCraft.API
X = Y = Z = value;
}
- public Coordinates3D(int x, int y, int z)
+ public Coordinates3D(int x = 0, int y = 0, int z = 0)
{
X = x;
Y = y;
diff --git a/TrueCraft.API/Logic/IBlockProvider.cs b/TrueCraft.API/Logic/IBlockProvider.cs
index 4ea085c..43aa8c6 100644
--- a/TrueCraft.API/Logic/IBlockProvider.cs
+++ b/TrueCraft.API/Logic/IBlockProvider.cs
@@ -20,7 +20,7 @@ namespace TrueCraft.API.Logic
bool BlockRightClicked(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user);
void BlockPlaced(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user);
void BlockMined(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user);
- void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world);
+ void BlockUpdate(BlockDescriptor descriptor, BlockDescriptor source, IMultiplayerServer server, IWorld world);
void BlockScheduledEvent(BlockDescriptor descriptor, IWorld world, object data);
}
}
\ No newline at end of file
diff --git a/TrueCraft.Core/Logic/BlockProvider.cs b/TrueCraft.Core/Logic/BlockProvider.cs
index ad6367f..7ff706b 100644
--- a/TrueCraft.Core/Logic/BlockProvider.cs
+++ b/TrueCraft.Core/Logic/BlockProvider.cs
@@ -54,7 +54,7 @@ namespace TrueCraft.Core.Logic
return true;
}
- public virtual void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world)
+ public virtual void BlockUpdate(BlockDescriptor descriptor, BlockDescriptor source, IMultiplayerServer server, IWorld world)
{
if (!IsSupported(descriptor, server, world))
{
diff --git a/TrueCraft.Core/Logic/Blocks/BedBlock.cs b/TrueCraft.Core/Logic/Blocks/BedBlock.cs
index fc26faa..b4ca601 100644
--- a/TrueCraft.Core/Logic/Blocks/BedBlock.cs
+++ b/TrueCraft.Core/Logic/Blocks/BedBlock.cs
@@ -83,11 +83,11 @@ namespace TrueCraft.Core.Logic.Blocks
return true;
}
- public override void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world)
+ public override void BlockUpdate(BlockDescriptor descriptor, BlockDescriptor source, IMultiplayerServer server, IWorld world)
{
if (!ValidBedPosition(descriptor, server.BlockRepository, world))
world.SetBlockID(descriptor.Coordinates, 0);
- base.BlockUpdate(descriptor, server, world);
+ base.BlockUpdate(descriptor, source, server, world);
}
}
}
\ No newline at end of file
diff --git a/TrueCraft.Core/Logic/Blocks/CropsBlock.cs b/TrueCraft.Core/Logic/Blocks/CropsBlock.cs
index 6c35681..a14a477 100644
--- a/TrueCraft.Core/Logic/Blocks/CropsBlock.cs
+++ b/TrueCraft.Core/Logic/Blocks/CropsBlock.cs
@@ -51,7 +51,7 @@ namespace TrueCraft.Core.Logic.Blocks
}
}
- public override void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world)
+ public override void BlockUpdate(BlockDescriptor descriptor, BlockDescriptor source, IMultiplayerServer server, IWorld world)
{
if (world.GetBlockID(descriptor.Coordinates + Coordinates3D.Down) != FarmlandBlock.BlockID)
{
diff --git a/TrueCraft.Core/Logic/Blocks/SugarcaneBlock.cs b/TrueCraft.Core/Logic/Blocks/SugarcaneBlock.cs
index a64a2de..9a12ca8 100644
--- a/TrueCraft.Core/Logic/Blocks/SugarcaneBlock.cs
+++ b/TrueCraft.Core/Logic/Blocks/SugarcaneBlock.cs
@@ -74,7 +74,7 @@ namespace TrueCraft.Core.Logic.Blocks
return true;
}
- public override void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world)
+ public override void BlockUpdate(BlockDescriptor descriptor, BlockDescriptor source, IMultiplayerServer server, IWorld world)
{
if (!ValidPlacement(descriptor, world))
{
diff --git a/TrueCraft.Core/Logic/Blocks/WaterBlock.cs b/TrueCraft.Core/Logic/Blocks/WaterBlock.cs
index be65895..48a0be3 100644
--- a/TrueCraft.Core/Logic/Blocks/WaterBlock.cs
+++ b/TrueCraft.Core/Logic/Blocks/WaterBlock.cs
@@ -5,12 +5,49 @@ using TrueCraft.API.World;
using TrueCraft.API;
using TrueCraft.API.Networking;
using System.Collections.Generic;
+using System.Linq;
namespace TrueCraft.Core.Logic.Blocks
{
public class WaterBlock : BlockProvider
{
- private const byte MaxFlow = 7;
+ // Fluids in Minecraft propegate according to a set of rules as cellular automata.
+ // Source blocks start at zero and each block progressively further from the source
+ // is one greater than the largest value nearby. When they reach 7, the water stops
+ // propgetating.
+
+ private const double SecondsBetweenUpdates = 0.25;
+
+ private const byte MaximumFluidDepletion = 7;
+
+ private static readonly Coordinates3D[] Neighbors =
+ {
+ Coordinates3D.Left,
+ Coordinates3D.Right,
+ Coordinates3D.Forwards,
+ Coordinates3D.Backwards
+ };
+
+ ///
+ /// Represents a block that the currently updating water block is able to flow outwards into.
+ ///
+ protected struct LiquidFlow
+ {
+ public LiquidFlow(Coordinates3D targetBlock, byte level)
+ {
+ TargetBlock = targetBlock;
+ Level = level;
+ }
+
+ ///
+ /// The block to be filled with water.
+ ///
+ public Coordinates3D TargetBlock;
+ ///
+ /// The water level to fill the target block with.
+ ///
+ public byte Level;
+ }
public static readonly byte BlockID = 0x08;
@@ -28,6 +65,11 @@ namespace TrueCraft.Core.Logic.Blocks
public override string DisplayName { get { return "Water"; } }
+ protected override ItemStack[] GetDrop(BlockDescriptor descriptor)
+ {
+ return new ItemStack[0];
+ }
+
public override BoundingBox? BoundingBox
{
get
@@ -36,16 +78,15 @@ namespace TrueCraft.Core.Logic.Blocks
}
}
- private bool PlaceWater(IMultiplayerServer server, Coordinates3D coords, IWorld world, byte meta = 0)
+ public void ScheduleNextEvent(Coordinates3D coords, IWorld world, IMultiplayerServer server)
{
- var old = world.GetBlockID(coords);
- if (old == WaterBlock.BlockID || old == StationaryWaterBlock.BlockID)
- return false;
- world.SetBlockID(coords, BlockID);
- world.SetMetadata(coords, meta);
- server.Scheduler.ScheduleEvent(DateTime.Now.AddSeconds(0.25), (s) =>
- AutomataUpdate(s, world, coords));
- return true;
+ server.Scheduler.ScheduleEvent(DateTime.Now.AddSeconds(SecondsBetweenUpdates), (_server) =>
+ AutomataUpdate(_server, world, coords));
+ }
+
+ public override void BlockPlaced(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user)
+ {
+ ScheduleNextEvent(descriptor.Coordinates, world, user.Server);
}
private void AutomataUpdate(IMultiplayerServer server, IWorld world, Coordinates3D coords)
@@ -57,200 +98,14 @@ namespace TrueCraft.Core.Logic.Blocks
server.BlockUpdatesEnabled = true;
if (again)
{
- server.Scheduler.ScheduleEvent(DateTime.Now.AddSeconds(0.25), (_server) =>
+ server.Scheduler.ScheduleEvent(DateTime.Now.AddSeconds(SecondsBetweenUpdates), (_server) =>
DoAutomata(_server, world, coords));
}
}
- internal bool CanFlow(IWorld world, Coordinates3D coords)
- {
- var down = world.BlockRepository.GetBlockProvider(world.GetBlockID(coords + Coordinates3D.Down));
- if (!down.Opaque)
- return true;
- const int maxDistance = 5;
- var extraLocations = new List();
- var nearest = new Coordinates3D(maxDistance + 1, -1, maxDistance + 1);
- for (int x = -maxDistance; x < maxDistance; x++)
- {
- for (int z = -maxDistance; z < maxDistance; z++)
- {
- if (Math.Abs(z) + Math.Abs(x) > maxDistance)
- continue;
- var check = new Coordinates3D(x, -1, z);
- var c = world.GetBlockID(check + coords);
- if (c == 0 || c == WaterBlock.BlockID || c == StationaryWaterBlock.BlockID)
- {
- if (!LineOfSight(world, check + coords, coords))
- continue;
- if (coords.DistanceTo(check + coords) == coords.DistanceTo(nearest + coords))
- extraLocations.Add(check);
- if (coords.DistanceTo(check + coords) < coords.DistanceTo(nearest + coords))
- {
- extraLocations.Clear();
- nearest = check;
- }
- }
- }
- }
- if (nearest == new Coordinates3D(maxDistance + 1, -1, maxDistance + 1))
- {
- extraLocations.Add(new Coordinates3D(-maxDistance - 1, -1, maxDistance + 1));
- extraLocations.Add(new Coordinates3D(maxDistance + 1, -1, -maxDistance - 1));
- extraLocations.Add(new Coordinates3D(-maxDistance - 1, -1, -maxDistance - 1));
- }
- extraLocations.Add(nearest);
- bool spread = false;
- for (int i = 0; i < extraLocations.Count; i++)
- {
- var location = extraLocations[i];
- location.Clamp(1);
- var xPotential = world.GetBlockID(new Coordinates3D(location.X, 0, 0) + coords);
- if (xPotential == 0)
- {
- var old = world.GetBlockID(coords);
- return old != WaterBlock.BlockID && old != StationaryWaterBlock.BlockID;
- }
-
- var zPotential = world.GetBlockID(new Coordinates3D(0, 0, location.Z) + coords);
- if (zPotential == 0)
- {
- var old = world.GetBlockID(coords);
- return old != WaterBlock.BlockID && old != StationaryWaterBlock.BlockID;
- }
- }
- return spread;
- }
-
- public bool DoAutomata(IMultiplayerServer server, IWorld world, Coordinates3D coords)
- {
- var meta = world.GetMetadata(coords);
- Coordinates3D[] neighbors =
- {
- Coordinates3D.Left,
- Coordinates3D.Right,
- Coordinates3D.Forwards,
- Coordinates3D.Backwards
- };
- var up = world.GetBlockID(coords + Coordinates3D.Up);
- var down = world.BlockRepository.GetBlockProvider(world.GetBlockID(coords + Coordinates3D.Down));
-
- if (!down.Opaque)
- {
- PlaceWater(server, coords + Coordinates3D.Down, world, 1);
- if (meta != 0)
- return true;
- }
-
- // Check inward flow
- if (up == WaterBlock.BlockID || up == StationaryWaterBlock.BlockID)
- meta = 1;
- else
- {
- if (meta != 0)
- {
- byte minMeta = 15;
- int sources = 0;
- for (int i = 0; i < neighbors.Length; i++)
- {
- var nId = world.GetBlockID(coords + neighbors[i]);
- if (nId == WaterBlock.BlockID || nId == StationaryWaterBlock.BlockID)
- {
- var _meta = world.GetMetadata(coords + neighbors[i]);
- if (_meta < minMeta)
- minMeta = _meta;
- if (_meta == 0)
- sources++;
- }
- }
- if (sources >= 2)
- {
- world.SetMetadata(coords, 0);
- return true;
- }
- if (minMeta > 0)
- {
- meta = (byte)(minMeta + 1);
- if (meta >= MaxFlow + 1)
- {
- world.SetBlockID(coords, 0);
- return true;
- }
- }
- }
- }
- world.SetMetadata(coords, meta);
-
- // Check outward flow
- if (meta < MaxFlow)
- {
- const int maxDistance = 5;
- var extraLocations = new List();
- var nearest = new Coordinates3D(maxDistance + 1, -1, maxDistance + 1);
- for (int x = -maxDistance; x < maxDistance; x++)
- {
- for (int z = -maxDistance; z < maxDistance; z++)
- {
- if (Math.Abs(z) + Math.Abs(x) > maxDistance)
- continue;
- var check = new Coordinates3D(x, -1, z);
- var c = world.BlockRepository.GetBlockProvider(world.GetBlockID(check + coords));
- if (!c.Opaque)
- {
- if (!LineOfSight(world, check + coords, coords))
- continue;
- if (coords.DistanceTo(check + coords) == coords.DistanceTo(nearest + coords))
- extraLocations.Add(check);
- if (coords.DistanceTo(check + coords) < coords.DistanceTo(nearest + coords))
- {
- extraLocations.Clear();
- nearest = check;
- }
- }
- }
- }
- if (nearest == new Coordinates3D(maxDistance + 1, -1, maxDistance + 1))
- {
- extraLocations.Add(new Coordinates3D(-maxDistance - 1, -1, maxDistance + 1));
- extraLocations.Add(new Coordinates3D(maxDistance + 1, -1, -maxDistance - 1));
- extraLocations.Add(new Coordinates3D(-maxDistance - 1, -1, -maxDistance - 1));
- }
- extraLocations.Add(nearest);
- bool spread = false;
- for (int i = 0; i < extraLocations.Count; i++)
- {
- var location = extraLocations[i];
- location.Clamp(1);
- var xPotential = world.BlockRepository.GetBlockProvider(world.GetBlockID(new Coordinates3D(location.X, 0, 0) + coords));
- if (xPotential.Hardness == 0 && xPotential.ID != WaterBlock.BlockID && xPotential.ID != StationaryWaterBlock.BlockID)
- {
- if (PlaceWater(server, new Coordinates3D(location.X, 0, 0) + coords, world, (byte)(meta + 1)))
- {
- spread = true;
- xPotential.GenerateDropEntity(new BlockDescriptor
- { Coordinates = new Coordinates3D(location.X, 0, 0) + coords, ID = xPotential.ID }, world, server);
- }
- }
-
- var zPotential = world.BlockRepository.GetBlockProvider(world.GetBlockID(new Coordinates3D(0, 0, location.Z) + coords));
- if (zPotential.Hardness == 0 && zPotential.ID != WaterBlock.BlockID && zPotential.ID != StationaryWaterBlock.BlockID)
- {
- if (PlaceWater(server, new Coordinates3D(0, 0, location.Z) + coords, world, (byte)(meta + 1)))
- {
- spread = true;
- zPotential.GenerateDropEntity(new BlockDescriptor
- { Coordinates = new Coordinates3D(0, 0, location.Z) + coords, ID = zPotential.ID }, world, server);
- }
- }
- }
- if (!spread)
- {
- world.SetBlockID(coords, StationaryWaterBlock.BlockID);
- return false;
- }
- }
- return true;
- }
-
+ ///
+ /// Returns true if the given candidate coordinate has a line-of-sight to the given target coordinate.
+ ///
private bool LineOfSight(IWorld world, Coordinates3D candidate, Coordinates3D target)
{
candidate += Coordinates3D.Up;
@@ -272,21 +127,184 @@ namespace TrueCraft.Core.Logic.Blocks
return true;
}
- public void ScheduleNextEvent(Coordinates3D coords, IWorld world, IMultiplayerServer server)
+ ///
+ /// Examines neighboring blocks and determines the new water level that this block should adopt.
+ ///
+ protected byte DetermineInwardFlow(IWorld world, Coordinates3D coords)
{
- server.Scheduler.ScheduleEvent(DateTime.Now.AddSeconds(0.25), (_server) =>
- AutomataUpdate(_server, world, coords));
+ var currentLevel = world.GetMetadata(coords);
+ var up = world.GetBlockID(coords + Coordinates3D.Up);
+ if (up == WaterBlock.BlockID || up == StationaryWaterBlock.BlockID) // Check for water above us
+ return currentLevel;
+ else
+ {
+ if (currentLevel != 0)
+ {
+ byte highestNeighboringFluid = 15;
+ int neighboringSourceBlocks = 0;
+ for (int i = 0; i < Neighbors.Length; i++)
+ {
+ var nId = world.GetBlockID(coords + Neighbors[i]);
+ if (nId == WaterBlock.BlockID || nId == StationaryWaterBlock.BlockID)
+ {
+ var neighborLevel = world.GetMetadata(coords + Neighbors[i]);
+ if (neighborLevel < highestNeighboringFluid)
+ highestNeighboringFluid = neighborLevel;
+ if (neighborLevel == 0)
+ neighboringSourceBlocks++;
+ }
+ }
+ if (neighboringSourceBlocks >= 2)
+ currentLevel = 0;
+ if (highestNeighboringFluid > 0)
+ currentLevel = (byte)(highestNeighboringFluid + 1);
+ }
+ }
+ return currentLevel;
}
- public override void BlockPlaced(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user)
+ ///
+ /// Produces a list of outward flow targets that this block may flow towards.
+ ///
+ protected LiquidFlow[] DetermineOutwardFlow(IWorld world, Coordinates3D coords)
{
- ScheduleNextEvent(descriptor.Coordinates, world, user.Server);
+ // The maximum distance we will search for lower ground to flow towards
+ const int DropCheckDistance = 5;
+
+ var outwardFlow = new List(5);
+
+ var currentLevel = world.GetMetadata(coords);
+ var blockBelow = world.BlockRepository.GetBlockProvider(world.GetBlockID(coords + Coordinates3D.Down));
+ if (!blockBelow.Opaque)
+ {
+ outwardFlow.Add(new LiquidFlow(coords + Coordinates3D.Down, 1));
+ if (currentLevel != 0)
+ return outwardFlow.ToArray();
+ }
+
+ if (currentLevel < MaximumFluidDepletion)
+ {
+ // This code is responsible for seeking out candidates for flowing towards.
+ // Water in Minecraft will flow in the direction of the nearest drop-off where
+ // there is at least one block removed on the Y axis.
+ // It will flow towards several equally strong candidates at once.
+
+ var candidateFlowPoints = new List(4);
+ var furthestPossibleCandidate = new Coordinates3D(x: DropCheckDistance + 1, z: DropCheckDistance + 1) + Coordinates3D.Down;
+
+ var nearestCandidate = furthestPossibleCandidate;
+ for (int x = -DropCheckDistance; x < DropCheckDistance; x++)
+ {
+ for (int z = -DropCheckDistance; z < DropCheckDistance; z++)
+ {
+ if (Math.Abs(z) + Math.Abs(x) > DropCheckDistance)
+ continue;
+ var check = new Coordinates3D(x: x, z: z) + Coordinates3D.Down;
+ var c = world.BlockRepository.GetBlockProvider(world.GetBlockID(check + coords));
+ if (!c.Opaque)
+ {
+ if (!LineOfSight(world, check + coords, coords))
+ continue;
+ if (coords.DistanceTo(check + coords) == coords.DistanceTo(nearestCandidate + coords))
+ candidateFlowPoints.Add(check);
+ if (coords.DistanceTo(check + coords) < coords.DistanceTo(nearestCandidate + coords))
+ {
+ candidateFlowPoints.Clear();
+ nearestCandidate = check;
+ }
+ }
+ }
+ }
+ if (nearestCandidate == furthestPossibleCandidate)
+ {
+ candidateFlowPoints.Add(new Coordinates3D(x: -DropCheckDistance - 1, z: DropCheckDistance + 1) + Coordinates3D.Down);
+ candidateFlowPoints.Add(new Coordinates3D(x: DropCheckDistance + 1, z: -DropCheckDistance - 1) + Coordinates3D.Down);
+ candidateFlowPoints.Add(new Coordinates3D(x: -DropCheckDistance - 1, z: -DropCheckDistance - 1) + Coordinates3D.Down);
+ }
+ candidateFlowPoints.Add(nearestCandidate);
+
+ // For each candidate, determine if we are actually capable of flowing towards it.
+ // We are able to flow through blocks with a hardness of zero, but no others. We are
+ // not able to flow through established water blocks.
+ for (int i = 0; i < candidateFlowPoints.Count; i++)
+ {
+ var location = candidateFlowPoints[i];
+ location.Clamp(1);
+
+ var xCoordinateCheck = new Coordinates3D(x: location.X) + coords;
+ var zCoordinateCheck = new Coordinates3D(z: location.Z) + coords;
+
+ var xID = world.BlockRepository.GetBlockProvider(world.GetBlockID(xCoordinateCheck));
+ var zID = world.BlockRepository.GetBlockProvider(world.GetBlockID(zCoordinateCheck));
+
+ if (xID.Hardness == 0 && xID.ID != WaterBlock.BlockID && xID.ID != StationaryWaterBlock.BlockID)
+ {
+ if (outwardFlow.All(f => f.TargetBlock != xCoordinateCheck))
+ outwardFlow.Add(new LiquidFlow(xCoordinateCheck, (byte)(currentLevel + 1)));
+ }
+
+ if (zID.Hardness == 0 && zID.ID != WaterBlock.BlockID && zID.ID != StationaryWaterBlock.BlockID)
+ {
+ if (outwardFlow.All(f => f.TargetBlock != zCoordinateCheck))
+ outwardFlow.Add(new LiquidFlow(zCoordinateCheck, (byte)(currentLevel + 1)));
+ }
+ }
+ }
+ return outwardFlow.ToArray();
+ }
+
+ public bool DoAutomata(IMultiplayerServer server, IWorld world, Coordinates3D coords)
+ {
+ var previousLevel = world.GetMetadata(coords);
+
+ var inward = DetermineInwardFlow(world, coords);
+ var outward = DetermineOutwardFlow(world, coords);
+
+ if (outward.Length == 1 && outward[0].TargetBlock == coords + Coordinates3D.Down)
+ {
+ // Exit early if we have placed a water block beneath us (and we aren't a source block)
+ if (previousLevel != 0)
+ return true;
+ }
+
+ // Process inward flow
+ if (inward > MaximumFluidDepletion)
+ {
+ world.SetBlockID(coords, 0);
+ return true;
+ }
+ world.SetMetadata(coords, inward);
+ if (inward == 0 && previousLevel != 0)
+ {
+ // Exit early if we have become a source block
+ return true;
+ }
+
+ // Process outward flow
+ for (int i = 0; i < outward.Length; i++)
+ {
+ var target = outward[i].TargetBlock;
+ // For each block we can flow into, generate an item entity if appropriate
+ var provider = world.BlockRepository.GetBlockProvider(world.GetBlockID(target));
+ provider.GenerateDropEntity(new BlockDescriptor { Coordinates = target, ID = provider.ID }, world, server);
+ // And overwrite the block with a new water block.
+ world.SetBlockID(target, WaterBlock.BlockID);
+ world.SetMetadata(target, outward[i].Level);
+ server.Scheduler.ScheduleEvent(DateTime.Now.AddSeconds(SecondsBetweenUpdates), s => AutomataUpdate(s, world, target));
+ }
+ // Set our block to still water if we are done spreading.
+ if (outward.Length == 0)
+ {
+ world.SetBlockID(coords, StationaryWaterBlock.BlockID);
+ return false;
+ }
+ return true;
}
}
- public class StationaryWaterBlock : BlockProvider
+ public class StationaryWaterBlock : WaterBlock
{
- public static readonly byte BlockID = 0x09;
+ public static readonly new byte BlockID = 0x09;
public override byte ID { get { return 0x09; } }
@@ -302,6 +320,11 @@ namespace TrueCraft.Core.Logic.Blocks
public override byte LightModifier { get { return 3; } }
+ protected override ItemStack[] GetDrop(BlockDescriptor descriptor)
+ {
+ return new ItemStack[0];
+ }
+
public override BoundingBox? BoundingBox
{
get
@@ -310,13 +333,20 @@ namespace TrueCraft.Core.Logic.Blocks
}
}
- public override void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world)
+ public override void BlockPlaced(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user)
{
- var provider = server.BlockRepository.GetBlockProvider(WaterBlock.BlockID) as WaterBlock;
- if (provider.CanFlow(world, descriptor.Coordinates))
+ // This space intentionally left blank
+ }
+
+ public override void BlockUpdate(BlockDescriptor descriptor, BlockDescriptor source, IMultiplayerServer server, IWorld world)
+ {
+ if (source.ID == StationaryWaterBlock.BlockID || source.ID == WaterBlock.BlockID)
+ return;
+ var outward = DetermineOutwardFlow(world, descriptor.Coordinates);
+ if (outward.Length != 0)
{
- world.SetBlockID(descriptor.Coordinates, provider.ID);
- provider.ScheduleNextEvent(descriptor.Coordinates, world, server);
+ world.SetBlockID(descriptor.Coordinates, WaterBlock.BlockID);
+ ScheduleNextEvent(descriptor.Coordinates, world, server);
}
}
}
diff --git a/TrueCraft/MultiplayerServer.cs b/TrueCraft/MultiplayerServer.cs
index 72e4fe4..8f7034f 100644
--- a/TrueCraft/MultiplayerServer.cs
+++ b/TrueCraft/MultiplayerServer.cs
@@ -142,12 +142,13 @@ namespace TrueCraft
while (PendingBlockUpdates.Count != 0)
{
var update = PendingBlockUpdates.Dequeue();
+ var source = update.World.GetBlockData(update.Coordinates);
foreach (var offset in adjacent)
{
var descriptor = update.World.GetBlockData(update.Coordinates + offset);
var provider = BlockRepository.GetBlockProvider(descriptor.ID);
if (provider != null)
- provider.BlockUpdate(descriptor, this, update.World);
+ provider.BlockUpdate(descriptor, source, this, update.World);
}
}
}
@@ -284,7 +285,9 @@ namespace TrueCraft
Clients.RemoveAt(i);
break;
}
- while (client.DataAvailable)
+ const long maxTicks = 100000 * 200; // 200ms
+ var start = DateTime.Now;
+ while (client.DataAvailable && (DateTime.Now.Ticks - start.Ticks) < maxTicks)
{
idle = false;
try