mirror of
https://github.com/ClassiCube/MCGalaxy.git
synced 2025-09-22 12:05:51 -04:00
Add /hold to make you hold a particular block
This commit is contained in:
parent
1d5a01231c
commit
9b1e9a7d7d
55
MCGalaxy/Commands/CPE/CmdHold.cs
Normal file
55
MCGalaxy/Commands/CPE/CmdHold.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,14 +27,16 @@ namespace MCGalaxy.Commands.CPE {
|
|||||||
|
|
||||||
public override void Use(Player p, string message, CommandData data) {
|
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;
|
float dist = 0;
|
||||||
if (!CommandParser.GetReal(p, message, "Distance", ref dist, 0, 1024)) return;
|
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) {
|
if (packedDist > short.MaxValue) {
|
||||||
p.Message("\"{0}\", is too long a reach distance. Max is 1023 blocks.", message);
|
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.Send(Packet.ClickDistance((short)packedDist));
|
||||||
p.ReachDistance = dist;
|
p.ReachDistance = dist;
|
||||||
|
@ -31,8 +31,7 @@ namespace MCGalaxy.Commands.Maintenance {
|
|||||||
if (cmd == "clear") {
|
if (cmd == "clear") {
|
||||||
Level[] loaded = LevelInfo.Loaded.Items;
|
Level[] loaded = LevelInfo.Loaded.Items;
|
||||||
foreach (Level lvl in loaded) {
|
foreach (Level lvl in loaded) {
|
||||||
lock (lvl.queueLock)
|
lvl.blockqueue.ClearAll();
|
||||||
lvl.blockqueue.Clear();
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ namespace MCGalaxy.Commands.Building {
|
|||||||
p.DefaultBrushArgs = "";
|
p.DefaultBrushArgs = "";
|
||||||
p.Transform = NoTransform.Instance;
|
p.Transform = NoTransform.Instance;
|
||||||
|
|
||||||
BlockQueue.RemoveAll(p);
|
p.level.blockqueue.RemoveAll(p);
|
||||||
p.Message("Every toggle or action was aborted.");
|
p.Message("Every toggle or action was aborted.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,11 +209,10 @@ namespace MCGalaxy.Drawing.Ops {
|
|||||||
if (!p.Ignores.DrawOutput) {
|
if (!p.Ignores.DrawOutput) {
|
||||||
p.Message("Changed over {0} blocks, preparing to reload map..", reloadThreshold);
|
p.Message("Changed over {0} blocks, preparing to reload map..", reloadThreshold);
|
||||||
}
|
}
|
||||||
|
lvl.blockqueue.ClearAll();
|
||||||
lock (lvl.queueLock) { lvl.blockqueue.Clear(); }
|
|
||||||
} else if (op.TotalModified < reloadThreshold) {
|
} else if (op.TotalModified < reloadThreshold) {
|
||||||
if (!Block.VisuallyEquals(old, b.Block)) {
|
if (!Block.VisuallyEquals(old, b.Block)) {
|
||||||
BlockQueue.Add(p, lvl, index, b.Block);
|
lvl.blockqueue.Add(p, index, b.Block);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lvl.physics > 0) {
|
if (lvl.physics > 0) {
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
permissions and limitations under the Licenses.
|
permissions and limitations under the Licenses.
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using MCGalaxy.Network;
|
using MCGalaxy.Network;
|
||||||
using MCGalaxy.Tasks;
|
using MCGalaxy.Tasks;
|
||||||
using BlockID = System.UInt16;
|
using BlockID = System.UInt16;
|
||||||
|
|
||||||
namespace MCGalaxy {
|
namespace MCGalaxy {
|
||||||
|
public sealed class BlockQueue : List<ulong> {
|
||||||
public static class BlockQueue {
|
|
||||||
|
|
||||||
public static int Interval = 100;
|
public static int Interval = 100;
|
||||||
public static int UpdatesPerTick = 750;
|
public static int UpdatesPerTick = 750;
|
||||||
@ -31,19 +31,21 @@ namespace MCGalaxy {
|
|||||||
const int posShift = 32;
|
const int posShift = 32;
|
||||||
const int idShift = 12;
|
const int idShift = 12;
|
||||||
const int blockMask = (1 << 12) - 1;
|
const int blockMask = (1 << 12) - 1;
|
||||||
|
readonly object locker = new object();
|
||||||
|
|
||||||
public static void Loop(SchedulerTask task) {
|
public static void Loop(SchedulerTask task) {
|
||||||
Level[] loaded = LevelInfo.Loaded.Items;
|
Level[] loaded = LevelInfo.Loaded.Items;
|
||||||
foreach (Level lvl in loaded) {
|
foreach (Level lvl in loaded) {
|
||||||
lock (lvl.queueLock)
|
lock (lvl.blockqueue.locker) {
|
||||||
ProcessLevelBlocks(lvl);
|
lvl.blockqueue.Process(lvl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bulkSender.level = null;
|
bulkSender.level = null;
|
||||||
task.Delay = TimeSpan.FromMilliseconds(Interval);
|
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
|
// Bit packing format
|
||||||
// 32-63: index
|
// 32-63: index
|
||||||
// 12-31: session ID
|
// 12-31: session ID
|
||||||
@ -52,37 +54,38 @@ namespace MCGalaxy {
|
|||||||
flags |= (ulong)p.SessionID << idShift;
|
flags |= (ulong)p.SessionID << idShift;
|
||||||
flags |= (ulong)block & blockMask;
|
flags |= (ulong)block & blockMask;
|
||||||
|
|
||||||
lock (lvl.queueLock) { lvl.blockqueue.Add(flags); }
|
lock (locker) Add(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RemoveAll(Player p) {
|
public void RemoveAll(Player p) {
|
||||||
lock (p.level.queueLock) {
|
lock (locker) {
|
||||||
p.level.blockqueue.RemoveAll(b => (int)((b >> idShift) & Player.SessionIDMask) == p.SessionID);
|
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 {
|
try {
|
||||||
if (lvl.blockqueue.Count == 0) return;
|
if (Count == 0) return;
|
||||||
if (!lvl.HasPlayers()) { lvl.blockqueue.Clear(); return; }
|
if (!lvl.HasPlayers()) { Clear(); return; }
|
||||||
|
|
||||||
bulkSender.level = lvl;
|
bulkSender.level = lvl;
|
||||||
int count = UpdatesPerTick;
|
int count = Count;
|
||||||
if (lvl.blockqueue.Count < UpdatesPerTick)
|
if (count > UpdatesPerTick) count = UpdatesPerTick;
|
||||||
count = lvl.blockqueue.Count;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
ulong flags = lvl.blockqueue[i];
|
ulong flags = this[i];
|
||||||
int index = (int)(flags >> posShift);
|
int index = (int)(flags >> posShift);
|
||||||
BlockID block = (BlockID)(flags & blockMask);
|
BlockID block = (BlockID)(flags & blockMask);
|
||||||
bulkSender.Add(index, block);
|
bulkSender.Add(index, block);
|
||||||
}
|
}
|
||||||
bulkSender.Send(true);
|
bulkSender.Send(true);
|
||||||
lvl.blockqueue.RemoveRange(0, count);
|
RemoveRange(0, count);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Logger.LogError(e);
|
Logger.LogError(e);
|
||||||
Logger.Log(LogType.Warning, "Block cache failed for map: {0}. {1} lost.", lvl.name, lvl.blockqueue.Count);
|
Logger.Log(LogType.Warning, "Block cache failed for map: {0}. {1} lost.", lvl.name, Count);
|
||||||
lvl.blockqueue.Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,7 +412,7 @@ namespace MCGalaxy {
|
|||||||
if (type == 1) return; // not different visually
|
if (type == 1) return; // not different visually
|
||||||
|
|
||||||
if (buffered) {
|
if (buffered) {
|
||||||
BlockQueue.Add(p, p.level, index, block);
|
p.level.blockqueue.Add(p, index, block);
|
||||||
} else {
|
} else {
|
||||||
Player.GlobalBlockchange(this, x, y, z, block);
|
Player.GlobalBlockchange(this, x, y, z, block);
|
||||||
}
|
}
|
||||||
|
@ -71,8 +71,8 @@ namespace MCGalaxy {
|
|||||||
/// <remarks> true if both worldChat and Server.worldChat are true. </remarks>
|
/// <remarks> true if both worldChat and Server.worldChat are true. </remarks>
|
||||||
public bool SeesServerWideChat { get { return Config.ServerWideChat && ServerConfig.ServerWideChat; } }
|
public bool SeesServerWideChat { get { return Config.ServerWideChat && ServerConfig.ServerWideChat; } }
|
||||||
|
|
||||||
internal readonly object queueLock = new object(), saveLock = new object(), botsIOLock = new object();
|
internal readonly object saveLock = new object(), botsIOLock = new object();
|
||||||
public List<ulong> blockqueue = new List<ulong>();
|
public BlockQueue blockqueue = new BlockQueue();
|
||||||
BufferedBlockSender bulkSender;
|
BufferedBlockSender bulkSender;
|
||||||
|
|
||||||
public List<UndoPos> UndoBuffer = new List<UndoPos>();
|
public List<UndoPos> UndoBuffer = new List<UndoPos>();
|
||||||
|
@ -90,8 +90,7 @@ namespace MCGalaxy {
|
|||||||
BlockDB.Cache.Clear();
|
BlockDB.Cache.Clear();
|
||||||
Zones.Clear();
|
Zones.Clear();
|
||||||
|
|
||||||
lock (queueLock)
|
blockqueue.ClearAll();
|
||||||
blockqueue.Clear();
|
|
||||||
lock (saveLock) {
|
lock (saveLock) {
|
||||||
blocks = null;
|
blocks = null;
|
||||||
CustomBlocks = null;
|
CustomBlocks = null;
|
||||||
|
@ -201,6 +201,7 @@
|
|||||||
<Compile Include="Commands\CPE\CmdCustomColors.cs" />
|
<Compile Include="Commands\CPE\CmdCustomColors.cs" />
|
||||||
<Compile Include="Commands\CPE\CmdEntityRot.cs" />
|
<Compile Include="Commands\CPE\CmdEntityRot.cs" />
|
||||||
<Compile Include="Commands\CPE\CmdEnvironment.cs" />
|
<Compile Include="Commands\CPE\CmdEnvironment.cs" />
|
||||||
|
<Compile Include="Commands\CPE\CmdHold.cs" />
|
||||||
<Compile Include="Commands\CPE\CmdModel.cs" />
|
<Compile Include="Commands\CPE\CmdModel.cs" />
|
||||||
<Compile Include="Commands\CPE\CmdPing.cs" />
|
<Compile Include="Commands\CPE\CmdPing.cs" />
|
||||||
<Compile Include="Commands\CPE\CmdReachDistance.cs" />
|
<Compile Include="Commands\CPE\CmdReachDistance.cs" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user