Make /maze allocate 85.35543% less memory.

This commit is contained in:
UnknownShadow200 2016-03-22 11:25:06 +11:00
parent 2353897f3a
commit f983d09a7c
2 changed files with 153 additions and 174 deletions

View File

@ -33,27 +33,32 @@ namespace MCGalaxy.Commands
public override LevelPermission defaultRank { get { return LevelPermission.AdvBuilder; } } public override LevelPermission defaultRank { get { return LevelPermission.AdvBuilder; } }
public override void Use(Player p, string message) { public override void Use(Player p, string message) {
if (message.Length > 0 && !int.TryParse(message, out MazeDrawOp.randomizer)) { CatchPos cpos = default(CatchPos);
if (message.Length > 0 && !int.TryParse(message, out cpos.randomizer)) {
Help(p); return; Help(p); return;
} }
Player.SendMessage(p, "Place two blocks to determine the edges."); Player.SendMessage(p, "Place two blocks to determine the edges.");
p.ClearBlockchange(); p.ClearBlockchange();
p.blockchangeObject = cpos;
p.Blockchange += new Player.BlockchangeEventHandler(Blockchange1); p.Blockchange += new Player.BlockchangeEventHandler(Blockchange1);
} }
void Blockchange1(Player p, ushort x, ushort y, ushort z, byte type, byte extType) { void Blockchange1(Player p, ushort x, ushort y, ushort z, byte type, byte extType) {
RevertAndClearState(p, x, y, z); RevertAndClearState(p, x, y, z);
p.blockchangeObject = new Vector3U16(x, y, z); CatchPos cpos = (CatchPos)p.blockchangeObject;
cpos.x = x; cpos.y = y; cpos.z = z;
p.blockchangeObject = cpos;
p.Blockchange += new Player.BlockchangeEventHandler(Blockchange2); p.Blockchange += new Player.BlockchangeEventHandler(Blockchange2);
} }
void Blockchange2(Player p, ushort x, ushort y, ushort z, byte type, byte extType) { void Blockchange2(Player p, ushort x, ushort y, ushort z, byte type, byte extType) {
RevertAndClearState(p, x, y, z); RevertAndClearState(p, x, y, z);
Vector3U16 cpos = (Vector3U16)p.blockchangeObject; CatchPos cpos = (CatchPos)p.blockchangeObject;
DrawOp drawOp = new MazeDrawOp(); MazeDrawOp drawOp = new MazeDrawOp();
drawOp.randomizer = cpos.randomizer;
if (!DrawOp.DoDrawOp(drawOp, null, p, cpos.X, cpos.Y, cpos.Z, x, y, z)) if (!DrawOp.DoDrawOp(drawOp, null, p, cpos.x, cpos.y, cpos.z, x, y, z))
return; return;
if (p.staticCommands) if (p.staticCommands)
p.Blockchange += new Player.BlockchangeEventHandler(Blockchange1); p.Blockchange += new Player.BlockchangeEventHandler(Blockchange1);
@ -63,5 +68,7 @@ namespace MCGalaxy.Commands
Player.SendMessage(p, "%T/maze"); Player.SendMessage(p, "%T/maze");
Player.SendMessage(p, "%HGenerates a random maze between two points."); Player.SendMessage(p, "%HGenerates a random maze between two points.");
} }
struct CatchPos { public ushort x, y, z; public int randomizer; }
} }
} }

View File

