diff --git a/Commands/building/CmdCopy.cs b/Commands/building/CmdCopy.cs index a07faa74c..e5d6d9670 100644 --- a/Commands/building/CmdCopy.cs +++ b/Commands/building/CmdCopy.cs @@ -205,7 +205,7 @@ namespace MCGalaxy.Commands using (FileStream fs = new FileStream(path, FileMode.Open)) using(GZipStream gs = new GZipStream(fs, CompressionMode.Decompress)) { - CopyState state = new CopyState(); + CopyState state = new CopyState(0, 0, 0, 0, 0, 0, null); state.LoadFrom(gs); p.CopyBuffer = state; } diff --git a/Commands/building/CmdSpin.cs b/Commands/building/CmdSpin.cs index dd56eabe3..ac39d206c 100644 --- a/Commands/building/CmdSpin.cs +++ b/Commands/building/CmdSpin.cs @@ -14,114 +14,151 @@ BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licenses for the specific language governing permissions and limitations under the Licenses. -*/ + */ using System.Collections.Generic; using MCGalaxy.Drawing; namespace MCGalaxy.Commands { - public sealed class CmdSpin : Command - { - public override string name { get { return "spin"; } } - public override string shortcut { get { return ""; } } - public override string type { get { return CommandTypes.Building; } } - public override bool museumUsable { get { return false; } } - public override LevelPermission defaultRank { get { return LevelPermission.AdvBuilder; } } - public CmdSpin() { } + public sealed class CmdSpin : Command + { + public override string name { get { return "spin"; } } + public override string shortcut { get { return ""; } } + public override string type { get { return CommandTypes.Building; } } + public override bool museumUsable { get { return false; } } + public override LevelPermission defaultRank { get { return LevelPermission.AdvBuilder; } } + public CmdSpin() { } - public override void Use(Player p, string message) - { - if (message.Split(' ').Length > 1) { Help(p); return; } - if (message == "") message = "y"; + public override void Use(Player p, string message) + { + if (message.Split(' ').Length > 1) { Help(p); return; } + if (message == "") message = "y"; - List newBuffer = new List(); - int TotalLoop = 0; ushort temp; - newBuffer.Clear(); + switch (message) + { + case "90": + case "y": + p.CopyBuffer = RotateY(p.CopyBuffer); + goto case "m"; + case "180": + FlipDiagonal(p.CopyBuffer); break; + case "upsidedown": + case "u": + FlipY(p.CopyBuffer); break; + case "mirror": + case "m": + FlipX(p.CopyBuffer); break; + case "z": + p.CopyBuffer = RotateZ(p.CopyBuffer); break; + case "x": + p.CopyBuffer = RotateX(p.CopyBuffer); break; - switch (message) - { - case "90": - case "y": - p.CopyBuffer.ForEach(delegate(Player.CopyPos Pos) - { - temp = Pos.z; Pos.z = Pos.x; Pos.x = temp; - p.CopyBuffer[TotalLoop] = Pos; - TotalLoop += 1; - }); - goto case "m"; - case "180": - TotalLoop = p.CopyBuffer.Count; - p.CopyBuffer.ForEach(delegate(Player.CopyPos Pos) - { - TotalLoop -= 1; - Pos.x = p.CopyBuffer[TotalLoop].x; - Pos.z = p.CopyBuffer[TotalLoop].z; - newBuffer.Add(Pos); - }); - p.CopyBuffer.Clear(); - p.CopyBuffer = newBuffer; - break; - case "upsidedown": - case "u": - TotalLoop = p.CopyBuffer.Count; - p.CopyBuffer.ForEach(delegate(Player.CopyPos Pos) - { - TotalLoop -= 1; - Pos.y = p.CopyBuffer[TotalLoop].y; - newBuffer.Add(Pos); - }); - p.CopyBuffer.Clear(); - p.CopyBuffer = newBuffer; - break; - case "mirror": - case "m": - TotalLoop = p.CopyBuffer.Count; - p.CopyBuffer.ForEach(delegate(Player.CopyPos Pos) - { - TotalLoop -= 1; - Pos.x = p.CopyBuffer[TotalLoop].x; - newBuffer.Add(Pos); - }); - p.CopyBuffer.Clear(); - p.CopyBuffer = newBuffer; - break; - case "z": - TotalLoop = p.CopyBuffer.Count; - p.CopyBuffer.ForEach(delegate(Player.CopyPos Pos) - { - TotalLoop -= 1; - Pos.x = (ushort)(p.CopyBuffer[TotalLoop].y - (2 * p.CopyBuffer[TotalLoop].y)); - Pos.y = p.CopyBuffer[TotalLoop].x; - newBuffer.Add(Pos); - }); - p.CopyBuffer.Clear(); - p.CopyBuffer = newBuffer; - break; - case "x": - TotalLoop = p.CopyBuffer.Count; - p.CopyBuffer.ForEach(delegate(Player.CopyPos Pos) - { - TotalLoop -= 1; - Pos.z = (ushort)(p.CopyBuffer[TotalLoop].y - (2 * p.CopyBuffer[TotalLoop].y)); - Pos.y = p.CopyBuffer[TotalLoop].z; - newBuffer.Add(Pos); - }); - p.CopyBuffer.Clear(); - p.CopyBuffer = newBuffer; - break; - - default: - Player.SendMessage(p, "Incorrect syntax"); Help(p); - return; - } - - Player.SendMessage(p, "Spun: &b" + message); - } - - public override void Help(Player p) - { - Player.SendMessage(p, "/spin - Spins the copied object."); - Player.SendMessage(p, "Shotcuts: m for mirror, u for upside down, x for spin 90 on x, y for spin 90 on y, z for spin 90 on z."); - } - } + default: + Player.SendMessage(p, "Incorrect syntax"); + Help(p); return; + } + Player.SendMessage(p, "Spun: &b" + message); + } + + CopyState RotateX(CopyState state) { + CopyState newState = new CopyState(state.X, state.Y, state.Z, + state.Width, state.Length, state.Height); + byte[] blocks = state.Blocks; + + for (int i = 0; i < blocks.Length; i++) { + ushort x, y, z; + state.GetCoords(i, out x, out y, out z); + newState.Set(x, z, y, blocks[i]); + } + return newState; + } + + CopyState RotateY(CopyState state) { + CopyState newState = new CopyState(state.X, state.Y, state.Z, + state.Length, state.Height, state.Width); + byte[] blocks = state.Blocks; + + for (int i = 0; i < blocks.Length; i++) { + ushort x, y, z; + state.GetCoords(i, out x, out y, out z); + newState.Set(z, y, x, blocks[i]); + } + return newState; + } + + CopyState RotateZ(CopyState state) { + CopyState newState = new CopyState(state.X, state.Y, state.Z, + state.Height, state.Width, state.Length); + byte[] blocks = state.Blocks; + + for (int i = 0; i < blocks.Length; i++) { + ushort x, y, z; + state.GetCoords(i, out x, out y, out z); + newState.Set(y, x, z, blocks[i]); + } + return newState; + } + + void FlipX(CopyState state) { + int midX = state.Width / 2, maxX = state.Width - 1; + byte[] blocks = state.Blocks; + + for (int y = 0; y < state.Height; y++) { + for (int z = 0; z < state.Length; z++) { + for (int x = 0; x < midX; x++) { + int endX = maxX - x; + int start = state.GetIndex(x, y, z); + int end = state.GetIndex(endX, y, z); + Swap(blocks, start, end); + } + } + } + } + + void FlipY(CopyState state) { + int midY = state.Height / 2, maxY = state.Height - 1; + byte[] blocks = state.Blocks; + + for (int y = 0; y < midY; y++) { + int endY = maxY - y; + int start = state.GetIndex(0, y, 0); + int end = state.GetIndex(0, endY, 0); + + for (int z = 0; z < state.Length; z++) { + for (int x = 0; x < state.Width; x++) { + Swap(blocks, start, end); + start++; end++; + } + } + } + } + + void FlipDiagonal(CopyState state) { + int midX = state.Width / 2, maxX = state.Width - 1; + int midZ = state.Length / 2, maxZ = state.Length - 1; + byte[] blocks = state.Blocks; + + for (int y = 0; y < state.Height; y++) { + for (int z = 0; z < midZ; z++) { + int endZ = maxZ - z; + for (int x = 0; x < midX; x++) { + int endX = maxX - x; + int start = state.GetIndex(x, y, z); + int end = state.GetIndex(endX, y, endZ); + Swap(blocks, start, end); + } + } + } + } + + static void Swap( byte[] b, int start, int end ) { + byte a = b[start]; b[start] = b[end]; b[end] = a; + } + + public override void Help(Player p) + { + Player.SendMessage(p, "/spin - Spins the copied object."); + Player.SendMessage(p, "Shotcuts: m for mirror, u for upside down, x for spin 90 on x, y for spin 90 on y, z for spin 90 on z."); + } + } } diff --git a/Drawing/CopyState.cs b/Drawing/CopyState.cs index c18ddce7f..d8a79aef5 100644 --- a/Drawing/CopyState.cs +++ b/Drawing/CopyState.cs @@ -22,57 +22,53 @@ namespace MCGalaxy.Drawing { public sealed class CopyState { - public ushort[] MinCoords; - public ushort[] MaxCoords; public byte[] Blocks; + public int X, Y, Z; + public int Width, Height, Length; - int width, height, length; const int identifier = 0x434F5059; // 'COPY' public int Volume { - get { return width * height * length; } + get { return Width * Height * Length; } } - public CopyState() { } + public CopyState(int x, int y, int z, int width, int height, int length, byte[] blocks) { + X = x; Y = y; Z = z; + Width = width; Height = height; Length = length; + Blocks = blocks; + } - public CopyState(ushort minX, ushort minY, ushort minZ, - ushort maxX, ushort maxY, ushort maxZ) { - SetBounds(minX, minY, minZ, maxX, maxY, maxZ); - width = maxX - minX + 1; - height = maxY - minY + 1; - length = maxZ - minZ + 1; + public CopyState(int x, int y, int z, int width, int height, int length) + : this(x, y, z, width, height, length, null) { Blocks = new byte[width * height * length]; } - public void SetBounds(ushort minX, ushort minY, ushort minZ, - ushort maxX, ushort maxY, ushort maxZ) { - MinCoords = new [] { minX, minY, minZ }; - MaxCoords = new [] { maxX, maxY, maxZ }; - } - public void Clear() { Blocks = null; - MinCoords = null; - MaxCoords = null; } public void GetCoords(int index, out ushort x, out ushort y, out ushort z) { - y = (ushort)(index / width / length); - index -= y * width * length; - z = (ushort)(index / width); - index -= z * width; + y = (ushort)(index / Width / Length); + index -= y * Width * Length; + z = (ushort)(index / Width); + index -= z * Width; x = (ushort)index; } + public int GetIndex(int x, int y, int z) { + return (y * Length + z) * Width + x; + } + + public void Set(int x, int y, int z, byte block) { + Blocks[(y * Length + z) * Width + x] = block; + } + public void SaveTo(Stream stream) { BinaryWriter w = new BinaryWriter(stream); w.Write(identifier); - w.Write(MinCoords[0]); w.Write(MinCoords[1]); w.Write(MinCoords[2]); - w.Write(MaxCoords[0]); w.Write(MaxCoords[1]); w.Write(MaxCoords[2]); - w.Write(width); - w.Write(height); - w.Write(length); + w.Write(X); w.Write(Y); w.Write(Z); + w.Write(Width); w.Write(Height); w.Write(Length); w.Write(Blocks); } @@ -80,14 +76,10 @@ namespace MCGalaxy.Drawing { BinaryReader r = new BinaryReader(stream); if (r.ReadInt32() != identifier) throw new InvalidDataException("invalid identifier"); - ushort minX = r.ReadUInt16(), minY = r.ReadUInt16(), minZ = r.ReadUInt16(); - ushort maxX = r.ReadUInt16(), maxY = r.ReadUInt16(), maxZ = r.ReadUInt16(); - SetBounds( minX, minY, minZ, maxX, maxY, maxZ ); - width = r.ReadInt32(); - height = r.ReadInt32(); - length = r.ReadInt32(); - Blocks = r.ReadBytes(width * height * length); + X = r.ReadInt32(); Y = r.ReadInt32(); Z = r.ReadInt32(); + Width = r.ReadInt32(); Height = r.ReadInt32(); Length = r.ReadInt32(); + Blocks = r.ReadBytes(Width * Height * Length); } } }