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") { diff --git a/Commands/Information/CmdMapInfo.cs b/Commands/Information/CmdMapInfo.cs index 22c165497..700f963bc 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."); } @@ -88,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); @@ -164,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; @@ -179,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; @@ -221,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/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/CmdPermissions.cs b/Commands/World/CmdPermissions.cs deleted file mode 100644 index 8f42f8785..000000000 --- a/Commands/World/CmdPermissions.cs +++ /dev/null @@ -1,123 +0,0 @@ -/* - 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.Commands.World { - public sealed class CmdPerbuildMax : Command { - 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); - } - - 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 sealed class CmdPermissionBuild : Command { - 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); - } - - 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 sealed class CmdPervisitMax : Command { - 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); - } - - 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 sealed class CmdPermissionVisit : Command { - 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(' '); - if (args.Length < 1 || args.Length > 2) { Help(p); return; } - - 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; - } - - PermissionCmd.Use( - p, args, true, "pervisit", l => l.permissionvisit, - (l, v) => l.permissionvisit = v); - } - - 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."); - } - } -} \ No newline at end of file diff --git a/Commands/World/PermissionCmd.cs b/Commands/World/PermissionCmd.cs index 517707de2..00526afea 100644 --- a/Commands/World/PermissionCmd.cs +++ b/Commands/World/PermissionCmd.cs @@ -18,58 +18,40 @@ 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, 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]; - 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); - 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, - 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); - name = name.Substring(1); + 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 == "") { Player.Message(p, "You must provide a player name to {0}.", mode); return; @@ -78,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; @@ -92,15 +70,32 @@ 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); + access.UpdateAllowBuild(); 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); } + + + 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 new file mode 100644 index 000000000..7a4731771 --- /dev/null +++ b/Commands/World/PermissionCmds.cs @@ -0,0 +1,91 @@ +/* + 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.Commands.World { + public sealed class CmdPerbuildMax : PermissionCmd { + public override string name { get { return "perbuildmax"; } } + + public override void Use(Player p, string message) { + string[] args = message.Split(' '); + if (args.Length < 1 || args.Length > 2) { Help(p); return; } + + Group grp = null; + Level lvl = GetArgs(p, args, ref grp); + if (lvl != null) lvl.BuildAccess.SetMax(p, grp); + } + + public override void Help(Player p) { MaxHelp(p, "build on"); } + } + + public sealed class CmdPermissionBuild : PermissionCmd { + public override string name { get { return "perbuild"; } } + + public override void Use(Player p, string message) { + 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) { NormalHelp(p, "build on", "build"); } + } + + public sealed class CmdPervisitMax : PermissionCmd { + public override string name { get { return "pervisitmax"; } } + + public override void Use(Player p, string message) { + string[] args = message.Split(' '); + if (args.Length < 1 || args.Length > 2) { Help(p); return; } + + Group grp = null; + Level lvl = GetArgs(p, args, ref grp); + if (lvl != null) lvl.VisitAccess.SetMax(p, grp); + } + + public override void Help(Player p) { MaxHelp(p, "visit"); } + } + + public sealed class CmdPermissionVisit : PermissionCmd { + public override string name { get { return "pervisit"; } } + + public override void Use(Player p, string message) { + 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, true); return; + } + + Group grp = null; + Level lvl = GetArgs(p, args, ref grp); + if (lvl != null) lvl.VisitAccess.SetMin(p, grp); + } + + public override void Help(Player p) { NormalHelp(p, "visit", "visit"); } + } +} \ 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/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..f39548cdd --- /dev/null +++ b/Levels/LevelAccess.cs @@ -0,0 +1,160 @@ +/* + 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; } + 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. + 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}%S and below may {1} {0}.", name, action, grpName); return false; + } + 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, Min, target, false)) return false; + if (!CheckRank(p, grp.Permission, target, true)) 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"; + 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(); + OnPermissionChanged(p, grp, target); + return true; + } + + + 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; + } + + 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); + } + + internal 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 fb352bbcf..574f373d0 100644 --- a/MCGalaxy_.csproj +++ b/MCGalaxy_.csproj @@ -386,7 +386,7 @@ - + @@ -498,6 +498,7 @@ + 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;