From 9b1e9a7d7de184fbb38289923fd97593d8b8ae16 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 11 Jul 2018 13:08:50 +1000 Subject: [PATCH] Add /hold to make you hold a particular block --- MCGalaxy/Commands/CPE/CmdHold.cs | 55 +++++++++++++++++++ MCGalaxy/Commands/CPE/CmdReachDistance.cs | 16 +++--- .../Commands/Maintenance/CmdBlockSpeed.cs | 3 +- MCGalaxy/Commands/building/CmdAbort.cs | 2 +- MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs | 7 +-- MCGalaxy/Levels/BlockQueue.cs | 43 ++++++++------- MCGalaxy/Levels/Level.Blocks.cs | 2 +- MCGalaxy/Levels/Level.Fields.cs | 4 +- MCGalaxy/Levels/Level.cs | 3 +- MCGalaxy/MCGalaxy_.csproj | 1 + 10 files changed, 97 insertions(+), 39 deletions(-) create mode 100644 MCGalaxy/Commands/CPE/CmdHold.cs diff --git a/MCGalaxy/Commands/CPE/CmdHold.cs b/MCGalaxy/Commands/CPE/CmdHold.cs new file mode 100644 index 000000000..20eecf878 --- /dev/null +++ b/MCGalaxy/Commands/CPE/CmdHold.cs @@ -0,0 +1,55 @@ +/* + Copyright 2015 MCGalaxy + + Dual-licensed under the Educational Community License, Version 2.0 and + the GNU General Public License, Version 3 (the "Licenses"); you may + not use this file except in compliance with the Licenses. You may + obtain a copy of the Licenses at + + http://www.opensource.org/licenses/ecl2.php + http://www.gnu.org/licenses/gpl-3.0.html + + Unless required by applicable law or agreed to in writing, + software distributed under the Licenses are distributed on an "AS IS" + 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 MCGalaxy.Network; +using BlockID = System.UInt16; + +namespace MCGalaxy.Commands.CPE { + public sealed class CmdHold : Command2 { + public override string name { get { return "Hold"; } } + public override string shortcut { get { return "HoldThis"; } } + public override string type { get { return CommandTypes.Building; } } + public override LevelPermission defaultRank { get { return LevelPermission.AdvBuilder; } } + public override bool SuperUseable { get { return false; } } + + public override void Use(Player p, string message, CommandData data) { + if (message.Length == 0) { Help(p); return; } + if (!p.Supports(CpeExt.HeldBlock)) { + p.Message("Your client doesn't support changing your held block."); return; + } + string[] args = message.SplitSpaces(2); + + BlockID block; + if (!CommandParser.GetBlock(p, args[0], out block)) return; + bool locked = false; + if (args.Length > 1 && !CommandParser.GetBool(p, args[1], ref locked)) return; + + if (Block.IsPhysicsType(block)) { + Player.Message(p, "Cannot hold physics blocks"); return; + } + + p.Send(Packet.HoldThis(Block.ToRaw(block), locked, p.hasExtBlocks)); + p.Message("Set your held block to {0}.", Block.GetName(p, block)); + } + + public override void Help(Player p) { + p.Message("%T/Hold [block] "); + p.Message("%HMakes you hold the given block in your hand"); + p.Message("%H optionally prevents you from changing it"); + } + } +} diff --git a/MCGalaxy/Commands/CPE/CmdReachDistance.cs b/MCGalaxy/Commands/CPE/CmdReachDistance.cs index 0abccc45a..27acc1e2b 100644 --- a/MCGalaxy/Commands/CPE/CmdReachDistance.cs +++ b/MCGalaxy/Commands/CPE/CmdReachDistance.cs @@ -17,8 +17,8 @@ */ using MCGalaxy.Network; -namespace MCGalaxy.Commands.CPE { - public sealed class CmdReachDistance : Command2 { +namespace MCGalaxy.Commands.CPE { + public sealed class CmdReachDistance : Command2 { public override string name { get { return "ReachDistance"; } } public override string shortcut { get { return "Reach"; } } public override string type { get { return CommandTypes.Building; } } @@ -26,16 +26,18 @@ namespace MCGalaxy.Commands.CPE { public override bool SuperUseable { get { return false; } } public override void Use(Player p, string message, CommandData data) { - if (message.Length == 0) { Help(p); return; } + if (message.Length == 0) { Help(p); return; } + if (!p.Supports(CpeExt.ClickDistance)) { + p.Message("Your client doesn't support changing your reach distance."); return; + } + float dist = 0; if (!CommandParser.GetReal(p, message, "Distance", ref dist, 0, 1024)) return; - int packedDist = (int)(dist * 32); + int packedDist = (int)(dist * 32); if (packedDist > short.MaxValue) { p.Message("\"{0}\", is too long a reach distance. Max is 1023 blocks.", message); - } else if (!p.Supports(CpeExt.ClickDistance)) { - p.Message("Your client doesn't support changing your reach distance."); - } else { + } else { p.Send(Packet.ClickDistance((short)packedDist)); p.ReachDistance = dist; p.Message("Set your reach distance to {0} blocks.", dist); diff --git a/MCGalaxy/Commands/Maintenance/CmdBlockSpeed.cs b/MCGalaxy/Commands/Maintenance/CmdBlockSpeed.cs index 12ebedefe..674840e8c 100644 --- a/MCGalaxy/Commands/Maintenance/CmdBlockSpeed.cs +++ b/MCGalaxy/Commands/Maintenance/CmdBlockSpeed.cs @@ -31,8 +31,7 @@ namespace MCGalaxy.Commands.Maintenance { if (cmd == "clear") { Level[] loaded = LevelInfo.Loaded.Items; foreach (Level lvl in loaded) { - lock (lvl.queueLock) - lvl.blockqueue.Clear(); + lvl.blockqueue.ClearAll(); } return; } diff --git a/MCGalaxy/Commands/building/CmdAbort.cs b/MCGalaxy/Commands/building/CmdAbort.cs index 8771b1b6d..913aa165b 100644 --- a/MCGalaxy/Commands/building/CmdAbort.cs +++ b/MCGalaxy/Commands/building/CmdAbort.cs @@ -38,7 +38,7 @@ namespace MCGalaxy.Commands.Building { p.DefaultBrushArgs = ""; p.Transform = NoTransform.Instance; - BlockQueue.RemoveAll(p); + p.level.blockqueue.RemoveAll(p); p.Message("Every toggle or action was aborted."); } diff --git a/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs b/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs index 7f7fa9d77..51694a300 100644 --- a/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs +++ b/MCGalaxy/Drawing/DrawOps/DrawOpPerformer.cs @@ -208,12 +208,11 @@ namespace MCGalaxy.Drawing.Ops { if (op.TotalModified == reloadThreshold) { if (!p.Ignores.DrawOutput) { p.Message("Changed over {0} blocks, preparing to reload map..", reloadThreshold); - } - - lock (lvl.queueLock) { lvl.blockqueue.Clear(); } + } + lvl.blockqueue.ClearAll(); } else if (op.TotalModified < reloadThreshold) { if (!Block.VisuallyEquals(old, b.Block)) { - BlockQueue.Add(p, lvl, index, b.Block); + lvl.blockqueue.Add(p, index, b.Block); } if (lvl.physics > 0) { diff --git a/MCGalaxy/Levels/BlockQueue.cs b/MCGalaxy/Levels/BlockQueue.cs index 3637313e3..d773aa30a 100644 --- a/MCGalaxy/Levels/BlockQueue.cs +++ b/MCGalaxy/Levels/BlockQueue.cs @@ -16,13 +16,13 @@ permissions and limitations under the Licenses. */ using System; +using System.Collections.Generic; using MCGalaxy.Network; using MCGalaxy.Tasks; using BlockID = System.UInt16; -namespace MCGalaxy { - - public static class BlockQueue { +namespace MCGalaxy { + public sealed class BlockQueue : List { public static int Interval = 100; public static int UpdatesPerTick = 750; @@ -31,19 +31,21 @@ namespace MCGalaxy { const int posShift = 32; const int idShift = 12; const int blockMask = (1 << 12) - 1; + readonly object locker = new object(); public static void Loop(SchedulerTask task) { Level[] loaded = LevelInfo.Loaded.Items; foreach (Level lvl in loaded) { - lock (lvl.queueLock) - ProcessLevelBlocks(lvl); + lock (lvl.blockqueue.locker) { + lvl.blockqueue.Process(lvl); + } } bulkSender.level = null; task.Delay = TimeSpan.FromMilliseconds(Interval); } - public static void Add(Player p, Level lvl, int index, BlockID block) { + public void Add(Player p, int index, BlockID block) { // Bit packing format // 32-63: index // 12-31: session ID @@ -52,37 +54,38 @@ namespace MCGalaxy { flags |= (ulong)p.SessionID << idShift; flags |= (ulong)block & blockMask; - lock (lvl.queueLock) { lvl.blockqueue.Add(flags); } + lock (locker) Add(flags); } - public static void RemoveAll(Player p) { - lock (p.level.queueLock) { - p.level.blockqueue.RemoveAll(b => (int)((b >> idShift) & Player.SessionIDMask) == p.SessionID); + public void RemoveAll(Player p) { + lock (locker) { + RemoveAll(b => (int)((b >> idShift) & Player.SessionIDMask) == p.SessionID); } } - static void ProcessLevelBlocks(Level lvl) { + public void ClearAll() { lock (locker) Clear(); } + + void Process(Level lvl) { try { - if (lvl.blockqueue.Count == 0) return; - if (!lvl.HasPlayers()) { lvl.blockqueue.Clear(); return; } + if (Count == 0) return; + if (!lvl.HasPlayers()) { Clear(); return; } bulkSender.level = lvl; - int count = UpdatesPerTick; - if (lvl.blockqueue.Count < UpdatesPerTick) - count = lvl.blockqueue.Count; + int count = Count; + if (count > UpdatesPerTick) count = UpdatesPerTick; for (int i = 0; i < count; i++) { - ulong flags = lvl.blockqueue[i]; + ulong flags = this[i]; int index = (int)(flags >> posShift); BlockID block = (BlockID)(flags & blockMask); bulkSender.Add(index, block); } bulkSender.Send(true); - lvl.blockqueue.RemoveRange(0, count); + RemoveRange(0, count); } catch (Exception e) { Logger.LogError(e); - Logger.Log(LogType.Warning, "Block cache failed for map: {0}. {1} lost.", lvl.name, lvl.blockqueue.Count); - lvl.blockqueue.Clear(); + Logger.Log(LogType.Warning, "Block cache failed for map: {0}. {1} lost.", lvl.name, Count); + Clear(); } } } diff --git a/MCGalaxy/Levels/Level.Blocks.cs b/MCGalaxy/Levels/Level.Blocks.cs index d8da50587..e96b9fb0d 100644 --- a/MCGalaxy/Levels/Level.Blocks.cs +++ b/MCGalaxy/Levels/Level.Blocks.cs @@ -412,7 +412,7 @@ namespace MCGalaxy { if (type == 1) return; // not different visually if (buffered) { - BlockQueue.Add(p, p.level, index, block); + p.level.blockqueue.Add(p, index, block); } else { Player.GlobalBlockchange(this, x, y, z, block); } diff --git a/MCGalaxy/Levels/Level.Fields.cs b/MCGalaxy/Levels/Level.Fields.cs index d10908732..d70088c69 100644 --- a/MCGalaxy/Levels/Level.Fields.cs +++ b/MCGalaxy/Levels/Level.Fields.cs @@ -71,8 +71,8 @@ namespace MCGalaxy { /// true if both worldChat and Server.worldChat are true. public bool SeesServerWideChat { get { return Config.ServerWideChat && ServerConfig.ServerWideChat; } } - internal readonly object queueLock = new object(), saveLock = new object(), botsIOLock = new object(); - public List blockqueue = new List(); + internal readonly object saveLock = new object(), botsIOLock = new object(); + public BlockQueue blockqueue = new BlockQueue(); BufferedBlockSender bulkSender; public List UndoBuffer = new List(); diff --git a/MCGalaxy/Levels/Level.cs b/MCGalaxy/Levels/Level.cs index 031bde971..c31ac37bd 100644 --- a/MCGalaxy/Levels/Level.cs +++ b/MCGalaxy/Levels/Level.cs @@ -90,8 +90,7 @@ namespace MCGalaxy { BlockDB.Cache.Clear(); Zones.Clear(); - lock (queueLock) - blockqueue.Clear(); + blockqueue.ClearAll(); lock (saveLock) { blocks = null; CustomBlocks = null; diff --git a/MCGalaxy/MCGalaxy_.csproj b/MCGalaxy/MCGalaxy_.csproj index 5fc16cbec..70da14d8c 100644 --- a/MCGalaxy/MCGalaxy_.csproj +++ b/MCGalaxy/MCGalaxy_.csproj @@ -201,6 +201,7 @@ +