Modularise out falling physics.

This commit is contained in:
UnknownShadow200 2016-05-20 16:04:02 +10:00
parent 9576ec39af
commit ad34d92a09
3 changed files with 94 additions and 55 deletions

View File

@ -270,6 +270,7 @@
<Compile Include="Selections\SelectionBox.cs" />
<Compile Include="Selections\SelectionBoxComparer.cs" />
<Compile Include="Selections\SelectionManager.cs" />
<Compile Include="Singleplayer\FallingPhysics.cs" />
<Compile Include="Singleplayer\Physics.cs" />
<Compile Include="Singleplayer\Server.cs" />
<Compile Include="TexturePack\EntryList.cs" />

View File

@ -0,0 +1,81 @@
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
using System;
using System.Collections.Generic;
using ClassicalSharp.Map;
using OpenTK;
namespace ClassicalSharp.Singleplayer {
public class FallingPhysics {
Game game;
World map;
BlockInfo info;
int width, length, height, oneY;
public FallingPhysics( Game game ) {
this.game = game;
map = game.World;
info = game.BlockInfo;
}
public void ResetMap() {
Falling.Clear();
width = map.Width;
height = map.Height;
length = map.Length;
oneY = width * length;
}
public void Clear() { Falling.Clear(); }
public void OnBlockPlace( int index, byte block ) {
Falling.Enqueue( defFallingTick | (uint)index );
}
public void OnRandomTick( int index, byte block ) {
if( index >= oneY ) PropagateFalling( index, block, 0 );
}
Queue<uint> Falling = new Queue<uint>();
const uint defFallingTick = 2u << Physics.tickShift;
public void Tick() {
int count = Falling.Count;
for( int i = 0; i < count; i++ ) {
int index, flags;
if( Physics.CheckItem( Falling, 0x2, out index, out flags ) ) {
byte block = map.blocks[index];
if( !(block == (byte)Block.Sand || block == (byte)Block.Gravel ) ) continue;
if( index >= oneY ) PropagateFalling( index, block, flags );
}
}
}
void PropagateFalling( int index, byte block, int flags ) {
byte newBlock = map.blocks[index - oneY];
if( newBlock == 0 || info.IsLiquid[newBlock] ) {
int x = index % width;
int y = index / oneY; // posIndex / (width * length)
int z = (index / width) % length;
uint newFlags = MakeFallingFlags( newBlock ) << Physics.tickShift;
Falling.Enqueue( newFlags | (uint)(index - oneY) );
game.UpdateBlock( x, y, z, oldBlock[flags >> 2] );
game.UpdateBlock( x, y - 1, z, block );
}
}
static byte[] oldBlock = new byte[] { (byte)Block.Air, (byte)Block.StillWater,
(byte)Block.Water, (byte)Block.StillLava, (byte)Block.Lava };
static uint MakeFallingFlags( byte above ) {
byte flags = 2;
if( above == (byte)Block.StillWater ) flags |= 0x04; // 1
else if( above == (byte)Block.Water ) flags |= 0x08; // 2
else if( above == (byte)Block.StillLava ) flags |= 0x0C; // 3
else if( above == (byte)Block.Lava ) flags |= 0x10; // 4
return flags;
}
}
}

View File

