From 060e48487d055f30307aef2381143298f27d8740 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 24 Aug 2016 12:30:13 +1000 Subject: [PATCH 1/7] Create LevelAccess class, for a more consistent and modular way of controlling visit/build access permissions. --- Levels/Level.Fields.cs | 9 +++- Levels/Level.cs | 13 +++--- Levels/LevelAccess.cs | 93 ++++++++++++++++++++++++++++++++++++++++++ MCGalaxy_.csproj | 1 + 4 files changed, 106 insertions(+), 10 deletions(-) create mode 100644 Levels/LevelAccess.cs diff --git a/Levels/Level.Fields.cs b/Levels/Level.Fields.cs index d7e7b19bd..e7ef6d8d4 100644 --- a/Levels/Level.Fields.cs +++ b/Levels/Level.Fields.cs @@ -141,6 +141,8 @@ namespace MCGalaxy { public bool Buildable = true; [ConfigBool("Deletable", "Permissions", null, true)] public bool Deletable = true; + public LevelAccess VisitAccess, BuildAccess; + [ConfigPerm("PerBuildMax", "Permissions", null, LevelPermission.Nobody, true)] public LevelPermission perbuildmax = LevelPermission.Nobody; [ConfigPerm("PerBuild", "Permissions", null, LevelPermission.Guest, true)] @@ -149,13 +151,16 @@ namespace MCGalaxy { [ConfigPerm("PerVisit", "Permissions", null, LevelPermission.Guest, true)] public LevelPermission permissionvisit = LevelPermission.Guest; [ConfigPerm("PerVisitMax", "Permissions", null, LevelPermission.Nobody, true)] - public LevelPermission pervisitmax = LevelPermission.Nobody; + public LevelPermission pervisitmax = LevelPermission.Nobody; // Other blacklists/whitelists [ConfigStringList("VisitWhitelist", "Permissions", null)] public List VisitWhitelist = new List(); [ConfigStringList("VisitBlacklist", "Permissions", null)] public List VisitBlacklist = new List(); - + [ConfigStringList("BuildWhitelist", "Permissions", null)] + public List BuildWhitelist = new List(); + [ConfigStringList("BuildBlacklist", "Permissions", null)] + public List BuildBlacklist = new List(); // Physics fields and settings public int physics { diff --git a/Levels/Level.cs b/Levels/Level.cs index 6a82c19b4..9cfb69440 100644 --- a/Levels/Level.cs +++ b/Levels/Level.cs @@ -60,6 +60,9 @@ namespace MCGalaxy { if (Height < 16) Height = 16; if (Length < 16) Length = 16; + VisitAccess = new LevelAccess(this, true); + BuildAccess = new LevelAccess(this, false); + #pragma warning disable 0612 width = Width; length = Height; @@ -136,17 +139,11 @@ namespace MCGalaxy { public bool CanJoin(Player p) { if (p == null) return true; - if (Player.BlacklistCheck(p.name, name) || VisitBlacklist.CaselessContains(p.name)) { + if (Player.BlacklistCheck(p.name, name)) { Player.Message(p, "You are blacklisted from going to {0}.", name); return false; } - bool whitelisted = VisitWhitelist.CaselessContains(p.name); - if (!p.ignorePermission && !whitelisted && p.Rank < permissionvisit) { - Player.Message(p, "You are not allowed to go to {0}.", name); return false; - } - if (!p.ignorePermission && !whitelisted && p.Rank > pervisitmax && !p.group.CanExecute("pervisitmax")) { - Player.Message(p, "Your rank must be ranked {1} or lower to go to {0}.", name, pervisitmax); return false; - } + if (!VisitAccess.CheckDetailed(p, p.ignorePermission)) return false; if (File.Exists("text/lockdown/map/" + name)) { Player.Message(p, "The level " + name + " is locked."); return false; } diff --git a/Levels/LevelAccess.cs b/Levels/LevelAccess.cs new file mode 100644 index 000000000..2af60a6d5 --- /dev/null +++ b/Levels/LevelAccess.cs @@ -0,0 +1,93 @@ +/* + 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 System; +using System.Collections.Generic; + +namespace MCGalaxy { + + /// Encapuslates access permissions (visit or build) for a level. + public sealed class LevelAccess { + + /// Whether these access permissions apply to + /// visit (true) or build (false) permission for the level. + public readonly bool IsVisit; + readonly Level lvl; + + public LevelAccess(Level lvl, bool isVisit) { + this.lvl = lvl; + IsVisit = isVisit; + } + + /// Lowest allowed rank. + public LevelPermission Min { + get { return IsVisit ? lvl.permissionvisit : lvl.permissionbuild; } + } + + /// Highest allowed rank. + public LevelPermission Max { + get { return IsVisit ? lvl.pervisitmax : lvl.perbuildmax; } + } + + /// List of always allowed players, overrides rank allowances. + public List Whitelisted { + get { return IsVisit ? lvl.VisitWhitelist : lvl.BuildWhitelist; } + } + + /// List of never allowed players, ignores rank allowances. + public List Blacklisted { + get { return IsVisit ? lvl.VisitBlacklist : lvl.BuildBlacklist; } + } + + /// Returns whether the given player is allowed by these access permissions. + public bool Check(Player p, bool ignoreRankPerm = false) { + if (Blacklisted.CaselessContains(p.name)) return false; + if (Whitelisted.CaselessContains(p.name) || ignoreRankPerm) return true; + + if (p.Rank < Min) return false; + string maxCmd = IsVisit ? "pervisitmax" : "perbuildmax"; + if (p.Rank > Max && !p.group.CanExecute(maxCmd)) return false; + return true; + } + + /// Returns whether the given player is allowed for these access permissions. + /// If the player is not allowed by these access permissions, + /// sends a message to the player describing why they are not. + public bool CheckDetailed(Player p, bool ignoreRankPerm = false) { + string name = lvl.name; + string action = IsVisit ? "going to" : "building in"; + if (Blacklisted.CaselessContains(p.name)) { + Player.Message(p, "You are blacklisted from {1} {0}.", name, action); return false; + } + if (Whitelisted.CaselessContains(p.name) || ignoreRankPerm) return true; + + action = IsVisit? "go to" : "build in"; + if (p.Rank < Min) { + Group grp = Group.findPerm(Min); + string grpName = grp == null ? "&f" + Min : grp.ColoredName; + Player.Message(p, "Only {2}%S+ may {1} {0}.", name, action, grpName); return false; + } + + string maxCmd = IsVisit ? "pervisitmax" : "perbuildmax"; + if (p.Rank > Max && !p.group.CanExecute(maxCmd)) { + Group grp = Group.findPerm(Max); + string grpName = grp == null ? "&f" + Max : grp.ColoredName; + Player.Message(p, "Only {2} and below may {1} in {0}.", name, action, grpName) return false; + } + } + } +} diff --git a/MCGalaxy_.csproj b/MCGalaxy_.csproj index 2ee79ff9f..2802ed379 100644 --- a/MCGalaxy_.csproj +++ b/MCGalaxy_.csproj @@ -497,6 +497,7 @@ + From 38eb620214a51f863074dc6f03503bd4ae8e83ad Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 24 Aug 2016 12:42:00 +1000 Subject: [PATCH 2/7] Latest backup in /mi uses relative time now. --- Commands/Information/CmdMapInfo.cs | 7 ++++--- Levels/LevelAccess.cs | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Commands/Information/CmdMapInfo.cs b/Commands/Information/CmdMapInfo.cs index 22c165497..79dd06602 100644 --- a/Commands/Information/CmdMapInfo.cs +++ b/Commands/Information/CmdMapInfo.cs @@ -65,9 +65,10 @@ namespace MCGalaxy.Commands { } if (Directory.Exists(Server.backupLocation + "/" + data.Name)) { - int latestBackup = Directory.GetDirectories(Server.backupLocation + "/" + data.Name).Length; - DateTime time = Directory.GetCreationTime(LevelInfo.BackupPath(data.Name, latestBackup.ToString())); - Player.Message(p, " Latest backup: &a{0} %Sat &a" + time.ToString("yyyy-MM-dd HH:mm:ss"), latestBackup); + int latest = Directory.GetDirectories(Server.backupLocation + "/" + data.Name).Length; + DateTime time = File.GetCreationTimeUtc(LevelInfo.BackupPath(data.Name, latest.ToString())); + TimeSpan delta = DateTime.UtcNow - time; + Player.Message(p, " Latest backup: &a{0} %S({1} ago)", latest, delta.Shorten()); } else { Player.Message(p, " No backups for this map exist yet."); } diff --git a/Levels/LevelAccess.cs b/Levels/LevelAccess.cs index 2af60a6d5..70fe33e92 100644 --- a/Levels/LevelAccess.cs +++ b/Levels/LevelAccess.cs @@ -86,8 +86,9 @@ namespace MCGalaxy { if (p.Rank > Max && !p.group.CanExecute(maxCmd)) { Group grp = Group.findPerm(Max); string grpName = grp == null ? "&f" + Max : grp.ColoredName; - Player.Message(p, "Only {2} and below may {1} in {0}.", name, action, grpName) return false; + Player.Message(p, "Only {2} and below may {1} in {0}.", name, action, grpName); return false; } + return true; } } } From 4c8e6fd95b82f8e6e2445e53f891b5e05d0c33e6 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 24 Aug 2016 16:15:39 +1000 Subject: [PATCH 3/7] Implement proper access permission checking for /perbuild too. --- Commands/World/CmdMuseum.cs | 2 +- Commands/World/PermissionCmd.cs | 12 ++++++ Levels/IO/McfFile.cs | 1 - Levels/Level.Blocks.cs | 75 ++++++++++++--------------------- Levels/LevelAccess.cs | 2 +- Network/Player.Networking.cs | 1 + Player/Player.Fields.cs | 2 + 7 files changed, 44 insertions(+), 51 deletions(-) diff --git a/Commands/World/CmdMuseum.cs b/Commands/World/CmdMuseum.cs index cf1d5056d..940b5db02 100644 --- a/Commands/World/CmdMuseum.cs +++ b/Commands/World/CmdMuseum.cs @@ -41,7 +41,7 @@ namespace MCGalaxy.Commands.World { Level lvl = LvlFile.Load(name, path); lvl.setPhysics(0); lvl.backedup = true; - lvl.permissionbuild = LevelPermission.Admin; + lvl.permissionbuild = LevelPermission.Nobody; lvl.jailx = (ushort)(lvl.spawnx * 32); lvl.jaily = (ushort)(lvl.spawny * 32); diff --git a/Commands/World/PermissionCmd.cs b/Commands/World/PermissionCmd.cs index 517707de2..3a3cd2df0 100644 --- a/Commands/World/PermissionCmd.cs +++ b/Commands/World/PermissionCmd.cs @@ -49,7 +49,9 @@ namespace MCGalaxy.Commands.World { } setter(level, grp.Permission); + UpdateAllowBuild(level); Level.SaveSettings(level); + Server.s.Log(level.name + " " + target + " permission changed to " + grp.Permission + "."); Chat.MessageLevel(level, target + " permission changed to " + grp.ColoredName + "%S."); if (p == null || p.level != level) @@ -95,12 +97,22 @@ namespace MCGalaxy.Commands.World { list.Add(name); other.CaselessRemove(name); + UpdateAllowBuild(level); Level.SaveSettings(level); + string msg = name + " was " + target + " " + mode + "ed"; Server.s.Log(msg + " on " + level.name); Chat.MessageLevel(level, msg); if (p == null || p.level != level) Player.Message(p, msg + " on {0}.", level.name); } + + static void UpdateAllowBuild(Level level) { + Player[] players = PlayerInfo.Online.Items; + foreach (Player p in players) { + if (p.level != level) continue; + p.AllowBuild = level.BuildAccess.Check(p, false); + } + } } } \ No newline at end of file diff --git a/Levels/IO/McfFile.cs b/Levels/IO/McfFile.cs index 9f7689c00..3f5c59cf1 100644 --- a/Levels/IO/McfFile.cs +++ b/Levels/IO/McfFile.cs @@ -41,7 +41,6 @@ namespace MCGalaxy.Levels.IO { ushort height = BitConverter.ToUInt16(header, 4); Level lvl = new Level(name, width, height, length); - lvl.permissionbuild = (LevelPermission)30; lvl.spawnx = BitConverter.ToUInt16(header, 6); lvl.spawnz = BitConverter.ToUInt16(header, 8); lvl.spawny = BitConverter.ToUInt16(header, 10); diff --git a/Levels/Level.Blocks.cs b/Levels/Level.Blocks.cs index c8c9173e1..2614a3685 100644 --- a/Levels/Level.Blocks.cs +++ b/Levels/Level.Blocks.cs @@ -173,28 +173,27 @@ namespace MCGalaxy { return true; } - bool CheckZonePerms(Player p, ushort x, ushort y, ushort z, - ref bool AllowBuild, ref bool inZone, ref string Owners) { + bool CheckZonePerms(Player p, ushort x, ushort y, ushort z, ref bool inZone) { if (p.Rank < LevelPermission.Admin) { - bool foundDel = FindZones(p, x, y, z, ref inZone, ref AllowBuild, ref Owners); - if (!AllowBuild) { - if (p.ZoneSpam <= DateTime.UtcNow) { - if (Owners != "") - Player.Message(p, "This zone belongs to &b" + Owners.Remove(0, 2) + "."); - else - Player.Message(p, "This zone belongs to no one."); - p.ZoneSpam = DateTime.UtcNow.AddSeconds(2); - } - return false; - } + string owners = ""; + bool zoneAllow = FindZones(p, x, y, z, ref inZone, ref owners); + if (zoneAllow) return true; + if (p.ZoneSpam > DateTime.UtcNow) return false; + + if (owners != "") + Player.Message(p, "This zone belongs to &b" + owners.Remove(0, 2) + "."); + else + Player.Message(p, "This zone belongs to no one."); + p.ZoneSpam = DateTime.UtcNow.AddSeconds(2); + return false; } return true; } bool FindZones(Player p, ushort x, ushort y, ushort z, - ref bool inZone, ref bool AllowBuild, ref string Owners) { - if (ZoneList.Count == 0) { AllowBuild = true; return false; } - bool foundDel = false; + ref bool inZone, ref string Owners) { + if (ZoneList.Count == 0) return true; + bool zoneAllow = true; for (int i = 0; i < ZoneList.Count; i++) { Zone zn = ZoneList[i]; @@ -204,39 +203,23 @@ namespace MCGalaxy { inZone = true; if (zn.Owner.Length >= 3 && zn.Owner.StartsWith("grp")) { string grpName = zn.Owner.Substring(3); - if (Group.Find(grpName).Permission <= p.Rank) { - AllowBuild = true; break; - } - AllowBuild = false; + if (Group.Find(grpName).Permission <= p.Rank) return true; Owners += ", " + grpName; } else { - if (zn.Owner.CaselessEq(p.name)) { - AllowBuild = true; break; - } - AllowBuild = false; + if (zn.Owner.CaselessEq(p.name)) return true; Owners += ", " + zn.Owner; } + zoneAllow = false; } - return foundDel; + return zoneAllow; } - bool CheckRank(Player p, bool AllowBuild, bool inZone) { - if (p.Rank < permissionbuild && (!inZone || !AllowBuild)) { - if (p.ZoneSpam <= DateTime.UtcNow) { - Player.Message(p, "Must be at least " + PermissionToName(permissionbuild) + " to build here"); - p.ZoneSpam = DateTime.UtcNow.AddSeconds(2); - } - return false; + bool CheckRank(Player p) { + if (p.ZoneSpam <= DateTime.UtcNow) { + BuildAccess.CheckDetailed(p, false); + p.ZoneSpam = DateTime.UtcNow.AddSeconds(2); } - - if (p.Rank > perbuildmax && (!inZone || !AllowBuild) && !p.group.CanExecute("perbuildmax")) { - if (p.ZoneSpam <= DateTime.UtcNow) { - Player.Message(p, "Your rank must be " + perbuildmax + " or lower to build here!"); - p.ZoneSpam = DateTime.UtcNow.AddSeconds(2); - } - return false; - } - return true; + return p.AllowBuild; } public bool CheckAffectPermissions(Player p, ushort x, ushort y, ushort z, @@ -244,13 +227,9 @@ namespace MCGalaxy { if (!Block.AllowBreak(b) && !Block.canPlace(p, b) && !Block.BuildIn(b)) return false; if (p.PlayingTntWars && !CheckTNTWarsChange(p, x, y, z, ref type)) return false; - string Owners = ""; - bool AllowBuild = true, inZone = false; - if (!CheckZonePerms(p, x, y, z, ref AllowBuild, ref inZone, ref Owners)) - return false; - if (Owners.Length == 0 && !CheckRank(p, AllowBuild, inZone)) - return false; - return true; + bool inZone = false; + if (!CheckZonePerms(p, x, y, z, ref inZone)) return false; + return inZone || CheckRank(p); } public void Blockchange(Player p, ushort x, ushort y, ushort z, diff --git a/Levels/LevelAccess.cs b/Levels/LevelAccess.cs index 70fe33e92..31e3156f4 100644 --- a/Levels/LevelAccess.cs +++ b/Levels/LevelAccess.cs @@ -86,7 +86,7 @@ namespace MCGalaxy { if (p.Rank > Max && !p.group.CanExecute(maxCmd)) { Group grp = Group.findPerm(Max); string grpName = grp == null ? "&f" + Max : grp.ColoredName; - Player.Message(p, "Only {2} and below may {1} in {0}.", name, action, grpName); return false; + Player.Message(p, "Only {2}%S and below may {1} {0}.", name, action, grpName); return false; } return true; } diff --git a/Network/Player.Networking.cs b/Network/Player.Networking.cs index ddb83d50c..c854ac974 100644 --- a/Network/Player.Networking.cs +++ b/Network/Player.Networking.cs @@ -321,6 +321,7 @@ namespace MCGalaxy { bool success = true; useCheckpointSpawn = false; lastCheckpointIndex = -1; + AllowBuild = level.BuildAccess.Check(this, false); try { if (hasBlockDefs) { diff --git a/Player/Player.Fields.cs b/Player/Player.Fields.cs index 4c4c3bc1f..2f467522d 100644 --- a/Player/Player.Fields.cs +++ b/Player/Player.Fields.cs @@ -149,6 +149,8 @@ namespace MCGalaxy { // Only used for possession. //Using for anything else can cause unintended effects! public bool canBuild = true; + /// Whether the player has build permission in the current world. + public bool AllowBuild = true; public int money, loginMoney; public long overallBlocks, TotalDrawn, TotalPlaced, TotalDeleted; From 362112697be35d07316bed3f03718f44c03e6c73 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 24 Aug 2016 16:36:34 +1000 Subject: [PATCH 4/7] Cleanup permission commands. --- Commands/World/PermissionCmd.cs | 45 ++++-------- .../{CmdPermissions.cs => PermissionCmds.cs} | 52 +++++--------- Levels/LevelAccess.cs | 68 ++++++++++++++++++- MCGalaxy_.csproj | 2 +- 4 files changed, 96 insertions(+), 71 deletions(-) rename Commands/World/{CmdPermissions.cs => PermissionCmds.cs} (61%) diff --git a/Commands/World/PermissionCmd.cs b/Commands/World/PermissionCmd.cs index 3a3cd2df0..6a8fd6fbf 100644 --- a/Commands/World/PermissionCmd.cs +++ b/Commands/World/PermissionCmd.cs @@ -18,44 +18,23 @@ using System; using System.Collections.Generic; -namespace MCGalaxy.Commands.World { - static class PermissionCmd { +namespace MCGalaxy.Commands.World { + public abstract class PermissionCmd : Command { + public override string shortcut { get { return ""; } } + public override string type { get { return CommandTypes.World; } } + public override bool museumUsable { get { return false; } } + public override LevelPermission defaultRank { get { return LevelPermission.Operator; } } - public static void Use(Player p, string[] args, bool skipNobodyPerm, string target, - Func getter, Action setter) { - if (args.Length == 1 && p == null) { - Player.Message(p, "You must provide a level name when using this command from console."); - return; + protected Level GetArgs(Player p, string[] args, out Group grp) { + if (args.Length == 1 && Player.IsSuper(p)) { + SuperRequiresArgs(p, "level"); return null; } Level level = args.Length == 1 ? p.level : LevelInfo.FindMatches(p, args[0]); if (level == null) return; string rank = args.Length == 1 ? args[0] : args[1]; - Group grp = Group.FindMatches(p, rank); - if (grp == null) return; - - if (p != null && getter(level) > p.Rank) { - if (skipNobodyPerm || (getter(level) != LevelPermission.Nobody)) { - Player.Message(p, "You cannot change the {0} of a level with a {0} higher than your rank.", target); - return; - } - } - - if (p != null && grp.Permission > p.Rank) { - if (skipNobodyPerm || (grp.Permission != LevelPermission.Nobody)) { - Player.Message(p, "You cannot change the {0} of a level to a {0} higher than your rank.", target); - return; - } - } - - setter(level, grp.Permission); - UpdateAllowBuild(level); - Level.SaveSettings(level); - - Server.s.Log(level.name + " " + target + " permission changed to " + grp.Permission + "."); - Chat.MessageLevel(level, target + " permission changed to " + grp.ColoredName + "%S."); - if (p == null || p.level != level) - Player.Message(p, "{0} permission changed to {1}%S on {2}.", target, grp.ColoredName, level.name); + grp = Group.FindMatches(p, rank); + return grp != null ? level : null; } public static void UseList(Player p, string[] args, string target, @@ -71,7 +50,7 @@ namespace MCGalaxy.Commands.World { string mode = name[0] == '+' ? "whitelist" : "blacklist"; List list = name[0] == '+' ? wlGetter(level) : blGetter(level); List other = name[0] == '+' ? blGetter(level) : wlGetter(level); - name = name.Substring(1); + name = name.Substring(1); if (name == "") { Player.Message(p, "You must provide a player name to {0}.", mode); return; diff --git a/Commands/World/CmdPermissions.cs b/Commands/World/PermissionCmds.cs similarity index 61% rename from Commands/World/CmdPermissions.cs rename to Commands/World/PermissionCmds.cs index 8f42f8785..ebd08754f 100644 --- a/Commands/World/CmdPermissions.cs +++ b/Commands/World/PermissionCmds.cs @@ -19,21 +19,16 @@ using System; using System.Collections.Generic; namespace MCGalaxy.Commands.World { - public sealed class CmdPerbuildMax : Command { + public sealed class CmdPerbuildMax : PermissionCmd { public override string name { get { return "perbuildmax"; } } - public override string shortcut { get { return ""; } } - public override string type { get { return CommandTypes.World; } } - public override bool museumUsable { get { return false; } } - public override LevelPermission defaultRank { get { return LevelPermission.Operator; } } - public CmdPerbuildMax() { } public override void Use(Player p, string message) { string[] args = message.Split(' '); if (args.Length < 1 || args.Length > 2) { Help(p); return; } - PermissionCmd.Use( - p, args, false, "perbuildmax", l => l.perbuildmax, - (l, v) => l.perbuildmax = v); + Group grp = null; + Level lvl = GetArgs(p, args, out grp); + if (lvl != null) lvl.BuildAccess.SetMax(p, grp); } public override void Help(Player p) { @@ -42,21 +37,16 @@ namespace MCGalaxy.Commands.World { } } - public sealed class CmdPermissionBuild : Command { + public sealed class CmdPermissionBuild : PermissionCmd { public override string name { get { return "perbuild"; } } - public override string shortcut { get { return ""; } } - public override string type { get { return CommandTypes.World; } } - public override bool museumUsable { get { return false; } } - public override LevelPermission defaultRank { get { return LevelPermission.Operator; } } - public CmdPermissionBuild() { } public override void Use(Player p, string message) { string[] args = message.Split(' '); if (args.Length < 1 || args.Length > 2) { Help(p); return; } - PermissionCmd.Use( - p, args, true, "perbuild", l => l.permissionbuild, - (l, v) => l.permissionbuild = v); + Group grp = null; + Level lvl = GetArgs(p, args, out grp); + if (lvl != null) lvl.BuildAccess.SetMin(p, grp); } public override void Help(Player p) { @@ -65,21 +55,16 @@ namespace MCGalaxy.Commands.World { } } - public sealed class CmdPervisitMax : Command { + public sealed class CmdPervisitMax : PermissionCmd { public override string name { get { return "pervisitmax"; } } - public override string shortcut { get { return ""; } } - public override string type { get { return CommandTypes.World; } } - public override bool museumUsable { get { return false; } } - public override LevelPermission defaultRank { get { return LevelPermission.Operator; } } - public CmdPervisitMax() { } public override void Use(Player p, string message) { string[] args = message.Split(' '); if (args.Length < 1 || args.Length > 2) { Help(p); return; } - PermissionCmd.Use( - p, args, false, "pervisitmax", l => l.pervisitmax, - (l, v) => l.pervisitmax = v); + Group grp = null; + Level lvl = GetArgs(p, args, out grp); + if (lvl != null) lvl.VisitAccess.SetMax(p, grp); } public override void Help(Player p) { @@ -88,13 +73,8 @@ namespace MCGalaxy.Commands.World { } } - public sealed class CmdPermissionVisit : Command { + public sealed class CmdPermissionVisit : PermissionCmd { public override string name { get { return "pervisit"; } } - public override string shortcut { get { return ""; } } - public override string type { get { return CommandTypes.World; } } - public override bool museumUsable { get { return false; } } - public override LevelPermission defaultRank { get { return LevelPermission.Operator; } } - public CmdPermissionVisit() { } public override void Use(Player p, string message) { string[] args = message.Split(' '); @@ -106,9 +86,9 @@ namespace MCGalaxy.Commands.World { l => l.VisitWhitelist, l => l.VisitBlacklist); return; } - PermissionCmd.Use( - p, args, true, "pervisit", l => l.permissionvisit, - (l, v) => l.permissionvisit = v); + Group grp = null; + Level lvl = GetArgs(p, args, out grp); + if (lvl != null) lvl.VisitAccess.SetMin(p, grp); } public override void Help(Player p) { diff --git a/Levels/LevelAccess.cs b/Levels/LevelAccess.cs index 31e3156f4..694ffd06d 100644 --- a/Levels/LevelAccess.cs +++ b/Levels/LevelAccess.cs @@ -36,11 +36,19 @@ namespace MCGalaxy { /// Lowest allowed rank. public LevelPermission Min { get { return IsVisit ? lvl.permissionvisit : lvl.permissionbuild; } + set { + if (IsVisit) lvl.permissionvisit = value; + else lvl.permissionbuild = value; + } } /// Highest allowed rank. public LevelPermission Max { get { return IsVisit ? lvl.pervisitmax : lvl.perbuildmax; } + set { + if (IsVisit) lvl.pervisitmax = value; + else lvl.perbuildmax = value; + } } /// List of always allowed players, overrides rank allowances. @@ -53,6 +61,7 @@ namespace MCGalaxy { get { return IsVisit ? lvl.VisitBlacklist : lvl.BuildBlacklist; } } + /// Returns whether the given player is allowed by these access permissions. public bool Check(Player p, bool ignoreRankPerm = false) { if (Blacklisted.CaselessContains(p.name)) return false; @@ -90,5 +99,62 @@ namespace MCGalaxy { } return true; } + + + /// Sets the minimum rank allowed to access these permissions. + /// true if the minimum rank was changed, false if the given player + /// had insufficient permission to change the minimum rank. + public bool SetMin(Player p, Group grp) { + string target = IsVisit ? "pervisit" : "perbuild"; + if (!CheckRank(p, grp, target)) return false; + Min = grp.Permission; + + UpdateAllowBuild(); + OnPermissionChanged(p, grp, target); + return true; + } + + /// Sets the minimum rank allowed to access these permissions. + /// true if the minimum rank was changed, false if the given player + /// had insufficient permission to change the minimum rank. + public bool SetMax(Player p, Group grp) { + string target = IsVisit ? "pervisitmax" : "perbuildmax"; + if (grp.Permission != LevelPermission.Nobody && !CheckRank(p, grp, target)) return false; + Max = grp.Permission; + + UpdateAllowBuild(); + OnPermissionChanged(p, grp, target); + return true; + } + + + bool CheckRank(Player p, Group grp, string target) { + if (p != null && Min > p.Rank) { + Player.Message(p, "You cannot change the {0} of a level with a {0} higher than your rank.", target); + return false; + } + if (p != null && grp.Permission > p.Rank) { + Player.Message(p, "You cannot change the {0} of a level to a {0} higher than your rank.", target); + return false; + } + return true; + } + + void OnPermissionChanged(Player p, Group grp, string target) { + Level.SaveSettings(lvl); + Server.s.Log(lvl.name + " " + target + " permission changed to " + grp.Permission + "."); + Chat.MessageLevel(lvl, target + " permission changed to " + grp.ColoredName + "%S."); + if (p == null || p.level != lvl) + Player.Message(p, "{0} permission changed to {1}%S on {2}.", target, grp.ColoredName, lvl.name); + } + + void UpdateAllowBuild() { + if (IsVisit) return; + Player[] players = PlayerInfo.Online.Items; + foreach (Player p in players) { + if (p.level != lvl) continue; + p.AllowBuild = lvl.BuildAccess.Check(p, false); + } + } } -} +} \ No newline at end of file diff --git a/MCGalaxy_.csproj b/MCGalaxy_.csproj index 2802ed379..7eb3b5b84 100644 --- a/MCGalaxy_.csproj +++ b/MCGalaxy_.csproj @@ -385,7 +385,7 @@ - + From cca3e10b8cdb883dc3d21f5339c17d363d7824b8 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 24 Aug 2016 16:46:47 +1000 Subject: [PATCH 5/7] Fix last commit. --- Commands/World/PermissionCmd.cs | 4 ++-- Commands/World/PermissionCmds.cs | 8 ++++---- Levels/LevelAccess.cs | 18 +++++++++--------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Commands/World/PermissionCmd.cs b/Commands/World/PermissionCmd.cs index 6a8fd6fbf..9f2f7a922 100644 --- a/Commands/World/PermissionCmd.cs +++ b/Commands/World/PermissionCmd.cs @@ -25,12 +25,12 @@ namespace MCGalaxy.Commands.World { public override bool museumUsable { get { return false; } } public override LevelPermission defaultRank { get { return LevelPermission.Operator; } } - protected Level GetArgs(Player p, string[] args, out Group grp) { + protected Level GetArgs(Player p, string[] args, ref Group grp) { if (args.Length == 1 && Player.IsSuper(p)) { SuperRequiresArgs(p, "level"); return null; } Level level = args.Length == 1 ? p.level : LevelInfo.FindMatches(p, args[0]); - if (level == null) return; + if (level == null) return null; string rank = args.Length == 1 ? args[0] : args[1]; grp = Group.FindMatches(p, rank); diff --git a/Commands/World/PermissionCmds.cs b/Commands/World/PermissionCmds.cs index ebd08754f..0e58b2e85 100644 --- a/Commands/World/PermissionCmds.cs +++ b/Commands/World/PermissionCmds.cs @@ -27,7 +27,7 @@ namespace MCGalaxy.Commands.World { if (args.Length < 1 || args.Length > 2) { Help(p); return; } Group grp = null; - Level lvl = GetArgs(p, args, out grp); + Level lvl = GetArgs(p, args, ref grp); if (lvl != null) lvl.BuildAccess.SetMax(p, grp); } @@ -45,7 +45,7 @@ namespace MCGalaxy.Commands.World { if (args.Length < 1 || args.Length > 2) { Help(p); return; } Group grp = null; - Level lvl = GetArgs(p, args, out grp); + Level lvl = GetArgs(p, args, ref grp); if (lvl != null) lvl.BuildAccess.SetMin(p, grp); } @@ -63,7 +63,7 @@ namespace MCGalaxy.Commands.World { if (args.Length < 1 || args.Length > 2) { Help(p); return; } Group grp = null; - Level lvl = GetArgs(p, args, out grp); + Level lvl = GetArgs(p, args, ref grp); if (lvl != null) lvl.VisitAccess.SetMax(p, grp); } @@ -87,7 +87,7 @@ namespace MCGalaxy.Commands.World { } Group grp = null; - Level lvl = GetArgs(p, args, out grp); + Level lvl = GetArgs(p, args, ref grp); if (lvl != null) lvl.VisitAccess.SetMin(p, grp); } diff --git a/Levels/LevelAccess.cs b/Levels/LevelAccess.cs index 694ffd06d..e197c7d86 100644 --- a/Levels/LevelAccess.cs +++ b/Levels/LevelAccess.cs @@ -106,7 +106,8 @@ namespace MCGalaxy { /// had insufficient permission to change the minimum rank. public bool SetMin(Player p, Group grp) { string target = IsVisit ? "pervisit" : "perbuild"; - if (!CheckRank(p, grp, target)) return false; + if (!CheckRank(p, Min, target, false)) return false; + if (!CheckRank(p, grp.Permission, target, true)) return false; Min = grp.Permission; UpdateAllowBuild(); @@ -119,7 +120,9 @@ namespace MCGalaxy { /// had insufficient permission to change the minimum rank. public bool SetMax(Player p, Group grp) { string target = IsVisit ? "pervisitmax" : "perbuildmax"; - if (grp.Permission != LevelPermission.Nobody && !CheckRank(p, grp, target)) return false; + const LevelPermission ignore = LevelPermission.Nobody; + if (Max != ignore && !CheckRank(p, Max, target, false)) return false; + if (grp.Permission != ignore && !CheckRank(p, grp.Permission, target, true)) return false; Max = grp.Permission; UpdateAllowBuild(); @@ -128,13 +131,10 @@ namespace MCGalaxy { } - bool CheckRank(Player p, Group grp, string target) { - if (p != null && Min > p.Rank) { - Player.Message(p, "You cannot change the {0} of a level with a {0} higher than your rank.", target); - return false; - } - if (p != null && grp.Permission > p.Rank) { - Player.Message(p, "You cannot change the {0} of a level to a {0} higher than your rank.", target); + bool CheckRank(Player p, LevelPermission perm, string target, bool newPerm) { + if (p != null && perm > p.Rank) { + Player.Message(p, "You cannot change the {0} of a level {1} a {0} higher than your rank.", + target, newPerm ? "to" : "with"); return false; } return true; From 5a8da27f6b6b8966416bae4a7d49b07e34aeb007 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 24 Aug 2016 18:33:21 +1000 Subject: [PATCH 6/7] Implement perbuild whitelist/blacklist in /mapinfo and /perbuild. --- Commands/Information/CmdMapInfo.cs | 25 +++++++++++----- Commands/World/PermissionCmd.cs | 46 ++++++++++++++++-------------- Commands/World/PermissionCmds.cs | 32 +++++++-------------- Levels/LevelAccess.cs | 2 +- 4 files changed, 54 insertions(+), 51 deletions(-) diff --git a/Commands/Information/CmdMapInfo.cs b/Commands/Information/CmdMapInfo.cs index 79dd06602..700f963bc 100644 --- a/Commands/Information/CmdMapInfo.cs +++ b/Commands/Information/CmdMapInfo.cs @@ -89,14 +89,19 @@ namespace MCGalaxy.Commands { " %S: Visit rank = " + Group.findPerm(data.visit).ColoredName); Player.Message(p, " BuildMax Rank = " + Group.findPerm(data.buildmax).ColoredName + " %S: VisitMax Rank = " + Group.findPerm(data.visitmax).ColoredName); - List whitelist = data.VisitWhitelist; - List blacklist = data.VisitBlacklist; - GetBlacklistedPlayers(data.Name, blacklist); + + List vWhitelist = data.VisitWhitelist, vBlacklist = data.VisitBlacklist; + List bWhitelist = data.BuildWhitelist, bBlacklist = data.BuildBlacklist; + GetBlacklistedPlayers(data.Name, vBlacklist); - if (whitelist.Count > 0) - Player.Message(p, " Visit whitelist: &a" + whitelist.Join("%S, &a")); - if (blacklist.Count > 0) - Player.Message(p, " Visit blacklist: &c" + blacklist.Join("%S, &c")); + if (vWhitelist.Count > 0) + Player.Message(p, " Visit whitelist: &a" + vWhitelist.Join("%S, &a")); + if (vBlacklist.Count > 0) + Player.Message(p, " Visit blacklist: &c" + vBlacklist.Join("%S, &c")); + if (bWhitelist.Count > 0) + Player.Message(p, " Build whitelist: &a" + bWhitelist.Join("%S, &a")); + if (bBlacklist.Count > 0) + Player.Message(p, " Build blacklist: &c" + bBlacklist.Join("%S, &c")); if (String.IsNullOrEmpty(data.RealmOwner)) data.RealmOwner = GetRealmMapOwner(data.Name); @@ -165,6 +170,8 @@ namespace MCGalaxy.Commands { public LevelPermission visit, build, visitmax, buildmax; public List VisitWhitelist = new List(); public List VisitBlacklist = new List(); + public List BuildWhitelist = new List(); + public List BuildBlacklist = new List(); // Zombie data public string Authors; public int TotalRounds, HumanRounds; @@ -180,6 +187,8 @@ namespace MCGalaxy.Commands { visitmax = lvl.pervisitmax; buildmax = lvl.perbuildmax; VisitWhitelist = new List(lvl.VisitWhitelist); VisitBlacklist = new List(lvl.VisitBlacklist); + BuildWhitelist = new List(lvl.BuildWhitelist); + BuildBlacklist = new List(lvl.BuildBlacklist); Fog = lvl.FogColor; Sky = lvl.SkyColor; Clouds = lvl.CloudColor; Light = lvl.LightColor; Shadow = lvl.ShadowColor; @@ -222,6 +231,8 @@ namespace MCGalaxy.Commands { case "pervisitmax": visitmax = GetPerm(value); break; case "visitwhitelist": VisitWhitelist = Parse(value); break; case "visitblacklist": VisitBlacklist = Parse(value); break; + case "buildwhitelist": BuildWhitelist = Parse(value); break; + case "buildblacklist": BuildBlacklist = Parse(value); break; case "authors": Authors = value; break; case "roundsplayed": TotalRounds = int.Parse(value); break; diff --git a/Commands/World/PermissionCmd.cs b/Commands/World/PermissionCmd.cs index 9f2f7a922..00526afea 100644 --- a/Commands/World/PermissionCmd.cs +++ b/Commands/World/PermissionCmd.cs @@ -37,19 +37,20 @@ namespace MCGalaxy.Commands.World { return grp != null ? level : null; } - public static void UseList(Player p, string[] args, string target, - Func getter, - Func> wlGetter, Func> blGetter) { + protected void UseList(Player p, string[] args, bool isVisit) { + string target = isVisit ? "pervisit" : "perbuild"; if (args.Length == 1 && Player.IsSuper(p)) { Command.SuperRequiresArgs(target, p, "level"); return; } Level level = args.Length == 1 ? p.level : LevelInfo.FindMatches(p, args[0]); if (level == null) return; + LevelAccess access = isVisit ? level.VisitAccess : level.BuildAccess; string name = args.Length == 1 ? args[0] : args[1]; - string mode = name[0] == '+' ? "whitelist" : "blacklist"; - List list = name[0] == '+' ? wlGetter(level) : blGetter(level); - List other = name[0] == '+' ? blGetter(level) : wlGetter(level); + bool include = name[0] == '+'; + string mode = include ? "whitelist" : "blacklist"; + List list = include ? access.Whitelisted : access.Blacklisted; + List other = include ? access.Blacklisted : access.Whitelisted; name = name.Substring(1); if (name == "") { @@ -59,12 +60,8 @@ namespace MCGalaxy.Commands.World { Player.Message(p, "You cannot {0} yourself.", mode); return; } - if (p != null && getter(level) > p.Rank) { - Player.Message(p, "You cannot change the {0} {1} permissions " + - "for a player higher than your rank.", target, mode); return; - } - if (p != null && blGetter(level).CaselessContains(p.name)) { - Player.Message(p, "You cannot change {0} permissions as you are blacklisted.", target); return; + if (p != null && !access.CheckDetailed(p, false)) { + Player.Message(p, "Hence you cannot modify the {0} {1}.", target, mode); return; } if (p != null && PlayerInfo.GetGroup(name).Permission > p.Rank) { Player.Message(p, "You cannot whitelist/blacklist players of a higher rank."); return; @@ -73,10 +70,10 @@ namespace MCGalaxy.Commands.World { if (list.CaselessContains(name)) { Player.Message(p, "\"{0}\" is already {1}ed.", name, mode); return; } - list.Add(name); - other.CaselessRemove(name); + if (!other.CaselessRemove(name)) + list.Add(name); - UpdateAllowBuild(level); + access.UpdateAllowBuild(); Level.SaveSettings(level); string msg = name + " was " + target + " " + mode + "ed"; @@ -85,13 +82,20 @@ namespace MCGalaxy.Commands.World { if (p == null || p.level != level) Player.Message(p, msg + " on {0}.", level.name); } + - static void UpdateAllowBuild(Level level) { - Player[] players = PlayerInfo.Online.Items; - foreach (Player p in players) { - if (p.level != level) continue; - p.AllowBuild = level.BuildAccess.Check(p, false); - } + protected void MaxHelp(Player p, string action) { + Player.Message(p, "%T/{0} [Level] [Rank]", name); + Player.Message(p, "%HSets the highest rank able to {0} the given level.", action); + } + + protected void NormalHelp(Player p, string action, string action2) { + Player.Message(p, "%T/{0} [level] [rank]", name); + Player.Message(p, "%HSets the lowest rank able to {0} the given level.", action); + Player.Message(p, "%T/{0} [level] +[name]", name); + Player.Message(p, "%HAllows [name] to {0}, even if their rank cannot.", action2); + Player.Message(p, "%T/{0} [level] -[name]", name); + Player.Message(p, "%HPrevents [name] from {0}ing, even if their rank can.", action2); } } } \ No newline at end of file diff --git a/Commands/World/PermissionCmds.cs b/Commands/World/PermissionCmds.cs index 0e58b2e85..7a4731771 100644 --- a/Commands/World/PermissionCmds.cs +++ b/Commands/World/PermissionCmds.cs @@ -31,10 +31,7 @@ namespace MCGalaxy.Commands.World { if (lvl != null) lvl.BuildAccess.SetMax(p, grp); } - public override void Help(Player p) { - Player.Message(p, "%T/perbuildmax [Level] [Rank]"); - Player.Message(p, "%HSets the highest rank able to build on the given level."); - } + public override void Help(Player p) { MaxHelp(p, "build on"); } } public sealed class CmdPermissionBuild : PermissionCmd { @@ -44,15 +41,17 @@ namespace MCGalaxy.Commands.World { string[] args = message.Split(' '); if (args.Length < 1 || args.Length > 2) { Help(p); return; } + string name = args[args.Length - 1]; + if (name.Length > 0 && (name[0] == '+' || name[0] == '-')) { + UseList(p, args, false); return; + } + Group grp = null; Level lvl = GetArgs(p, args, ref grp); if (lvl != null) lvl.BuildAccess.SetMin(p, grp); } - public override void Help(Player p) { - Player.Message(p, "%T/perbuild [Level] [Rank]"); - Player.Message(p, "%HSets the lowest rank able to build on the given level."); - } + public override void Help(Player p) { NormalHelp(p, "build on", "build"); } } public sealed class CmdPervisitMax : PermissionCmd { @@ -67,10 +66,7 @@ namespace MCGalaxy.Commands.World { if (lvl != null) lvl.VisitAccess.SetMax(p, grp); } - public override void Help(Player p) { - Player.Message(p, "%T/pervisitmax [level] [rank]"); - Player.Message(p, "%HSets the highest rank able to visit the given level."); - } + public override void Help(Player p) { MaxHelp(p, "visit"); } } public sealed class CmdPermissionVisit : PermissionCmd { @@ -82,8 +78,7 @@ namespace MCGalaxy.Commands.World { string name = args[args.Length - 1]; if (name.Length > 0 && (name[0] == '+' || name[0] == '-')) { - PermissionCmd.UseList(p, args, "pervisit", l => l.permissionvisit, - l => l.VisitWhitelist, l => l.VisitBlacklist); return; + UseList(p, args, true); return; } Group grp = null; @@ -91,13 +86,6 @@ namespace MCGalaxy.Commands.World { if (lvl != null) lvl.VisitAccess.SetMin(p, grp); } - public override void Help(Player p) { - Player.Message(p, "%T/pervisit [level] [rank]"); - Player.Message(p, "%HSets the lowest rank able to visit the given level."); - Player.Message(p, "%T/pervisit [level] +[name]"); - Player.Message(p, "%HAllows [name] to visit the map, even if their rank cannot."); - Player.Message(p, "%T/pervisit [level] -[name]"); - Player.Message(p, "%HPrevents [name] from visiting the map, even if their rank can."); - } + public override void Help(Player p) { NormalHelp(p, "visit", "visit"); } } } \ No newline at end of file diff --git a/Levels/LevelAccess.cs b/Levels/LevelAccess.cs index e197c7d86..f39548cdd 100644 --- a/Levels/LevelAccess.cs +++ b/Levels/LevelAccess.cs @@ -148,7 +148,7 @@ namespace MCGalaxy { Player.Message(p, "{0} permission changed to {1}%S on {2}.", target, grp.ColoredName, lvl.name); } - void UpdateAllowBuild() { + internal void UpdateAllowBuild() { if (IsVisit) return; Player[] players = PlayerInfo.Online.Items; foreach (Player p in players) { From 816b6b5724c767f12c68cb0799e649a211791544 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 24 Aug 2016 18:39:33 +1000 Subject: [PATCH 7/7] Make /os map add use perbuild whitelist instead of zoning your own name. --- Commands/CmdOverseer.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Commands/CmdOverseer.cs b/Commands/CmdOverseer.cs index 5d22283ac..4447be35f 100644 --- a/Commands/CmdOverseer.cs +++ b/Commands/CmdOverseer.cs @@ -125,19 +125,18 @@ namespace MCGalaxy.Commands { Command.all.Find("newlvl").Use(p, level + " " + value); // Set default perbuild permissions - Command.all.Find("load").Use(p, level); + Command.all.Find("load").Use(null, level); Level lvl = LevelInfo.FindExact(level); if (lvl == null) return; + Command.all.Find("perbuild").Use(null, lvl.name + " +" + p.name); LevelPermission osPerm = Server.osPerbuildDefault; if (osPerm == LevelPermission.Nobody) osPerm = GrpCommands.MinPerm(this); - - CmdZone.ZoneAll(lvl, p.name); Group grp = Group.findPerm(osPerm); if (grp == null) return; - Command.all.Find("perbuild").Use(null, lvl.name + " " + grp.name); + Command.all.Find("perbuild").Use(null, lvl.name + " " + grp.name); Player.Message(p, "Use %T/os zone add [name] %Sto allow " + "players ranked below " + grp.ColoredName + " %Sto build in the map."); } else if (cmd == "PHYSICS") {