diff --git a/MCGalaxy/Commands/Moderation/ZoneCmds.cs b/MCGalaxy/Commands/Moderation/ZoneCmds.cs
index 16f2cc942..54e976b9e 100644
--- a/MCGalaxy/Commands/Moderation/ZoneCmds.cs
+++ b/MCGalaxy/Commands/Moderation/ZoneCmds.cs
@@ -25,7 +25,11 @@ namespace MCGalaxy.Commands.Moderation {
public override string type { get { return CommandTypes.Moderation; } }
public override bool museumUsable { get { return false; } }
public override LevelPermission defaultRank { get { return LevelPermission.Operator; } }
-
+ public override CommandAlias[] Aliases {
+ get { return new[] { new CommandAlias("ZRemove", "del"), new CommandAlias("ZDelete", "del"),
+ new CommandAlias("ZAdd"), new CommandAlias("ZEdit", "edit") }; }
+ }
+
public override void Use(Player p, string message) {
string[] args = message.SplitSpaces();
if (message.Length == 0) { Help(p); return; }
@@ -34,17 +38,25 @@ namespace MCGalaxy.Commands.Moderation {
if (args.Length == 1) { Help(p); return; }
CreateZone(p, args, 1);
} else if (args[0].CaselessEq("del")) {
- Player.Message(p, "Place a block where you would like to delete a zone.");
- p.MakeSelection(1, null, DeleteZone);
+ if (args.Length == 1) { Help(p); return; }
+ DeleteZone(p, args);
+ } else if (args[0].CaselessEq("edit")) {
+ if (args.Length < 3) { Help(p); return; }
+ EditZone(p, args);
} else {
CreateZone(p, args, 0);
}
}
void CreateZone(Player p, string[] args, int offset) {
- Zone z = new Zone(p.level);
+ if (p.level.FindZoneExact(args[offset]) != null) {
+ Player.Message(p, "A zone with that name already exists. Use %T/zedit %Sto change it.");
+ return;
+ }
+
+ Zone z = new Zone(p.level);
z.Config.Name = args[offset];
- PermissionCmd.Do(p, args, offset + 1, false, z.Access);
+ if (!PermissionCmd.Do(p, args, offset + 1, false, z.Access)) return;
Player.Message(p, "Creating zone " + z.ColoredName);
Player.Message(p, "Place or break two blocks to determine the edges.");
@@ -52,47 +64,60 @@ namespace MCGalaxy.Commands.Moderation {
}
bool AddZone(Player p, Vec3S32[] marks, object state, ExtBlock block) {
- Zone z = (Zone)state;
- z.MinX = (ushort)Math.Min(marks[0].X, marks[1].X);
- z.MinY = (ushort)Math.Min(marks[0].Y, marks[1].Y);
- z.MinZ = (ushort)Math.Min(marks[0].Z, marks[1].Z);
- z.MaxX = (ushort)Math.Max(marks[0].X, marks[1].X);
- z.MaxY = (ushort)Math.Max(marks[0].Y, marks[1].Y);
- z.MaxZ = (ushort)Math.Max(marks[0].Z, marks[1].Z);
+ Zone zone = (Zone)state;
+ zone.MinX = (ushort)Math.Min(marks[0].X, marks[1].X);
+ zone.MinY = (ushort)Math.Min(marks[0].Y, marks[1].Y);
+ zone.MinZ = (ushort)Math.Min(marks[0].Z, marks[1].Z);
+ zone.MaxX = (ushort)Math.Max(marks[0].X, marks[1].X);
+ zone.MaxY = (ushort)Math.Max(marks[0].Y, marks[1].Y);
+ zone.MaxZ = (ushort)Math.Max(marks[0].Z, marks[1].Z);
- p.level.Zones.Add(z);
+ p.level.Zones.Add(zone);
p.level.Save(true);
- Player.Message(p, "Created zone " + z.ColoredName);
- return false;
- }
-
- bool DeleteZone(Player p, Vec3S32[] marks, object state, ExtBlock block) {
- Level lvl = p.level;
- bool foundDel = false;
- Vec3S32 P = marks[0];
-
- for (int i = 0; i < lvl.Zones.Count; i++) {
- Zone zn = lvl.Zones[i];
- if (P.X < zn.MinX || P.X > zn.MaxX || P.Y < zn.MinY || P.Y > zn.MaxY || P.Z < zn.MinZ || P.Z > zn.MaxZ) continue;
-
- if (!zn.Access.CheckDetailed(p)) {
- Player.Message(p, "Hence, you cannot delete this zone.");
- continue;
- }
-
- lvl.Zones.RemoveAt(i); i--;
- Player.Message(p, "Zone " + zn.ColoredName + " %sdeleted");
- foundDel = true;
- }
-
- if (!foundDel) Player.Message(p, "No zones found to delete.");
+ Player.Message(p, "Created zone " + zone.ColoredName);
return false;
}
+ void DeleteZone(Player p, string[] args) {
+ Level lvl = p.level;
+ Zone zone = Matcher.FindZones(p, lvl, args[1]);
+ if (zone == null) return;
+ if (!zone.Access.CheckDetailed(p)) {
+ Player.Message(p, "Hence, you cannot delete this zone."); return;
+ }
+
+ lvl.Zones.Remove(zone);
+ Player.Message(p, "Zone " + zone.ColoredName + " %Sdeleted");
+ lvl.Save();
+ }
+
+ void EditZone(Player p, string[] args) {
+ Level lvl = p.level;
+ Zone zone = Matcher.FindZones(p, lvl, args[1]);
+ if (zone == null) return;
+ if (!zone.Access.CheckDetailed(p)) {
+ Player.Message(p, "Hence, you cannot edit this zone."); return;
+ }
+
+ if (args[2].CaselessEq("col")) {
+ ColorDesc desc = default(ColorDesc);
+ if (!CommandParser.GetHex(p, args[3], ref desc)) return;
+
+ zone.Config.ShowColor = args[3];
+ zone.ShowAll(lvl);
+ } else if (args[2].CaselessEq("alpha")) {
+ if (!CommandParser.GetByte(p, args[3], "Alpha", ref zone.Config.ShowAlpha)) return;
+ zone.ShowAll(lvl);
+ } else if (!PermissionCmd.Do(p, args, 2, false, zone.Access)) {
+ return;
+ }
+ lvl.Save(true);
+ }
+
public override void Help(Player p) {
- Player.Message(p, "%T/Zone add [name] %H- Creates a zone only [name] can build in");
- Player.Message(p, "%T/Zone add [rank] %H- Creates a zone only [rank]+ can build in");
- Player.Message(p, "%T/Zone del %H- Deletes the zone clicked");
+ Player.Message(p, "%T/Zone add [name] %H- Creates a new zone");
+ Player.Message(p, "%T/Zone del [name] %H- Deletes the given zone");
+ Player.Message(p, "%T/Zone edit [name] [args] %H- Edits/Updates the given zone");
}
}
diff --git a/MCGalaxy/Commands/World/PermissionCmds.cs b/MCGalaxy/Commands/World/PermissionCmds.cs
index 2451152b2..6e0e0ba2b 100644
--- a/MCGalaxy/Commands/World/PermissionCmds.cs
+++ b/MCGalaxy/Commands/World/PermissionCmds.cs
@@ -24,19 +24,22 @@ namespace MCGalaxy.Commands.World {
public override bool museumUsable { get { return false; } }
public override LevelPermission defaultRank { get { return LevelPermission.Operator; } }
- public static void Do(Player p, string[] args, int offset, bool max, AccessController access) {
+ public static bool Do(Player p, string[] args, int offset, bool max, AccessController access) {
for (int i = offset; i < args.Length; i++) {
string arg = args[i];
if (arg[0] == '+' || arg[0] == '-') {
- SetList(p, access, arg);
+ if (!SetList(p, access, arg)) return false;
} else if (max) {
Group grp = Matcher.FindRanks(p, arg);
- if (grp != null) access.SetMax(p, grp);
+ if (grp == null) return false;
+ access.SetMax(p, grp);
} else {
Group grp = Matcher.FindRanks(p, arg);
- if (grp != null) access.SetMin(p, grp);
+ if (grp == null) return false;
+ access.SetMin(p, grp);
}
}
+ return true;
}
protected void DoLevel(Player p, string message, bool visit) {
@@ -58,20 +61,21 @@ namespace MCGalaxy.Commands.World {
Do(p, args, offset, max, access);
}
- static void SetList(Player p, AccessController access, string name) {
+ static bool SetList(Player p, AccessController access, string name) {
bool include = name[0] == '+';
string mode = include ? "whitelist" : "blacklist";
name = name.Substring(1);
if (name.Length == 0) {
- Player.Message(p, "You must provide a player name to {0}.", mode); return;
+ Player.Message(p, "You must provide a player name to {0}.", mode);
+ return false;
}
- if (!Formatter.ValidName(p, name, "player")) return;
+ if (!Formatter.ValidName(p, name, "player")) return false;
name = PlayerInfo.FindMatchesPreferOnline(p, name);
- if (name == null) return;
+ if (name == null) return false;
if (p != null && name.CaselessEq(p.name)) {
- Player.Message(p, "You cannot {0} yourself.", mode); return;
+ Player.Message(p, "You cannot {0} yourself.", mode); return false;
}
if (include) {
@@ -79,8 +83,8 @@ namespace MCGalaxy.Commands.World {
} else {
access.Blacklist(p, name);
}
- }
-
+ return true;
+ }
protected void ShowHelp(Player p, string action, string action2) {
Player.Message(p, "%T/{0} [level] [rank]", name);
@@ -93,12 +97,12 @@ namespace MCGalaxy.Commands.World {
Player.Message(p, "%HPrevents [name] from {0}ing, even if their rank can.", action2);
}
}
-
+
public sealed class CmdPermissionBuild : PermissionCmd {
public override string name { get { return "PerBuild"; } }
+ public override string shortcut { get { return "WBuild"; } }
public override CommandAlias[] Aliases {
- get { return new[] { new CommandAlias("WBuild"), new CommandAlias("WorldBuild"),
- new CommandAlias("PerBuildMax", "-max") }; }
+ get { return new[] { new CommandAlias("WorldBuild"), new CommandAlias("PerBuildMax", "-max") }; }
}
public override CommandPerm[] ExtraPerms {
get { return new[] { new CommandPerm(LevelPermission.Operator, "+ bypasses max build rank restriction") }; }
@@ -110,9 +114,9 @@ namespace MCGalaxy.Commands.World {
public sealed class CmdPermissionVisit : PermissionCmd {
public override string name { get { return "PerVisit"; } }
+ public override string shortcut { get { return "WAccess"; } }
public override CommandAlias[] Aliases {
- get { return new[] { new CommandAlias("WAccess"), new CommandAlias("WorldAccess"),
- new CommandAlias("PerVisitMax", "-max") }; }
+ get { return new[] { new CommandAlias("WorldAccess"), new CommandAlias("PerVisitMax", "-max") }; }
}
public override CommandPerm[] ExtraPerms {
get { return new[] { new CommandPerm(LevelPermission.Operator, "+ bypasses max visit rank restriction") }; }
@@ -120,5 +124,5 @@ namespace MCGalaxy.Commands.World {
public override void Use(Player p, string message) { DoLevel(p, message, true); }
public override void Help(Player p) { ShowHelp(p, "visit", "visit"); }
- }
+ }
}
\ No newline at end of file
diff --git a/MCGalaxy/CorePlugin/MiscHandlers.cs b/MCGalaxy/CorePlugin/MiscHandlers.cs
index f62bd362b..63dbbdeec 100644
--- a/MCGalaxy/CorePlugin/MiscHandlers.cs
+++ b/MCGalaxy/CorePlugin/MiscHandlers.cs
@@ -56,6 +56,11 @@ namespace MCGalaxy.Core {
p.SendCurrentEnvColors();
p.SendCurrentMapAppearance();
p.SendCurrentBlockPermissions();
+
+ // TODO: unshow old zones here??
+ if (p.Supports(CpeExt.SelectionCuboid)) {
+ foreach (Zone zn in level.Zones) { zn.Show(p); }
+ }
if (!level.Config.Guns && p.aiming) {
p.aiming = false;
diff --git a/MCGalaxy/Levels/AccessController.cs b/MCGalaxy/Levels/AccessController.cs
index 53f2396d3..70270a90d 100644
--- a/MCGalaxy/Levels/AccessController.cs
+++ b/MCGalaxy/Levels/AccessController.cs
@@ -228,8 +228,9 @@ namespace MCGalaxy {
Update();
Logger.Log(LogType.UserActivity, "{0} rank changed to {1} on {2}.", type, grp.Name, lvl.name);
Chat.MessageLevel(lvl, type + " rank changed to " + grp.ColoredName + "%S.");
- if (p != null && p.level != lvl)
+ if (p != null && p.level != lvl) {
Player.Message(p, "{0} rank changed to {1} %Son {2}%S.", type, grp.ColoredName, ColoredName);
+ }
}
public override void OnListChanged(Player p, string name, bool whitelist, bool removedFromOpposite) {
@@ -244,8 +245,9 @@ namespace MCGalaxy {
Update();
Logger.Log(LogType.UserActivity, "{0} on {1}", msg, lvl.name);
Chat.MessageLevel(lvl, msg);
- if (p != null && p.level != lvl)
+ if (p != null && p.level != lvl) {
Player.Message(p, "{0} on %S{1}", msg, ColoredName);
+ }
}
diff --git a/MCGalaxy/Levels/IO/Importers/LvlImporter.cs b/MCGalaxy/Levels/IO/Importers/LvlImporter.cs
index afabcab14..7f2310e9b 100644
--- a/MCGalaxy/Levels/IO/Importers/LvlImporter.cs
+++ b/MCGalaxy/Levels/IO/Importers/LvlImporter.cs
@@ -159,6 +159,8 @@ namespace MCGalaxy.Levels.IO {
string line = Encoding.UTF8.GetString(buffer, 0, size), key, value;
PropertiesFile.ParseLine(line, '=', out key, out value);
if (key == null) continue;
+
+ value = value.Trim();
ConfigElement.Parse(elems, key, value, z.Config);
}
diff --git a/MCGalaxy/Levels/Level.cs b/MCGalaxy/Levels/Level.cs
index c3c348a5f..d0cd5ecf1 100644
--- a/MCGalaxy/Levels/Level.cs
+++ b/MCGalaxy/Levels/Level.cs
@@ -103,6 +103,13 @@ namespace MCGalaxy {
if (Config.MOTD != "ignore") return Config.MOTD;
return String.IsNullOrEmpty(p.group.MOTD) ? ServerConfig.MOTD : p.group.MOTD;
}
+
+ public Zone FindZoneExact(string name) {
+ foreach (Zone zone in Zones) {
+ if (zone.Config.Name.CaselessEq(name)) return zone;
+ }
+ return null;
+ }
/// Whether block changes made on this level should be saved to the BlockDB and .lvl files.
public bool ShouldSaveChanges() {
diff --git a/MCGalaxy/Levels/Zone.cs b/MCGalaxy/Levels/Zone.cs
index ab8ecfeee..ac75f0b1e 100644
--- a/MCGalaxy/Levels/Zone.cs
+++ b/MCGalaxy/Levels/Zone.cs
@@ -18,16 +18,22 @@
using System;
using System.Collections.Generic;
using MCGalaxy.Config;
+using MCGalaxy.Network;
+using MCGalaxy.Maths;
namespace MCGalaxy {
public sealed class ZoneConfig : AreaConfig {
[ConfigString("Name", "General", "", true)]
public string Name = "";
+ [ConfigString("ShowColor", "General", "", true)]
+ public string ShowColor = "";
+ [ConfigByte("ShowAlpha", "General", 0)]
+ public byte ShowAlpha = 0;
public string Color { get { return Group.GetColor(BuildMin); } }
- }
-
+ }
+
/// Encapuslates build access permissions for a zone.
public sealed class ZoneAccessController : AccessController {
@@ -47,7 +53,7 @@ namespace MCGalaxy {
get { return cfg.BuildMax; } set { cfg.BuildMax = value; }
}
- public override List Whitelisted { get { return cfg.BuildWhitelist; } }
+ public override List Whitelisted { get { return cfg.BuildWhitelist; } }
public override List Blacklisted { get { return cfg.BuildBlacklist; } }
protected override string ColoredName { get { return "zone " + cfg.Color + cfg.Name; } }
@@ -59,9 +65,10 @@ namespace MCGalaxy {
public override void OnPermissionChanged(Player p, Group grp, string type) {
Update();
Logger.Log(LogType.UserActivity, "{0} rank changed to {1} in zone {2}.", type, grp.Name, cfg.Name);
- Chat.MessageLevel(lvl, type + " rank changed to " + grp.ColoredName + "%S.");
- if (p != null && p.level != lvl)
+ Chat.MessageLevel(lvl, type + " rank changed to " + grp.ColoredName + " %Sin zone " + cfg.Color + cfg.Name);
+ if (p != null && p.level != lvl) {
Player.Message(p, "{0} rank changed to {1} %Sin {2}%S.", type, grp.ColoredName, ColoredName);
+ }
}
public override void OnListChanged(Player p, string name, bool whitelist, bool removedFromOpposite) {
@@ -74,10 +81,11 @@ namespace MCGalaxy {
Update();
Logger.Log(LogType.UserActivity, "{0} in zone {1}", msg, cfg.Name);
- Chat.MessageLevel(lvl, msg);
- if (p != null && p.level != lvl)
+ Chat.MessageLevel(lvl, msg + " in zone " + cfg.Color + cfg.Name);
+ if (p != null && p.level != lvl) {
Player.Message(p, "{0} in %S{1}", msg, ColoredName);
- }
+ }
+ }
void Update() { lvl.Save(true); }
}
@@ -85,6 +93,7 @@ namespace MCGalaxy {
public class Zone {
public ushort MinX, MinY, MinZ;
public ushort MaxX, MaxY, MaxZ;
+ public byte ID;
public ZoneConfig Config;
public ZoneAccessController Access;
@@ -95,10 +104,28 @@ namespace MCGalaxy {
}
public bool CoversMap(Level lvl) {
- return MinX == 0 && MinY == 0 && MinZ == 0 &&
+ return MinX == 0 && MinY == 0 && MinZ == 0 &&
MaxX == lvl.Width - 1 && MaxY == lvl.Height - 1 && MaxZ == lvl.Length - 1;
}
+ public bool Shows { get { return Config.ShowAlpha != 0 && Config.ShowColor != ""; } }
+ public void Show(Player p) {
+ if (!p.Supports(CpeExt.SelectionCuboid) || !Shows) return;
+
+ ColorDesc col = Colors.ParseHex(Config.ShowColor);
+ p.Send(Packet.MakeSelection(
+ ID, "", new Vec3U16(MinX, MinY, MinZ),
+ new Vec3U16((ushort)(MaxX + 1), (ushort)(MaxY + 1), (ushort)(MaxZ + 1)),
+ col.R, col.G, col.B, Config.ShowAlpha, p.hasCP437));
+ }
+
+ public void ShowAll(Level lvl) {
+ Player[] players = PlayerInfo.Online.Items;
+ foreach (Player p in players) {
+ if (p.level == lvl) Show(p);
+ }
+ }
+
public Zone(Level lvl) {
Config = new ZoneConfig();
Access = new ZoneAccessController(lvl, Config);
diff --git a/MCGalaxy/util/Formatting/Matcher.cs b/MCGalaxy/util/Formatting/Matcher.cs
index a9ce1e66f..11753a7c0 100644
--- a/MCGalaxy/util/Formatting/Matcher.cs
+++ b/MCGalaxy/util/Formatting/Matcher.cs
@@ -87,6 +87,13 @@ namespace MCGalaxy {
null, wp => wp.Name, group);
}
+ /// Find partial matches of 'name' against the list of zones in a map.
+ public static Zone FindZones(Player p, Level lvl, string name) {
+ int matches = 0;
+ return Find(p, name, out matches, lvl.Zones,
+ null, z => z.Config.Name, "zones");
+ }
+
/// Finds partial matches of 'name' against the names of the items in the 'items' enumerable.
/// If exactly one match, the matching item.