@ -15,9 +15,10 @@ namespace ClassicalSharp.Singleplayer {
int width, length, height, oneY;
int maxX, maxY, maxZ, maxWaterX, maxWaterY, maxWaterZ;
const uint tickMask = 0xF8000000;
const uint posMask = 0x07FFFFFF;
const int tickShift = 27;
public const uint tickMask = 0xF8000000;
public const uint posMask = 0x07FFFFFF;
public const int tickShift = 27;
FallingPhysics falling;
bool enabled = true;
public bool Enabled {
@ -31,9 +32,10 @@ namespace ClassicalSharp.Singleplayer {
info = game.BlockInfo;
game.WorldEvents.OnNewMapLoaded += ResetMap;
enabled = Options.GetBool( OptionsKey.SingleplayerPhysics, true );
falling = new FallingPhysics( game );
}
bool CheckItem( Queue<uint> queue, out int posIndex ) {
internal static bool CheckItem( Queue<uint> queue, out int posIndex ) {
uint packed = queue.Dequeue();
int tickDelay = (int)((packed & tickMask) >> tickShift);
posIndex = (int)(packed & posMask);
@ -46,7 +48,7 @@ namespace ClassicalSharp.Singleplayer {
return true;
}
bool CheckItem( Queue<uint> queue, int mask, out int posIndex, out int flags ) {
internal static bool CheckItem( Queue<uint> queue, int mask, out int posIndex, out int flags ) {
uint packed = queue.Dequeue();
flags = (int)((packed & tickMask) >> tickShift);
posIndex = (int)(packed & posMask);
@ -69,7 +71,7 @@ namespace ClassicalSharp.Singleplayer {
//if( (tickCount % 5) == 0 ) {
TickLava();
TickWater();
TickFalling();
falling.Tick();
//}
tickCount++;
TickRandomBlocks();
@ -84,7 +86,7 @@ namespace ClassicalSharp.Singleplayer {
} else if( block == (byte)Block.Water ) {
Water.Enqueue( defWaterTick | (uint)index );
} else if( block == (byte)Block.Sand || block == (byte)Block.Gravel ) {
Falling.Enqueue( defFallingTick | (uint)index );
falling.OnBlockPlace( index, block );
} else if( block == (byte)Block.TNT ) {
Explode( 4, x, y, z );
} else if( block == (byte)Block.Sapling ) {
@ -95,7 +97,7 @@ namespace ClassicalSharp.Singleplayer {
}
void ResetMap( object sender, EventArgs e ) {
ClearQueuedEvents();
falling.ResetMap();
width = map.Width; maxX = width - 1; maxWaterX = maxX - 2;
height = map.Height; maxY = height - 1; maxWaterY = maxY - 2;
length = map.Length; maxZ = length - 1; maxWaterZ = maxZ - 2;
@ -105,7 +107,7 @@ namespace ClassicalSharp.Singleplayer {
void ClearQueuedEvents() {
Lava.Clear();
Water.Clear();
Falling.Clear();
falling.Clear();
}
public void Dispose() {
@ -162,7 +164,7 @@ namespace ClassicalSharp.Singleplayer {
case (byte)Block.Sand:
case (byte)Block.Gravel:
if( y > 0 ) PropagateFalling( posIndex, x, y, z, block, 0 );
falling.OnRandomTick( posIndex, block );
break;
case (byte)Block.Lava:
@ -259,51 +261,6 @@ namespace ClassicalSharp.Singleplayer {
#endregion
#region Sand/Gravel
Queue<uint> Falling = new Queue<uint>();
const uint defFallingTick = 2u << tickShift;
void TickFalling() {
int count = Falling.Count;
for( int i = 0; i < count; i++ ) {
int posIndex, flags;
if( CheckItem( Falling, 0x2, out posIndex, out flags ) ) {
byte block = map.blocks[posIndex];
if( !(block == (byte)Block.Sand || block == (byte)Block.Gravel ) ) continue;
int x = posIndex % width;
int y = posIndex / oneY; // posIndex / (width * length)
int z = (posIndex / width) % length;
if( y > 0 ) PropagateFalling( posIndex, x, y, z, block, flags );
}
}
}
void PropagateFalling( int posIndex, int x, int y, int z, byte block, int flags ) {
byte newBlock = map.blocks[posIndex - oneY];
if( newBlock == 0 || info.IsLiquid[newBlock] ) {
uint newFlags = MakeFallingFlags( newBlock ) << tickShift;
Falling.Enqueue( newFlags | (uint)(posIndex - oneY) );
game.UpdateBlock( x, y, z, oldBlock[flags >> 2] );
game.UpdateBlock( x, y - 1, z, block );
}
}
static byte[] oldBlock = new byte[] { (byte)Block.Air, (byte)Block.StillWater,
(byte)Block.Water, (byte)Block.StillLava, (byte)Block.Lava };
static uint MakeFallingFlags( byte above ) {
byte flags = 2;
if( above == (byte)Block.StillWater ) flags |= 0x04; // 1
else if( above == (byte)Block.Water ) flags |= 0x08; // 2
else if( above == (byte)Block.StillLava ) flags |= 0x0C; // 3
else if( above == (byte)Block.Lava ) flags |= 0x10; // 4
return flags;
}
#endregion
#region TNT
Vector3[] rayDirs;