// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT using System; using ClassicalSharp.Blocks; using OpenTK; namespace ClassicalSharp { public enum SoundType : byte { None, Wood, Gravel, Grass, Stone, Metal, Glass, Cloth, Sand, Snow, } public enum BlockDraw : byte { Opaque, Transparent, TransparentLeaves, Translucent, Gas, Sprite, } public enum CollideType : byte { WalkThrough, // i.e. gas or sprite SwimThrough, // i.e. liquid Solid, // i.e. solid } /// Stores various properties about the blocks in Minecraft Classic. public partial class BlockInfo { /// Gets whether the given block id is transparent/fully see through. /// Alpha values are treated as either 'fully see through' or 'fully solid'. public bool[] IsTransparent = new bool[Block.Count]; /// Gets whether the given block id is translucent/partially see through. /// Colour values are blended into both the transparent and opaque blocks behind them. public bool[] IsTranslucent = new bool[Block.Count]; /// Gets whether the given block id is opaque/not partially see through. public bool[] IsOpaque = new bool[Block.Count]; // Gets whether the given block id is opaque/not partially see through on the y axis. //public bool[] IsOpaqueY = new bool[Block.Count]; /// Gets whether the given block id is a sprite. (e.g. flowers, saplings, fire) public bool[] IsSprite = new bool[Block.Count]; /// Gets whether the given block id is a liquid. (water and lava) public bool IsLiquid( byte block ) { return block >= Block.Water && block <= Block.StillLava; } /// Gets whether the given block blocks sunlight. public bool[] BlocksLight = new bool[Block.Count]; /// Gets whether the given block should draw all it faces with a full white colour component. public bool[] FullBright = new bool[Block.Count]; public string[] Name = new string[Block.Count]; /// Gets the custom fog colour that should be used when the player is standing within this block. /// Note that this is only used for exponential fog mode. public FastColour[] FogColour = new FastColour[Block.Count]; public float[] FogDensity = new float[Block.Count]; public CollideType[] Collide = new CollideType[Block.Count]; public float[] SpeedMultiplier = new float[Block.Count]; public bool[] CullWithNeighbours = new bool[Block.Count]; public byte[] LightOffset = new byte[Block.Count]; public uint[] DefinedCustomBlocks = new uint[Block.Count >> 5]; public SoundType[] DigSounds = new SoundType[Block.Count]; public SoundType[] StepSounds = new SoundType[Block.Count]; public void Reset( Game game ) { Init(); // TODO: Make this part of TerrainAtlas2D maybe? using( FastBitmap fastBmp = new FastBitmap( game.TerrainAtlas.AtlasBitmap, true, true ) ) RecalculateSpriteBB( fastBmp ); } public void Init() { for( int i = 0; i < DefinedCustomBlocks.Length; i++ ) DefinedCustomBlocks[i] = 0; for( int block = 0; block < Block.Count; block++ ) ResetBlockProps( (byte)block ); UpdateCulling(); } public void SetDefaultBlockPerms( InventoryPermissions place, InventoryPermissions delete ) { for( int block = Block.Stone; block <= Block.MaxDefinedBlock; block++ ) { place[block] = true; delete[block] = true; } place[Block.Lava] = false; place[Block.Water] = false; place[Block.StillLava] = false; place[Block.StillWater] = false; place[Block.Bedrock] = false; delete[Block.Bedrock] = false; delete[Block.Lava] = false; delete[Block.Water] = false; delete[Block.StillWater] = false; delete[Block.StillLava] = false; } public void SetBlockDraw( byte id, BlockDraw draw ) { IsTranslucent[id] = draw == BlockDraw.Translucent; IsAir[id] = draw == BlockDraw.Gas; IsSprite[id] = draw == BlockDraw.Sprite; CullWithNeighbours[id] = draw != BlockDraw.TransparentLeaves; IsTransparent[id] = draw != BlockDraw.Opaque && draw != BlockDraw.Translucent; IsOpaque[id] = draw == BlockDraw.Opaque; } public void ResetBlockProps( byte id ) { BlocksLight[id] = DefaultSet.BlocksLight( id ); FullBright[id] = DefaultSet.FullBright( id ); CullWithNeighbours[id] = id != Block.Leaves; FogColour[id] = DefaultSet.FogColour( id ); FogDensity[id] = DefaultSet.FogDensity( id ); Collide[id] = DefaultSet.Collide( id ); DigSounds[id] = DefaultSet.DigSound( id ); StepSounds[id] = DefaultSet.StepSound( id ); SetBlockDraw( id, DefaultSet.Draw( id ) ); SpeedMultiplier[id] = 1; Name[id] = DefaultName( id ); if( IsSprite[id] ) { MinBB[id] = new Vector3( 2.50f/16f, 0, 2.50f/16f ); MaxBB[id] = new Vector3( 13.5f/16f, 1, 13.5f/16f ); } else { MinBB[id] = Vector3.Zero; MaxBB[id] = Vector3.One; MaxBB[id].Y = DefaultSet.Height( id ); } LightOffset[id] = CalcLightOffset( id ); if( id >= Block.CpeCount ) { SetTex( 0, Side.Top, id ); SetTex( 0, Side.Bottom, id ); SetSide( 0, id ); } else { SetTex( topTex[id], Side.Top, id ); SetTex( bottomTex[id], Side.Bottom, id ); SetSide( sideTex[id], id ); } } static StringBuffer buffer = new StringBuffer( 64 ); static string DefaultName( byte block ) { if( block >= Block.CpeCount ) return "Invalid"; // Find start and end of this particular block name int start = 0; for( int i = 0; i < block; i++) start = Block.Names.IndexOf( ' ', start ) + 1; int end = Block.Names.IndexOf( ' ', start ); if( end == -1 ) end = Block.Names.Length; buffer.Clear(); SplitUppercase( buffer, start, end ); return buffer.ToString(); } static void SplitUppercase( StringBuffer buffer, int start, int end ) { int index = 0; for( int i = start; i < end; i++ ) { char c = Block.Names[i]; bool upper = Char.IsUpper( c ) && i > start; bool nextLower = i < end - 1 && !Char.IsUpper( Block.Names[i + 1] ); if( upper && nextLower ) { buffer.Append( ref index, ' ' ); buffer.Append( ref index, Char.ToLower( c ) ); } else { buffer.Append( ref index, c ); } } } } }