Add /hold to make you hold a particular block

This commit is contained in:
UnknownShadow200 2018-07-11 13:08:50 +10:00
parent 1d5a01231c
commit 9b1e9a7d7d
10 changed files with 97 additions and 39 deletions

View File

@ -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] <locked>");
p.Message("%HMakes you hold the given block in your hand");
p.Message("%H <locked> optionally prevents you from changing it");
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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.");
}

View File

@ -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) {

View File

@ -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<ulong> {
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();
}
}
}

View File

@ -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);
}

View File

@ -71,8 +71,8 @@ namespace MCGalaxy {
/// <remarks> true if both worldChat and Server.worldChat are true. </remarks>
public bool SeesServerWideChat { get { return Config.ServerWideChat && ServerConfig.ServerWideChat; } }
internal readonly object queueLock = new object(), saveLock = new object(), botsIOLock = new object();
public List<ulong> blockqueue = new List<ulong>();
internal readonly object saveLock = new object(), botsIOLock = new object();
public BlockQueue blockqueue = new BlockQueue();
BufferedBlockSender bulkSender;
public List<UndoPos> UndoBuffer = new List<UndoPos>();

View File

@ -90,8 +90,7 @@ namespace MCGalaxy {
BlockDB.Cache.Clear();
Zones.Clear();
lock (queueLock)
blockqueue.Clear();
blockqueue.ClearAll();
lock (saveLock) {
blocks = null;
CustomBlocks = null;

View File

@ -201,6 +201,7 @@
<Compile Include="Commands\CPE\CmdCustomColors.cs" />
<Compile Include="Commands\CPE\CmdEntityRot.cs" />
<Compile Include="Commands\CPE\CmdEnvironment.cs" />
<Compile Include="Commands\CPE\CmdHold.cs" />
<Compile Include="Commands\CPE\CmdModel.cs" />
<Compile Include="Commands\CPE\CmdPing.cs" />
<Compile Include="Commands\CPE\CmdReachDistance.cs" />