@ -21,177 +21,149 @@ using System.Security.Cryptography;
using MCGalaxy.Drawing.Brushes; using MCGalaxy.Drawing.Brushes;
namespace MCGalaxy.Drawing.Ops { namespace MCGalaxy.Drawing.Ops {
public class MazeDrawOp : CuboidHollowsDrawOp { public class MazeDrawOp : CuboidHollowsDrawOp {
public override string Name { get { return "Maze"; } } public override string Name { get { return "Maze"; } }
public static int randomizer = 0; internal int randomizer = 0;
public static bool[,] wall; bool[,] wall;
RNGCryptoServiceProvider rng1;
public override int GetBlocksAffected(Level lvl, Vector3U16[] marks) { Random rng2;
int lenX = (Math.Abs(marks[1].X - marks[0].X) + 1) / 2; byte[] r = new byte[1];
int lenZ = (Math.Abs(marks[1].Z - marks[0].Z) + 1) / 2; int width, length;
return lenX * lenZ * 3;
} public override int GetBlocksAffected(Level lvl, Vector3U16[] marks) {
int lenX = (Math.Abs(marks[1].X - marks[0].X) + 1) / 2;
public override void Perform(Vector3U16[] marks, Player p, Level lvl, Brush brush) { int lenZ = (Math.Abs(marks[1].Z - marks[0].Z) + 1) / 2;
int width = Max.X - Min.X; return lenX * lenZ * 3;
if (width % 2 != 0) { width++; Min.X--; } }
width -= 2;
int length = Max.Z - Min.Z; public override void Perform(Vector3U16[] marks, Player p, Level lvl, Brush brush) {
if (length % 2 != 0) { length++; Min.Z--; } width = Max.X - Min.X;
length -= 2; if (width % 2 != 0) { width++; Min.X--; }
width -= 2;
if (width < 0 || length < 0) { length = Max.Z - Min.Z;
Player.SendMessage(p, "The corners of the maze need to be further apart."); return; if (length % 2 != 0) { length++; Min.Z--; }
} length -= 2;
Player.SendMessage(p, "Generating maze... this could take a while");
//substract 2 cause we will just make the inner. the outer wall is made seperately if (width <= 0 || length <= 0) {
wall = new bool[width+1, length+1];//+1 cause we begin at 0 so we need one object more Player.SendMessage(p, "The corners of the maze need to be further apart."); return;
for (int w = 0; w <= width; w++) }
for (int h = 0; h <= length; h++) Player.SendMessage(p, "Generating maze... this could take a while");
{ //substract 2 cause we will just make the inner. the outer wall is made seperately
wall[w, h] = true; wall = new bool[width + 1, length + 1];//+1 cause we begin at 0 so we need one object more
} for (int w = 0; w <= width; w++)
for (int h = 0; h <= length; h++)
GridNode.maxX = width; {
GridNode.maxY = length; wall[w, h] = true;
//Make a Stack }
Stack<GridNode> s = new Stack<GridNode>(width * length); rng1 = new RNGCryptoServiceProvider();
//Random rand = new Random(DateTime.Now.Millisecond);//ha yeah randomized :P rng2 = new Random();
//lets begin in the lower left corner eh?(0,0)
s.Push(new GridNode(0, 0)); Stack<GridNode> stack = new Stack<GridNode>(width * length);
wall[0, 0] = false; stack.Push(new GridNode(0, 0));
while (true) { wall[0, 0] = false;
GridNode node = s.Peek(); while (true) {
if (node.turnsPossible()) { GridNode P = stack.Peek();
GridNode[] nodearray = node.getRandomNext(); if (TurnsPossible(P)) {
wall[nodearray[0].X, nodearray[0].Y] = false; GridNode P1, P2;
wall[nodearray[1].X, nodearray[1].Y] = false; MoveRandomDir(P, out P1, out P2);
s.Push(nodearray[1]); wall[P1.X, P1.Y] = false;
//we get the next two nodes wall[P2.X, P2.Y] = false;
//the first is a middle node from which there shouldnt start a new corridor stack.Push(P2);
//the second is added to the stack. next try will be with this node //we get the next two nodes
//i hope this will work this time... //the first is a middle node from which there shouldnt start a new corridor
} else { //the second is added to the stack. next try will be with this node
s.Pop();//if this node is a dead and it will be removed //i hope this will work this time...
} } else {
if (s.Count < 1) break;//if no nodes are free anymore we will end the generation here stack.Pop();//if this node is a dead and it will be removed
} }
if (stack.Count < 1) break;//if no nodes are free anymore we will end the generation here
Player.SendMessage(p, "Maze is generated. now painting..."); }
//seems to be there are no more moves possible
ushort minX = Min.X, minZ = Min.Z, maxX = Max.X, maxZ = Max.Z, y = Min.Y; Player.SendMessage(p, "Generated maze, now drawing.");
maxX++; maxZ++; ushort minX = Min.X, minZ = Min.Z, maxX = Max.X, maxZ = Max.Z, y = Min.Y;
for (ushort xx = 0; xx <= width; xx++)
for (ushort xx = 0; xx <= width; xx++) for (ushort zz = 0; zz <= length; zz++)
for (ushort zz = 0; zz <= length; zz++) if (wall[xx, zz])
if (wall[xx, zz]) {
{ PlaceBlock(p, lvl, (ushort)(xx + minX + 1), y, (ushort)(zz + minZ + 1), Block.staircasefull, 0);
PlaceBlock(p, lvl, (ushort)(xx + minX + 1), y, (ushort)(zz + minZ + 1), Block.staircasefull, 0); PlaceBlock(p, lvl, (ushort)(xx + minX + 1), (ushort)(y + 1), (ushort)(zz + minZ + 1), Block.leaf, 0);
PlaceBlock(p, lvl, (ushort)(xx + minX + 1), (ushort)(y + 1), (ushort)(zz + minZ + 1), Block.leaf, 0); PlaceBlock(p, lvl, (ushort)(xx + minX + 1), (ushort)(y + 2), (ushort)(zz + minZ + 1), Block.leaf, 0);
PlaceBlock(p, lvl, (ushort)(xx + minX + 1), (ushort)(y + 2), (ushort)(zz + minZ + 1), Block.leaf, 0); }
}
brush = new SolidBrush(Block.staircasefull, 0);
brush = new SolidBrush(Block.staircasefull, 0); QuadX(minX, y, minZ, y, maxZ, p, lvl, brush);
QuadX(minX, y, minZ, y, maxZ, p, lvl, brush); QuadX(maxX, y, minZ, y, maxZ, p, lvl, brush);
QuadX(maxX, y, minZ, y, maxZ, p, lvl, brush); QuadZ(minZ, y, minX, y, maxX, p, lvl, brush);
QuadZ(minZ, y, minX, y, maxX, p, lvl, brush); QuadZ(maxZ, y, minX, y, maxX, p, lvl, brush);
QuadZ(maxZ, y, minX, y, maxX, p, lvl, brush);
brush = new SolidBrush(Block.leaf, 0);
brush = new SolidBrush(Block.leaf, 0); QuadX(minX, (ushort)(y + 1), minZ, (ushort)(y + 2), maxZ, p, lvl, brush);
QuadX(minX, (ushort)(y + 1), minZ, (ushort)(y + 2), maxZ, p, lvl, brush); QuadX(maxX, (ushort)(y + 1), minZ, (ushort)(y + 2), maxZ, p, lvl, brush);
QuadX(maxX, (ushort)(y + 1), minZ, (ushort)(y + 2), maxZ, p, lvl, brush); QuadZ(minZ, (ushort)(y + 1), minX, (ushort)(y + 2), maxX, p, lvl, brush);
QuadZ(minZ, (ushort)(y + 1), minX, (ushort)(y + 2), maxX, p, lvl, brush); QuadZ(maxZ, (ushort)(y + 1), minX, (ushort)(y + 2), maxX, p, lvl, brush);
QuadZ(maxZ, (ushort)(y + 1), minX, (ushort)(y + 2), maxX, p, lvl, brush);
Player.SendMessage(p, "Maze painted. Build your entrance and exit yourself"); Player.SendMessage(p, "Maze painted. Build your entrance and exit yourself");
randomizer = 0; randomizer = 0;
} }
private class GridNode void MoveRandomDir(GridNode P, out GridNode P1, out GridNode P2) {
{ while (true) {
public static int maxX = 0; r[0] = 0;
public static int maxY = 0; if (randomizer == 0) {
public ushort X; rng1.GetBytes(r);
public ushort Y; r[0] /= (255 / 4);
private Random rand2 = new Random(Environment.TickCount); } else {
r[0] = (byte)rng2.Next(4);
public GridNode[] getRandomNext() { }
byte[] r = new byte[1];
switch (randomizer) {
case 0:
RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();
rand.GetBytes(r);
r[0] /= (255 / 4);
break;
default:
r[0] = (byte)rand2.Next(4);
break;
}
ushort rx = 0, ry = 0, rx2 = 0, ry2 = 0;
switch (r[0]) {
case 0: //go up
if (isWall(X, Y + 2)) {
rx = X;
rx2 = X;
ry = (ushort)(Y + 1);
ry2 = (ushort)(Y + 2);
} else {
return this.getRandomNext();
}
break;
case 1: //go down
if (isWall(X, Y - 2)) {
rx = X;
rx2 = X;
ry = (ushort)(Y - 1);
ry2 = (ushort)(Y - 2);
} else {
return this.getRandomNext();
}
break;
case 2: //go right
if (isWall(X + 2, Y)) {
rx = (ushort)(X + 1);
rx2 = (ushort)(X + 2);
ry = Y;
ry2 = Y;
} else {
return this.getRandomNext();
}
break;
case 3:
if (isWall(X - 2, Y)) {
//go left
rx = (ushort)(X - 1);
rx2 = (ushort)(X - 2);
ry = Y;
ry2 = Y;
} else {
return this.getRandomNext();
}
break;
}
return new GridNode[] { new GridNode(rx, ry), new GridNode(rx2, ry2) };
}
public bool turnsPossible() {
return (isWall(X, Y + 2) || isWall(X, Y - 2) || isWall(X + 2, Y) || isWall(X - 2, Y));
}
private bool isWall(int x, int y) { switch (r[0]) {
try { case 0: //go up
return wall[x, y]; if (IsWall(P.X, P.Y + 2)) {
} catch (IndexOutOfRangeException) { P1 = new GridNode(P.X, (ushort)(P.Y + 1));
return false; P2 = new GridNode(P.X, (ushort)(P.Y + 2));
} return;
} } break;
case 1: //go down
public GridNode(ushort x, ushort y) { if (IsWall(P.X, P.Y - 2)) {
X = x; Y = y; P1 = new GridNode(P.X, (ushort)(P.Y - 1));
} P2 = new GridNode(P.X, (ushort)(P.Y - 2));
} return;
} } break;
case 2: //go right
if (IsWall(P.X + 2, P.Y)) {
P1 = new GridNode((ushort)(P.X + 1), P.Y);
P2 = new GridNode((ushort)(P.X + 2), P.Y);
return;
} break;
case 3: //go left
if (IsWall(P.X - 2, P.Y)) {
P1 = new GridNode((ushort)(P.X - 1), P.Y);
P2 = new GridNode((ushort)(P.X - 2), P.Y);
return;
} break;
}
}
}
bool TurnsPossible(GridNode P) {
return IsWall(P.X, P.Y + 2) || IsWall(P.X, P.Y - 2)
|| IsWall(P.X + 2, P.Y) || IsWall(P.X - 2, P.Y);
}
bool IsWall(int x, int y) {
if (x < 0 || y < 0 || x >= width || y >= length) return false;
return wall[x, y];
}
struct GridNode {
public ushort X, Y;
public GridNode(ushort x, ushort y) {
X = x; Y = y;
}
}
}
} }