diff --git a/Drawing/DrawOps/DrawOp.Performer.cs b/Drawing/DrawOps/DrawOp.Performer.cs index b64b36c18..208b549f4 100644 --- a/Drawing/DrawOps/DrawOp.Performer.cs +++ b/Drawing/DrawOps/DrawOp.Performer.cs @@ -16,6 +16,7 @@ permissions and limitations under the Licenses. */ using System; +using System.Collections.Generic; using MCGalaxy.BlockPhysics; using MCGalaxy.Commands; using MCGalaxy.Drawing.Brushes; @@ -52,6 +53,8 @@ namespace MCGalaxy.Drawing.Ops { } long affected = checkLimit ? 0L : op.GetBlocksAffected(op.Level, marks); + if (p != null) p.Transform.GetBlocksAffected(ref affected); + if (checkLimit && !op.CanDraw(marks, p, out affected)) return false; if (brush != null && affected != -1) { @@ -134,10 +137,13 @@ namespace MCGalaxy.Drawing.Ops { static void DoDrawOp(PendingDrawOp item, Player p) { Level lvl = item.Level; + //p.Transform = new Transforms.ScaleTransform() { XMul = 2, XDiv = 1, YMul = 2, YDiv = 1, ZMul = 2, ZDiv = 1 }; + IEnumerable iterator = + p.Transform.Perform(item.Marks, p, lvl, item.Op, item.Brush); if (item.Affected > Server.DrawReloadLimit) { - foreach (var b in item.Op.Perform(item.Marks, p, lvl, item.Brush)) { - if (b.Block == Block.Zero) continue; + foreach (var b in iterator) { + if (b.Block == Block.Zero) continue; byte old = lvl.GetTile(b.X, b.Y, b.Z); if (old == Block.Zero || !lvl.CheckAffectPermissions(p, b.X, b.Y, b.Z, old, b.Block, b.ExtBlock)) continue; @@ -146,8 +152,8 @@ namespace MCGalaxy.Drawing.Ops { p.IncrementBlockStats(b.Block, true); } } else if (item.Level.bufferblocks) { - foreach (var b in item.Op.Perform(item.Marks, p, lvl, item.Brush)) { - if (b.Block == Block.Zero) continue; + foreach (var b in iterator) { + if (b.Block == Block.Zero) continue; if (!lvl.DoBlockchange(p, b.X, b.Y, b.Z, b.Block, b.ExtBlock, true)) continue; int index = lvl.PosToInt(b.X, b.Y, b.Z); @@ -155,8 +161,8 @@ namespace MCGalaxy.Drawing.Ops { BlockQueue.Addblock(p, index, b.Block, b.ExtBlock); } } else { - foreach (var b in item.Op.Perform(item.Marks, p, item.Level, item.Brush)) { - if (b.Block == Block.Zero) continue; + foreach (var b in iterator) { + if (b.Block == Block.Zero) continue; if (!lvl.DoBlockchange(p, b.X, b.Y, b.Z, b.Block, b.ExtBlock, true)) continue; int index = lvl.PosToInt(b.X, b.Y, b.Z); diff --git a/Drawing/DrawOps/UndoDrawOp.cs b/Drawing/DrawOps/UndoDrawOp.cs index e349bc603..6edab105a 100644 --- a/Drawing/DrawOps/UndoDrawOp.cs +++ b/Drawing/DrawOps/UndoDrawOp.cs @@ -41,9 +41,9 @@ namespace MCGalaxy.Drawing.Ops { public override long GetBlocksAffected(Level lvl, Vec3S32[] marks) { return -1; } public override IEnumerable Perform(Vec3S32[] marks, Player p, Level lvl, Brush brush) { - UndoCache cache = p.UndoBuffer; + UndoCache cache = who.UndoBuffer; using (IDisposable locker = cache.ClearLock.AccquireReadLock()) { - if (UndoBlocks(p)) yield break; + if (UndoBlocks(who)) yield break; } bool found = false; string target = who.name.ToLower(); diff --git a/Drawing/Transform/SimpleTransforms.cs b/Drawing/Transform/SimpleTransforms.cs index 8bd20e103..bfb43f67f 100644 --- a/Drawing/Transform/SimpleTransforms.cs +++ b/Drawing/Transform/SimpleTransforms.cs @@ -23,12 +23,44 @@ using MCGalaxy.Drawing.Ops; namespace MCGalaxy.Drawing.Transforms { public sealed class NoTransform : Transform { - /// Human friendly name of this transform. public override string Name { get { return "None"; } } + public static NoTransform Instance = new NoTransform(); - public override IEnumerable Perform(Vec3S32[] marks, Player p, - Level lvl, DrawOp op, Brush brush) { + public override IEnumerable Perform(Vec3S32[] marks, Player p, + Level lvl, DrawOp op, Brush brush) { return op.Perform(marks, p, lvl, brush); } } + + public sealed class ScaleTransform : Transform { + + public override string Name { get { return "Scale"; } } + public bool CentreOrigin; + public int XMul, XDiv, YMul, YDiv, ZMul, ZDiv; + + public override void GetBlocksAffected(ref long affected) { + // NOTE: We do not the actual size of the drawop on each axis, so we take + // the overly conversative case and use the maximum scale for all three axes. + long x = affected * XMul / XDiv, y = affected * YMul / YDiv, z = affected * ZMul / ZDiv; + affected = Math.Max(x, Math.Max(y, z)); + } + + public override IEnumerable Perform(Vec3S32[] marks, Player p, + Level lvl, DrawOp op, Brush brush) { + Vec3S32 P = CentreOrigin ? (op.Min + op.Max) / 2 : op.Origin; + foreach (DrawOpBlock b in op.Perform(marks, p, lvl, brush)) { + int dx = b.X - P.X, dy = b.Y - P.Y, dz = b.Z - P.Z; + DrawOpBlock cur = b; + + for (int y = b.Y + dy * YMul / YDiv; y < b.Y + (dy + 1) * YMul / YDiv; y++) + for (int z = b.Z + dz * ZMul / ZDiv; b.Z + z < (dz + 1) * ZMul / ZDiv; z++) + for (int x = b.X + dx * XMul / XDiv; b.X + x < (dx + 1) * XMul / XDiv; x++) + { + if (!lvl.IsValidPos(x, y, z)) continue; + cur.X = (ushort)x; cur.Y = (ushort)y; cur.Z = (ushort)z; + yield return cur; + } + } + } + } } diff --git a/Drawing/Transform/Transform.cs b/Drawing/Transform/Transform.cs index 80ec1ae43..aac0338ff 100644 --- a/Drawing/Transform/Transform.cs +++ b/Drawing/Transform/Transform.cs @@ -26,6 +26,10 @@ namespace MCGalaxy.Drawing.Transforms { /// Human friendly name of this transform. public abstract string Name { get; } + /// Estimates the total number of blocks that the drawing commands affects, + /// after this transformation (e.g. scaling) has been applied to it. + public virtual void GetBlocksAffected(ref long affected) { } + /// Performs calcuations (if necessary) for the given drawop. public virtual void Configure(DrawOp op, Player p) { } diff --git a/Drawing/TransformFactories/SimpleTransforms.cs b/Drawing/TransformFactories/SimpleTransforms.cs index e7493dba5..ac39e0fd6 100644 --- a/Drawing/TransformFactories/SimpleTransforms.cs +++ b/Drawing/TransformFactories/SimpleTransforms.cs @@ -29,9 +29,7 @@ namespace MCGalaxy.Drawing.Transforms { "%HDoes not affect the output of draw operations.", }; - public override Transform Construct(BrushArgs args) { - return new NoTransform(); - } + public override Transform Construct(BrushArgs args) { return NoTransform.Instance; } public override bool Validate(BrushArgs args) { return true; } } diff --git a/Levels/Level.Blocks.cs b/Levels/Level.Blocks.cs index 2614a3685..f2c71eb08 100644 --- a/Levels/Level.Blocks.cs +++ b/Levels/Level.Blocks.cs @@ -407,6 +407,10 @@ namespace MCGalaxy { return pos.X < Width && pos.Y < Height && pos.Z < Length; } + public bool IsValidPos(int x, int y, int z) { + return x >= 0 && y >= 0 && z >= 0 && x < Width && y < Height && z < Length; + } + public void AddToBlockDB(Player p, int index, byte block, byte extBlock, bool delete) { if (!UseBlockDB) return; BlockPos bP = default(BlockPos); diff --git a/Player/Player.Fields.cs b/Player/Player.Fields.cs index a1e658126..d46913161 100644 --- a/Player/Player.Fields.cs +++ b/Player/Player.Fields.cs @@ -17,6 +17,7 @@ using System.Collections.Generic; using System.Net.Sockets; using System.Security.Cryptography; using MCGalaxy.Drawing; +using MCGalaxy.Drawing.Transforms; using MCGalaxy.Games; using MCGalaxy.Undo; @@ -72,7 +73,8 @@ namespace MCGalaxy { public bool IsAfk = false, AutoAfk; public bool cmdTimer = false; public bool UsingWom = false; - public string BrushName = "normal", DefaultBrushArgs = "", TransformName = "none"; + public string BrushName = "normal", DefaultBrushArgs = ""; + public Transform Transform = NoTransform.Instance; public string afkMessage; byte[] leftBuffer = new byte[0];