diff --git a/Substrate/SubstrateCS/Examples/Maze/Maze.csproj b/Substrate/SubstrateCS/Examples/Maze/Maze.csproj
new file mode 100644
index 0000000..27cb739
--- /dev/null
+++ b/Substrate/SubstrateCS/Examples/Maze/Maze.csproj
@@ -0,0 +1,94 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {62D70576-FE3A-4530-B283-889C14B52E9E}
+ Exe
+ Properties
+ Maze
+ Maze
+ v4.0
+ 512
+
+
+
+
+ 3.5
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\..\bin\Release\Substrate.dll
+
+
+
+
+
+
+
+
+
+ False
+ Microsoft .NET Framework 4 %28x86 and x64%29
+ true
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+ False
+ Windows Installer 3.1
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/Substrate/SubstrateCS/Examples/Maze/Program.cs b/Substrate/SubstrateCS/Examples/Maze/Program.cs
new file mode 100644
index 0000000..4d7c40c
--- /dev/null
+++ b/Substrate/SubstrateCS/Examples/Maze/Program.cs
@@ -0,0 +1,352 @@
+using System;
+using System.Collections.Generic;
+using Substrate;
+
+namespace Maze
+{
+ class Program
+ {
+ static void Main (string[] args)
+ {
+ BetaWorld world = BetaWorld.Open("F:\\Minecraft\\test");
+ BlockManager bm = world.GetBlockManager();
+
+ bm.AutoLight = false;
+
+ Grid grid = new Grid();
+ grid.BuildInit(bm);
+
+ Generator gen = new Generator();
+ List edges = gen.Generate();
+
+ foreach (Generator.Edge e in edges) {
+ int x1;
+ int y1;
+ int z1;
+ gen.UnIndex(e.node1, out x1, out y1, out z1);
+
+ int x2;
+ int y2;
+ int z2;
+ gen.UnIndex(e.node2, out x2, out y2, out z2);
+
+ grid.LinkRooms(bm, x1, y1, z1, x2, y2, z2);
+ }
+
+ // Entrance Room
+ grid.BuildRoom(bm, 2, 5, 2);
+ grid.LinkRooms(bm, 2, 5, 2, 1, 5, 2);
+ grid.LinkRooms(bm, 2, 5, 2, 3, 5, 2);
+ grid.LinkRooms(bm, 2, 5, 2, 2, 5, 1);
+ grid.LinkRooms(bm, 2, 5, 2, 2, 5, 3);
+ grid.LinkRooms(bm, 2, 4, 2, 2, 5, 2);
+
+ // Exit Room
+ grid.BuildRoom(bm, 2, -1, 2);
+ grid.LinkRooms(bm, 2, -1, 2, 2, 0, 2);
+ grid.AddPrize(bm, 2, -1, 2);
+
+ Console.WriteLine("Relight Chunks");
+
+ ChunkManager cm = world.GetChunkManager();
+ cm.RelightDirtyChunks();
+
+ world.Save();
+ }
+
+ }
+
+ class Grid
+ {
+ int originx;
+ int originy;
+ int originz;
+
+ int xlen;
+ int ylen;
+ int zlen;
+
+ int cellxlen;
+ int cellylen;
+ int cellzlen;
+ int wallxwidth;
+ int wallywidth;
+ int wallzwidth;
+
+ public Grid ()
+ {
+ originx = 0;
+ originy = 27;
+ originz = 0;
+
+ xlen = 5;
+ ylen = 5;
+ zlen = 5;
+
+ cellxlen = 5;
+ cellylen = 5;
+ cellzlen = 5;
+ wallxwidth = 2;
+ wallywidth = 2;
+ wallzwidth = 2;
+ }
+
+ public void BuildInit (BlockManager bm)
+ {
+ for (int xi = 0; xi < xlen; xi++) {
+ for (int yi = 0; yi < ylen; yi++) {
+ for (int zi = 0; zi < zlen; zi++) {
+ BuildRoom(bm, xi, yi, zi);
+ }
+ }
+ }
+ }
+
+ public void BuildRoom (BlockManager bm, int x, int y, int z)
+ {
+ int ox = originx + (cellxlen + wallxwidth) * x;
+ int oy = originy + (cellylen + wallywidth) * y;
+ int oz = originz + (cellzlen + wallzwidth) * z;
+
+ // Hollow out room
+ for (int xi = 0; xi < cellxlen; xi++) {
+ int xx = ox + wallxwidth + xi;
+ for (int zi = 0; zi < cellzlen; zi++) {
+ int zz = oz + wallzwidth + zi;
+ for (int yi = 0; yi < cellylen; yi++) {
+ int yy = oy + wallywidth + yi;
+ bm.SetID(xx, yy, zz, (int)BlockType.AIR);
+ }
+ }
+ }
+
+ // Build walls
+ for (int xi = 0; xi < cellxlen + 2 * wallxwidth; xi++) {
+ for (int zi = 0; zi < cellzlen + 2 * wallzwidth; zi++) {
+ for (int yi = 0; yi < wallywidth; yi++) {
+ bm.SetID(ox + xi, oy + yi, oz + zi, (int)BlockType.BEDROCK);
+ bm.SetID(ox + xi, oy + yi + cellylen + wallywidth, oz + zi, (int)BlockType.BEDROCK);
+ }
+ }
+ }
+
+ for (int xi = 0; xi < cellxlen + 2 * wallxwidth; xi++) {
+ for (int zi = 0; zi < wallzwidth; zi++) {
+ for (int yi = 0; yi < cellylen + 2 * wallywidth; yi++) {
+ bm.SetID(ox + xi, oy + yi, oz + zi, (int)BlockType.BEDROCK);
+ bm.SetID(ox + xi, oy + yi, oz + zi + cellzlen + wallzwidth, (int)BlockType.BEDROCK);
+ }
+ }
+ }
+
+ for (int xi = 0; xi < wallxwidth; xi++) {
+ for (int zi = 0; zi < cellzlen + 2 * wallzwidth; zi++) {
+ for (int yi = 0; yi < cellylen + 2 * wallywidth; yi++) {
+ bm.SetID(ox + xi, oy + yi, oz + zi, (int)BlockType.BEDROCK);
+ bm.SetID(ox + xi + cellxlen + wallxwidth, oy + yi, oz + zi, (int)BlockType.BEDROCK);
+ }
+ }
+ }
+
+ // Torchlight
+ bm.SetID(ox + wallxwidth, oy + wallywidth + 2, oz + wallzwidth + 1, (int)BlockType.TORCH);
+ bm.SetID(ox + wallxwidth, oy + wallywidth + 2, oz + wallzwidth + cellzlen - 2, (int)BlockType.TORCH);
+ bm.SetID(ox + wallxwidth + cellxlen - 1, oy + wallywidth + 2, oz + wallzwidth + 1, (int)BlockType.TORCH);
+ bm.SetID(ox + wallxwidth + cellxlen - 1, oy + wallywidth + 2, oz + wallzwidth + cellzlen - 2, (int)BlockType.TORCH);
+ bm.SetID(ox + wallxwidth + 1, oy + wallywidth + 2, oz + wallzwidth, (int)BlockType.TORCH);
+ bm.SetID(ox + wallxwidth + cellxlen - 2, oy + wallywidth + 2, oz + wallzwidth, (int)BlockType.TORCH);
+ bm.SetID(ox + wallxwidth + 1, oy + wallywidth + 2, oz + wallzwidth + cellzlen - 1, (int)BlockType.TORCH);
+ bm.SetID(ox + wallxwidth + cellxlen - 2, oy + wallywidth + 2, oz + wallzwidth + cellzlen - 1, (int)BlockType.TORCH);
+ }
+
+ public void LinkRooms (BlockManager bm, int x1, int y1, int z1, int x2, int y2, int z2)
+ {
+ int xx = originx + (cellxlen + wallxwidth) * x1;
+ int yy = originy + (cellylen + wallywidth) * y1;
+ int zz = originz + (cellzlen + wallzwidth) * z1;
+
+ if (x1 != x2) {
+ xx = originx + (cellxlen + wallxwidth) * Math.Max(x1, x2);
+ for (int xi = 0; xi < wallxwidth; xi++) {
+ int zc = zz + wallzwidth + (cellzlen / 2);
+ int yb = yy + wallywidth;
+ bm.SetID(xx + xi, yb, zc - 1, (int)BlockType.AIR);
+ bm.SetID(xx + xi, yb, zc, (int)BlockType.AIR);
+ bm.SetID(xx + xi, yb, zc + 1, (int)BlockType.AIR);
+ bm.SetID(xx + xi, yb + 1, zc - 1, (int)BlockType.AIR);
+ bm.SetID(xx + xi, yb + 1, zc, (int)BlockType.AIR);
+ bm.SetID(xx + xi, yb + 1, zc + 1, (int)BlockType.AIR);
+ bm.SetID(xx + xi, yb + 2, zc, (int)BlockType.AIR);
+ }
+ }
+ else if (z1 != z2) {
+ zz = originz + (cellzlen + wallzwidth) * Math.Max(z1, z2);
+ for (int zi = 0; zi < wallxwidth; zi++) {
+ int xc = xx + wallxwidth + (cellxlen / 2);
+ int yb = yy + wallywidth;
+ bm.SetID(xc - 1, yb, zz + zi, (int)BlockType.AIR);
+ bm.SetID(xc, yb, zz + zi, (int)BlockType.AIR);
+ bm.SetID(xc + 1, yb, zz + zi, (int)BlockType.AIR);
+ bm.SetID(xc - 1, yb + 1, zz + zi, (int)BlockType.AIR);
+ bm.SetID(xc, yb + 1, zz + zi, (int)BlockType.AIR);
+ bm.SetID(xc + 1, yb + 1, zz + zi, (int)BlockType.AIR);
+ bm.SetID(xc, yb + 2, zz + zi, (int)BlockType.AIR);
+ }
+ }
+ else if (y1 != y2) {
+ yy = originy + (cellylen + wallywidth) * Math.Max(y1, y2);
+ for (int yi = 0 - cellylen + 1; yi < wallywidth + 1; yi++) {
+ int xc = xx + wallxwidth + (cellxlen / 2);
+ int zc = zz + wallzwidth + (cellzlen / 2);
+
+ bm.SetID(xc, yy + yi, zc, (int)BlockType.BEDROCK);
+ bm.SetID(xc - 1, yy + yi, zc, (int)BlockType.LADDER);
+ bm.SetData(xc - 1, yy + yi, zc, 4);
+ bm.SetID(xc + 1, yy + yi, zc, (int)BlockType.LADDER);
+ bm.SetData(xc + 1, yy + yi, zc, 5);
+ bm.SetID(xc, yy + yi, zc - 1, (int)BlockType.LADDER);
+ bm.SetData(xc, yy + yi, zc - 1, 2);
+ bm.SetID(xc, yy + yi, zc + 1, (int)BlockType.LADDER);
+ bm.SetData(xc, yy + yi, zc + 1, 3);
+ }
+ }
+ }
+
+ public void AddPrize (BlockManager bm, int x, int y, int z)
+ {
+ int ox = originx + (cellxlen + wallxwidth) * x + wallxwidth;
+ int oy = originy + (cellylen + wallywidth) * y + wallywidth;
+ int oz = originz + (cellzlen + wallzwidth) * z + wallzwidth;
+
+ Random rand = new Random();
+ for (int xi = 0; xi < cellxlen; xi++) {
+ for (int zi = 0; zi < cellzlen; zi++) {
+ if (rand.NextDouble() < 0.1) {
+ bm.SetID(ox + xi, oy, oz + zi, (int)BlockType.DIAMOND_BLOCK);
+ }
+ }
+ }
+ }
+ }
+
+ class Generator
+ {
+ public struct Edge
+ {
+ public int node1;
+ public int node2;
+
+ public Edge (int n1, int n2)
+ {
+ node1 = n1;
+ node2 = n2;
+ }
+ }
+
+ int xlen;
+ int ylen;
+ int zlen;
+
+ List _edges;
+ int[] _cells;
+
+ public Generator ()
+ {
+ xlen = 5;
+ ylen = 5;
+ zlen = 5;
+
+ _edges = new List();
+ _cells = new int[xlen * zlen * ylen];
+
+ for (int x = 0; x < xlen; x++) {
+ for (int z = 0; z < zlen; z++) {
+ for (int y = 0; y < ylen; y++) {
+ int n1 = Index(x, y, z);
+ _cells[n1] = n1;
+ }
+ }
+ }
+
+ for (int x = 0; x < xlen - 1; x++) {
+ for (int z = 0; z < zlen; z++) {
+ for (int y = 0; y < ylen; y++) {
+ int n1 = Index(x, y, z);
+ int n2 = Index(x + 1, y, z);
+ _edges.Add(new Edge(n1, n2));
+ }
+ }
+ }
+
+ for (int x = 0; x < xlen; x++) {
+ for (int z = 0; z < zlen - 1; z++) {
+ for (int y = 0; y < ylen; y++) {
+ int n1 = Index(x, y, z);
+ int n2 = Index(x, y, z + 1);
+ _edges.Add(new Edge(n1, n2));
+ }
+ }
+ }
+
+ for (int x = 0; x < xlen; x++) {
+ for (int z = 0; z < zlen; z++) {
+ for (int y = 0; y < ylen - 1; y++) {
+ int n1 = Index(x, y, z);
+ int n2 = Index(x, y + 1, z);
+ _edges.Add(new Edge(n1, n2));
+ }
+ }
+ }
+ }
+
+ public List Generate ()
+ {
+ Random rand = new Random();
+
+ List passages = new List();
+
+ // Randomize edges
+ Queue redges = new Queue();
+ while (_edges.Count > 0) {
+ int index = rand.Next(_edges.Count);
+ Edge e = _edges[index];
+ _edges.RemoveAt(index);
+ redges.Enqueue(e);
+ }
+
+ while (redges.Count > 0) {
+ Edge e = redges.Dequeue();
+
+ if (_cells[e.node1] == _cells[e.node2]) {
+ continue;
+ }
+
+ passages.Add(e);
+
+ int n1 = _cells[e.node2];
+ int n2 = _cells[e.node1];
+ for (int i = 0; i < _cells.Length; i++) {
+ if (_cells[i] == n2) {
+ _cells[i] = n1;
+ }
+ }
+ }
+
+ return passages;
+ }
+
+ public int Index (int x, int y, int z)
+ {
+ return (x * zlen + z) * ylen + y;
+ }
+
+ public void UnIndex (int index, out int x, out int y, out int z)
+ {
+ x = index / (zlen * ylen);
+ int xstr = index - (x * zlen * ylen);
+ z = xstr / ylen;
+ int ystr = xstr - (z * ylen);
+ y = ystr;
+ }
+ }
+}
diff --git a/Substrate/SubstrateCS/Examples/Maze/Properties/AssemblyInfo.cs b/Substrate/SubstrateCS/Examples/Maze/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..268d7a5
--- /dev/null
+++ b/Substrate/SubstrateCS/Examples/Maze/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Maze")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Maze")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("1f8659a6-81aa-4f18-abb6-7e56f8ba9d34")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]