// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT using System; using System.Collections.Generic; using ClassicalSharp.Blocks; using OpenTK; namespace ClassicalSharp { public enum SoundType : byte { None, Wood, Gravel, Grass, Stone, Metal, Glass, Cloth, Sand, Snow, } public static class DrawType { public const byte Opaque = 0; public const byte Transparent = 1; public const byte TransparentThick = 2; // e.g. leaves render all neighbours public const byte Translucent = 3; public const byte Gas = 4; public const byte Sprite = 5; } 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 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 byte[] LightOffset = new byte[Block.Count]; public byte[] Draw = 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 bool[] Tinted = new bool[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, byte draw) { if (draw == DrawType.Opaque && Collide[id] != CollideType.Solid) draw = DrawType.Transparent; Draw[id] = draw; } public void ResetBlockProps(byte id) { BlocksLight[id] = DefaultSet.BlocksLight(id); FullBright[id] = DefaultSet.FullBright(id); 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); Tinted[id] = false; if (Draw[id] == DrawType.Sprite) { 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); } } public int FindID(string name) { for (int i = 0; i < Block.Count; i++) { if (Utils.CaselessEquals(Name[i], name)) return i; } return -1; } 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); } } } } }