mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-26 14:54:12 -04:00
Make /maze allocate 85.35543% less memory.
This commit is contained in:
parent
2353897f3a
commit
f983d09a7c
@ -33,27 +33,32 @@ namespace MCGalaxy.Commands
|
||||
public override LevelPermission defaultRank { get { return LevelPermission.AdvBuilder; } }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Player.SendMessage(p, "Place two blocks to determine the edges.");
|
||||
Player.SendMessage(p, "Place two blocks to determine the edges.");
|
||||
p.ClearBlockchange();
|
||||
p.blockchangeObject = cpos;
|
||||
p.Blockchange += new Player.BlockchangeEventHandler(Blockchange1);
|
||||
}
|
||||
|
||||
void Blockchange1(Player p, ushort x, ushort y, ushort z, byte type, byte extType) {
|
||||
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);
|
||||
}
|
||||
|
||||
void Blockchange2(Player p, ushort x, ushort y, ushort z, byte type, byte extType) {
|
||||
RevertAndClearState(p, x, y, z);
|
||||
Vector3U16 cpos = (Vector3U16)p.blockchangeObject;
|
||||
DrawOp drawOp = new MazeDrawOp();
|
||||
CatchPos cpos = (CatchPos)p.blockchangeObject;
|
||||
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;
|
||||
if (p.staticCommands)
|
||||
p.Blockchange += new Player.BlockchangeEventHandler(Blockchange1);
|
||||
@ -63,5 +68,7 @@ namespace MCGalaxy.Commands
|
||||
Player.SendMessage(p, "%T/maze");
|
||||
Player.SendMessage(p, "%HGenerates a random maze between two points.");
|
||||
}
|
||||
|
||||
struct CatchPos { public ushort x, y, z; public int randomizer; }
|
||||
}
|
||||
}
|
||||
|
@ -21,177 +21,149 @@ using System.Security.Cryptography;
|
||||
using MCGalaxy.Drawing.Brushes;
|
||||
|
||||
namespace MCGalaxy.Drawing.Ops {
|
||||
|
||||
public class MazeDrawOp : CuboidHollowsDrawOp {
|
||||
|
||||
public override string Name { get { return "Maze"; } }
|
||||
|
||||
public static int randomizer = 0;
|
||||
public static bool[,] wall;
|
||||
|
||||
public override int GetBlocksAffected(Level lvl, Vector3U16[] marks) {
|
||||
int lenX = (Math.Abs(marks[1].X - marks[0].X) + 1) / 2;
|
||||
int lenZ = (Math.Abs(marks[1].Z - marks[0].Z) + 1) / 2;
|
||||
return lenX * lenZ * 3;
|
||||
}
|
||||
|
||||
public override void Perform(Vector3U16[] marks, Player p, Level lvl, Brush brush) {
|
||||
int width = Max.X - Min.X;
|
||||
if (width % 2 != 0) { width++; Min.X--; }
|
||||
width -= 2;
|
||||
int length = Max.Z - Min.Z;
|
||||
if (length % 2 != 0) { length++; Min.Z--; }
|
||||
length -= 2;
|
||||
|
||||
if (width < 0 || length < 0) {
|
||||
Player.SendMessage(p, "The corners of the maze need to be further apart."); return;
|
||||
}
|
||||
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 = 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++)
|
||||
{
|
||||
wall[w, h] = true;
|
||||
}
|
||||
|
||||
GridNode.maxX = width;
|
||||
GridNode.maxY = length;
|
||||
//Make a Stack
|
||||
Stack<GridNode> s = new Stack<GridNode>(width * length);
|
||||
//Random rand = new Random(DateTime.Now.Millisecond);//ha yeah randomized :P
|
||||
//lets begin in the lower left corner eh?(0,0)
|
||||
s.Push(new GridNode(0, 0));
|
||||
wall[0, 0] = false;
|
||||
while (true) {
|
||||
GridNode node = s.Peek();
|
||||
if (node.turnsPossible()) {
|
||||
GridNode[] nodearray = node.getRandomNext();
|
||||
wall[nodearray[0].X, nodearray[0].Y] = false;
|
||||
wall[nodearray[1].X, nodearray[1].Y] = false;
|
||||
s.Push(nodearray[1]);
|
||||
//we get the next two nodes
|
||||
//the first is a middle node from which there shouldnt start a new corridor
|
||||
//the second is added to the stack. next try will be with this node
|
||||
//i hope this will work this time...
|
||||
} else {
|
||||
s.Pop();//if this node is a dead and it will be removed
|
||||
}
|
||||
if (s.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;
|
||||
maxX++; maxZ++;
|
||||
|
||||
for (ushort xx = 0; xx <= width; xx++)
|
||||
for (ushort zz = 0; zz <= length; 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), (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);
|
||||
}
|
||||
|
||||
brush = new SolidBrush(Block.staircasefull, 0);
|
||||
QuadX(minX, 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(maxZ, y, minX, y, maxX, p, lvl, brush);
|
||||
|
||||
brush = new SolidBrush(Block.leaf, 0);
|
||||
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);
|
||||
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);
|
||||
|
||||
|
||||
public class MazeDrawOp : CuboidHollowsDrawOp {
|
||||
|
||||
public override string Name { get { return "Maze"; } }
|
||||
|
||||
internal int randomizer = 0;
|
||||
bool[,] wall;
|
||||
RNGCryptoServiceProvider rng1;
|
||||
Random rng2;
|
||||
byte[] r = new byte[1];
|
||||
int width, length;
|
||||
|
||||
public override int GetBlocksAffected(Level lvl, Vector3U16[] marks) {
|
||||
int lenX = (Math.Abs(marks[1].X - marks[0].X) + 1) / 2;
|
||||
int lenZ = (Math.Abs(marks[1].Z - marks[0].Z) + 1) / 2;
|
||||
return lenX * lenZ * 3;
|
||||
}
|
||||
|
||||
public override void Perform(Vector3U16[] marks, Player p, Level lvl, Brush brush) {
|
||||
width = Max.X - Min.X;
|
||||
if (width % 2 != 0) { width++; Min.X--; }
|
||||
width -= 2;
|
||||
length = Max.Z - Min.Z;
|
||||
if (length % 2 != 0) { length++; Min.Z--; }
|
||||
length -= 2;
|
||||
|
||||
if (width <= 0 || length <= 0) {
|
||||
Player.SendMessage(p, "The corners of the maze need to be further apart."); return;
|
||||
}
|
||||
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 = 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++)
|
||||
{
|
||||
wall[w, h] = true;
|
||||
}
|
||||
rng1 = new RNGCryptoServiceProvider();
|
||||
rng2 = new Random();
|
||||
|
||||
Stack<GridNode> stack = new Stack<GridNode>(width * length);
|
||||
stack.Push(new GridNode(0, 0));
|
||||
wall[0, 0] = false;
|
||||
while (true) {
|
||||
GridNode P = stack.Peek();
|
||||
if (TurnsPossible(P)) {
|
||||
GridNode P1, P2;
|
||||
MoveRandomDir(P, out P1, out P2);
|
||||
wall[P1.X, P1.Y] = false;
|
||||
wall[P2.X, P2.Y] = false;
|
||||
stack.Push(P2);
|
||||
//we get the next two nodes
|
||||
//the first is a middle node from which there shouldnt start a new corridor
|
||||
//the second is added to the stack. next try will be with this node
|
||||
//i hope this will work this time...
|
||||
} else {
|
||||
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, "Generated maze, now drawing.");
|
||||
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 zz = 0; zz <= length; 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), (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);
|
||||
}
|
||||
|
||||
brush = new SolidBrush(Block.staircasefull, 0);
|
||||
QuadX(minX, 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(maxZ, y, minX, y, maxX, p, lvl, brush);
|
||||
|
||||
brush = new SolidBrush(Block.leaf, 0);
|
||||
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);
|
||||
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);
|
||||
|
||||
Player.SendMessage(p, "Maze painted. Build your entrance and exit yourself");
|
||||
randomizer = 0;
|
||||
}
|
||||
|
||||
private class GridNode
|
||||
{
|
||||
public static int maxX = 0;
|
||||
public static int maxY = 0;
|
||||
public ushort X;
|
||||
public ushort Y;
|
||||
private Random rand2 = new Random(Environment.TickCount);
|
||||
|
||||
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));
|
||||
}
|
||||
void MoveRandomDir(GridNode P, out GridNode P1, out GridNode P2) {
|
||||
while (true) {
|
||||
r[0] = 0;
|
||||
if (randomizer == 0) {
|
||||
rng1.GetBytes(r);
|
||||
r[0] /= (255 / 4);
|
||||
} else {
|
||||
r[0] = (byte)rng2.Next(4);
|
||||
}
|
||||
|
||||
private bool isWall(int x, int y) {
|
||||
try {
|
||||
return wall[x, y];
|
||||
} catch (IndexOutOfRangeException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public GridNode(ushort x, ushort y) {
|
||||
X = x; Y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (r[0]) {
|
||||
case 0: //go up
|
||||
if (IsWall(P.X, P.Y + 2)) {
|
||||
P1 = new GridNode(P.X, (ushort)(P.Y + 1));
|
||||
P2 = new GridNode(P.X, (ushort)(P.Y + 2));
|
||||
return;
|
||||
} break;
|
||||
case 1: //go down
|
||||
if (IsWall(P.X, P.Y - 2)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user