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) {
|
||||
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);
|
||||
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 {
|
||||
p.Send(Packet.ClickDistance((short)packedDist));
|
||||
p.ReachDistance = dist;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.");
|
||||
}
|
||||
|
||||
|
@ -209,11 +209,10 @@ namespace MCGalaxy.Drawing.Ops {
|
||||
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) {
|
||||
|
@ -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 {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>();
|
||||
|
@ -90,8 +90,7 @@ namespace MCGalaxy {
|
||||
BlockDB.Cache.Clear();
|
||||
Zones.Clear();
|
||||
|
||||
lock (queueLock)
|
||||
blockqueue.Clear();
|
||||
blockqueue.ClearAll();
|
||||
lock (saveLock) {
|
||||
blocks = null;
|
||||
CustomBlocks = null;
|
||||
|
@ -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" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user