/// <summary> /// Update this chunk's voxels /// </summary> public void UpdateChunk(uint Tick) { byte tickNumber = (byte)Tick; List <Notify> Changes = new List <Notify>(); // Update voxels for (int x = 0; x < ChunkWidth; ++x) { for (int y = 0; y < ChunkHeight; ++y) { for (int z = 0; z < ChunkWidth; ++z) { // Abort early, as this chunk has gone out of usage if (!bInUse) { return; } // Ignore VoxelInstance voxel = Get(x, y, z); if (voxel == null || voxel.mBehaviour == null) { continue; } // Check if this hasn't already been altered this tick (Maybe by another behaviour) if (voxel.mTickNumber == tickNumber) { continue; } else { voxel.mTickNumber = tickNumber; } ushort wasID = voxel.mID; // Notify if there was a change if (voxel.mBehaviour.UpdateVoxel(Tick, new Point(x, y, z), voxel, this)) { Changes.Add(new Notify(new Point(x, y, z), wasID, voxel.mID)); } } } } if (Changes.Count != 0) { QueueJob(new Job_QueueNotifies(this, Changes), 10); } }
/// <summary> /// Attempt to place a voxel, and then create the required notfies /// </summary> /// <param name="OverwriteTypeMask">Bit mask to determine what voxel types are allowed to be overwritten</param> /// <returns>If successful</returns> public bool PlaceVoxel(int x, int y, int z, ushort ID, ushort MetaFlags = ushort.MaxValue, int OverwriteTypeMask = 1) { VoxelInstance voxel = GetVoxel(x, y, z); // Place if current voxel type is none or is in overwrite task mask if (voxel != null && (voxel.mType == VoxelType.None || ((1 << (int)voxel.mType) & OverwriteTypeMask) != 0)) { voxel.SetNew(ID, MetaFlags); NotifyVoxelChange(x, y, z, 0, ID); return(true); } return(false); }
/// <summary> /// Set data for a specific voxel (in local coordinates; will use another chunk if out of bounds) /// </summary> public VoxelInstance Set(int x, int y, int z, ushort ID, ushort MetaFlags = ushort.MaxValue) { if (x >= 0 && x < ChunkWidth && y >= 0 && y < ChunkHeight && z >= 0 && z < ChunkWidth) { VoxelInstance voxel = mVoxelData[x, y, z]; voxel.SetNew(ID, MetaFlags); return(voxel); } // Try to use another chunk, if out of range else { return(mTerrain.SetVoxel(mChunkID.X * ChunkWidth + x, y, mChunkID.Z * ChunkWidth + z, ID, MetaFlags)); } }
/// <summary> /// Attempt to destroy a voxel, and then create the required notfies /// </summary> /// <returns>If successful</returns> public bool DestroyVoxel(int x, int y, int z) { // Cannot destroy bottom of world if (y == 0) { return(false); } VoxelInstance voxel = GetVoxel(x, y, z); if (voxel != null && voxel.mType != VoxelType.None) { ushort oldID = voxel.mID; voxel.SetNew(0); NotifyVoxelChange(x, y, z, oldID, 0); return(true); } return(false); }
private void AttemptAirDisperse(VoxelInstance From, VoxelInstance To, bool ForceFill = false) { if (To == null || From.mMetaFlags == 0 || To.mType != VoxelType.None) { return; } // Fill air with liquid if (ForceFill) { To.SetNew(From.mID, From.mMetaFlags); From.mMetaFlags = 0; To.mTickNumber = From.mTickNumber; } else { To.SetNew(From.mID, 1); From.mMetaFlags--; To.mTickNumber = From.mTickNumber; } }
/// <summary> /// Attempt to get the voxel the creature is currently embedded in or stood on /// </summary> /// <param name="IsEmbedded">Is the creature actually inside of a voxel (Non-air)</param> /// <returns>If succeeds to get a voxel or not i.e. Is it in voxel space</returns> public virtual bool TryGetFloor(out VoxelInstance Voxel, out bool IsEmbedded) { // Check to see if embedded, if so, return that VoxelInstance voxel = mTerrain.GetVoxel(mWorldLocation.x, mWorldLocation.y, mWorldLocation.z); // Out of voxel space, so no further check will be correct anyway if (voxel == null) { Voxel = null; IsEmbedded = false; return(false); } // Embedded in voxel if (voxel.mType != VoxelType.None) { Voxel = voxel; IsEmbedded = true; return(true); } // Check voxel below voxel = mTerrain.GetVoxel(mWorldLocation.x, mWorldLocation.y - 1, mWorldLocation.z); if (voxel != null) { Voxel = voxel; IsEmbedded = false; return(true); } // Failed (Must be about to fall out of world) Voxel = null; IsEmbedded = false; return(false); }
private void AttemptLiquidDisperse(VoxelInstance From, VoxelInstance To, bool ForceFill = false) { if (To == null || From.mMetaFlags == 0 || To.mType != VoxelType.Liquid) { return; } // Clamp liquid to max height if (To.mMetaFlags > VoxelData_Liquid.MaxHeight) { To.mMetaFlags = (ushort)VoxelData_Liquid.MaxHeight; } // Same liquid, so fill if (From.mID == To.mID) { if (ForceFill) { if (To.mMetaFlags != VoxelData_Liquid.MaxHeight) { ushort amount = (ushort)(VoxelData_Liquid.MaxHeight - To.mMetaFlags); amount = amount > From.mMetaFlags ? From.mMetaFlags : amount; To.mMetaFlags += amount; From.mMetaFlags -= amount; To.mTickNumber = From.mTickNumber; } } else if (To.mMetaFlags < From.mMetaFlags) { To.mMetaFlags++; From.mMetaFlags--; To.mTickNumber = From.mTickNumber; } } }
/// <summary> /// Attempt to get the voxel the creature is currently embedded in or stood on /// </summary> /// <returns>If succeeds to get a voxel or not i.e. Is it in voxel space</returns> public bool TryGetFloor(out VoxelInstance Voxel) { bool e; return(TryGetFloor(out Voxel, out e)); }
/// <summary> /// Build the mesh data /// </summary> public override void Execute() { mMeshData.Clear(); for (int x = 0; x < VoxelChunk.ChunkWidth; ++x) { for (int y = 0; y < VoxelChunk.ChunkHeight; ++y) { for (int z = 0; z < VoxelChunk.ChunkWidth; ++z) { if (bIsAborted) { return; } VoxelInstance voxel = mChunk.Get(x, y, z); VoxelInstance check = null; // Ignore if not part of terrain if (voxel.mType != VoxelType.Liquid) { continue; } bool bBuildTop, bBuildLeft, bBuildRight, bBuildFront, bBuildBack; bBuildTop = ((check = mChunk.Get(x, y + 1, z)) == null || check.mType != VoxelType.Liquid); bBuildLeft = (check = mChunk.Get(x - 1, y, z)) != null && (check.mType != VoxelType.Liquid || (!bBuildTop && GetLiquidHeight(check) != 1.0f)); bBuildRight = (check = mChunk.Get(x + 1, y, z)) != null && (check.mType != VoxelType.Liquid || (!bBuildTop && GetLiquidHeight(check) != 1.0f)); bBuildFront = (check = mChunk.Get(x, y, z - 1)) != null && (check.mType != VoxelType.Liquid || (!bBuildTop && GetLiquidHeight(check) != 1.0f)); bBuildBack = (check = mChunk.Get(x, y, z + 1)) != null && (check.mType != VoxelType.Liquid || (!bBuildTop && GetLiquidHeight(check) != 1.0f)); // Do height changes for top layer if (bBuildTop) { float mHeight = GetLiquidHeight(voxel); VoxelInstance vForwardLeft = mChunk.Get(x - 1, y, z - 1); VoxelInstance vForwardCentre = mChunk.Get(x, y, z - 1); VoxelInstance vForwardRight = mChunk.Get(x + 1, y, z - 1); VoxelInstance vMiddleLeft = mChunk.Get(x - 1, y, z); VoxelInstance vMiddleCentre = mChunk.Get(x, y, z); VoxelInstance vMiddleRight = mChunk.Get(x + 1, y, z); VoxelInstance vBackLeft = mChunk.Get(x - 1, y, z + 1); VoxelInstance vBackCentre = mChunk.Get(x, y, z + 1); VoxelInstance vBackRight = mChunk.Get(x + 1, y, z + 1); // Work out heights by taking average at corners float forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight; { ushort c = 1; forwardLeftHeight = mHeight; if (vForwardCentre != null && vForwardCentre.mType == VoxelType.Liquid) { ++c; forwardLeftHeight += GetLiquidHeight(vForwardCentre); } if (vForwardLeft != null && vForwardLeft.mType == VoxelType.Liquid) { ++c; forwardLeftHeight += GetLiquidHeight(vForwardLeft); } if (vMiddleLeft != null && vMiddleLeft.mType == VoxelType.Liquid) { ++c; forwardLeftHeight += GetLiquidHeight(vMiddleLeft); } forwardLeftHeight /= (float)c; } { ushort c = 1; forwardRightHeight = mHeight; if (vForwardCentre != null && vForwardCentre.mType == VoxelType.Liquid) { ++c; forwardRightHeight += GetLiquidHeight(vForwardCentre); } if (vForwardRight != null && vForwardRight.mType == VoxelType.Liquid) { ++c; forwardRightHeight += GetLiquidHeight(vForwardRight); } if (vMiddleRight != null && vMiddleRight.mType == VoxelType.Liquid) { ++c; forwardRightHeight += GetLiquidHeight(vMiddleRight); } forwardRightHeight /= (float)c; } { ushort c = 1; backLeftHeight = mHeight; if (vBackCentre != null && vBackCentre.mType == VoxelType.Liquid) { ++c; backLeftHeight += GetLiquidHeight(vBackCentre); } if (vBackLeft != null && vBackLeft.mType == VoxelType.Liquid) { ++c; backLeftHeight += GetLiquidHeight(vBackLeft); } if (vMiddleLeft != null && vMiddleLeft.mType == VoxelType.Liquid) { ++c; backLeftHeight += GetLiquidHeight(vMiddleLeft); } backLeftHeight /= (float)c; } { ushort c = 1; backRightHeight = mHeight; if (vBackCentre != null && vBackCentre.mType == VoxelType.Liquid) { ++c; backRightHeight += GetLiquidHeight(vBackCentre); } if (vBackRight != null && vBackRight.mType == VoxelType.Liquid) { ++c; backRightHeight += GetLiquidHeight(vBackRight); } if (vMiddleRight != null && vMiddleRight.mType == VoxelType.Liquid) { ++c; backRightHeight += GetLiquidHeight(vMiddleRight); } backRightHeight /= (float)c; } mMeshData.AddTopPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight); if (bBuildLeft) { mMeshData.AddLeftPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight); } if (bBuildRight) { mMeshData.AddRightPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight); } if (bBuildFront) { mMeshData.AddFrontPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight); } if (bBuildBack) { mMeshData.AddBackPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight); } } else { if (bBuildLeft) { mMeshData.AddLeftPanel(x, y, z, voxel.mMainTileID, 1, 1, 1, 1); } if (bBuildRight) { mMeshData.AddRightPanel(x, y, z, voxel.mMainTileID, 1, 1, 1, 1); } if (bBuildFront) { mMeshData.AddFrontPanel(x, y, z, voxel.mMainTileID, 1, 1, 1, 1); } if (bBuildBack) { mMeshData.AddBackPanel(x, y, z, voxel.mMainTileID, 1, 1, 1, 1); } } } } } mMeshData.Cook(); }
private float GetLiquidHeight(VoxelInstance Voxel) { return((Voxel.mMetaFlags > VoxelData_Liquid.MaxHeight ? VoxelData_Liquid.MaxHeight : Voxel.mMetaFlags) / (float)VoxelData_Liquid.MaxHeight); }
/// <summary> /// Update a specific voxel (Called from world update thread) /// </summary> public override bool UpdateVoxel(uint Tick, Point LocalPosition, VoxelInstance Voxel, VoxelChunk Chunk) { // Perform cleanup, if liquid too small if (Tick % mCleanRate == 0 && mRandom.Next(0, 100) < mCleanPercent) { // Replace with air, if no fill if (Voxel.mMetaFlags <= 1) { Voxel.SetNew(0); return(true); } } // Attempt to settle liquids other than puddles (Put at multiple of 2) if (Tick % mSettleRate == 0 && Voxel.mMetaFlags > 1) { if (Voxel.mMetaFlags % 2 != 0) { Voxel.mMetaFlags--; return(true); } if (Voxel.mMetaFlags == 0) { Voxel.SetNew(0); return(true); } } // Only update at given tick rate if (Tick % mUpdateRate != 0) { return(false); } // Clamp liquid to max height if (Voxel.mMetaFlags > VoxelData_Liquid.MaxHeight) { Voxel.mMetaFlags = (ushort)VoxelData_Liquid.MaxHeight; } ushort startHeight = Voxel.mMetaFlags; VoxelInstance above = Chunk.Get(LocalPosition.x, LocalPosition.y + 1, LocalPosition.z); VoxelInstance below = Chunk.Get(LocalPosition.x, LocalPosition.y - 1, LocalPosition.z); VoxelInstance left = Chunk.Get(LocalPosition.x - 1, LocalPosition.y, LocalPosition.z); VoxelInstance right = Chunk.Get(LocalPosition.x + 1, LocalPosition.y, LocalPosition.z); VoxelInstance front = Chunk.Get(LocalPosition.x, LocalPosition.y, LocalPosition.z - 1); VoxelInstance back = Chunk.Get(LocalPosition.x, LocalPosition.y, LocalPosition.z + 1); // Move liquid down and then out AttemptLiquidDisperse(Voxel, below, true); AttemptAirDisperse(Voxel, below, true); if (Voxel.mMetaFlags > 1) { // Shuffle order everytime to prevent any flattening issues uint order = (uint)mRandom.Next(0, 4); switch (order) { case 0: AttemptAirDisperse(Voxel, left); AttemptAirDisperse(Voxel, right); AttemptAirDisperse(Voxel, front); AttemptAirDisperse(Voxel, back); AttemptLiquidDisperse(Voxel, left); AttemptLiquidDisperse(Voxel, right); AttemptLiquidDisperse(Voxel, front); AttemptLiquidDisperse(Voxel, back); break; case 1: AttemptAirDisperse(Voxel, back); AttemptAirDisperse(Voxel, left); AttemptAirDisperse(Voxel, right); AttemptAirDisperse(Voxel, front); AttemptLiquidDisperse(Voxel, back); AttemptLiquidDisperse(Voxel, left); AttemptLiquidDisperse(Voxel, right); AttemptLiquidDisperse(Voxel, front); break; case 2: AttemptAirDisperse(Voxel, front); AttemptAirDisperse(Voxel, back); AttemptAirDisperse(Voxel, left); AttemptAirDisperse(Voxel, right); AttemptLiquidDisperse(Voxel, front); AttemptLiquidDisperse(Voxel, back); AttemptLiquidDisperse(Voxel, left); AttemptLiquidDisperse(Voxel, right); break; case 3: AttemptAirDisperse(Voxel, right); AttemptAirDisperse(Voxel, front); AttemptAirDisperse(Voxel, back); AttemptAirDisperse(Voxel, left); AttemptLiquidDisperse(Voxel, right); AttemptLiquidDisperse(Voxel, front); AttemptLiquidDisperse(Voxel, back); AttemptLiquidDisperse(Voxel, left); break; } } // Replace with air, if no fill if (Voxel.mMetaFlags == 0) { Voxel.SetNew(0); return(true); } return(Voxel.mMetaFlags != startHeight); }
public void OnRender(List <Vector3> verts, List <int> tris, List <Vector2> uvs, int i, Chunk chunk, VoxelInstance voxel) { Vector3 corner = voxel.GetPosInChunk().GetVector(); Rect textPos = TextureHandler.Instance.GetTexture(texture); Vector2 padd = new Vector2(textPos.width / 100000.0f, textPos.height / 100000.0f); Vector2 uvMin = textPos.min + padd; Vector2 uvMax = textPos.max - padd; if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.SOUTH)) { RenderHelper.AddQuad(verts, tris, uvs, corner, Vector3.up, Vector3.right, uvMin, uvMax, i + verts.Count); } if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.NORTH)) { RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.forward + Vector3.right, Vector3.up, Vector3.left, uvMin, uvMax, i + verts.Count); } if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.EAST)) { RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.right, Vector3.up, Vector3.forward, uvMin, uvMax, i + verts.Count); } if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.WEST)) { RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.forward, Vector3.up, Vector3.back, uvMin, uvMax, i + verts.Count); } if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.DOWN)) { RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.forward, Vector3.back, Vector3.right, uvMin, uvMax, i + verts.Count); } if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.UP)) { RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.up, Vector3.forward, Vector3.right, uvMin, uvMax, i + verts.Count); } }
public float GetMiningDifficulty(VoxelInstance voxel) { return(miningDifficulty); }
/// <summary> /// Build the mesh data /// </summary> public override void Execute() { mMeshData.Clear(); byte[] endodedData = new byte[4]; for (int x = 0; x < VoxelChunk.ChunkWidth; ++x) { for (int y = 0; y < VoxelChunk.ChunkHeight; ++y) { for (int z = 0; z < VoxelChunk.ChunkWidth; ++z) { if (bIsAborted) { return; } VoxelInstance voxel = mChunk.Get(x, y, z); VoxelInstance check = null; // Ignore if collision disabled if (voxel.bDisableCollision) { continue; } // Check all sides // Up if ((check = mChunk.Get(x, y + 1, z)) == null || check.bDisableCollision) { mMeshData.AddTopPanel(x, y, z, endodedData, true); } // Bottom if ((check = mChunk.Get(x, y - 1, z)) != null && check.bDisableCollision) { mMeshData.AddBottomPanel(x, y, z, endodedData, true); } // Left if ((check = mChunk.Get(x - 1, y, z)) != null && check.bDisableCollision) { mMeshData.AddLeftPanel(x, y, z, endodedData, true); } // Right if ((check = mChunk.Get(x + 1, y, z)) != null && check.bDisableCollision) { mMeshData.AddRightPanel(x, y, z, endodedData, true); } // Back if ((check = mChunk.Get(x, y, z + 1)) != null && check.bDisableCollision) { mMeshData.AddBackPanel(x, y, z, endodedData, true); } // Front if ((check = mChunk.Get(x, y, z - 1)) != null && check.bDisableCollision) { mMeshData.AddFrontPanel(x, y, z, endodedData, true); } } } } mMeshData.Cook(); }
/// <summary> /// Perform ray cast against all terrain /// </summary> /// <param name="R">Ray in unit space</param> /// <param name="MaxDistance"></param> /// <param name="Hit">Information of the hit, if hit successfully</param> /// <param name="IgnoreTransparent">Should voxels with transparent type just be ignoreed in this check</param> /// <param name="TypeMask">Bit mask to determine what voxel types to check against</param> /// <returns>Does the ray hit</returns> public bool PerformRayCast(Ray R, out VoxelHitInfo Hit, float MaxDistance = 32.0f, bool IgnoreTransparent = false, int TypeMask = int.MaxValue) { Point lastCheck = new Point(); bool started = false; for (float i = 0; i < MaxDistance; i += 0.5f) { Point check = new Point((R.origin + R.direction * i) * WorldManager.UnitToVoxelScale); // Don't repeat checks if (started && lastCheck == check) { continue; } // Ignore invalid height if (check.y < 0 || check.y >= VoxelChunk.ChunkHeight) { // If we were in bounds exit out, as we've left if (started) { break; } // Ignore invalid height until we get in bounds else { continue; } } lastCheck = check; started = true; VoxelInstance voxel = GetVoxel(check.x, check.y, check.z); // Ignore invalid checks if (voxel == null || voxel.mType == VoxelType.None || ((1 << (int)voxel.mType) & TypeMask) == 0 || (IgnoreTransparent && voxel.bIsTransparent)) { continue; } // Intersect ray against bounding box and see if it hits Bounds bounds = new Bounds(new Vector3(check.x, check.y, check.z) * WorldManager.VoxelToUnitScale, new Vector3(1, 1, 1) * WorldManager.VoxelToUnitScale); float d; if (bounds.IntersectRay(R, out d)) { Vector3 c = bounds.ClosestPoint(R.origin + R.direction * (d - 0.0001f)); Vector3 normal = new Vector3(0, 0, 0); // Work out normal based on closest point if (c.y == bounds.min.y) { normal.y = -1; } if (c.y == bounds.max.y) { normal.y = 1; } if (c.x == bounds.min.x) { normal.x = -1; } if (c.x == bounds.max.x) { normal.x = 1; } if (c.z == bounds.min.z) { normal.z = -1; } if (c.z == bounds.max.z) { normal.z = 1; } Hit = new VoxelHitInfo(check.x, check.y, check.z, voxel, normal.normalized); return(true); } } Hit = new VoxelHitInfo(); return(false); }
/// <summary> /// Build the mesh data /// </summary> public override void Execute() { mMeshData.Clear(); // First 2 bits are the tile id // Second bit is the tile's exposure (How close is it to air 0-4; 0:Next to air, 4:No air within 3 voxels) byte[] endodedData = new byte[4]; for (int x = 0; x < VoxelChunk.ChunkWidth; ++x) { for (int y = 0; y < VoxelChunk.ChunkHeight; ++y) { for (int z = 0; z < VoxelChunk.ChunkWidth; ++z) { if (bIsAborted) { return; } VoxelInstance voxel = mChunk.Get(x, y, z); VoxelInstance check = null; bool transparent = voxel.bIsTransparent; // Ignore if not part of terrain if (voxel.mType != VoxelType.Terrain) { continue; } byte[] tileBits; // Use main tile for top tile tileBits = System.BitConverter.GetBytes(voxel.mMainTileID); endodedData[0] = tileBits[0]; endodedData[1] = tileBits[1]; endodedData[2] = 0; // Check all sides // Up if ((check = mChunk.Get(x, y + 1, z)) == null || check.mType != VoxelType.Terrain || transparent != check.bIsTransparent) { mMeshData.AddTopPanel(x, y, z, endodedData); } // Include top tile and work out how exposed this tile is (Will be later culled in rendering, if neccessary) else { byte airExposure = 0; // Work out the air exposure for this exposure voxel if ((check = mChunk.Get(x, y + 1, z)) == null || check.mType == VoxelType.None || transparent != check.bIsTransparent) { airExposure = 0; } else if ((check = mChunk.Get(x, y + 2, z)) == null || check.mType == VoxelType.None || transparent != check.bIsTransparent) { airExposure = 1; } else if ((check = mChunk.Get(x, y + 3, z)) == null || check.mType == VoxelType.None || transparent != check.bIsTransparent) { airExposure = 2; } else if ((check = mChunk.Get(x, y + 4, z)) == null || check.mType == VoxelType.None || transparent != check.bIsTransparent) { airExposure = 3; } else { airExposure = 4; } // Check adjacent tiles if (airExposure == 4) { for (byte c = 1; c <= 3; ++c) { if ((check = mChunk.Get(x + c, y, z)) != null && (check.mType == VoxelType.None || transparent != check.bIsTransparent)) { airExposure = c; break; } if ((check = mChunk.Get(x - c, y, z)) != null && (check.mType == VoxelType.None || transparent != check.bIsTransparent)) { airExposure = c; break; } if ((check = mChunk.Get(x, y, z + c)) != null && (check.mType == VoxelType.None || transparent != check.bIsTransparent)) { airExposure = c; break; } if ((check = mChunk.Get(x, y, z - c)) != null && (check.mType == VoxelType.None || transparent != check.bIsTransparent)) { airExposure = c; break; } } } endodedData[2] = airExposure; mMeshData.AddTopPanel(x, y, z, endodedData); } // Switch to secondary tile tileBits = System.BitConverter.GetBytes(voxel.mSecondaryTileID); endodedData[0] = tileBits[0]; endodedData[1] = tileBits[1]; endodedData[2] = 0; // Left if ((check = mChunk.Get(x - 1, y, z)) != null && (check.mType != VoxelType.Terrain || transparent != check.bIsTransparent)) { mMeshData.AddLeftPanel(x, y, z, endodedData); } // Right if ((check = mChunk.Get(x + 1, y, z)) != null && (check.mType != VoxelType.Terrain || transparent != check.bIsTransparent)) { mMeshData.AddRightPanel(x, y, z, endodedData); } // Back if ((check = mChunk.Get(x, y, z + 1)) != null && (check.mType != VoxelType.Terrain || transparent != check.bIsTransparent)) { mMeshData.AddBackPanel(x, y, z, endodedData); } // Front if ((check = mChunk.Get(x, y, z - 1)) != null && (check.mType != VoxelType.Terrain || transparent != check.bIsTransparent)) { mMeshData.AddFrontPanel(x, y, z, endodedData); } } } } mMeshData.Cook(); }