diff --git a/FoxCore-Sponge b/FoxCore-Sponge index 5e5c52f..821f8b3 160000 --- a/FoxCore-Sponge +++ b/FoxCore-Sponge @@ -1 +1 @@ -Subproject commit 5e5c52f9e3fd9a9f470f54250cd38e44bf851d23 +Subproject commit 821f8b3313a888175d66668a727d154eb3d25c45 diff --git a/build.gradle b/build.gradle index b22af3a..99b3a4a 100644 --- a/build.gradle +++ b/build.gradle @@ -8,11 +8,17 @@ buildscript { name = "forge" url = "http://files.minecraftforge.net/maven" } + maven { + name = "sponge" + url = "https://repo.spongepowered.org/maven" + } } dependencies { classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT' - classpath 'gradle.plugin.org.spongepowered:spongegradle:0.7' - classpath 'gradle.plugin.org.spongepowered:event-impl-gen:5.0.2' + classpath 'org.spongepowered:spongegradle:0.8.2-SNAPSHOT' + classpath 'org.spongepowered:event-impl-gen:5.1.0-SNAPSHOT' + //classpath 'gradle.plugin.org.spongepowered:event-impl-gen:5.0.2' + //classpath 'gradle.plugin.org.spongepowered:event-impl-gen:5.1.0-SNAPSHOT' classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3' } } @@ -22,9 +28,10 @@ apply from: fcsp.file("gradle/versions.gradle") apply plugin: 'org.spongepowered.plugin' apply plugin: 'net.minecraftforge.gradle.forge' +apply plugin: 'idea' group 'net.foxdenstudio.sponge' -version 'api6-SNAPSHOT' +version 'api7-SNAPSHOT' apply from: fcsp.file("gradle/fox.gradle") apply from: fcsp.file("gradle/publish.gradle") diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index fbae4b4..d8ea031 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 95a46c8..0cd056e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Sun May 27 00:37:29 PDT 2018 +#Wed May 30 12:43:00 PDT 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FGManager.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FGManager.java index afb9094..354492f 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FGManager.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FGManager.java @@ -30,18 +30,24 @@ import com.flowpowered.math.vector.Vector3i; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; import com.google.common.collect.SetMultimap; import net.foxdenstudio.sponge.foxcore.common.util.CacheMap; +import net.foxdenstudio.sponge.foxcore.plugin.util.Aliases; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; import net.foxdenstudio.sponge.foxguard.plugin.event.factory.FGEventFactory; import net.foxdenstudio.sponge.foxguard.plugin.handler.GlobalHandler; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.ILinkable; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.ServerOwner; import net.foxdenstudio.sponge.foxguard.plugin.region.GlobalRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.GlobalWorldRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGStorageManagerNew; import net.foxdenstudio.sponge.foxguard.plugin.util.RegionCache; import org.spongepowered.api.Sponge; import org.spongepowered.api.util.GuavaCollectors; @@ -49,17 +55,23 @@ import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.*; import java.util.stream.Collectors; +import static com.google.common.base.Preconditions.checkNotNull; + public final class FGManager { - public static final String[] ILLEGAL_NAMES = {"all", "state", "full", "everything"}; + public static final UUID SERVER_UUID_DEPRECATED = new UUID(0, 0); + public static final ServerOwner SERVER_OWNER = ServerOwner.SERVER; + public static final String[] ILLEGAL_NAMES = {"all", "state", "full", "everything", "users", "owners"}; private static FGManager instance; - private final Map> worldRegions; - private final Set regions; - private final Set handlers; + private final Map> worldRegions; + private final Multimap regions; + private final Multimap handlers; private final GlobalRegion globalRegion; private final GlobalHandler globalHandler; @@ -68,163 +80,343 @@ public final class FGManager { private FGManager() { worldRegions = new CacheMap<>((key, map) -> { if (key instanceof World) { - Set set = new HashSet<>(); - map.put((World) key, set); - return set; - } else return new HashSet<>(); + Multimap uuidMap = HashMultimap.create(); + map.put((World) key, uuidMap); + return uuidMap; + } else return null; }); - regions = new HashSet<>(); - handlers = new HashSet<>(); + regions = HashMultimap.create(); + handlers = HashMultimap.create(); globalRegion = new GlobalRegion(); globalHandler = new GlobalHandler(); - regions.add(globalRegion); - handlers.add(globalHandler); + regions.put(SERVER_OWNER, globalRegion); + handlers.put(SERVER_OWNER, globalHandler); this.regionCache = new RegionCache(regions, worldRegions); } - public static synchronized void init() { - if (instance == null) { - instance = new FGManager(); - instance.globalRegion.addHandler(instance.globalHandler); - } - } - public static FGManager getInstance() { return instance; } + public static synchronized void init() { + if (instance == null) instance = new FGManager(); + if (instance.regions.isEmpty()) instance.regions.put(SERVER_OWNER, instance.globalRegion); + if (instance.handlers.isEmpty()) instance.handlers.put(SERVER_OWNER, instance.globalHandler); + if (!instance.globalRegion.getLinks().contains(instance.globalHandler)) + instance.globalRegion.addLink(instance.globalHandler); + } + public static boolean isNameValid(String name) { - if (name.matches("^.*[ :.=;\"\'\\\\/{}()\\[\\]<>#@|?*].*$")) return false; - for (String s : FGStorageManager.FS_ILLEGAL_NAMES) { - if (name.equalsIgnoreCase(s)) return false; - } - for (String s : ILLEGAL_NAMES) { - if (name.equalsIgnoreCase(s)) return false; - } - return true; + return !name.isEmpty() && + !name.matches("^.*[ :.=;\"\'\\\\/{}()\\[\\]<>#@|?*].*$") && + !Aliases.isIn(FGStorageManagerNew.FS_ILLEGAL_NAMES, name) && + !Aliases.isIn(ILLEGAL_NAMES, name); + } + + public boolean contains(IGuardObject object) { + if (object instanceof IRegion) { + if (object instanceof IWorldRegion) { + World world = ((IWorldRegion) object).getWorld(); + if (world != null) { + return this.worldRegions.get(world).containsValue(object); + } else { + for (Multimap map : this.worldRegions.values()) { + if (map.containsValue(object)) return true; + } + return false; + } + } else { + return this.regions.containsValue(object); + } + } else if (object instanceof IHandler) { + return this.handlers.containsValue(object); + } else return false; } - public boolean isRegistered(IHandler handler) { - return handlers.contains(handler); + public boolean addHandler(IHandler handler) { + IOwner owner = handler.getOwner(); + if (owner == null) owner = SERVER_OWNER; + return addHandler(handler, owner); } - public boolean isRegionNameAvailable(String name) { - if (getRegion(name) != null) return false; - for (World world : worldRegions.keySet()) { - if (getWorldRegion(world, name) != null) return false; - } + public boolean addHandler(IHandler handler, IOwner owner) { + if (handler == null + || !isNameValid(handler.getName()) + || !isHandlerNameAvailable(handler.getName(), owner) + || this.handlers.containsValue(handler)) + return false; + handler.setOwner(owner); + handlers.put(owner, handler); + FGStorageManagerNew.getInstance().addObject(handler); + Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), handler)); return true; } - public boolean isWorldRegionNameAvailable(String name, World world) { - if (getWorldRegion(world, name) != null || getRegion(name) != null) return false; - else return true; + public boolean addRegion(IRegion region) { + IOwner owner = region.getOwner(); + if (owner == null) owner = SERVER_OWNER; + return addRegion(region, owner); + } + + public boolean addRegion(IRegion region, @Nonnull IOwner owner) { + checkNotNull(owner); + if (region == null + || !isNameValid(region.getName()) + || !isRegionNameAvailable(region.getName(), owner) + || region instanceof IWorldRegion + || this.regions.containsValue(region)) return false; + region.setOwner(owner); + this.regions.put(owner, region); + this.regionCache.markDirty(region, RegionCache.DirtyType.ADDED); + FGStorageManagerNew.getInstance().addObject(region); + Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), region)); + return true; } - public Tristate isWorldRegionNameAvailable(String name) { - Tristate available = null; - for (World world : worldRegions.keySet()) { - if (getWorldRegion(world, name) == null) { - if (available == null) { - available = Tristate.TRUE; - } else if (available == Tristate.FALSE) { - available = Tristate.UNDEFINED; - } - } else { - if (available == null) { - available = Tristate.FALSE; - } else if (available == Tristate.TRUE) { - available = Tristate.UNDEFINED; - } - } - } - return available; + public boolean addRegion(IRegion region, @Nullable World world) { + IOwner owner = region.getOwner(); + if (owner == null) owner = SERVER_OWNER; + return addRegion(region, owner, world); + } + + public boolean addRegion(IRegion region, IOwner owner, @Nullable World world) { + if (region instanceof IWorldRegion) { + return world != null && addWorldRegion((IWorldRegion) region, owner, world); + } else return addRegion(region, owner); + } + + public boolean addWorldRegion(IWorldRegion region, World world) { + IOwner owner = region.getOwner(); + if (owner == null) owner = SERVER_OWNER; + return addWorldRegion(region, owner, world); } - public boolean addWorldRegion(World world, IWorldRegion region) { - if (region == null || region.getWorld() != null || - !isWorldRegionNameAvailable(region.getName(), world) || !isNameValid(region.getName())) + public boolean addWorldRegion(IWorldRegion region, @Nonnull IOwner owner, World world) { + checkNotNull(owner); + if (region == null + || world == null + || region.getWorld() != null + || !isNameValid(region.getName()) + || !isWorldRegionNameAvailable(region.getName(), owner, world)) return false; region.setWorld(world); - this.worldRegions.get(world).add(region); + region.setOwner(owner); + this.worldRegions.get(world).put(owner, region); this.regionCache.markDirty(region, RegionCache.DirtyType.ADDED); - FGStorageManager.getInstance().addObject(region); + FGStorageManagerNew.getInstance().addObject(region); Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), region)); return true; } - public boolean addRegion(IRegion region) { - if (region == null || !isRegionNameAvailable(region.getName()) || !isNameValid(region.getName())) return false; - this.regions.add(region); - this.regionCache.markDirty(region, RegionCache.DirtyType.ADDED); - FGStorageManager.getInstance().addObject(region); - Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), region)); - return true; + public void clearRegionCache() { + this.regionCache.clearCaches(); } - public boolean addRegion(IRegion region, World world) { - if (region instanceof IWorldRegion) { - return world != null && addWorldRegion(world, (IWorldRegion) region); - } else return addRegion(region); + @Nonnull + public Set getAllRegions() { + Set set = new HashSet<>(); + this.worldRegions.forEach((world, worldMultimap) -> set.addAll(worldMultimap.values())); + set.addAll(this.regions.values()); + return ImmutableSet.copyOf(set); } - public IWorldRegion getWorldRegion(World world, String name) { - for (IWorldRegion region : this.worldRegions.get(world)) { - if (region.getName().equalsIgnoreCase(name)) { - return region; + @Nonnull + public Set getAllRegions(@Nonnull IOwner owner) { + checkNotNull(owner); + Set set = new HashSet<>(); + this.worldRegions.forEach((world, worldMultimap) -> set.addAll(worldMultimap.get(owner))); + set.addAll(this.regions.get(owner)); + return ImmutableSet.copyOf(set); + } + + @Nonnull + public Set getAllRegions(World world) { + if (world == null) return getRegions(); + Set set = new HashSet<>(); + set.addAll(this.worldRegions.get(world).values()); + set.addAll(this.regions.values()); + return ImmutableSet.copyOf(set); + } + + @Nonnull + public Set getAllRegions(String name, @Nonnull IOwner owner) { + checkNotNull(owner); + Set set = new HashSet<>(); + for (IRegion region : this.regions.get(owner)) { + if (region.getName().equalsIgnoreCase(name)) set.add(region); + } + + for (Multimap map : this.worldRegions.values()) { + for (IWorldRegion region : map.get(owner)) { + if (region.getName().equalsIgnoreCase(name)) set.add(region); } } - return null; + return ImmutableSet.copyOf(set); } - public IRegion getRegion(String name) { - for (IRegion region : this.regions) { - if (region.getName().equalsIgnoreCase(name)) { - return region; + @Nonnull + public Set getAllRegions(World world, @Nonnull IOwner owner) { + checkNotNull(owner); + if (world == null) return getRegions(); + Set set = new HashSet<>(); + set.addAll(this.worldRegions.get(world).get(owner)); + set.addAll(this.regions.get(owner)); + return ImmutableSet.copyOf(set); + } + + @Nonnull + public Set getAllRegionsWithUniqueNames(@Nonnull IOwner owner) { + return getAllRegionsWithUniqueNames(owner, null); + } + + @Nonnull + public Set getAllRegionsWithUniqueNames(@Nonnull IOwner owner, @Nullable World world) { + checkNotNull(owner); + Set returnSet = new HashSet<>(); + returnSet.addAll(this.regions.get(owner)); + Map duplicates = new HashMap<>(); + Map regions = new HashMap<>(); + this.worldRegions.forEach((wld, map) -> map.get(owner).forEach(region -> { + String name = region.getName(); + Boolean duplicate = duplicates.get(name); + if (wld == world) { + duplicates.put(name, true); + regions.put(name, region); + } else if (duplicate == null) { + duplicates.put(name, false); + regions.put(name, region); + } else if (!duplicate) { + duplicates.put(name, true); + regions.remove(name); + } + })); + returnSet.addAll(regions.values()); + return ImmutableSet.copyOf(returnSet); + } + + @Nonnull + public Set getAllServerRegions() { + return getAllRegions(SERVER_OWNER); + } + + @Nonnull + public Set getAllServerRegions(World world) { + return getAllRegions(world, SERVER_OWNER); + } + + @Nonnull + public Optional getController(String name) { + return getController(name, SERVER_OWNER); + } + + @Nonnull + public Optional getController(String name, @Nonnull IOwner owner) { + checkNotNull(owner); + for (IHandler handler : handlers.get(owner)) { + if ((handler instanceof IController) && handler.getName().equalsIgnoreCase(name)) { + return Optional.of((IController) handler); } } - return null; + return Optional.empty(); } - public IRegion getRegionFromWorld(World world, String name) { - IRegion region = getWorldRegion(world, name); - if (region == null) { - return getRegion(name); - } else return region; + @Nonnull + public Set getControllers() { + return this.handlers.values().stream() + .filter(handler -> handler instanceof IController) + .map(handler -> ((IController) handler)) + .collect(GuavaCollectors.toImmutableSet()); } - public Set getRegions() { - return ImmutableSet.copyOf(this.regions); + @Nonnull + public Set getControllers(@Nonnull IOwner owner) { + checkNotNull(owner); + return this.handlers.get(owner).stream() + .filter(handler -> handler instanceof IController) + .map(handler -> ((IController) handler)) + .collect(GuavaCollectors.toImmutableSet()); } - public Set getWorldRegions(World world) { - return ImmutableSet.copyOf(this.worldRegions.get(world)); + @Nonnull + public GlobalHandler getGlobalHandler() { + return globalHandler; } - public Set getAllRegions() { - Set set = new HashSet<>(); - this.worldRegions.forEach((world, worldSet) -> worldSet.forEach(set::add)); - this.regions.forEach(set::add); - return ImmutableSet.copyOf(set); + @Nonnull + public Optional getHandler(String name) { + return getHandler(name, SERVER_OWNER); } - public Set getAllRegions(World world) { - if (world == null) return getRegions(); - Set set = new HashSet<>(); - this.worldRegions.get(world).forEach(set::add); - this.regions.forEach(set::add); - return ImmutableSet.copyOf(set); + @Nonnull + public Optional getHandler(String name, @Nonnull IOwner owner) { + checkNotNull(owner); + for (IHandler handler : handlers.get(owner)) { + if (handler.getName().equalsIgnoreCase(name)) { + return Optional.of(handler); + } + } + return Optional.empty(); + } + + @Nonnull + public Set getHandlers() { + return ImmutableSet.copyOf(this.handlers.values()); } + @Nonnull public Set getAllRegions(World world, Vector3i chunk) { return this.getAllRegions(world, chunk, false); } + @Nonnull public Set getAllRegions(World world, Vector3i chunk, boolean includeDisabled) { return this.regionCache.getData(world, chunk).getRegions(includeDisabled); } + @Nonnull + public Set getHandlers(@Nonnull IOwner owner) { + checkNotNull(owner); + return ImmutableSet.copyOf(this.handlers.get(owner)); + } + + @Nonnull + public Set getHandlers(boolean includeControllers) { + if (includeControllers) { + return getHandlers(); + } else { + return this.handlers.values().stream() + .filter(handler -> !(handler instanceof IController)) + .collect(GuavaCollectors.toImmutableSet()); + } + } + + @Nonnull + public Set getHandlers(boolean includeControllers, IOwner owner) { + if (includeControllers) { + return getHandlers(owner); + } else { + return this.handlers.get(owner).stream() + .filter(handler -> !(handler instanceof IController)) + .collect(GuavaCollectors.toImmutableSet()); + } + } + + @Nonnull + public Optional getRegion(String name) { + return getRegion(name, SERVER_OWNER); + } + + @Nonnull + public Optional getRegion(String name, IOwner owner) { + for (IRegion region : this.regions.get(owner)) { + if (region.getName().equalsIgnoreCase(name)) { + return Optional.of(region); + } + } + return Optional.empty(); + } + public Set getRegionsAtPos(World world, Vector3i position) { return this.getRegionsInChunkAtPos(world, position).stream() .filter(region -> region.contains(position, world)) @@ -237,25 +429,39 @@ public Set getRegionsAtPos(World world, Vector3i position, boolean incl .collect(Collectors.toSet()); } - public Set getRegionsAtPos(World world, Vector3d position) { - return this.getRegionsInChunkAtPos(world, position).stream() - .filter(region -> region.contains(position, world)) - .collect(Collectors.toSet()); + @Nonnull + public Optional getRegionFromWorld(World world, String name) { + return getRegionFromWorld(world, name, SERVER_OWNER); } - public Set getRegionsAtPos(World world, Vector3d position, boolean includeDisabled) { - return this.getRegionsInChunkAtPos(world, position, includeDisabled).stream() - .filter(region -> region.contains(position, world)) - .collect(Collectors.toSet()); + @Nonnull + public Optional getRegionFromWorld(World world, String name, @Nonnull IOwner owner) { + checkNotNull(owner); + + Optional region = getWorldRegion(world, name, owner); + return region.>map(Optional::of).orElseGet(() -> getRegion(name, owner)); } - public Set getRegionsAtMultiLocI(Iterable> locations) { - return getRegionsAtMultiLocI(locations, false); + @Nonnull + public Set getRegions() { + return ImmutableSet.copyOf(this.regions.values()); } - public Set getRegionsAtMultiLocI(Iterable> locations, boolean includeDisabled) { + @Nonnull + public Set getRegions(@Nonnull IOwner owner) { + checkNotNull(owner); + return ImmutableSet.copyOf(this.regions.get(owner)); + } + + @Nonnull + public Set getRegionsAtMultiLocD(Iterable> locations) { + return getRegionsAtMultiLocD(locations, false); + } + + @Nonnull + public Set getRegionsAtMultiLocD(Iterable> locations, boolean includeDisabled) { Set set = new HashSet<>(); - SetMultimap chunkPosMap = HashMultimap.create(); + SetMultimap chunkPosMap = HashMultimap.create(); for (Location loc : locations) { Vector3i pos = loc.getBlockPosition(); chunkPosMap.put( @@ -267,15 +473,15 @@ public Set getRegionsAtMultiLocI(Iterable> locations, b ), loc.getExtent() ), - loc.getBlockPosition() + loc.getPosition() ); } - for (Map.Entry> entry : chunkPosMap.asMap().entrySet()) { + for (Map.Entry> entry : chunkPosMap.asMap().entrySet()) { Chunk chunk = entry.getKey(); RegionCache.ChunkData data = this.regionCache.getData(chunk.world, chunk.chunk); Set candidates = new HashSet<>(data.getRegions(includeDisabled)); candidates.removeAll(set); - for (Vector3i pos : entry.getValue()) { + for (Vector3d pos : entry.getValue()) { if (candidates.isEmpty()) break; Iterator regionIterator = candidates.iterator(); do { @@ -291,13 +497,15 @@ public Set getRegionsAtMultiLocI(Iterable> locations, b return set; } - public Set getRegionsAtMultiLocD(Iterable> locations) { - return getRegionsAtMultiLocD(locations, false); + @Nonnull + public Set getRegionsAtMultiLocI(Iterable> locations) { + return getRegionsAtMultiLocI(locations, false); } - public Set getRegionsAtMultiLocD(Iterable> locations, boolean includeDisabled) { + @Nonnull + public Set getRegionsAtMultiLocI(Iterable> locations, boolean includeDisabled) { Set set = new HashSet<>(); - SetMultimap chunkPosMap = HashMultimap.create(); + SetMultimap chunkPosMap = HashMultimap.create(); for (Location loc : locations) { Vector3i pos = loc.getBlockPosition(); chunkPosMap.put( @@ -309,15 +517,15 @@ public Set getRegionsAtMultiLocD(Iterable> locations, b ), loc.getExtent() ), - loc.getPosition() + loc.getBlockPosition() ); } - for (Map.Entry> entry : chunkPosMap.asMap().entrySet()) { + for (Map.Entry> entry : chunkPosMap.asMap().entrySet()) { Chunk chunk = entry.getKey(); RegionCache.ChunkData data = this.regionCache.getData(chunk.world, chunk.chunk); Set candidates = new HashSet<>(data.getRegions(includeDisabled)); candidates.removeAll(set); - for (Vector3d pos : entry.getValue()) { + for (Vector3i pos : entry.getValue()) { if (candidates.isEmpty()) break; Iterator regionIterator = candidates.iterator(); do { @@ -333,10 +541,36 @@ public Set getRegionsAtMultiLocD(Iterable> locations, b return set; } + @Nonnull + public Set getRegionsAtPos(World world, Vector3d position) { + return this.getRegionsInChunkAtPos(world, position).stream() + .filter(region -> region.contains(position, world)) + .collect(Collectors.toSet()); + } + + @Nonnull + public Set getRegionsAtPos(World world, Vector3d position, boolean includeDisabled) { + return this.getRegionsInChunkAtPos(world, position, includeDisabled).stream() + .filter(region -> region.contains(position, world)) + .collect(Collectors.toSet()); + } + + @Nonnull + public Set getRegionsInChunk(World world, Vector3i chunk) { + return getRegionsInChunk(world, chunk, false); + } + + @Nonnull + public Set getRegionsInChunk(World world, Vector3i chunk, boolean includeDisabled) { + return this.regionCache.getData(world, chunk).getRegions(includeDisabled); + } + + @Nonnull public Set getRegionsInChunkAtPos(World world, Vector3i pos) { return getRegionsInChunkAtPos(world, pos, false); } + @Nonnull public Set getRegionsInChunkAtPos(World world, Vector3i pos, boolean includeDisabled) { return this.regionCache.getData(world, new Vector3i( @@ -346,10 +580,12 @@ public Set getRegionsInChunkAtPos(World world, Vector3i pos, boolean in ).getRegions(includeDisabled); } + @Nonnull public Set getRegionsInChunkAtPos(World world, Vector3d pos) { return getRegionsInChunkAtPos(world, pos, false); } + @Nonnull public Set getRegionsInChunkAtPos(World world, Vector3d pos, boolean includeDisabled) { return this.regionCache.getData(world, new Vector3i( @@ -359,67 +595,152 @@ public Set getRegionsInChunkAtPos(World world, Vector3d pos, boolean in ).getRegions(includeDisabled); } - public Set getHandlers() { - return ImmutableSet.copyOf(this.handlers); + @Nonnull + public Set getServerControllers() { + return getControllers(SERVER_OWNER); } - public Set getHandlers(boolean includeControllers) { - if (includeControllers) { - return ImmutableSet.copyOf(this.handlers); - } else { - return this.handlers.stream() - .filter(handler -> !(handler instanceof IController)) - .collect(GuavaCollectors.toImmutableSet()); - } + @Nonnull + public Set getServerHandlers() { + return getHandlers(SERVER_OWNER); } - public Set getControllers() { - return this.handlers.stream() - .filter(handler -> handler instanceof IController) - .map(handler -> ((IController) handler)) - .collect(GuavaCollectors.toImmutableSet()); + @Nonnull + public Set getServerHandlers(boolean includeControllers) { + return getHandlers(includeControllers, SERVER_OWNER); } - public boolean addHandler(IHandler handler) { - if (handler == null) return false; - if (gethandler(handler.getName()) != null) return false; - handlers.add(handler); - FGStorageManager.getInstance().addObject(handler); - Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), handler)); - return true; + @Nonnull + public Set getServerRegions() { + return getRegions(SERVER_OWNER); } - public IHandler gethandler(String name) { - for (IHandler handler : handlers) { - if (handler.getName().equalsIgnoreCase(name)) { - return handler; + @Nonnull + public Set getServerWorldRegions(World world) { + return getWorldRegions(world, SERVER_OWNER); + } + + @Nonnull + public Optional getWorldRegion(World world, String name) { + return getWorldRegion(world, name, SERVER_OWNER); + } + + @Nonnull + public Optional getWorldRegion(World world, String name, @Nonnull IOwner owner) { + checkNotNull(owner); + for (IWorldRegion region : this.worldRegions.get(world).get(owner)) { + if (region.getName().equalsIgnoreCase(name)) { + return Optional.of(region); } } - return null; + return Optional.empty(); } - public IController getController(String name) { - for (IHandler handler : handlers) { - if ((handler instanceof IController) && handler.getName().equalsIgnoreCase(name)) { - return (IController) handler; + @Nonnull + public Set getWorldRegions(World world) { + return ImmutableSet.copyOf(this.worldRegions.get(world).values()); + } + + @Nonnull + public Set getWorldRegions(World world, @Nonnull IOwner owner) { + checkNotNull(owner); + return ImmutableSet.copyOf(this.worldRegions.get(world).get(owner)); + } + + public void initWorld(World world) { + GlobalWorldRegion gwr = new GlobalWorldRegion(); + gwr.setWorld(world); + this.worldRegions.get(world).put(SERVER_OWNER, gwr); + this.regionCache.markDirty(gwr, RegionCache.DirtyType.ADDED); + } + + public boolean isHandlerNameAvailable(String name) { + return isHandlerNameAvailable(name, SERVER_OWNER); + } + + public boolean isHandlerNameAvailable(String name, @Nonnull IOwner owner) { + return !getHandler(name, owner).isPresent(); + } + + public boolean isRegionNameAvailable(String name) { + return isRegionNameAvailable(name, SERVER_OWNER); + } + + public boolean isRegionNameAvailable(String name, @Nonnull IOwner owner) { + if (getRegion(name, owner).isPresent()) return false; + for (World world : worldRegions.keySet()) { + if (getWorldRegion(world, name, owner).isPresent()) return false; + } + return true; + } + + public boolean isRegistered(IHandler handler) { + return handlers.containsValue(handler); + } + + public boolean isWorldRegionNameAvailable(String name, World world) { + return isWorldRegionNameAvailable(name, SERVER_OWNER, world); + } + + public boolean isWorldRegionNameAvailable(String name, @Nonnull IOwner owner, World world) { + return !(getWorldRegion(world, name, owner).isPresent() || getRegion(name, owner).isPresent()); + } + + @Nonnull + public Tristate isWorldRegionNameAvailable(String name) { + return isWorldRegionNameAvailable(name, SERVER_OWNER); + } + + @Nonnull + public Tristate isWorldRegionNameAvailable(String name, @Nonnull IOwner owner) { + checkNotNull(owner); + if (getRegion(name, owner).isPresent()) return Tristate.FALSE; + Tristate available = null; + for (World world : worldRegions.keySet()) { + if (getWorldRegion(world, name, owner).isPresent()) { + if (available == null) { + available = Tristate.FALSE; + } else if (available == Tristate.TRUE) { + available = Tristate.UNDEFINED; + } + } else { + if (available == null) { + available = Tristate.TRUE; + } else if (available == Tristate.FALSE) { + available = Tristate.UNDEFINED; + } } } - return null; + if (available == null) available = Tristate.TRUE; + return available; + } + + public boolean link(ILinkable linkable, IHandler handler) { + if (linkable == null || handler == null || linkable.getLinks().contains(handler)) return false; + Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateEvent(FoxGuardMain.getCause())); + return !(handler instanceof IGlobal) && linkable.addLink(handler); + } + + public void markDirty(IRegion region, RegionCache.DirtyType type) { + regionCache.markDirty(region, type); + } + + public boolean removeObject(IGuardObject object) { + if (object instanceof IRegion) return removeRegion(((IRegion) object)); + else return object instanceof IHandler && removeHandler(((IHandler) object)); } public boolean removeHandler(IHandler handler) { if (handler == null || handler instanceof GlobalHandler) return false; - this.worldRegions.forEach((world, set) -> { - set.stream() - .filter(region -> region.getHandlers().contains(handler)) - .forEach(region -> region.removeHandler(handler)); - }); - if (!this.handlers.contains(handler)) { + this.worldRegions.forEach((world, set) -> set.values().stream() + .filter(region -> region.getLinks().contains(handler)) + .forEach(region -> region.removeLink(handler))); + if (!this.handlers.values().contains(handler)) { return false; } - FGStorageManager.getInstance().removeObject(handler); + handlers.values().remove(handler); + FGStorageManagerNew.getInstance().removeObject(handler); Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), handler)); - handlers.remove(handler); return true; } @@ -428,9 +749,9 @@ public boolean removeRegion(IRegion region) { return removeWorldRegion((IWorldRegion) region); } else { if (region == null) return false; - if (!this.regions.contains(region)) return false; - this.regions.remove(region); - FGStorageManager.getInstance().removeObject(region); + if (!this.regions.values().contains(region)) return false; + this.regions.values().remove(region); + FGStorageManagerNew.getInstance().removeObject(region); Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), region)); this.regionCache.markDirty(region, RegionCache.DirtyType.REMOVED); return true; @@ -441,73 +762,113 @@ public boolean removeWorldRegion(IWorldRegion region) { if (region == null || region instanceof GlobalWorldRegion) return false; boolean removed = false; if (region.getWorld() != null) { - if (!this.worldRegions.get(region.getWorld()).contains(region)) { + Collection regions = this.worldRegions.get(region.getWorld()).values(); + if (!regions.contains(region)) { return false; } - this.worldRegions.get(region.getWorld()).remove(region); + regions.remove(region); removed = true; } else { - for (Set set : this.worldRegions.values()) { - if (set.contains(region)) { - set.remove(region); + for (Multimap multimap : this.worldRegions.values()) { + if (multimap.values().contains(region)) { + multimap.values().remove(region); removed = true; } } } if (removed) { - FGStorageManager.getInstance().removeObject(region); + FGStorageManagerNew.getInstance().removeObject(region); Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), region)); this.regionCache.markDirty(region, RegionCache.DirtyType.REMOVED); } return removed; } - public boolean link(ILinkable linkable, IHandler handler) { - if (linkable == null || handler == null || linkable.getHandlers().contains(handler)) return false; - Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateEvent(FoxGuardMain.getCause())); - return !(handler instanceof GlobalHandler && !(linkable instanceof GlobalWorldRegion || linkable instanceof GlobalRegion)) && linkable.addHandler(handler); - } - - public boolean unlink(ILinkable linkable, IHandler handler) { - if (linkable == null || handler == null || !linkable.getHandlers().contains(handler)) return false; - Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateEvent(FoxGuardMain.getCause())); - return !(handler instanceof GlobalHandler) && linkable.removeHandler(handler); - } + public boolean move(IGuardObject object, @Nullable String newName, @Nullable IOwner newOwner, @Nullable World + newWorld) { + boolean changed = false, nameChanged = false, ownerChanged = false, worldChanged = false; + String tryName = object.getName(); + if (newName != null && !newName.isEmpty() && isNameValid(newName)) { + changed = true; + nameChanged = true; + tryName = newName; + } + IOwner tryOwner = object.getOwner(); + if (newOwner != null) { + changed = true; + ownerChanged = true; + tryOwner = newOwner; + } + World tryWorld = null; + if (object instanceof IWorldRegion && newWorld != null) { + changed = true; + worldChanged = true; + tryWorld = ((IWorldRegion) object).getWorld(); + } + if (!changed) return false; - public boolean rename(IFGObject object, String newName) { - if (object instanceof IWorldRegion) { - IWorldRegion region = (IWorldRegion) object; - if (this.getWorldRegion(region.getWorld(), newName) != null) return false; + if (object instanceof IRegion) { + if (object instanceof IWorldRegion) { + if (!this.worldRegions.containsKey(tryWorld)) return false; + if (!isWorldRegionNameAvailable(tryName, tryOwner, tryWorld)) return false; + } else { + if (this.getRegion(tryName, tryOwner).isPresent()) return false; + } } else if (object instanceof IHandler) { - if (this.gethandler(newName) != null) return false; + if (this.getHandler(tryName, tryOwner).isPresent()) return false; } - FGStorageManager.getInstance().removeObject(object); - object.setName(newName); - FGStorageManager.getInstance().addObject(object); - return true; - } - - public void initWorld(World world) { - GlobalWorldRegion gwr = new GlobalWorldRegion(); - gwr.setWorld(world); - this.worldRegions.get(world).add(gwr); - this.regionCache.markDirty(gwr, RegionCache.DirtyType.ADDED); - } - public void unloadWorld(World world) { - this.worldRegions.remove(world); + FGStorageManagerNew.getInstance().removeObject(object); + if (nameChanged) + object.setName(newName); + if (ownerChanged || worldChanged) { + if (object instanceof IHandler) { + this.handlers.remove(object.getOwner(), object); + } else if (object instanceof IRegion) { + if (object instanceof IWorldRegion) { + this.worldRegions.get(((IWorldRegion) object).getWorld()).remove(object.getOwner(), object); + } else { + this.regions.remove(object.getOwner(), object); + } + } + if (ownerChanged) + object.setOwner(newOwner); + if (worldChanged) { + ((IWorldRegion) object).setWorld(newWorld); + } + if (object instanceof IHandler) { + this.handlers.put(object.getOwner(), (IHandler) object); + } else if (object instanceof IRegion) { + if (object instanceof IWorldRegion) { + this.worldRegions.get(((IWorldRegion) object).getWorld()).put(object.getOwner(), (IWorldRegion) object); + } else { + this.regions.put(object.getOwner(), (IRegion) object); + } + } + if (worldChanged) { + IWorldRegion region = ((IWorldRegion) object); + this.regionCache.markDirty(region, RegionCache.DirtyType.ADDED); + Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), region)); + } + } + FGStorageManagerNew.getInstance().addObject(object); + return true; } - public GlobalHandler getGlobalHandler() { - return globalHandler; + public boolean unlink(ILinkable linkable, IHandler handler) { + if (linkable == null || handler == null || !linkable.getLinks().contains(handler)) return false; + Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateEvent(FoxGuardMain.getCause())); + return !(handler instanceof IGlobal) && linkable.removeLink(handler); } - public void markDirty(IRegion region, RegionCache.DirtyType type) { - regionCache.markDirty(region, type); + public void unloadServer() { + this.regions.clear(); + this.handlers.clear(); + this.regionCache.clearCaches(); } - public void clearRegionCache() { - this.regionCache.clearCaches(); + public void unloadWorld(World world) { + this.worldRegions.remove(world); } private static class Chunk { diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FGStorageManager.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FGStorageManager.java deleted file mode 100644 index 7240979..0000000 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FGStorageManager.java +++ /dev/null @@ -1,1211 +0,0 @@ -/* - * This file is part of FoxGuard, licensed under the MIT License (MIT). - * - * Copyright (c) gravityfox - https://gravityfox.net/ - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package net.foxdenstudio.sponge.foxguard.plugin; - -import net.foxdenstudio.sponge.foxcore.common.util.CacheMap; -import net.foxdenstudio.sponge.foxguard.plugin.config.FGConfigManager; -import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; -import net.foxdenstudio.sponge.foxguard.plugin.handler.GlobalHandler; -import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; -import net.foxdenstudio.sponge.foxguard.plugin.object.factory.FGFactoryManager; -import net.foxdenstudio.sponge.foxguard.plugin.region.GlobalRegion; -import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; -import net.foxdenstudio.sponge.foxguard.plugin.region.world.GlobalWorldRegion; -import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; -import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; -import org.mapdb.*; -import org.slf4j.Logger; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.world.World; - -import java.io.IOException; -import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.*; - -/** - * Created by Fox on 4/6/2016. - */ -public final class FGStorageManager { - - public static final String[] FS_ILLEGAL_NAMES = {"con", "prn", "aux", "nul", "com0", "com1", "com2", "com3", "com4", - "com5", "com6", "com7", "com8", "com9", "lpt0", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"}; - - public final HashMap defaultModifiedMap; - private static FGStorageManager instance; - private final Logger logger = FoxGuardMain.instance().getLogger(); - private final Set loaded = new HashSet<>(); - private final Path directory = getDirectory(); - private final Map worldDirectories; - - private FGStorageManager() { - defaultModifiedMap = new CacheMap<>((k, m) -> { - if (k instanceof IFGObject) { - m.put((IFGObject) k, true); - return true; - } else return null; - }); - worldDirectories = new CacheMap<>((k, m) -> { - if (k instanceof String) { - Path dir = getWorldDirectory((String) k); - m.put((String) k, dir); - return dir; - } else return null; - }); - } - - public static FGStorageManager getInstance() { - if (instance == null) instance = new FGStorageManager(); - return instance; - } - - public void saveRegions() { - saveRegions(false); - } - - public synchronized void saveRegions(boolean force) { - logger.info("Saving regions" + (force ? " (forced save)" : "")); - Path dbFile = directory.resolve("regions.foxdb").normalize(); - try (DB mainDB = DBMaker.fileDB(dbFile.toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map linksMap = mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen(); - - mainMap.clear(); - linksMap.clear(); - - Path dir = directory.resolve("regions"); - constructDirectory(dir); - FGManager.getInstance().getRegions().forEach(fgObject -> { - String name = fgObject.getName(); - if (fgObject.autoSave()) { - Path singleDir = dir.resolve(name.toLowerCase()); - boolean shouldSave = fgObject.shouldSave(); - if (force || shouldSave) { - logger.info((shouldSave ? "S" : "Force s") + "aving region \"" + name + "\" in directory: " + singleDir); - constructDirectory(singleDir); - try { - fgObject.save(singleDir); - } catch (Exception e) { - logger.error("There was an error while saving region \"" + name + "\"!", e); - } - - logger.info("Saving metadata for region \"" + name + "\""); - try (DB metaDB = DBMaker.fileDB(singleDir.resolve("metadata.foxdb").normalize().toString()).make()) { - Atomic.String metaName = metaDB.atomicString("name").createOrOpen(); - Atomic.String metaCategory = metaDB.atomicString("category").createOrOpen(); - Atomic.String metaType = metaDB.atomicString("type").createOrOpen(); - Atomic.Boolean metaEnabled = metaDB.atomicBoolean("enabled").createOrOpen(); - metaName.set(name); - metaCategory.set(FGUtil.getCategory(fgObject)); - metaType.set(fgObject.getUniqueTypeString()); - metaEnabled.set(fgObject.isEnabled()); - } - } else { - logger.info("Region \"" + name + "\" is already up to date. Skipping..."); - } - mainMap.put(name, FGUtil.getCategory(fgObject)); - typeMap.put(name, fgObject.getUniqueTypeString()); - enabledMap.put(name, fgObject.isEnabled()); - - defaultModifiedMap.put(fgObject, false); - } else { - logger.info("Region " + fgObject.getName() + " does not need saving. Skipping..."); - } - if (fgObject.saveLinks()) { - linksMap.put(name, serializeHandlerList(fgObject.getHandlers())); - } else { - logger.info("Region " + fgObject.getName() + " does not need its links saved. Skipping..."); - } - }); - } catch (DBException.DataCorruption e) { - try { - FoxGuardMain.instance().getLogger().error("Database file \"" + dbFile + "\" appears to be corrupted:", e); - FoxGuardMain.instance().getLogger().error("Deleting the database file and trying again"); - Files.deleteIfExists(dbFile); - saveRegions(force); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - } - - public void saveWorldRegions(World world) { - saveWorldRegions(world, false); - } - - public synchronized void saveWorldRegions(World world, boolean force) { - logger.info("Saving world regions in world \"" + world.getName() + "\"" + (force ? " (forced save)" : "")); - Path dbFile = worldDirectories.get(world.getName()).resolve("wregions.foxdb").normalize(); - try (DB mainDB = DBMaker.fileDB(dbFile.toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map linksMap = mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen(); - - mainMap.clear(); - linksMap.clear(); - - Path dir = worldDirectories.get(world.getName()).resolve("wregions"); - constructDirectory(dir); - FGManager.getInstance().getWorldRegions(world).forEach(fgObject -> { - String name = fgObject.getName(); - if (fgObject.autoSave()) { - Path singleDir = dir.resolve(name.toLowerCase()); - boolean shouldSave = fgObject.shouldSave(); - if (force || shouldSave) { - logger.info((shouldSave ? "S" : "Force s") + "aving world region \"" + name + "\" in directory: " + singleDir); - constructDirectory(singleDir); - try { - fgObject.save(singleDir); - } catch (Exception e) { - logger.error("There was an error while saving world region \"" + name + "\" in world \"" + world.getName() + "\"!", e); - } - - logger.info("Saving metadata for world region \"" + name + "\""); - try (DB metaDB = DBMaker.fileDB(singleDir.resolve("metadata.foxdb").normalize().toString()).make()) { - Atomic.String metaName = metaDB.atomicString("name").createOrOpen(); - Atomic.String metaCategory = metaDB.atomicString("category").createOrOpen(); - Atomic.String metaType = metaDB.atomicString("type").createOrOpen(); - Atomic.Boolean metaEnabled = metaDB.atomicBoolean("enabled").createOrOpen(); - metaName.set(name); - metaCategory.set(FGUtil.getCategory(fgObject)); - metaType.set(fgObject.getUniqueTypeString()); - metaEnabled.set(fgObject.isEnabled()); - } - } else { - logger.info("Region \"" + name + "\" is already up to date. Skipping..."); - } - - mainMap.put(name, FGUtil.getCategory(fgObject)); - typeMap.put(name, fgObject.getUniqueTypeString()); - enabledMap.put(name, fgObject.isEnabled()); - - defaultModifiedMap.put(fgObject, false); - } else { - logger.info("World region " + fgObject.getName() + " does not need saving. Skipping..."); - } - if (fgObject.saveLinks()) { - linksMap.put(name, serializeHandlerList(fgObject.getHandlers())); - } else { - logger.info("World region " + fgObject.getName() + " does not need its links saved. Skipping..."); - } - }); - } catch (DBException.DataCorruption e) { - try { - FoxGuardMain.instance().getLogger().error("Database file \"" + dbFile + "\" appears to be corrupted:", e); - FoxGuardMain.instance().getLogger().error("Deleting the database file and trying again"); - Files.deleteIfExists(dbFile); - saveWorldRegions(world, force); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - } - - public void saveHandlers() { - saveHandlers(false); - } - - public synchronized void saveHandlers(boolean force) { - logger.info("Saving handlers" + (force ? " (forced save)" : "")); - Path dbFile = directory.resolve("handlers.foxdb").normalize(); - try (DB mainDB = DBMaker.fileDB(dbFile.toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map priorityMap = mainDB.hashMap("priority", Serializer.STRING, Serializer.INTEGER).createOrOpen(); - - mainMap.clear(); - - Path dir = directory.resolve("handlers"); - constructDirectory(dir); - FGManager.getInstance().getHandlers().forEach(fgObject -> { - if (fgObject.autoSave()) { - String name = fgObject.getName(); - Path singleDir = dir.resolve(name.toLowerCase()); - boolean shouldSave = fgObject.shouldSave(); - if (force || shouldSave) { - logger.info((shouldSave ? "S" : "Force s") + "aving handler \"" + name + "\" in directory: " + singleDir); - constructDirectory(singleDir); - try { - fgObject.save(singleDir); - } catch (Exception e) { - logger.error("There was an error while saving handler \"" + name + "\"!", e); - } - - logger.info("Saving metadata for handler \"" + name + "\""); - try (DB metaDB = DBMaker.fileDB(singleDir.resolve("metadata.foxdb").normalize().toString()).make()) { - Atomic.String metaName = metaDB.atomicString("name").createOrOpen(); - Atomic.String metaCategory = metaDB.atomicString("category").createOrOpen(); - Atomic.String metaType = metaDB.atomicString("type").createOrOpen(); - Atomic.Boolean metaEnabled = metaDB.atomicBoolean("enabled").createOrOpen(); - Atomic.Integer metaPriority = metaDB.atomicInteger("priority").createOrOpen(); - metaName.set(name); - metaCategory.set(FGUtil.getCategory(fgObject)); - metaType.set(fgObject.getUniqueTypeString()); - metaEnabled.set(fgObject.isEnabled()); - metaPriority.set(fgObject.getPriority()); - } - } else { - logger.info("Region \"" + name + "\" is already up to date. Skipping..."); - } - - mainMap.put(name, FGUtil.getCategory(fgObject)); - typeMap.put(name, fgObject.getUniqueTypeString()); - enabledMap.put(name, fgObject.isEnabled()); - priorityMap.put(name, fgObject.getPriority()); - - defaultModifiedMap.put(fgObject, false); - } else { - logger.info("Handler " + fgObject.getName() + " does not need saving. Skipping..."); - } - }); - } catch (DBException.DataCorruption e) { - try { - FoxGuardMain.instance().getLogger().error("Database file \"" + dbFile + "\" appears to be corrupted:", e); - FoxGuardMain.instance().getLogger().error("Deleting the database file and trying again"); - Files.deleteIfExists(dbFile); - saveHandlers(force); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - } - - public void saveRegion(IRegion fgObject) { - saveRegion(fgObject, false); - } - - public synchronized void saveRegion(IRegion fgObject, boolean force) { - if (fgObject instanceof IWorldRegion) saveWorldRegion((IWorldRegion) fgObject, force); - else { - Path dbFile = directory.resolve("regions.foxdb").normalize(); - try (DB mainDB = DBMaker.fileDB(dbFile.toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map linksMap = mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen(); - - Path dir = directory.resolve("regions"); - constructDirectory(dir); - String name = fgObject.getName(); - if (fgObject.autoSave()) { - Path singleDir = dir.resolve(name.toLowerCase()); - boolean shouldSave = fgObject.shouldSave(); - if (force || shouldSave) { - logger.info((shouldSave ? "S" : "Force s") + "aving region \"" + name + "\" in directory: " + singleDir); - constructDirectory(singleDir); - try { - fgObject.save(singleDir); - } catch (Exception e) { - logger.error("There was an error while saving region \"" + name + "\"!", e); - } - - logger.info("Saving metadata for region \"" + name + "\""); - try (DB metaDB = DBMaker.fileDB(singleDir.resolve("metadata.foxdb").normalize().toString()).make()) { - Atomic.String metaName = metaDB.atomicString("name").createOrOpen(); - Atomic.String metaCategory = metaDB.atomicString("category").createOrOpen(); - Atomic.String metaType = metaDB.atomicString("type").createOrOpen(); - Atomic.Boolean metaEnabled = metaDB.atomicBoolean("enabled").createOrOpen(); - metaName.set(name); - metaCategory.set(FGUtil.getCategory(fgObject)); - metaType.set(fgObject.getUniqueTypeString()); - metaEnabled.set(fgObject.isEnabled()); - } - } else { - logger.info("Region \"" + name + "\" is already up to date. Skipping..."); - } - mainMap.put(name, FGUtil.getCategory(fgObject)); - typeMap.put(name, fgObject.getUniqueTypeString()); - enabledMap.put(name, fgObject.isEnabled()); - - defaultModifiedMap.put(fgObject, false); - } else { - logger.info("Region " + fgObject.getName() + " does not need saving. Skipping..."); - } - if (fgObject.saveLinks()) { - linksMap.put(name, serializeHandlerList(fgObject.getHandlers())); - } else { - logger.info("Region " + fgObject.getName() + " does not need its links saved. Skipping..."); - } - } catch (DBException.DataCorruption e) { - try { - FoxGuardMain.instance().getLogger().error("Database file \"" + dbFile + "\" appears to be corrupted:", e); - FoxGuardMain.instance().getLogger().error("Deleting the database file and trying again"); - Files.deleteIfExists(dbFile); - saveRegions(); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - } - } - - public void saveWorldRegion(IWorldRegion fgObject) { - saveWorldRegion(fgObject, false); - } - - public synchronized void saveWorldRegion(IWorldRegion fgObject, boolean force) { - World world = fgObject.getWorld(); - Path dbFile = worldDirectories.get(world.getName()).resolve("wregions.foxdb").normalize(); - try (DB mainDB = DBMaker.fileDB(dbFile.toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map linksMap = mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen(); - - Path dir = worldDirectories.get(world.getName()).resolve("wregions"); - constructDirectory(dir); - String name = fgObject.getName(); - if (fgObject.autoSave()) { - Path singleDir = dir.resolve(name.toLowerCase()); - boolean shouldSave = fgObject.shouldSave(); - if (force || shouldSave) { - logger.info((shouldSave ? "S" : "Force s") + "aving world region \"" + name + "\" in directory: " + singleDir); - constructDirectory(singleDir); - try { - fgObject.save(singleDir); - } catch (Exception e) { - logger.error("There was an error while saving world region \"" + name + "\" in world \"" + world.getName() + "\"!", e); - } - - logger.info("Saving metadata for world region \"" + name + "\""); - try (DB metaDB = DBMaker.fileDB(singleDir.resolve("metadata.foxdb").normalize().toString()).make()) { - Atomic.String metaName = metaDB.atomicString("name").createOrOpen(); - Atomic.String metaCategory = metaDB.atomicString("category").createOrOpen(); - Atomic.String metaType = metaDB.atomicString("type").createOrOpen(); - Atomic.Boolean metaEnabled = metaDB.atomicBoolean("enabled").createOrOpen(); - metaName.set(name); - metaCategory.set(FGUtil.getCategory(fgObject)); - metaType.set(fgObject.getUniqueTypeString()); - metaEnabled.set(fgObject.isEnabled()); - } - } else { - logger.info("Region \"" + name + "\" is already up to date. Skipping..."); - } - - mainMap.put(name, FGUtil.getCategory(fgObject)); - typeMap.put(name, fgObject.getUniqueTypeString()); - enabledMap.put(name, fgObject.isEnabled()); - - defaultModifiedMap.put(fgObject, false); - } else { - logger.info("World region " + fgObject.getName() + " does not need saving. Skipping..."); - } - if (fgObject.saveLinks()) { - linksMap.put(name, serializeHandlerList(fgObject.getHandlers())); - } else { - logger.info("World region " + fgObject.getName() + " does not need its links saved. Skipping..."); - } - } catch (DBException.DataCorruption e) { - try { - FoxGuardMain.instance().getLogger().error("Database file \"" + dbFile + "\" appears to be corrupted:", e); - FoxGuardMain.instance().getLogger().error("Deleting the database file and trying again"); - Files.deleteIfExists(dbFile); - saveWorldRegions(fgObject.getWorld()); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - } - - public void saveHandler(IHandler fgObject) { - saveHandler(fgObject, false); - } - - public synchronized void saveHandler(IHandler fgObject, boolean force) { - Path dbFile = directory.resolve("handlers.foxdb").normalize(); - try (DB mainDB = DBMaker.fileDB(dbFile.toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map priorityMap = mainDB.hashMap("priority", Serializer.STRING, Serializer.INTEGER).createOrOpen(); - - Path dir = directory.resolve("handlers"); - constructDirectory(dir); - if (fgObject.autoSave()) { - String name = fgObject.getName(); - Path singleDir = dir.resolve(name.toLowerCase()); - boolean shouldSave = fgObject.shouldSave(); - if (force || shouldSave) { - logger.info((shouldSave ? "S" : "Force s") + "aving handler \"" + name + "\" in directory: " + singleDir); - constructDirectory(singleDir); - try { - fgObject.save(singleDir); - } catch (Exception e) { - logger.error("There was an error while saving handler \"" + name + "\"!", e); - } - - logger.info("Saving metadata for handler \"" + name + "\""); - try (DB metaDB = DBMaker.fileDB(singleDir.resolve("metadata.foxdb").normalize().toString()).make()) { - Atomic.String metaName = metaDB.atomicString("name").createOrOpen(); - Atomic.String metaCategory = metaDB.atomicString("category").createOrOpen(); - Atomic.String metaType = metaDB.atomicString("type").createOrOpen(); - Atomic.Boolean metaEnabled = metaDB.atomicBoolean("enabled").createOrOpen(); - Atomic.Integer metaPriority = metaDB.atomicInteger("priority").createOrOpen(); - metaName.set(name); - metaCategory.set(FGUtil.getCategory(fgObject)); - metaType.set(fgObject.getUniqueTypeString()); - metaEnabled.set(fgObject.isEnabled()); - metaPriority.set(fgObject.getPriority()); - } - } else { - logger.info("Region \"" + name + "\" is already up to date. Skipping..."); - } - - mainMap.put(name, FGUtil.getCategory(fgObject)); - typeMap.put(name, fgObject.getUniqueTypeString()); - enabledMap.put(name, fgObject.isEnabled()); - priorityMap.put(name, fgObject.getPriority()); - - defaultModifiedMap.put(fgObject, false); - } else { - logger.info("Handler " + fgObject.getName() + " does not need saving. Skipping..."); - } - } catch (DBException.DataCorruption e) { - try { - FoxGuardMain.instance().getLogger().error("Database file \"" + dbFile + "\" appears to be corrupted:", e); - FoxGuardMain.instance().getLogger().error("Deleting the database file and trying again"); - Files.deleteIfExists(dbFile); - saveHandlers(); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - } - - public synchronized void removeRegion(IRegion fgObject) { - if (fgObject instanceof IWorldRegion) removeWorldRegion((IWorldRegion) fgObject); - else try (DB mainDB = DBMaker.fileDB(directory.resolve("regions.foxdb").normalize().toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map linksMap = mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen(); - - mainMap.remove(fgObject.getName()); - typeMap.remove(fgObject.getName()); - enabledMap.remove(fgObject.getName()); - linksMap.remove(fgObject.getName()); - } catch (DBException.DataCorruption e) { - try { - Files.deleteIfExists(directory.resolve("regions.foxdb")); - saveRegions(); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - if (FGConfigManager.getInstance().cleanupFiles()) { - Path singleDir = new LoadEntry(fgObject).getPath(); - if (Files.exists(singleDir)) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } - - public synchronized void removeWorldRegion(IWorldRegion fgObject) { - try (DB mainDB = DBMaker.fileDB(worldDirectories.get(fgObject.getWorld().getName()).resolve("wregions.foxdb").normalize().toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map linksMap = mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen(); - - mainMap.remove(fgObject.getName()); - typeMap.remove(fgObject.getName()); - enabledMap.remove(fgObject.getName()); - linksMap.remove(fgObject.getName()); - } catch (DBException.DataCorruption e) { - try { - Files.deleteIfExists(directory.resolve("regions.foxdb")); - saveWorldRegions(fgObject.getWorld()); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - if (FGConfigManager.getInstance().cleanupFiles()) { - Path singleDir = new LoadEntry(fgObject).getPath(); - if (Files.exists(singleDir)) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } - - public synchronized void removeHandler(IHandler fgObject) { - try (DB mainDB = DBMaker.fileDB(directory.resolve("handlers.foxdb").normalize().toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map priorityMap = mainDB.hashMap("priority", Serializer.STRING, Serializer.INTEGER).createOrOpen(); - - mainMap.remove(fgObject.getName()); - typeMap.remove(fgObject.getName()); - enabledMap.remove(fgObject.getName()); - priorityMap.remove(fgObject.getName()); - } catch (DBException.DataCorruption e) { - try { - Files.deleteIfExists(directory.resolve("regions.foxdb")); - saveHandlers(); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - if (FGConfigManager.getInstance().cleanupFiles()) { - Path singleDir = new LoadEntry(fgObject).getPath(); - if (Files.exists(singleDir)) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } - - public synchronized void loadRegions() { - Path dbFile = directory.resolve("regions.foxdb").normalize(); - try (DB mainDB = DBMaker.fileDB(dbFile.toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - - Path dir = directory.resolve("regions"); - mainMap.entrySet().forEach((entry) -> { - String name = entry.getKey(); - Path singleDir = dir.resolve(name.toLowerCase()); - Path metaDataFile = singleDir.resolve("metadata.foxdb"); - logger.info("Loading region \"" + name + "\" from " + singleDir); - if (Files.exists(metaDataFile) && !Files.isDirectory(metaDataFile)) { - String category; - String type; - Boolean enabled; - try (DB metaDB = DBMaker.fileDB(metaDataFile.normalize().toString()).make()) { - category = metaDB.exists("category") ? metaDB.atomicString("category").createOrOpen().get() : entry.getValue(); - type = metaDB.exists("type") ? metaDB.atomicString("type").createOrOpen().get() : typeMap.get(name); - enabled = metaDB.exists("enabled") ? metaDB.atomicBoolean("enabled").createOrOpen().get() : enabledMap.get(name); - } - logger.info("Region info loaded! Name: \"" + name + - "\", Category: \"" + category + - "\", Type: \"" + type + - "\", Enabled: " + enabled); - if (name.equalsIgnoreCase(GlobalRegion.NAME)) { - logger.info("Global region found! Skipping..."); - return; - } - if (!FGManager.getInstance().isRegionNameAvailable(name)) { - logger.error("Name conflict detected! \"" + name + "\" is already in use! A world region is likely already using that name."); - if (FGConfigManager.getInstance().cleanupFiles()) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - if (category == null) category = ""; - if (type == null) type = ""; - IRegion object = null; - try { - if (category.equalsIgnoreCase("region")) - object = FGFactoryManager.getInstance().createRegion(singleDir, name, type, enabled); - else logger.warn("Category \"" + category + "\" is invalid!"); - } catch (Exception e) { - logger.error("There was an error creating the region!", e); - } - if (object != null) { - loaded.add(new LoadEntry(object)); - FGManager.getInstance().addRegion(object); - logger.info("Successfully created and added region \"" + name + "\"!"); - } else { - logger.warn("A region was unable to be created. Either the metadata is incorrect, or there is no longer a factory available to create it."); - if (FGConfigManager.getInstance().cleanupFiles()) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } else { - logger.warn("Metadata file not found! Skipping..."); - if (Files.exists(singleDir)) { - if (isEmptyDirectory(singleDir)) { - logger.warn("Empty region directory found. Deleting..."); - try { - Files.delete(singleDir); - } catch (IOException e) { - logger.error("There was an error deleting the region directory: " + singleDir, e); - } - } else { - if (FGConfigManager.getInstance().cleanupFiles()) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } - } - }); - } catch (DBException.DataCorruption e) { - try { - FoxGuardMain.instance().getLogger().error("Database file \"" + dbFile + "\" appears to be corrupted:", e); - FoxGuardMain.instance().getLogger().error("Deleting the database file"); - Files.deleteIfExists(dbFile); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - } - - public synchronized void loadWorldRegions(World world) { - Path dbFile = worldDirectories.get(world.getName()).resolve("wregions.foxdb").normalize(); - try (DB mainDB = DBMaker.fileDB(dbFile.toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - - Path dir = worldDirectories.get(world.getName()).resolve("wregions"); - mainMap.entrySet().forEach((entry) -> { - String name = entry.getKey(); - Path singleDir = dir.resolve(name.toLowerCase()); - Path metaDataFile = singleDir.resolve("metadata.foxdb"); - logger.info("Loading world region \"" + name + "\" from " + singleDir); - if (Files.exists(metaDataFile) && !Files.isDirectory(metaDataFile)) { - String category; - String type; - Boolean enabled; - try (DB metaDB = DBMaker.fileDB(metaDataFile.normalize().toString()).make()) { - category = metaDB.exists("category") ? metaDB.atomicString("category").createOrOpen().get() : entry.getValue(); - type = metaDB.exists("type") ? metaDB.atomicString("type").createOrOpen().get() : typeMap.get(name); - enabled = metaDB.exists("enabled") ? metaDB.atomicBoolean("enabled").createOrOpen().get() : enabledMap.get(name); - } - logger.info("World region info loaded! Name: \"" + name + - "\", Category: \"" + category + - "\", Type: \"" + type + - "\", Enabled: " + enabled); - if (category == null) category = ""; - if (type == null) type = ""; - if (name.equalsIgnoreCase(GlobalWorldRegion.NAME) || type.equals(GlobalWorldRegion.TYPE)) { - logger.info("Global world region found! Skipping..."); - return; - } - if (!FGManager.getInstance().isWorldRegionNameAvailable(name, world)) { - logger.error("Name conflict detected! \"" + name + "\" is already in use! A super region is likely already using that name."); - if (FGConfigManager.getInstance().cleanupFiles()) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - IWorldRegion object = null; - try { - if (category.equalsIgnoreCase("worldregion")) - object = FGFactoryManager.getInstance().createWorldRegion(singleDir, name, type, enabled); - else logger.warn("Category \"" + category + "\" is invalid!"); - } catch (Exception e) { - logger.error("There was an error creating the world region!", e); - } - if (object != null) { - loaded.add(new LoadEntry(object, world.getName())); - FGManager.getInstance().addWorldRegion(world, object); - logger.info("Successfully created and added world region \"" + name + "\"!"); - } else { - logger.warn("A world region was unable to be created. Either the metadata is incorrect, or there is no longer a factory available to create it."); - if (FGConfigManager.getInstance().cleanupFiles()) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } else { - logger.warn("Metadata file not found! Skipping..."); - if (Files.exists(singleDir)) { - if (isEmptyDirectory(singleDir)) { - logger.warn("Empty world region directory found. Deleting..."); - try { - Files.delete(singleDir); - } catch (IOException e) { - logger.error("There was an error deleting the world region directory: " + singleDir, e); - } - } else { - if (FGConfigManager.getInstance().cleanupFiles()) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } - } - }); - } catch (DBException.DataCorruption e) { - try { - FoxGuardMain.instance().getLogger().error("Database file \"" + dbFile + "\" appears to be corrupted:", e); - FoxGuardMain.instance().getLogger().error("Deleting the database file"); - Files.deleteIfExists(dbFile); - } catch (IOException e1) { - e1.printStackTrace(); - } - } - } - - public synchronized void loadHandlers() { - try (DB mainDB = DBMaker.fileDB(directory.resolve("handlers.foxdb").normalize().toString()).make()) { - Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); - Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); - Map priorityMap = mainDB.hashMap("priority", Serializer.STRING, Serializer.INTEGER).createOrOpen(); - - Path dir = directory.resolve("handlers"); - mainMap.entrySet().forEach((entry) -> { - String name = entry.getKey(); - Path singleDir = dir.resolve(name.toLowerCase()); - Path metaDataFile = singleDir.resolve("metadata.foxdb"); - logger.info("Loading handler \"" + name + "\" from " + singleDir); - if (Files.exists(metaDataFile) && !Files.isDirectory(metaDataFile)) { - String category; - String type; - Boolean enabled; - Integer priority; - try (DB metaDB = DBMaker.fileDB(metaDataFile.normalize().toString()).make()) { - category = metaDB.exists("category") ? metaDB.atomicString("category").createOrOpen().get() : entry.getValue(); - type = metaDB.exists("type") ? metaDB.atomicString("type").createOrOpen().get() : typeMap.get(name); - enabled = metaDB.exists("enabled") ? metaDB.atomicBoolean("enabled").createOrOpen().get() : enabledMap.get(name); - priority = metaDB.exists("priority") ? metaDB.atomicInteger("priority").createOrOpen().get() : priorityMap.get(name); - } - logger.info("Handler info loaded! Name: \"" + name + - "\", Category: \"" + category + - "\", Type: \"" + type + - "\", Enabled: " + enabled + - ", Priority: " + priority); - if (name.equalsIgnoreCase(GlobalHandler.NAME)) { - logger.info("Global handler found! Skipping..."); - return; - } - if (category == null) category = ""; - if (type == null) type = ""; - IHandler object = null; - try { - if (category.equalsIgnoreCase("handler")) - object = FGFactoryManager.getInstance().createHandler(singleDir, name, type, enabled, priority); - else if (category.equalsIgnoreCase("controller")) - object = FGFactoryManager.getInstance().createController(singleDir, name, type, enabled, priority); - else logger.warn("Category \"" + category + "\" is invalid!"); - } catch (Exception e) { - logger.error("There was an error creating the handler!", e); - } - if (object != null) { - loaded.add(new LoadEntry(object)); - FGManager.getInstance().addHandler(object); - logger.info("Successfully created and added handler \"" + name + "\"!"); - } else { - logger.warn("A handler was unable to be created. Either the metadata is incorrect, or there is no longer a factory available to create it."); - if (FGConfigManager.getInstance().cleanupFiles()) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } else { - if (name.equalsIgnoreCase(GlobalHandler.NAME)) { - logger.info("Global handler found! Skipping..."); - return; - } - logger.warn("Metadata file not found! Skipping..."); - if (Files.exists(singleDir)) { - if (isEmptyDirectory(singleDir)) { - logger.warn("Empty handler directory found. Deleting..."); - try { - Files.delete(singleDir); - } catch (IOException e) { - logger.error("There was an error deleting the handler directory: " + singleDir, e); - } - } else { - if (FGConfigManager.getInstance().cleanupFiles()) { - logger.warn("Cleaning up unused files"); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDir); - } - } - } - } - }); - } - } - - public synchronized void loadGlobalHandler() { - Path path; - constructDirectory(path = directory.resolve("handlers")); - constructDirectory(path = path.resolve(GlobalHandler.NAME.toLowerCase())); - FGManager.getInstance().getGlobalHandler().load(path); - } - - public void loadLinks() { - loadRegionLinks(); - Sponge.getServer().getWorlds().forEach(this::loadWorldRegionLinks); - loadControllerLinks(); - } - - public synchronized void loadRegionLinks() { - logger.info("Loading region links"); - try (DB mainDB = DBMaker.fileDB(directory.resolve("regions.foxdb").normalize().toString()).make()) { - Map linksMap = mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen(); - linksMap.entrySet().forEach(entry -> { - IRegion region = FGManager.getInstance().getRegion(entry.getKey()); - if (region != null) { - logger.info("Loading links for region \"" + region.getName() + "\""); - String handlersString = entry.getValue(); - if (handlersString != null && !handlersString.isEmpty()) { - String[] handlersNames = handlersString.split(","); - Arrays.stream(handlersNames).forEach(handlerName -> { - IHandler handler = FGManager.getInstance().gethandler(handlerName); - if (handler != null) { - if (FGManager.getInstance().link(region, handler)) - logger.info("Linked region \"" + region.getName() + "\" to handler \"" + handler.getName() + "\""); - } - }); - } - } - }); - } - } - - public synchronized void loadWorldRegionLinks(World world) { - logger.info("Loading world region links for world \"" + world.getName() + "\""); - try (DB mainDB = DBMaker.fileDB(worldDirectories.get(world.getName()).resolve("wregions.foxdb").normalize().toString()).make()) { - Map linksMap = mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen(); - linksMap.entrySet().forEach(entry -> { - IRegion region = FGManager.getInstance().getWorldRegion(world, entry.getKey()); - if (region != null) { - logger.info("Loading links for world region \"" + region.getName() + "\""); - String handlersString = entry.getValue(); - if (handlersString != null && !handlersString.isEmpty()) { - String[] handlersNames = handlersString.split(","); - Arrays.stream(handlersNames).forEach(handlerName -> { - IHandler handler = FGManager.getInstance().gethandler(handlerName); - if (handler != null) { - if (FGManager.getInstance().link(region, handler)) - logger.info("Linked world region \"" + region.getName() + "\" to handler \"" + handler.getName() + "\""); - } - }); - } - } - }); - } - } - - public synchronized void loadControllerLinks() { - logger.info("Loading controller links"); - Path dir = directory.resolve("handlers"); - for (IController controller : FGManager.getInstance().getControllers()) { - logger.info("Loading links for controller \"" + controller.getName() + "\""); - controller.loadLinks(dir.resolve(controller.getName().toLowerCase())); - } - } - - public synchronized void addObject(IFGObject object) { - LoadEntry entry = new LoadEntry(object); - if (!loaded.contains(entry)) { - Path singleDirectory = entry.getPath(); - if (Files.exists(singleDirectory)) { - logger.info("Deleting directory \"" + singleDirectory + "\" to make room for new data."); - System.gc(); - System.runFinalization(); - deleteDirectory(singleDirectory, true); - } - loaded.add(entry); - if (object instanceof IRegion) { - if (object instanceof IWorldRegion) { - this.saveWorldRegion((IWorldRegion) object, true); - } else { - this.saveRegion((IRegion) object, true); - } - } else if (object instanceof IHandler) { - this.saveHandler((IHandler) object, true); - } - } - } - - public void removeObject(IFGObject object) { - if (object instanceof IRegion) { - if (object instanceof IWorldRegion) { - this.removeWorldRegion((IWorldRegion) object); - } else { - this.removeRegion((IRegion) object); - } - } else if (object instanceof IHandler) { - this.removeHandler((IHandler) object); - } - } - - public void constructDirectory(Path directory) { - if (!Files.exists(directory)) { - try { - int counter = 1; - while (true) { - try { - Files.createDirectory(directory); - break; - } catch (AccessDeniedException e) { - if (counter > 5) throw e; - else { - logger.error("Unable to create directory: " + directory + " Trying again in " + counter + " second(s)"); - try { - Thread.sleep(1000 * counter); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - } - } - counter++; - } - logger.info("Created directory: " + directory); - } catch (IOException e) { - logger.error("There was an error creating the directory: " + directory, e); - } - } else if (!Files.isDirectory(directory)) { - logger.warn("There is a file at " + directory + " where a directory was expected. Deleting and replacing with a directory..."); - try { - Files.delete(directory); - try { - int counter = 1; - while (true) { - try { - Files.createDirectory(directory); - break; - } catch (AccessDeniedException e) { - if (counter > 5) throw e; - else { - logger.error("Unable to create directory: " + directory + " Trying again in " + counter + " second(s)"); - try { - Thread.sleep(1000 * counter); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - } - } - counter++; - } - logger.info("Created directory: " + directory); - } catch (IOException e) { - logger.error("Error creating the directory: " + directory, e); - } - } catch (IOException e) { - logger.error("Error deleting the file: " + directory, e); - } - } - } - - private Path getDirectory() { - Path path = Sponge.getGame().getSavesDirectory(); - if (FGConfigManager.getInstance().saveInWorldFolder()) { - path = path.resolve(Sponge.getServer().getDefaultWorldName()); - } else if (FGConfigManager.getInstance().useConfigFolder()) { - path = FoxGuardMain.instance().getConfigDirectory(); - } - path = path.resolve("foxguard"); - constructDirectory(path); - return path; - } - - private Path getWorldDirectory(String world) { - Path path = Sponge.getGame().getSavesDirectory(); - if (FGConfigManager.getInstance().saveWorldRegionsInWorldFolders()) { - path = path.resolve(Sponge.getServer().getDefaultWorldName()); - if (!Sponge.getServer().getDefaultWorld().get().getWorldName().equalsIgnoreCase(world)) { - path = path.resolve(world); - } - path = path.resolve("foxguard"); - } else { - if (FGConfigManager.getInstance().useConfigFolder()) { - path = FoxGuardMain.instance().getConfigDirectory(); - } - path = path.resolve("foxguard").resolve("worlds").resolve(world); - } - constructDirectory(path); - return path; - } - - private void deleteDirectory(Path directory) { - deleteDirectory(directory, false); - } - - private void deleteDirectory(Path directory, boolean innerOnly) { - FoxGuardMain.instance().getLogger().info("Deleting directory: " + directory); - if (Files.exists(directory) && Files.isDirectory(directory)) - try { - Files.walkFileTree(directory, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - try { - Files.delete(file); - logger.info("Deleted file: " + file); - } catch (IOException e) { - logger.error("There was an error deleting the file: " + file, e); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - if (exc == null && (!innerOnly || !Files.isSameFile(dir, directory))) { - try { - Files.delete(dir); - logger.info("Deleted directory: " + dir); - } catch (IOException e) { - logger.error("There was an error deleting the directory: " + dir, e); - } - } - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - logger.error("There was an error while trying to recursively delete the directory: " + directory, e); - } - else if (Files.exists(directory)) { - logger.warn(directory + "is a file. A directory was expected. Deleting..."); - try { - Files.delete(directory); - } catch (IOException e) { - logger.error("There was an error deleting the file: " + directory, e); - } - } - } - - private boolean isEmptyDirectory(Path directory) { - if (!Files.exists(directory)) return true; - if (!Files.isDirectory(directory)) return false; - try { - DirectoryStream stream = Files.newDirectoryStream(directory); - return !stream.iterator().hasNext(); - } catch (IOException e) { - logger.error("Could not read contents of directory: " + directory, e); - return false; - } - } - - private String serializeHandlerList(Collection handlers) { - StringBuilder builder = new StringBuilder(); - for (Iterator it = handlers.iterator(); it.hasNext(); ) { - builder.append(it.next().getName()); - if (it.hasNext()) builder.append(","); - } - return builder.toString(); - } - - private final class LoadEntry { - public final String name; - public final Type type; - public final String world; - - public LoadEntry(String name, Type type, String world) { - this.name = name; - this.type = type; - this.world = world; - } - - public LoadEntry(IFGObject object) { - name = object.getName(); - if (object instanceof IWorldRegion) { - type = Type.WREGION; - world = ((IWorldRegion) object).getWorld().getName(); - } else if (object instanceof IRegion) { - type = Type.REGION; - world = ""; - } else if (object instanceof IHandler) { - type = Type.HANDLER; - world = ""; - } else throw new IllegalArgumentException("Object is not of a valid subtype!"); - } - - public LoadEntry(IFGObject object, String altWorld) { - name = object.getName(); - if (object instanceof IWorldRegion) { - type = Type.WREGION; - world = altWorld; - } else if (object instanceof IRegion) { - type = Type.REGION; - world = ""; - } else if (object instanceof IHandler) { - type = Type.HANDLER; - world = ""; - } else throw new IllegalArgumentException("Object is not of a valid subtype!"); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - LoadEntry entry = (LoadEntry) o; - - if (name != null ? !name.equals(entry.name) : entry.name != null) return false; - if (type != entry.type) return false; - return world != null ? world.equals(entry.world) : entry.world == null; - - } - - @Override - public int hashCode() { - int result = name != null ? name.hashCode() : 0; - result = 31 * result + (type != null ? type.hashCode() : 0); - result = 31 * result + (world != null ? world.hashCode() : 0); - return result; - } - - public Path getPath() { - Path singleDirectory; - switch (this.type) { - case REGION: - singleDirectory = directory.resolve("regions"); - break; - case WREGION: - singleDirectory = worldDirectories.get(this.world).resolve("wregions"); - break; - case HANDLER: - singleDirectory = directory.resolve("handlers"); - break; - default: - singleDirectory = null; - break; - } - return singleDirectory.resolve(this.name.toLowerCase()); - } - } - - public enum Type { - REGION, WREGION, HANDLER - } -} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FoxGuardMain.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FoxGuardMain.java index b29dd78..dfb4627 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FoxGuardMain.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/FoxGuardMain.java @@ -50,6 +50,8 @@ import net.foxdenstudio.sponge.foxguard.plugin.state.factory.ControllersStateFieldFactory; import net.foxdenstudio.sponge.foxguard.plugin.state.factory.HandlersStateFieldFactory; import net.foxdenstudio.sponge.foxguard.plugin.state.factory.RegionsStateFieldFactory; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGStorageManagerNew; +import net.foxdenstudio.sponge.foxguard.plugin.util.DebugManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongepowered.api.Game; @@ -61,9 +63,9 @@ import org.spongepowered.api.event.block.ChangeBlockEvent; import org.spongepowered.api.event.block.InteractBlockEvent; import org.spongepowered.api.event.cause.Cause; +import org.spongepowered.api.event.cause.EventContext; import org.spongepowered.api.event.entity.DamageEntityEvent; import org.spongepowered.api.event.entity.InteractEntityEvent; -import org.spongepowered.api.event.entity.MoveEntityEvent; import org.spongepowered.api.event.entity.SpawnEntityEvent; import org.spongepowered.api.event.game.state.*; import org.spongepowered.api.event.world.ExplosionEvent; @@ -74,11 +76,10 @@ import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.service.economy.EconomyService; import org.spongepowered.api.service.permission.PermissionService; -import org.spongepowered.api.service.permission.SubjectData; import org.spongepowered.api.service.user.UserStorageService; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; -import org.spongepowered.api.util.Tristate; +import org.spongepowered.api.world.World; import javax.annotation.Nullable; import java.nio.file.Path; @@ -97,14 +98,15 @@ url = "https://github.com/FoxDenStudio/FoxGuard") public final class FoxGuardMain { - public final Cause pluginCause = Cause.builder().named("plugin", this).build(); + public static final String LOGGER_NAME = FoxCoreMain.FOX_BASE_LOGGER_NAME + ".guard"; + public final Cause pluginCause = Cause.builder().append(this).build(EventContext.empty()); /** * FoxGuardMain instance object. */ private static FoxGuardMain instanceField; - private Logger logger = LoggerFactory.getLogger("fox.guard"); + private Logger logger = LoggerFactory.getLogger(LOGGER_NAME); @Inject private Game game; @@ -140,7 +142,11 @@ public static FoxGuardMain instance() { return instanceField; } - //my uuid - f275f223-1643-4fac-9fb8-44aaf5b4b371 + // my uuid - f275f223-1643-4fac-9fb8-44aaf5b4b371 + + public static Cause getCause() { + return instance().pluginCause; + } @Listener public void construct(GameConstructionEvent event) { @@ -229,7 +235,7 @@ public void registerCommands(GameInitializationEvent event) { fgDispatcher.register(new CommandCreate(), "create", "construct", "new", "make", "define", "mk", "cr"); fgDispatcher.register(new CommandDelete(), "delete", "del", "remove", "rem", "rm", "destroy"); fgDispatcher.register(new CommandModify(), "modify", "mod", "change", "edit", "update", "md", "ch"); - fgDispatcher.register(new CommandRename(), "rename", "name", "rn"); + fgDispatcher.register(new CommandMove(), "move", "mv", "rename", "name", "rn"); fgDispatcher.register(new CommandLink(), "link", "connect", "attach"); fgDispatcher.register(new CommandUnlink(), "unlink", "disconnect", "detach"); fgDispatcher.register(new CommandEnableDisable(true), "enable", "activate", "engage", "on"); @@ -241,9 +247,14 @@ public void registerCommands(GameInitializationEvent event) { fgDispatcher.register(new CommandPriority(), "priority", "prio", "level", "rank"); - fgDispatcher.register(new CommandTest(), "test"); fgDispatcher.register(new CommandLink2(true), "link2", "connect2", "attach2"); fgDispatcher.register(new CommandLink2(false), "unlink2", "disconnect2", "detach2"); + + // DEBUG USE + fgDispatcher.register(new CommandTest(), "test"); + fgDispatcher.register(DebugManager.INSTANCE, "debug"); + + registerCoreCommands(fgDispatcher); game.getCommandManager().register(this, fgDispatcher, "foxguard", "foxg", "fguard", "fg"); @@ -261,35 +272,26 @@ public void setupEconomy(GamePostInitializationEvent event) { public void configurePermissions(GamePostInitializationEvent event) { logger.info("Configuring permissions"); PermissionService service = game.getServiceManager().provide(PermissionService.class).get(); - service.getDefaults().getTransientSubjectData().setPermission(SubjectData.GLOBAL_CONTEXT, "foxguard.override", Tristate.FALSE); + //service.getDefaults().getTransientSubjectData().setPermission(SubjectData.GLOBAL_CONTEXT, "foxguard.override", Tristate.FALSE); service.registerContextCalculator(new FGContextCalculator()); } - @Listener - public void serverStarting(GameStartingServerEvent event) { - if (managerOk) { - logger.info("Loading regions"); - FGStorageManager.getInstance().loadRegions(); - logger.info("Loading global handler"); - FGStorageManager.getInstance().loadGlobalHandler(); - logger.info("Loading handlers"); - FGStorageManager.getInstance().loadHandlers(); - logger.info("Loading linkages"); - FGStorageManager.getInstance().loadLinks(); - loaded = true; - logger.info("Finished loading FoxGuard!"); - } else { - logger.warn("Skipping server protection object loading due to manager initialization failure"); - } - } - @Listener public void serverStopping(GameStoppingServerEvent event) { if (managerOk) { - FGStorageManager.getInstance().saveRegions(); - FGStorageManager.getInstance().saveHandlers(); + FGStorageManagerNew storage = FGStorageManagerNew.getInstance(); + storage.saveRegionIndex(); + storage.saveHandlerIndex(); + + FGManager manager = FGManager.getInstance(); + logger.info("Saving regions"); + storage.saveObjects(manager.getRegions()); + logger.info("Saving handlers"); + storage.saveObjects(manager.getHandlers()); + logger.info("Saving configs"); FGConfigManager.getInstance().save(); + FGManager.getInstance().unloadServer(); } else { logger.warn("Skipping server-stop saving due to manager initialization failure"); } @@ -298,9 +300,15 @@ public void serverStopping(GameStoppingServerEvent event) { @Listener public void worldUnload(UnloadWorldEvent event) { if (managerOk) { - logger.info("Unloading world \"" + event.getTargetWorld().getName() + "\""); - FGStorageManager.getInstance().saveWorldRegions(event.getTargetWorld()); - FGManager.getInstance().unloadWorld(event.getTargetWorld()); + World world = event.getTargetWorld(); + logger.info("Unloading world \"" + world.getName() + "\""); + FGStorageManagerNew storage = FGStorageManagerNew.getInstance(); + storage.saveWorldRegionIndex(event.getTargetWorld()); + + FGManager manager = FGManager.getInstance(); + logger.info("Saving worldregions for world: " + world.getName()); + storage.saveObjects(manager.getWorldRegions(world)); + manager.unloadWorld(event.getTargetWorld()); } else { logger.warn("Skipping world-unload saving due to manager initialization failure"); } @@ -309,14 +317,14 @@ public void worldUnload(UnloadWorldEvent event) { @Listener public void worldLoad(LoadWorldEvent event) { if (managerOk) { - logger.info("Initializing global worldregion for world: \"" + event.getTargetWorld().getName() + "\""); - FGManager.getInstance().initWorld(event.getTargetWorld()); - logger.info("Loading worldregions for world: \"" + event.getTargetWorld().getName() + "\""); - FGStorageManager.getInstance().loadWorldRegions(event.getTargetWorld()); - if (loaded) { - logger.info("Loading links for world : \"" + event.getTargetWorld().getName() + "\""); - FGStorageManager.getInstance().loadWorldRegionLinks(event.getTargetWorld()); - } + World world = event.getTargetWorld(); + FGStorageManagerNew storage = FGStorageManagerNew.getInstance(); + storage.loadServer(); + + logger.info("Initializing global worldregion for world: \"" + world.getName() + "\""); + FGManager.getInstance().initWorld(world); + + storage.loadWorld(world); } else { logger.warn("Skipping world object loading due to manager initialization failure."); } @@ -350,12 +358,12 @@ private void registerFactories() { manager.registerHandlerFactory(new GroupHandler.Factory()); manager.registerHandlerFactory(new PermissionHandler.Factory()); manager.registerHandlerFactory(new DebugHandler.Factory()); + manager.registerHandlerFactory(new WelcomeHandler.Factory()); //manager.registerControllerFactory(new MessageController.Factory()); manager.registerControllerFactory(new LogicController.Factory()); } - /** * A private method that registers the Listener class and the corresponding event class. */ @@ -474,10 +482,6 @@ public boolean isLoaded() { return loaded; } - public static Cause getCause() { - return instance().pluginCause; - } - public EconomyService getEconomyService() { return economyService; } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandCreate.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandCreate.java index 8461c79..28dcf80 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandCreate.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandCreate.java @@ -26,22 +26,27 @@ package net.foxdenstudio.sponge.foxguard.plugin.command; import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxcore.common.util.FCCUtil; import net.foxdenstudio.sponge.foxcore.plugin.command.FCCommandBase; import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; import net.foxdenstudio.sponge.foxcore.plugin.command.util.FlagMapper; import net.foxdenstudio.sponge.foxcore.plugin.state.FCStateManager; import net.foxdenstudio.sponge.foxcore.plugin.state.PositionStateField; -import net.foxdenstudio.sponge.foxguard.plugin.config.FGConfigManager; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; +import net.foxdenstudio.sponge.foxguard.plugin.config.FGConfigManager; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.factory.FGFactoryManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.OwnerManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.provider.IOwnerProvider; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; +import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.ArgumentParseException; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.util.GuavaCollectors; @@ -55,13 +60,19 @@ import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; public class CommandCreate extends FCCommandBase { private static final String[] PRIORITY_ALIASES = {"priority", "prio", "p", "order", "level", "rank"}; - private static final String[] STATE_ALIASES = {"state", "s", "buffer"}; + // private static final String[] STATE_ALIASES = {"state", "s", "buffer"}; + private static final String[] OWNER_ALIASES = {"owner", "own", "o"}; + + private static final String CHAR_REGEX = "^.*[^0-9a-zA-Z_$\\-].*$"; + private static final String START_REGEX = "^[0-9\\-].*$"; private static final FlagMapper MAPPER = map -> key -> value -> { map.put(key, value); @@ -69,9 +80,11 @@ public class CommandCreate extends FCCommandBase { map.put("world", value); } else if (isIn(PRIORITY_ALIASES, key) && !map.containsKey("priority")) { map.put("priority", value); - } else if (isIn(STATE_ALIASES, key) && !map.containsKey("state")) { + } /*else if (isIn(STATE_ALIASES, key) && !map.containsKey("state")) { map.put("state", value); - } + }*/ /*else if (isIn(OWNER_ALIASES, key) && !map.containsKey("owner")) { + map.put("owner", value); + }*/ return true; }; @@ -84,93 +97,102 @@ public CommandResult process(@Nonnull CommandSource source, @Nonnull String argu } AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).limit(3).flagMapper(MAPPER).parse(); - if (parse.args.length == 0) { + int num = parse.args.length; + + if (num < 1) { source.sendMessage(Text.builder() .append(Text.of(TextColors.GREEN, "Usage: ")) .append(getUsage(source)) .build()); return CommandResult.empty(); - //---------------------------------------------------------------------------------------------------------------------- - } else if (isIn(REGIONS_ALIASES, parse.args[0]) || isIn(WORLDREGIONS_ALIASES, parse.args[0])) { - boolean isWorldRegion = isIn(WORLDREGIONS_ALIASES, parse.args[0]); - if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a name!")); - String worldName = parse.flags.get("world"); - World world = null; - if (isWorldRegion) { - if (source instanceof Locatable) world = ((Locatable) source).getWorld(); - if (!worldName.isEmpty()) { - Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); - if (optWorld.isPresent()) { - world = optWorld.get(); - } else { - if (world == null) - throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); - } + } + + String category = parse.args[0]; + FGCat fgCat = FGCat.from(category); + if (fgCat == null) throw new CommandException(Text.of("\"" + category + "\" is not a valid category!")); + + if (num < 2) throw new CommandException(Text.of("Must specify a name!")); + String name = parse.args[1]; + + if (name.isEmpty()) throw new CommandException(Text.of("Name must not be blank!")); + + if (name.matches(CHAR_REGEX)) + throw new CommandException(Text.of("Name must be alphanumeric!")); + if (name.matches(START_REGEX)) + throw new CommandException(Text.of("Name can't start with a number or hyphen!")); + if (!FGManager.isNameValid(name)) + throw new CommandException(Text.of("You may not use \"" + name + "\" as a name!")); + int lengthLimit = FGConfigManager.getInstance().getNameLengthLimit(); + if (lengthLimit > 0 && name.length() > lengthLimit) + throw new CommandException(Text.of("Name is too long! Max " + lengthLimit + " characters.")); + + /*UUID owner = FGManager.SERVER_UUID_DEPRECATED; + if (parse.flags.containsKey("owner")) { + String ownerString = parse.flags.get("owner"); + if (ownerString.isEmpty()) { + if (source instanceof Identifiable) { + owner = ((Identifiable) source).getUniqueId(); } - if (world == null) throw new CommandException(Text.of("Must specify a world!")); - } - if (parse.args[1].matches("^.*[^0-9a-zA-Z_$].*$")) - throw new CommandException(Text.of("Name must be alphanumeric!")); - if (parse.args[1].matches("^[0-9].*$")) - throw new CommandException(Text.of("Name can't start with a number!")); - if (!FGManager.isNameValid(parse.args[1])) - throw new CommandException(Text.of("You may not use \"" + parse.args[1] + "\" as a name!")); - int lengthLimit = FGConfigManager.getInstance().getNameLengthLimit(); - if (lengthLimit > 0 && parse.args[1].length() > lengthLimit) - throw new CommandException(Text.of("Name is too long!")); - if (isWorldRegion) { - if (!FGManager.getInstance().isWorldRegionNameAvailable(parse.args[1], world)) - throw new ArgumentParseException(Text.of("That name is already taken!"), parse.args[1], 1); } else { - if (!FGManager.getInstance().isRegionNameAvailable(parse.args[1])) - throw new ArgumentParseException(Text.of("That name is already taken!"), parse.args[1], 1); - } - if (parse.args.length < 3) throw new CommandException(Text.of("Must specify a type!")); - IRegion newRegion; - if (isWorldRegion) { - List aliases = FGFactoryManager.getInstance().getWorldRegionTypeAliases(); - if (!isIn(aliases.toArray(new String[aliases.size()]), parse.args[2])) { - throw new CommandException(Text.of("The type \"" + parse.args[2] + "\" is invalid!")); + String[] parts = ownerString.split(":", 2); + OwnerManager registry = OwnerManager.getInstance(); + Optional ownerOpt; + if (parts.length == 1) { + ownerOpt = registry.getUUIDForOwner(null, parts[0]); + } else if (parts.length == 2) { + ownerOpt = registry.getUUIDForOwner(parts[0], parts[1]); + } else ownerOpt = Optional.empty(); + if (ownerOpt.isPresent()) { + owner = ownerOpt.get(); + } else { + throw new CommandException(Text.of("\"" + ownerString + "\" is not a valid owner!")); } - newRegion = FGFactoryManager.getInstance().createWorldRegion( - parse.args[1], parse.args[2], - parse.args.length < 4 ? "" : parse.args[3], - source); - } else { - List aliases = FGFactoryManager.getInstance().getRegionTypeAliases(); - if (!isIn(aliases.toArray(new String[aliases.size()]), parse.args[2])) { - throw new CommandException(Text.of("The type \"" + parse.args[2] + "\" is invalid!")); + } + }*/ + + IOwner owner = FGManager.SERVER_OWNER; + + World world = null; + if (fgCat == FGCat.WORLDREGION) { + if (source instanceof Locatable) world = ((Locatable) source).getWorld(); + String worldName = parse.flags.get("world"); + if (!worldName.isEmpty()) { + Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); + if (optWorld.isPresent()) { + world = optWorld.get(); + } else { + if (world == null) + throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); } - newRegion = FGFactoryManager.getInstance().createRegion( - parse.args[1], parse.args[2], - parse.args.length < 4 ? "" : parse.args[3], - source); } - if (newRegion == null) - throw new CommandException(Text.of("Failed to create region! Perhaps the type is invalid?")); - boolean success = FGManager.getInstance().addRegion(newRegion, world); - if (!success) - throw new CommandException(Text.of("There was an error trying to create the " + (isWorldRegion ? "World" : "") + "Region!")); - FCStateManager.instance().getStateMap().get(source).flush(PositionStateField.ID); - source.sendMessage(Text.of(TextColors.GREEN, (isWorldRegion ? "Worldr" : "R") + "egion created successfully")); - FoxGuardMain.instance().getLogger().info( - source.getName() + " created a " + (isWorldRegion ? "world" : "") + "region with name \"" + newRegion.getName() + "\"" + - (isWorldRegion ? (" in world \"" + world.getName() + "\"") : "") - ); - return CommandResult.success(); - //---------------------------------------------------------------------------------------------------------------------- - } else if (isIn(HANDLERS_ALIASES, parse.args[0]) || isIn(CONTROLLERS_ALIASES, parse.args[0])) { - boolean isController = isIn(CONTROLLERS_ALIASES, parse.args[0]); - if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a name!")); - if (parse.args[1].matches("^.*[^0-9a-zA-Z_$].*$")) - throw new ArgumentParseException(Text.of("Name must be alphanumeric!"), parse.args[1], 1); - if (parse.args[1].matches("^[0-9].*$")) - throw new ArgumentParseException(Text.of("Name can't start with a number!"), parse.args[1], 1); - if (!FGManager.isNameValid(parse.args[1])) - throw new CommandException(Text.of("You may not use \"" + parse.args[1] + "\" as a name!")); - int lengthLimit = FGConfigManager.getInstance().getNameLengthLimit(); - if (lengthLimit > 0 && parse.args[1].length() > lengthLimit) - throw new CommandException(Text.of("Name is too long!")); + if (world == null) throw new CommandException(Text.of("Must specify a world!")); + } + + if (!fgCat.isNameAvailable(name, owner, world)) { + throw new CommandException(Text.of("That name is already in use!")); + } + + if (num < 3) throw new CommandException(Text.of("Must specify a type!")); + String type = parse.args[2]; + + List typeAliases = fgCat.typeAliases.get(); + if (!isIn(typeAliases.toArray(new String[typeAliases.size()]), type)) { + throw new CommandException(Text.of("The type \"" + type + "\" is invalid!")); + } + + String finalBlock = num < 4 ? "" : parse.args[3]; + IGuardObject object; + try { + object = fgCat.create(name, type, finalBlock, source); + } catch (CommandException e) { + throw e; + } catch (Exception e) { + throw new CommandException(Text.of("There was an exception creating the " + fgCat.lName + "!", e)); + } + if (object == null) + throw new CommandException(Text.of("Failed to construct " + fgCat.lName + " for an unknown reason!")); + + if (object instanceof IHandler) { int priority = 0; try { priority = Integer.parseInt(parse.flags.get("priority")); @@ -178,45 +200,50 @@ public CommandResult process(@Nonnull CommandSource source, @Nonnull String argu else if (priority > Integer.MAX_VALUE / 2) priority = Integer.MAX_VALUE / 2; } catch (NumberFormatException ignored) { } + ((IHandler) object).setPriority(priority); + } - if (parse.args.length < 3) throw new CommandException(Text.of("Must specify a type!")); - IHandler newHandler; - if (isController) { - List aliases = FGFactoryManager.getInstance().getControllerTypeAliases(); - if (!isIn(aliases.toArray(new String[aliases.size()]), parse.args[2])) { - throw new CommandException(Text.of("The type \"" + parse.args[2] + "\" is invalid!")); - } - newHandler = FGFactoryManager.getInstance().createController( - parse.args[1], parse.args[2], priority, - parse.args.length < 4 ? "" : parse.args[3], - source); - } else { - List aliases = FGFactoryManager.getInstance().getHandlerTypeAliases(); - if (!isIn(aliases.toArray(new String[aliases.size()]), parse.args[2])) { - throw new CommandException(Text.of("The type \"" + parse.args[2] + "\" is invalid!")); - } - newHandler = FGFactoryManager.getInstance().createHandler( - parse.args[1], parse.args[2], priority, - parse.args.length < 4 ? "" : parse.args[3], - source); - } - if (newHandler == null) - throw new CommandException(Text.of("Failed to create " + (isController ? "controller" : "handler") + "! Perhaps the type is invalid?")); - boolean success = FGManager.getInstance().addHandler(newHandler); - if (!success) - throw new ArgumentParseException(Text.of("That name is already taken!"), parse.args[1], 1); - source.sendMessage(Text.of(TextColors.GREEN, (isController ? "Controller" : "Handler") + " created successfully!")); - FoxGuardMain.instance().getLogger().info( - source.getName() + " created a " + (isController ? "controller" : "handler") + " with name \"" + newHandler.getName() + "\"" - ); - return CommandResult.success(); - //---------------------------------------------------------------------------------------------------------------------- - } else throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); + boolean success = fgCat.add(object, owner, world); + if (!success) + throw new CommandException(Text.of("Successfully constructed but failed to add " + fgCat.lName + " for an unknown reason!")); + + if (object instanceof IRegion) { + FCStateManager.instance().getStateMap().get(source).flush(PositionStateField.ID); + } + + source.sendMessage(Text.of(TextColors.GREEN, fgCat.uName + " created successfully")); + + StringBuilder logMessage = new StringBuilder(); + logMessage.append(source.getName()) + .append(" created a ") + .append(fgCat.lName) + .append(": Name: ") + .append(object.getName()); + + /*if (owner != null && !owner.equals(FGManager.SERVER_OWNER)) { + logMessage.append(" Owner: ").append(OwnerManager.getInstance().getKeyword(owner, null)) + .append(" (").append(owner).append(")"); + }*/ + + if (owner != null && !owner.equals(FGManager.SERVER_OWNER)) { + logMessage.append(" Owner: ").append(owner.toString()); + } + + if (object instanceof IWorldRegion) { + logMessage.append(" World: ").append(((IWorldRegion) object).getWorld().getName()); + } + + FoxGuardMain.instance().getLogger().info(logMessage.toString()); + + return CommandResult.empty(); } + @Nonnull @Override - public List getSuggestions(@Nonnull CommandSource source, @Nonnull String arguments, @Nullable Location targetPosition) throws CommandException { + public List getSuggestions(@Nonnull CommandSource source, + @Nonnull String arguments, + @Nullable Location targetPosition) throws CommandException { if (!testPermission(source)) return ImmutableList.of(); AdvCmdParser.ParseResult parse = AdvCmdParser.builder() .arguments(arguments) @@ -228,51 +255,54 @@ public List getSuggestions(@Nonnull CommandSource source, @Nonnull Strin .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) - return ImmutableList.of("region", "worldregion", "handler", "controller").stream() + return Stream.of("region", "worldregion", "handler", "controller") .filter(new StartsWithPredicate(parse.current.token)) .collect(GuavaCollectors.toImmutableList()); - else if (parse.current.index == 1) { - if (parse.current.token == null || parse.current.token.isEmpty()) return ImmutableList.of(); - if (parse.current.token.matches("^.*[^0-9a-zA-Z_$].*$")) { - source.sendMessage(Text.of(TextColors.RED, "Name must be alphanumeric!")); - return ImmutableList.of(); - } - if (parse.current.token.matches("^[0-9].*$")) { - source.sendMessage(Text.of(TextColors.RED, "Name can't start with a number!")); - return ImmutableList.of(); - } - if (!FGManager.isNameValid(parse.current.token)) { - source.sendMessage(Text.of(TextColors.RED, "You may not use \"" + parse.current.token + "\" as a name!")); - return ImmutableList.of(); - } - int lengthLimit = FGConfigManager.getInstance().getNameLengthLimit(); - if (lengthLimit > 0 && parse.current.token.length() > lengthLimit) { - source.sendMessage(Text.of(TextColors.RED, "Name is too long!")); - return ImmutableList.of(); - } + else { + FGCat fgCat = FGCat.from(parse.args[0]); + if (parse.current.index == 1) { + if (parse.current.token == null || parse.current.token.isEmpty()) return ImmutableList.of(); + if (parse.current.token.matches(CHAR_REGEX)) { + source.sendMessage(Text.of(TextColors.RED, "Name must be alphanumeric!")); + return ImmutableList.of(); + } + if (parse.current.token.matches(START_REGEX)) { + source.sendMessage(Text.of(TextColors.RED, "Name can't start with a number!")); + return ImmutableList.of(); + } + if (!FGManager.isNameValid(parse.current.token)) { + source.sendMessage(Text.of(TextColors.RED, "You may not use \"" + parse.current.token + "\" as a name!")); + return ImmutableList.of(); + } + int lengthLimit = FGConfigManager.getInstance().getNameLengthLimit(); + if (lengthLimit > 0 && parse.current.token.length() > lengthLimit) { + source.sendMessage(Text.of(TextColors.RED, "Name is too long!")); + return ImmutableList.of(); + } - Tristate available = null; - if (isIn(REGIONS_ALIASES, parse.args[0])) { - available = Tristate.fromBoolean(FGManager.getInstance().isRegionNameAvailable(parse.current.token)); - } else if (isIn(WORLDREGIONS_ALIASES, parse.args[0])) { - String worldName = parse.flags.get("world"); - World world = null; - if (source instanceof Locatable) world = ((Locatable) source).getWorld(); - if (!worldName.isEmpty()) { - Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); - if (optWorld.isPresent()) { - world = optWorld.get(); + Tristate available; + if (fgCat == FGCat.REGION) { + available = Tristate.fromBoolean(FGManager.getInstance().isRegionNameAvailable(parse.current.token)); + } else if (fgCat == FGCat.WORLDREGION) { + String worldName = parse.flags.get("world"); + World world = null; + if (source instanceof Locatable) world = ((Locatable) source).getWorld(); + if (!worldName.isEmpty()) { + Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); + if (optWorld.isPresent()) { + world = optWorld.get(); + } } - } - if (world == null) { - available = FGManager.getInstance().isWorldRegionNameAvailable(parse.current.token); + if (world == null) { + available = FGManager.getInstance().isWorldRegionNameAvailable(parse.current.token); + } else { + available = Tristate.fromBoolean(FGManager.getInstance().isWorldRegionNameAvailable(parse.current.token, world)); + } + } else if (fgCat == FGCat.HANDLER || fgCat == FGCat.CONTROLLER) { + available = Tristate.fromBoolean(!FGManager.getInstance().getHandler(parse.current.token).isPresent()); } else { - available = Tristate.fromBoolean(FGManager.getInstance().isWorldRegionNameAvailable(parse.current.token, world)); + return ImmutableList.of(); } - } else if (isIn(HANDLERS_ALIASES, parse.args[0]) || isIn(CONTROLLERS_ALIASES, parse.args[0])) { - available = Tristate.fromBoolean(FGManager.getInstance().gethandler(parse.current.token) == null); - } - if (available != null) { switch (available) { case TRUE: source.sendMessage(Text.of(TextColors.GREEN, "Name is available!")); @@ -284,44 +314,79 @@ else if (parse.current.index == 1) { source.sendMessage(Text.of(TextColors.YELLOW, "Name might be available. Must specify a world to confirm.")); } - } - } else if (parse.current.index == 2) { - if (isIn(REGIONS_ALIASES, parse.args[0])) { - return FGFactoryManager.getInstance().getPrimaryRegionTypeAliases().stream() - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); - } else if (isIn(WORLDREGIONS_ALIASES, parse.args[0])) { - return FGFactoryManager.getInstance().getPrimaryWorldRegionTypeAliases().stream() - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); - } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { - return FGFactoryManager.getInstance().getPrimaryHandlerTypeAliases().stream() - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); - } else if (isIn(CONTROLLERS_ALIASES, parse.args[0])) { - return FGFactoryManager.getInstance().getPrimaryControllerTypeAliases().stream() - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); + } else if (parse.current.index == 2) { + if (fgCat == null) return ImmutableList.of(); + switch (fgCat) { + + case REGION: + return FGFactoryManager.getInstance().getPrimaryRegionTypeAliases().stream() + .filter(new StartsWithPredicate(parse.current.token)) + .map(args -> parse.current.prefix + args) + .collect(GuavaCollectors.toImmutableList()); + + case WORLDREGION: + return FGFactoryManager.getInstance().getPrimaryWorldRegionTypeAliases().stream() + .filter(new StartsWithPredicate(parse.current.token)) + .map(args -> parse.current.prefix + args) + .collect(GuavaCollectors.toImmutableList()); + + case HANDLER: + return FGFactoryManager.getInstance().getPrimaryHandlerTypeAliases().stream() + .filter(new StartsWithPredicate(parse.current.token)) + .map(args -> parse.current.prefix + args) + .collect(GuavaCollectors.toImmutableList()); + case CONTROLLER: + return FGFactoryManager.getInstance().getPrimaryControllerTypeAliases().stream() + .filter(new StartsWithPredicate(parse.current.token)) + .map(args -> parse.current.prefix + args) + .collect(GuavaCollectors.toImmutableList()); + } } } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world", "priority").stream() + return Stream.of("world", "priority", "owner") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGVALUE)) { - if (isIn(WORLD_ALIASES, parse.current.key)) + if (isIn(WORLD_ALIASES, parse.current.key)) { return Sponge.getGame().getServer().getWorlds().stream() .map(World::getName) .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); + } else if (isIn(OWNER_ALIASES, parse.current.key)) { + String[] parts = parse.current.token.split(":", 2); + System.out.println(parts.length); + if (parts.length == 1) { + ImmutableList collect = OwnerManager.getInstance().getProviders().stream() + .map(IOwnerProvider::getPrimaryAlias) + .filter(string -> string != null && !string.isEmpty()) + .filter(new StartsWithPredicate(parse.current.token)) + .map(args -> parse.current.prefix + args) + .collect(GuavaCollectors.toImmutableList()); + System.out.println(collect); + return collect; + + } else if (parts.length == 2) { + Optional providerOpt = OwnerManager.getInstance().getProvider(parts[0]); + if (providerOpt.isPresent()) { + IOwnerProvider provider = providerOpt.get(); + System.out.println(provider.getOwnerKeywords()); + return provider.getOwnerKeywords().stream() + .filter(new StartsWithPredicate(parts[1])) + .map(args -> parse.current.prefix + parts[0] + ":" + args) + .collect(GuavaCollectors.toImmutableList()); + } + } + } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.FINAL)) { if (isIn(REGIONS_ALIASES, parse.args[0])) { + return FGFactoryManager.getInstance().regionSuggestions(source, parse.current.token, parse.args[2]) + .stream() + .map(args -> parse.current.prefix + args) + .collect(GuavaCollectors.toImmutableList()); + } else if (isIn(WORLDREGIONS_ALIASES, parse.args[0])) { return FGFactoryManager.getInstance().worldRegionSuggestions(source, parse.current.token, parse.args[2]) .stream() .map(args -> parse.current.prefix + args) @@ -364,4 +429,100 @@ public Optional getHelp(@Nonnull CommandSource source) { public Text getUsage(@Nonnull CommandSource source) { return Text.of("create ] | handler> [--priority:] [args...]"); } + + private enum FGCat { + REGION(REGIONS_ALIASES, FGFactoryManager.getInstance()::getRegionTypeAliases) { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + return FGManager.getInstance().isRegionNameAvailable(name, owner); + } + + @Override + public IGuardObject create(String name, String type, String arguments, CommandSource source) throws CommandException { + return FGFactoryManager.getInstance().createRegion(name, type, arguments, source); + } + + @Override + public boolean add(IGuardObject object, IOwner owner, @Nullable World world) { + return object instanceof IRegion + && FGManager.getInstance().addRegion(((IRegion) object), owner, world); + } + }, + WORLDREGION(WORLDREGIONS_ALIASES, FGFactoryManager.getInstance()::getWorldRegionTypeAliases) { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + if (world == null) + return FGManager.getInstance().isWorldRegionNameAvailable(name, owner) == Tristate.TRUE; + else return FGManager.getInstance().isWorldRegionNameAvailable(name, owner, world); + } + + @Override + public IGuardObject create(String name, String type, String arguments, CommandSource source) throws CommandException { + return FGFactoryManager.getInstance().createWorldRegion(name, type, arguments, source); + } + + @Override + public boolean add(IGuardObject object, IOwner owner, @Nullable World world) { + return world != null + && object instanceof IWorldRegion + && FGManager.getInstance().addWorldRegion(((IWorldRegion) object), owner, world); + } + }, + HANDLER(HANDLERS_ALIASES, FGFactoryManager.getInstance()::getHandlerTypeAliases) { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + return FGManager.getInstance().isHandlerNameAvailable(name, owner); + } + + @Override + public IGuardObject create(String name, String type, String arguments, CommandSource source) throws CommandException { + return FGFactoryManager.getInstance().createHandler(name, type, arguments, source); + } + + @Override + public boolean add(IGuardObject object, IOwner owner, @Nullable World world) { + return object instanceof IHandler + && FGManager.getInstance().addHandler(((IHandler) object), owner); + } + }, + CONTROLLER(CONTROLLERS_ALIASES, FGFactoryManager.getInstance()::getControllerTypeAliases) { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + return HANDLER.isNameAvailable(name, owner, world); + } + + @Override + public IGuardObject create(String name, String type, String arguments, CommandSource source) throws CommandException { + return FGFactoryManager.getInstance().createController(name, type, arguments, source); + } + + @Override + public boolean add(IGuardObject object, IOwner owner, @Nullable World world) { + return HANDLER.add(object, owner, world); + } + }; + + String[] catAliases; + Supplier> typeAliases; + String lName = name().toLowerCase(); + String uName = FCCUtil.toCapitalCase(name()); + + FGCat(String[] catAliases, Supplier> typeAliases) { + this.catAliases = catAliases; + this.typeAliases = typeAliases; + } + + public static FGCat from(String category) { + for (FGCat cat : values()) { + if (isIn(cat.catAliases, category)) return cat; + } + return null; + } + + public abstract boolean isNameAvailable(String name, IOwner owner, @Nullable World world); + + public abstract IGuardObject create(String name, String type, String arguments, CommandSource source) throws CommandException; + + public abstract boolean add(IGuardObject object, IOwner owner, @Nullable World world); + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandDelete.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandDelete.java index 549ca26..97c035a 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandDelete.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandDelete.java @@ -27,23 +27,23 @@ import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxcore.common.util.FCCUtil; import net.foxdenstudio.sponge.foxcore.plugin.command.FCCommandBase; import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; import net.foxdenstudio.sponge.foxcore.plugin.command.util.FlagMapper; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; -import net.foxdenstudio.sponge.foxguard.plugin.handler.GlobalHandler; -import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; -import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; -import net.foxdenstudio.sponge.foxguard.plugin.region.world.GlobalWorldRegion; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.UUIDOwner; +import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; +import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.ArgumentParseException; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.util.GuavaCollectors; @@ -52,9 +52,11 @@ import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; -import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; + +import javax.annotation.Nullable; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; @@ -68,7 +70,7 @@ public class CommandDelete extends FCCommandBase { return true; }; - @Override + public CommandResult process(CommandSource source, String arguments) throws CommandException { if (!testPermission(source)) { source.sendMessage(Text.of(TextColors.RED, "You don't have permission to use this command!")); @@ -84,51 +86,60 @@ public CommandResult process(CommandSource source, String arguments) throws Comm .append(getUsage(source)) .build()); return CommandResult.empty(); - } else if (isIn(REGIONS_ALIASES, parse.args[0])) { + } else { + String category = parse.args[0]; + FGCat fgCat = FGCat.from(category); + if (fgCat == null) throw new CommandException(Text.of("\"" + category + "\" is not a valid category!")); + if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a name!")); - IRegion region = FGManager.getInstance().getRegion(parse.args[1]); - boolean isWorldRegion = false; - if (region == null) { - String worldName = parse.flags.get("world"); - World world = null; - if (source instanceof Locatable) world = ((Locatable) source).getWorld(); - if (!worldName.isEmpty()) { - Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); - if (optWorld.isPresent()) { - world = optWorld.get(); - } else { - if (world == null) - throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); - } - } - if (world == null) throw new CommandException(Text.of("Must specify a world!")); - region = FGManager.getInstance().getWorldRegion(world, parse.args[1]); - isWorldRegion = true; + + FGUtil.OwnerResult ownerResult = FGUtil.processUserInput(parse.args[1]); + + IGuardObject object; + FGManager fgManager = FGManager.getInstance(); + switch (fgCat) { + case REGION: + object = FGUtil.getRegionFromCommand(source, ownerResult, parse.flags.containsKey("world"), parse.flags.get("world")); + if (object instanceof IWorldRegion) fgCat = FGCat.WORLDREGION; + break; + case HANDLER: + object = FGUtil.getHandlerFromCommand(ownerResult); + if (object instanceof IController) fgCat = FGCat.CONTROLLER; + break; + default: + throw new CommandException(Text.of("Something went horribly wrong.")); } - if (region == null) - throw new CommandException(Text.of("No region exists with the name \"" + parse.args[1] + "\"!")); - if (region instanceof GlobalWorldRegion) { - throw new CommandException(Text.of("You may not delete the global region!")); + + if (object instanceof IGlobal) { + throw new CommandException(Text.of("You may not delete the global " + fgCat.lName + "!")); } - boolean success = FGManager.getInstance().removeRegion(region); - if (!success) throw new CommandException(Text.of("There was an error trying to delete the region!")); - source.sendMessage(Text.of(TextColors.GREEN, "Region deleted successfully!")); - FoxGuardMain.instance().getLogger().info( - source.getName() + " deleted " + (isWorldRegion ? "world" : "") + "region" - ); - return CommandResult.success(); - } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { - if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a name!")); - IHandler handler = FGManager.getInstance().gethandler(parse.args[1]); - if (handler == null) - throw new ArgumentParseException(Text.of("No handler exists with that name!"), parse.args[1], 1); - if (handler instanceof GlobalHandler) - throw new CommandException(Text.of("You may not delete the global handler!")); - boolean success = FGManager.getInstance().removeHandler(handler); - if (!success) throw new CommandException(Text.of("There was an error trying to delete the handler!")); - source.sendMessage(Text.of(TextColors.GREEN, "Handler deleted successfully!")); + + boolean success = fgManager.removeObject(object); + if (!success) + throw new CommandException(Text.of("There was an error trying to delete the " + fgCat.lName + "!")); + source.sendMessage(Text.of(TextColors.GREEN, fgCat.uName + " deleted successfully!")); + + StringBuilder logMessage = new StringBuilder(); + logMessage.append(source.getName()) + .append(" deleted the ") + .append(fgCat.lName) + .append(": Name: ") + .append(object.getName()); + + IOwner owner = ownerResult.getOwner(); + if (owner != null && !owner.equals(FGManager.SERVER_OWNER)) { + logMessage.append(" Owner: ").append(owner.toString()) + .append(" (").append(owner).append(")"); + } + + if (object instanceof IWorldRegion) { + logMessage.append(" World: ").append(((IWorldRegion) object).getWorld().getName()); + } + + FoxGuardMain.instance().getLogger().info(logMessage.toString()); + return CommandResult.success(); - } else throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); + } } @Override @@ -142,13 +153,22 @@ public List getSuggestions(CommandSource source, String arguments, @Null .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) - return ImmutableList.of("region", "handler").stream() + return Stream.of("region", "handler") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); else if (parse.current.index == 1) { + System.out.println(parse.current.token); + FGUtil.OwnerTabResult result = FGUtil.getOwnerSuggestions(parse.current.token); + if (result.isComplete()) { + return result.getSuggestions().stream() + .map(str -> parse.current.prefix + str) + .collect(GuavaCollectors.toImmutableList()); + } + if (isIn(REGIONS_ALIASES, parse.args[0])) { String worldName = parse.flags.get("world"); + boolean key = parse.flags.containsKey("world"); World world = null; if (source instanceof Locatable) world = ((Locatable) source).getWorld(); if (!worldName.isEmpty()) { @@ -157,29 +177,32 @@ else if (parse.current.index == 1) { world = optWorld.get(); } } - if (world == null) return FGManager.getInstance().getRegions().stream() - .filter(region -> !(region instanceof IGlobal)) - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); - else return FGManager.getInstance().getAllRegions(world).stream() - .filter(region -> !(region instanceof IGlobal)) - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); + if (key && world != null) { + return FGManager.getInstance().getAllRegions(world, new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() + .filter(region -> !(region instanceof IGlobal)) + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } else { + return FGManager.getInstance().getAllRegionsWithUniqueNames(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner()), world).stream() + .filter(region -> !(region instanceof IGlobal)) + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { - return FGManager.getInstance().getHandlers().stream() + return FGManager.getInstance().getHandlers(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() .filter(handler -> !(handler instanceof IGlobal)) - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) .collect(GuavaCollectors.toImmutableList()); } } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world").stream() + return Stream.of("world") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -214,4 +237,26 @@ public Optional getHelp(CommandSource source) { public Text getUsage(CommandSource source) { return Text.of("delete ] | handler> "); } + + private enum FGCat { + REGION(REGIONS_ALIASES), + WORLDREGION(null), + HANDLER(HANDLERS_ALIASES), + CONTROLLER(null); + + public final String[] catAliases; + public final String lName = name().toLowerCase(); + public final String uName = FCCUtil.toCapitalCase(name()); + + FGCat(String[] catAliases) { + this.catAliases = catAliases; + } + + public static FGCat from(String category) { + for (FGCat cat : values()) { + if (isIn(cat.catAliases, category)) return cat; + } + return null; + } + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandDetail.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandDetail.java index ecdd18d..89456b8 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandDetail.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandDetail.java @@ -26,15 +26,20 @@ package net.foxdenstudio.sponge.foxguard.plugin.command; import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxcore.common.util.FCCUtil; import net.foxdenstudio.sponge.foxcore.plugin.command.FCCommandBase; import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; import net.foxdenstudio.sponge.foxcore.plugin.command.util.FlagMapper; +import net.foxdenstudio.sponge.foxcore.plugin.util.IWorldBound; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.ILinkable; +import net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.OwnerManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.UUIDOwner; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; @@ -42,7 +47,6 @@ import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.ArgumentParseException; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; @@ -54,14 +58,16 @@ import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; -import javax.annotation.Nullable; +import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.stream.Stream; +import javax.annotation.Nullable; + import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; -public class CommandDetail extends FCCommandBase { +public class CommandDetail extends FCCommandBase { private static final FlagMapper MAPPER = map -> key -> value -> { map.put(key, value); @@ -73,6 +79,7 @@ public class CommandDetail extends FCCommandBase { return true; }; + @SuppressWarnings("Duplicates") @Override public CommandResult process(CommandSource source, String arguments) throws CommandException { if (!testPermission(source)) { @@ -91,275 +98,182 @@ public CommandResult process(CommandSource source, String arguments) throws Comm .append(getUsage(source)) .build()); return CommandResult.empty(); - } else if (isIn(REGIONS_ALIASES, parse.args[0])) { + } else { + String category = parse.args[0]; + FGCat fgCat = FGCat.from(category); + if (fgCat == null) throw new CommandException(Text.of("\"" + category + "\" is not a valid category!")); + if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a name!")); - IRegion region = FGManager.getInstance().getRegion(parse.args[1]); - if (region == null) { - String worldName = parse.flags.get("world"); - World world = null; - if (source instanceof Locatable) world = ((Locatable) source).getWorld(); - if (!worldName.isEmpty()) { - Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); - if (optWorld.isPresent()) { - world = optWorld.get(); - } else { - if (world == null) - throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); - } - } - if (world == null) throw new CommandException(Text.of("Must specify a world!")); - region = FGManager.getInstance().getWorldRegion(world, parse.args[1]); + + FGUtil.OwnerResult ownerResult = FGUtil.processUserInput(parse.args[1]); + + IGuardObject object; + switch (fgCat) { + case REGION: + object = FGUtil.getRegionFromCommand(source, ownerResult, parse.flags.containsKey("world"), parse.flags.get("world")); + if (object instanceof IWorldRegion) fgCat = FGCat.WORLDREGION; + break; + case HANDLER: + object = FGUtil.getHandlerFromCommand(ownerResult); + if (object instanceof IController) fgCat = FGCat.CONTROLLER; + break; + default: + throw new CommandException(Text.of("Something went horribly wrong.")); } - if (region == null) - throw new CommandException(Text.of("No region exists with the name \"" + parse.args[1] + "\"!")); + IOwner owner = object.getOwner(); + String name = object.getName(); + String fullName = name; + boolean hasOwner = false; + if (owner != null && !owner.equals(FGManager.SERVER_OWNER)) { + fullName = owner + ":" + fullName; + hasOwner = true; + } + + boolean general = false; + if (parse.args.length < 3 || parse.args[2].isEmpty() || parse.flags.containsKey("all")) general = true; + Text.Builder builder = Text.builder(); builder.append(Text.of(TextColors.GOLD, "\n-----------------------------------------------------\n")); - if (parse.args.length < 3 || parse.args[2].isEmpty() || parse.flags.containsKey("all")) { - builder.append(Text.of(TextActions.runCommand("/foxguard detail region " + FGUtil.genWorldFlag(region) + region.getName()), - TextActions.showText(Text.of("View details for region \"" + region.getName() + "\"")), + if (general) { + builder.append(Text.of(TextActions.runCommand("/foxguard det " + fgCat.sName + " " + FGUtil.genWorldFlag(object) + fullName), + TextActions.showText(Text.of("View details for " + fgCat.lName + " \"" + name + "\"")), TextColors.GREEN, "------- General -------\n", - TextColors.GOLD, "Name: ", TextColors.RESET, region.getName() + "\n")); - builder.append(Text.of(TextColors.GOLD, "Type: "), Text.of(TextColors.RESET, region.getLongTypeName() + "\n")); + TextColors.GOLD, "Name: ", TextColors.RESET, name + "\n")); + if (hasOwner) { + OwnerManager registry = OwnerManager.getInstance(); + builder.append(Text.builder() + .append(Text.of(TextColors.GOLD, "Owner: ")) + //.append(registry.getDisplayText(owner, null, source)) + .append(Text.NEW_LINE) + //.onHover(TextActions.showText(registry.getHoverText(owner, null, source))) + .onShiftClick(TextActions.insertText(owner.toString())) + .build() + ); + } + builder.append(Text.of(TextColors.GOLD, "Type: "), Text.of(TextColors.RESET, object.getLongTypeName() + "\n")); builder.append(Text.builder() .append(Text.of(TextColors.GOLD, "Enabled: ")) - .append(Text.of(TextColors.RESET, (region.isEnabled() ? "True" : "False") + "\n")) - .onClick(TextActions.runCommand("/foxguard " + (region.isEnabled() ? "disable" : "enable") + - " r " + FGUtil.genWorldFlag(region) + region.getName())) - .onHover(TextActions.showText(Text.of("Click to " + (region.isEnabled() ? "disable" : "enable")))) + .append(Text.of((object.isEnabled() ? TextColors.GREEN : TextColors.RED), (object.isEnabled() ? "True" : "False") + "\n")) + .onClick(TextActions.runCommand("/foxguard " + (object.isEnabled() ? "disable" : "enable") + + " " + fgCat.sName + " " + FGUtil.genWorldFlag(object) + fullName)) + .onHover(TextActions.showText(Text.of("Click to " + (object.isEnabled() ? "disable" : "enable")))) .build()); - if (region instanceof IWorldRegion) - builder.append(Text.of(TextColors.GOLD, "World: "), Text.of(TextColors.RESET, ((IWorldRegion) region).getWorld().getName() + "\n")); - builder.append(Text.of(TextActions.suggestCommand("/foxguard modify region " + FGUtil.genWorldFlag(region) + region.getName() + " "), - TextActions.showText(Text.of("Click to modify region \"" + region.getName() + "\"")), - TextColors.GREEN, "------- Details -------\n")); - try { - Text objectDetails = region.details(source, parse.args.length < 3 ? "" : parse.args[2]); - if (objectDetails == null) objectDetails = Text.of(); - builder.append(objectDetails); - } catch (Exception e) { - builder.append(Text.of(TextColors.RED, TextStyles.ITALIC, "There was an error getting details for region \"" + region.getName() + "\".")); - FoxGuardMain.instance().getLogger().error( - (region instanceof IWorldRegion ? "Worldregion \"" : "Region \"") - + region.getName() + "\" of type \"" + region.getLongTypeName() + "\"" - + (region instanceof IWorldRegion ? " in world \"" + ((IWorldRegion) region).getWorld().getName() + "\"" : "") - + " threw an exception while getting details", e - ); + + if (object instanceof IWorldBound) + builder.append(Text.of(TextColors.GOLD, "World: "), Text.of(TextColors.RESET, ((IWorldBound) object).getWorld().getName() + "\n")); + + if (object instanceof IHandler) { + builder.append(Text.builder() + .append(Text.of(TextColors.GOLD, "Priority: ")) + .append(Text.of(TextColors.RESET, ((IHandler) object).getPriority() + "\n")) + .onClick(TextActions.suggestCommand("/foxguard prio " + fullName + " ")) + .onHover(TextActions.showText(Text.of("Click to change priority"))) + .build()); } - outboundLinks(builder, region, source); + + builder.append(Text.of(TextActions.suggestCommand("/foxguard modify " + fgCat.sName + " " + FGUtil.genWorldFlag(object) + fullName + " "), + TextActions.showText(Text.of("Click to modify " + fgCat.lName + " \"" + name + "\"")), + TextColors.GREEN, "------- Details -------\n")); } else { - builder.append(Text.of(TextColors.GREEN, "------- Details for Region \"" + region.getName() + "\"" + - (region instanceof IWorldRegion ? (" in World \"" + ((IWorldRegion) region).getWorld().getName() + "\"") : "") + + builder.append(Text.of(TextColors.GREEN, "------- Details for " + fgCat.lName + " \"" + name + "\"" + + (object instanceof IWorldBound ? (" in World \"" + ((IWorldBound) object).getWorld().getName() + "\"") : "") + " -------\n")); - try { - Text objectDetails = region.details(source, parse.args.length < 3 ? "" : parse.args[2]); - if (objectDetails == null) objectDetails = Text.of(); - builder.append(objectDetails); - } catch (Exception e) { - builder.append(Text.of(TextColors.RED, TextStyles.ITALIC, "There was an error getting details for region \"" + region.getName() + "\".")); - FoxGuardMain.instance().getLogger().error( - (region instanceof IWorldRegion ? "Worldregion \"" : "Region \"") - + region.getName() + "\" of type \"" + region.getLongTypeName() + "\"" - + (region instanceof IWorldRegion ? " in world \"" + ((IWorldRegion) region).getWorld().getName() + "\"" : "") - + " threw an exception while getting details", e - ); - } } - source.sendMessage(builder.build()); - return CommandResult.empty(); - } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { - if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a name!")); - IHandler handler = FGManager.getInstance().gethandler(parse.args[1]); - if (handler == null) - throw new CommandException(Text.of("No handler with name \"" + parse.args[1] + "\"!")); - Text.Builder builder = Text.builder(); - builder.append(Text.of(TextColors.GOLD, "\n-----------------------------------------------------\n")); - if (parse.args.length <= 2 || parse.args[2].isEmpty() || parse.flags.containsKey("all")) { - builder.append(Text.of(TextActions.runCommand("/foxguard detail handler " + handler.getName()), - TextActions.showText(Text.of("View details for handler \"" + handler.getName() + "\"")), - TextColors.GREEN, "------- General -------\n", - TextColors.GOLD, "Name: ", TextColors.RESET, handler.getName() + "\n")); - builder.append(Text.of(TextColors.GOLD, "Type: "), Text.of(TextColors.RESET, handler.getLongTypeName() + "\n")); - builder.append(Text.builder() - .append(Text.of(TextColors.GOLD, "Enabled: ")) - .append(Text.of(TextColors.RESET, (handler.isEnabled() ? "True" : "False") + "\n")) - .onClick(TextActions.runCommand("/foxguard " + (handler.isEnabled() ? "disable" : "enable") + " h " + handler.getName())) - .onHover(TextActions.showText(Text.of("Click to " + (handler.isEnabled() ? "disable" : "enable")))) - .build()); - builder.append(Text.builder() - .append(Text.of(TextColors.GOLD, "Priority: ")) - .append(Text.of(TextColors.RESET, handler.getPriority() + "\n")) - .onClick(TextActions.suggestCommand("/foxguard prio " + handler.getName() + " ")) - .onHover(TextActions.showText(Text.of("Click to change priority"))) - .build()); - builder.append(Text.of(TextActions.suggestCommand("/foxguard modify handler " + handler.getName() + " "), - TextActions.showText(Text.of("Click to modify handler \"" + handler.getName() + "\"")), - TextColors.GREEN, "------- Details -------\n")); - try { - Text objectDetails = handler.details(source, parse.args.length < 3 ? "" : parse.args[2]); - if (objectDetails == null) objectDetails = Text.of(); - builder.append(objectDetails); - } catch (Exception e) { - builder.append(Text.of(TextColors.RED, TextStyles.ITALIC, "There was an error getting details for handler \"" + handler.getName() + "\".")); - FoxGuardMain.instance().getLogger().error( - "Handler \"" + handler.getName() + "\" of type \"" + handler.getLongTypeName() + "\" threw an exception while getting details", e - ); - } - builder.append(Text.of(TextColors.GREEN, "\n------- Inbound Links -------")); - List controllerList = FGManager.getInstance().getControllers().stream() - .filter(controller -> controller.getHandlers().contains(handler)) - .sorted((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())) - .collect(GuavaCollectors.toImmutableList()); - List regionList = FGManager.getInstance().getAllRegions().stream() - .filter(region -> region.getHandlers().contains(handler)) - .sorted((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())) - .collect(GuavaCollectors.toImmutableList()); - if (controllerList.size() == 0 && regionList.size() == 0) - builder.append(Text.of(TextStyles.ITALIC, "\nNo inbound links!")); - controllerList.forEach(controller -> { - builder.append(Text.NEW_LINE); - if (source instanceof Player) { - List selectedHandlers = FGUtil.getSelectedHandlers(source); - List selectedControllers = FGUtil.getSelectedControllers(source); - if (selectedHandlers.contains(controller)) { - builder.append(Text.of(TextColors.GRAY, "[h+]")); - builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s h remove " + controller.getName()), - TextActions.showText(Text.of("Remove from handler state buffer")), - "[h-]")); - } else { - builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s h add " + controller.getName()), - TextActions.showText(Text.of("Add to handler state buffer")), - "[h+]")); - builder.append(Text.of(TextColors.GRAY, "[h-]")); - } - if (selectedControllers.contains(controller)) { - builder.append(Text.of(TextColors.GRAY, "[c+]")); - builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s c remove " + controller.getName()), - TextActions.showText(Text.of("Remove from controller state buffer")), - "[c-]")); - } else { - builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s c add " + controller.getName()), - TextActions.showText(Text.of("Add to controller state buffer")), - "[c+]")); - builder.append(Text.of(TextColors.GRAY, "[c-]")); + try { + Text objectDetails = object.details(source, parse.args.length < 3 ? "" : parse.args[2]); + if (objectDetails == null) objectDetails = Text.of(); + builder.append(objectDetails); + } catch (Exception e) { + builder.append(Text.of(TextColors.RED, TextStyles.ITALIC, "There was an exception getting details for " + fgCat.lName + " \"" + name + "\".")); + FoxGuardMain.instance().getLogger().error( + fgCat.uName + "\"" + name + "\" of type \"" + object.getLongTypeName() + "\"" + + (object instanceof IWorldBound ? " in world \"" + ((IWorldBound) object).getWorld().getName() + "\"" : "") + + " threw an exception while getting details", e + ); + } + + if (general) { + if (object instanceof IHandler) { + IHandler handler = ((IHandler) object); + builder.append(Text.of(TextColors.GREEN, "\n------- Inbound Links -------")); + List controllerList = FGManager.getInstance().getControllers().stream() + .filter(controller -> controller.getLinks().contains(handler)) + .sorted((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())) + .collect(GuavaCollectors.toImmutableList()); + List regionList = FGManager.getInstance().getAllRegions().stream() + .filter(region -> region.getLinks().contains(handler)) + .sorted((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())) + .collect(GuavaCollectors.toImmutableList()); + if (controllerList.size() == 0 && regionList.size() == 0) + builder.append(Text.of(TextStyles.ITALIC, "\nNo inbound links!")); + controllerList.forEach(controller -> { + builder.append(Text.NEW_LINE); + if (source instanceof Player) { + FGUtil.genStatePrefix(builder, controller, source); } - builder.append(Text.of(" ")); - } - builder.append(Text.of(FGUtil.getColorForObject(controller), - TextActions.runCommand("/foxguard det c " + controller.getName()), - TextActions.showText(Text.of("View details for controller \"" + controller.getName() + "\"")), - controller.getShortTypeName() + " : " + controller.getName())); - }); - - regionList.forEach(region -> { - builder.append(Text.NEW_LINE); - if (source instanceof Player) { - List selectedRegions = FGUtil.getSelectedRegions(source); - if (selectedRegions.contains(region)) { - builder.append(Text.of(TextColors.GRAY, "[+]")); - builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s r remove " + - FGUtil.genWorldFlag(region) + - region.getName()), - TextActions.showText(Text.of("Remove from state buffer")), - "[-]")); - } else { - builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s r add " + - FGUtil.genWorldFlag(region) + - region.getName()), - TextActions.showText(Text.of("Add to state buffer")), - "[+]")); - builder.append(Text.of(TextColors.GRAY, "[-]")); + builder.append(Text.of(FGUtil.getColorForObject(controller), + TextActions.runCommand("/foxguard det c " + controller.getFullName()), + TextActions.showText(Text.of("View details for controller \"" + controller.getName() + "\"")), + FGUtil.getObjectDisplayName(controller, false, null, source) + )); + }); + + regionList.forEach(region -> { + builder.append(Text.NEW_LINE); + if (source instanceof Player) { + FGUtil.genStatePrefix(builder, region, source); } - builder.append(Text.of(" ")); - } - builder.append(Text.of(FGUtil.getColorForObject(region), - TextActions.runCommand("/foxguard detail region " + FGUtil.genWorldFlag(region) + region.getName()), - TextActions.showText(Text.of("View details for region \"" + region.getName() + "\"")), - FGUtil.getRegionName(region, true) - )); - }); - if (handler instanceof IController) { - outboundLinks(builder, (IController) handler, source); - } - } else { - builder.append(Text.of(TextColors.GREEN, "------- Details for Handler \"" + handler.getName() + "\" -------\n")); - try { - Text objectDetails = handler.details(source, parse.args[2]); - if (objectDetails == null) objectDetails = Text.of(); - builder.append(objectDetails); - } catch (Exception e) { - builder.append(Text.of(TextColors.RED, TextStyles.ITALIC, "There was an error getting details for handler \"" + handler.getName() + "\".")); - FoxGuardMain.instance().getLogger().error( - "Handler \"" + handler.getName() + "\" of type \"" + handler.getLongTypeName() + "\" threw an exception while getting details", e - ); + builder.append(Text.of(FGUtil.getColorForObject(region), + TextActions.runCommand("/foxguard det r " + FGUtil.genWorldFlag(region) + region.getFullName()), + TextActions.showText(Text.of("View details for region \"" + region.getName() + "\"")), + FGUtil.getObjectDisplayName(region, true, null, source) + )); + }); } + if (object instanceof ILinkable) + outboundLinks(builder, (ILinkable) object, source); + + source.sendMessage(builder.build()); } - source.sendMessage(builder.build()); + + return CommandResult.empty(); - } else { - throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); } } private void outboundLinks(Text.Builder builder, ILinkable linkable, CommandSource source) { builder.append(Text.of(TextColors.GREEN, "\n------- Outbound Links -------")); - if (linkable.getHandlers().size() == 0) + Collection links = linkable.getLinks(); + if (links.size() == 0) builder.append(Text.of(TextStyles.ITALIC, "\nNo outbound links!")); - Stream handlerStream = linkable.getHandlers().stream(); + boolean hc = false; + if (source instanceof Player) { + for (IHandler handler : links) { + if (handler instanceof IController) { + hc = true; + break; + } + } + } + final boolean hasControllers = hc; + Stream handlerStream = links.stream(); if (!(linkable instanceof IController)) handlerStream = handlerStream.sorted((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); handlerStream.forEach(handler -> { builder.append(Text.NEW_LINE); if (source instanceof Player) { - List selectedHandlers = FGUtil.getSelectedHandlers(source); - List selectedControllers = FGUtil.getSelectedControllers(source); - if (selectedHandlers.contains(handler)) { - builder.append(Text.of(TextColors.GRAY, "[h+]")); - builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s h remove " + handler.getName()), - TextActions.showText(Text.of("Remove from handler state buffer")), - "[h-]")); - } else { - builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s h add " + handler.getName()), - TextActions.showText(Text.of("Add to handler state buffer")), - "[h+]")); - builder.append(Text.of(TextColors.GRAY, "[h-]")); - } - if (handler instanceof IController) { - IController controller = ((IController) handler); - if (selectedControllers.contains(controller)) { - builder.append(Text.of(TextColors.GRAY, "[c+]")); - builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s c remove " + controller.getName()), - TextActions.showText(Text.of("Remove from controller state buffer")), - "[c-]")); - } else { - builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s c add " + controller.getName()), - TextActions.showText(Text.of("Add to controller state buffer")), - "[c+]")); - builder.append(Text.of(TextColors.GRAY, "[c-]")); - } - } else { - builder.append(Text.of(TextColors.DARK_GRAY, "[c+][c-]")); - } - builder.append(Text.of(" ")); + FGUtil.genStatePrefix(builder, handler, source, hasControllers); } builder.append(Text.of(FGUtil.getColorForObject(handler), - TextActions.runCommand("/foxguard det h " + handler.getName()), + TextActions.runCommand("/foxguard det h " + handler.getFullName()), TextActions.showText(Text.of("View details for " + (handler instanceof IController ? "controller" : "handler") + " \"" + handler.getName() + "\"")), - handler.getShortTypeName() + " : " + handler.getName() + FGUtil.getObjectDisplayName(handler, false, null, source) )); }); } + @SuppressWarnings("Duplicates") @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { if (!testPermission(source)) return ImmutableList.of(); @@ -372,13 +286,21 @@ public List getSuggestions(CommandSource source, String arguments, @Null .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) - return ImmutableList.of("region", "handler").stream() + return Stream.of("region", "handler") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); else if (parse.current.index == 1) { + FGUtil.OwnerTabResult result = FGUtil.getOwnerSuggestions(parse.current.token); + if (result.isComplete()) { + return result.getSuggestions().stream() + .map(str -> parse.current.prefix + str) + .collect(GuavaCollectors.toImmutableList()); + } + if (isIn(REGIONS_ALIASES, parse.args[0])) { String worldName = parse.flags.get("world"); + boolean key = parse.flags.containsKey("world"); World world = null; if (source instanceof Locatable) world = ((Locatable) source).getWorld(); if (!worldName.isEmpty()) { @@ -387,26 +309,29 @@ else if (parse.current.index == 1) { world = optWorld.get(); } } - if (world == null) return FGManager.getInstance().getRegions().stream() - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); - return FGManager.getInstance().getAllRegions(world).stream() - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); + if (key && world != null) { + return FGManager.getInstance().getAllRegions(world, new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } else { + return FGManager.getInstance().getAllRegionsWithUniqueNames(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner()), world).stream() + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { - return FGManager.getInstance().getHandlers().stream() - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) + return FGManager.getInstance().getHandlers(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) .collect(GuavaCollectors.toImmutableList()); } } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world").stream() + return Stream.of("world") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -442,4 +367,29 @@ public Optional getHelp(CommandSource source) { public Text getUsage(CommandSource source) { return Text.of("detail ] | handler> [args...]"); } + + private enum FGCat { + REGION(REGIONS_ALIASES, "r"), + WORLDREGION(null, REGION.sName), + HANDLER(HANDLERS_ALIASES, "h"), + CONTROLLER(null, HANDLER.sName); + + public final String[] catAliases; + public final String lName = name().toLowerCase(); + public final String uName = FCCUtil.toCapitalCase(name()); + public final String sName; + + FGCat(String[] catAliases, String sName) { + this.catAliases = catAliases; + this.sName = sName; + } + + public static FGCat from(String category) { + for (FGCat cat : values()) { + if (isIn(cat.catAliases, category)) return cat; + } + return null; + } + } + } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandEnableDisable.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandEnableDisable.java index 72a14c2..80f5ab8 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandEnableDisable.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandEnableDisable.java @@ -26,6 +26,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.command; import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxcore.common.util.FCCUtil; import net.foxdenstudio.sponge.foxcore.plugin.command.FCCommandBase; import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; import net.foxdenstudio.sponge.foxcore.plugin.command.util.FlagMapper; @@ -35,11 +36,11 @@ import net.foxdenstudio.sponge.foxguard.plugin.event.factory.FGEventFactory; import net.foxdenstudio.sponge.foxguard.plugin.handler.GlobalHandler; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.UUIDOwner; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.GlobalWorldRegion; -import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import net.foxdenstudio.sponge.foxguard.plugin.state.HandlersStateField; import net.foxdenstudio.sponge.foxguard.plugin.state.RegionsStateField; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; @@ -48,7 +49,6 @@ import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.command.args.ArgumentParseException; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.util.GuavaCollectors; @@ -57,11 +57,12 @@ import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; -import javax.annotation.Nullable; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; + +import javax.annotation.Nullable; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; @@ -81,7 +82,118 @@ public CommandEnableDisable(boolean enableState) { this.enableState = enableState; } + @SuppressWarnings("Duplicates") @Override + public CommandResult process(CommandSource source, String arguments) throws CommandException { + if (!testPermission(source)) { + source.sendMessage(Text.of(TextColors.RED, "You don't have permission to use this command!")); + return CommandResult.empty(); + } + AdvCmdParser.ParseResult parse = AdvCmdParser.builder() + .arguments(arguments) + .flagMapper(MAPPER) + .parse(); + + + List selectedRegions = FGUtil.getSelectedRegions(source); + List selectedHandlers = FGUtil.getSelectedHandlers(source); + if (parse.args.length == 0 && selectedRegions.isEmpty() && selectedHandlers.isEmpty()) { + source.sendMessage(Text.builder() + .append(Text.of(TextColors.GREEN, "Usage: ")) + .append(getUsage(source)) + .build()); + return CommandResult.empty(); + } + + List objects = new ArrayList<>(); + + FGCat cat = FGCat.OBJECT; + if (parse.args.length > 0) { + cat = FGCat.from(parse.args[0]); + if (cat == null) throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); + } + + switch (cat) { + case OBJECT: + objects.addAll(selectedHandlers); + FCStateManager.instance().getStateMap().get(source).flush(HandlersStateField.ID); + case REGION: + objects.addAll(selectedRegions); + FCStateManager.instance().getStateMap().get(source).flush(RegionsStateField.ID); + break; + case HANDLER: + objects.addAll(selectedHandlers); + FCStateManager.instance().getStateMap().get(source).flush(HandlersStateField.ID); + } + + boolean worldKey = parse.flags.containsKey("world"); + String worldValue = parse.flags.get("world"); + for (int i = 1; i < parse.args.length; i++) { + FGUtil.OwnerResult ownerResult = FGUtil.processUserInput(parse.args[i]); + IGuardObject object; + switch (cat) { + case REGION: + object = FGUtil.getRegionFromCommand(source, ownerResult, worldKey, worldValue); + break; + case HANDLER: + object = FGUtil.getHandlerFromCommand(ownerResult); + break; + default: + throw new CommandException(Text.of("Something went horribly wrong.")); + } + objects.add(object); + } + + int successes = 0; + int failures = 0; + for (IGuardObject object : objects) { + if (object instanceof GlobalWorldRegion || object instanceof GlobalHandler || object.isEnabled() == this.enableState) + failures++; + else { + object.setEnabled(this.enableState); + successes++; + } + } + + if (successes == 1 && failures == 0) { + Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateEvent(FoxGuardMain.getCause())); + source.sendMessage(Text.of(TextColors.GREEN, "Successfully " + (this.enableState ? "enabled" : "disabled") + " " + cat.lName + "!")); + return CommandResult.success(); + } else if (successes > 0) { + Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateEvent(FoxGuardMain.getCause())); + source.sendMessage(Text.of(TextColors.GREEN, "Successfully " + (this.enableState ? "enabled" : "disabled") + " " + cat.lName + "s with " + + successes + " successes" + (failures > 0 ? " and " + failures + " failures!" : "!"))); + return CommandResult.builder().successCount(successes).build(); + } else { + throw new CommandException(Text.of(failures + " failures while trying to " + (this.enableState ? "enable" : "disable") + + " " + failures + (failures > 1 ? " " + cat.lName + "s" : " " + cat.lName) + + ". Check to make sure you spelled their names correctly and that they are not already " + + (this.enableState ? "enabled." : "disabled."))); + } + } + + private enum FGCat { + REGION(REGIONS_ALIASES), + HANDLER(HANDLERS_ALIASES), + OBJECT(null); + + public final String[] catAliases; + public final String lName = name().toLowerCase(); + public final String uName = FCCUtil.toCapitalCase(name()); + + FGCat(String[] catAliases) { + this.catAliases = catAliases; + } + + public static FGCat from(String category) { + for (FGCat cat : values()) { + if (isIn(cat.catAliases, category)) return cat; + } + return null; + } + } + + /*@Override public CommandResult process(CommandSource source, String arguments) throws CommandException { if (!testPermission(source)) { source.sendMessage(Text.of(TextColors.RED, "You don't have permission to use this command!")); @@ -97,15 +209,15 @@ public CommandResult process(CommandSource source, String arguments) throws Comm return CommandResult.empty(); } else { List objects = new ArrayList<>(); - FGUtil.getSelectedRegions(source).forEach(objects::add); - FGUtil.getSelectedHandlers(source).forEach(objects::add); + objects.addAll(FGUtil.getSelectedRegions(source)); + objects.addAll(FGUtil.getSelectedHandlers(source)); int successes = 0; int failures = 0; for (IFGObject object : objects) { if (object instanceof GlobalWorldRegion || object instanceof GlobalHandler || object.isEnabled() == this.enableState) failures++; else { - object.setIsEnabled(this.enableState); + object.setEnabled(this.enableState); successes++; } } @@ -139,10 +251,10 @@ public CommandResult process(CommandSource source, String arguments) throws Comm int successes = 0; int failures = 0; List regions = new ArrayList<>(); - FGUtil.getSelectedRegions(source).forEach(regions::add); + regions.addAll(FGUtil.getSelectedRegions(source)); if (parse.args.length > 1) { for (String name : Arrays.copyOfRange(parse.args, 1, parse.args.length)) { - IWorldRegion region = FGManager.getInstance().getWorldRegion(world, name); + IWorldRegion region = FGManager.getInstance().getWorldRegion(world, name).orElse(null); if (region == null) failures++; else { regions.add(region); @@ -153,7 +265,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm for (IRegion region : regions) { if (region instanceof IGlobal || region.isEnabled() == this.enableState) failures++; else { - region.setIsEnabled(this.enableState); + region.setEnabled(this.enableState); successes++; } } @@ -178,9 +290,9 @@ public CommandResult process(CommandSource source, String arguments) throws Comm int successes = 0; int failures = 0; List handlers = new ArrayList<>(); - FGUtil.getSelectedHandlers(source).forEach(handlers::add); + handlers.addAll(FGUtil.getSelectedHandlers(source)); for (String name : Arrays.copyOfRange(parse.args, 1, parse.args.length)) { - IHandler handler = FGManager.getInstance().gethandler(name); + IHandler handler = FGManager.getInstance().getHandler(name).orElse(null); if (handler == null) failures++; else { handlers.add(handler); @@ -190,7 +302,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm for (IHandler handler : handlers) { if (handler instanceof IGlobal || handler.isEnabled() == this.enableState) failures++; else { - handler.setIsEnabled(this.enableState); + handler.setEnabled(this.enableState); successes++; } } @@ -210,8 +322,9 @@ public CommandResult process(CommandSource source, String arguments) throws Comm + (this.enableState ? "enabled." : "disabled."))); } } else throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); - } + }*/ + @SuppressWarnings("Duplicates") @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { if (!testPermission(source)) return ImmutableList.of(); @@ -223,13 +336,21 @@ public List getSuggestions(CommandSource source, String arguments, @Null .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) - return ImmutableList.of("region", "handler").stream() + return Stream.of("region", "handler") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); else if (parse.current.index > 0) { + FGUtil.OwnerTabResult result = FGUtil.getOwnerSuggestions(parse.current.token); + if (result.isComplete()) { + return result.getSuggestions().stream() + .map(str -> parse.current.prefix + str) + .collect(GuavaCollectors.toImmutableList()); + } + if (isIn(REGIONS_ALIASES, parse.args[0])) { String worldName = parse.flags.get("world"); + boolean key = parse.flags.containsKey("world"); World world = null; if (source instanceof Locatable) world = ((Locatable) source).getWorld(); if (!worldName.isEmpty()) { @@ -238,34 +359,32 @@ else if (parse.current.index > 0) { world = optWorld.get(); } } - String[] existing = Arrays.copyOfRange(parse.args, 1, parse.args.length); - if (world == null) return FGManager.getInstance().getRegions().stream() - .filter(region -> region.isEnabled() != this.enableState && !(region instanceof IGlobal)) - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .filter(alias -> !isIn(existing, alias)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); - return FGManager.getInstance().getAllRegions(world).stream() - .filter(region -> region.isEnabled() != this.enableState && !(region instanceof IGlobal)) - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .filter(alias -> !isIn(existing, alias)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); + if (key && world != null) { + return FGManager.getInstance().getAllRegions(world, new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() + .filter(object -> object.isEnabled() != this.enableState && !(object instanceof IGlobal)) + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } else { + return FGManager.getInstance().getAllRegionsWithUniqueNames(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner()), world).stream() + .filter(object -> object.isEnabled() != this.enableState && !(object instanceof IGlobal)) + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { - String[] existing = Arrays.copyOfRange(parse.args, 1, parse.args.length); - return FGManager.getInstance().getHandlers().stream() - .filter(handler -> handler.isEnabled() != this.enableState && !(handler instanceof IGlobal)) - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .filter(alias -> !isIn(existing, alias)) - .map(args -> parse.current.prefix + args) + return FGManager.getInstance().getHandlers(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() + .filter(object -> object.isEnabled() != this.enableState && !(object instanceof IGlobal)) + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) .collect(GuavaCollectors.toImmutableList()); } } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world").stream() + return Stream.of("world") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandHere.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandHere.java index 87b53b2..069a6f9 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandHere.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandHere.java @@ -35,7 +35,7 @@ import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.listener.PlayerMoveListenerNew; +import net.foxdenstudio.sponge.foxguard.plugin.listener.PlayerMoveListener; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.Sponge; @@ -56,6 +56,7 @@ import javax.annotation.Nullable; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; @@ -85,7 +86,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm } AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).flagMapper(MAPPER).parse(); boolean hud = false; - PlayerMoveListenerNew.HUDConfig hudConfig = new PlayerMoveListenerNew.HUDConfig(false, false, false); + PlayerMoveListener.HUDConfig hudConfig = new PlayerMoveListener.HUDConfig(false, false, false); String worldName = parse.flags.get("world"); World world = null; @@ -145,31 +146,17 @@ public CommandResult process(CommandSource source, String arguments) throws Comm output.append(Text.of(TextColors.AQUA, "----- Position: (" + String.format("%.1f, %.1f, %.1f", x, y, z) + ") -----\n")); if (!parse.flags.containsKey("handler") || parse.flags.containsKey("region")) { output.append(Text.of(TextColors.GREEN, "------- Regions Located Here -------\n")); - Collections.sort(regionList, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); + regionList.sort((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); ListIterator regionListIterator = regionList.listIterator(); while (regionListIterator.hasNext()) { IRegion region = regionListIterator.next(); if (source instanceof Player) { - List selectedRegions = FGUtil.getSelectedRegions(source); - if (selectedRegions.contains(region)) { - output.append(Text.of(TextColors.GRAY, "[+]")); - output.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s r remove " + FGUtil.genWorldFlag(region) + region.getName()), - TextActions.showText(Text.of("Remove from state buffer")), - "[-]")); - } else { - output.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s r add " + FGUtil.genWorldFlag(region) + region.getName()), - TextActions.showText(Text.of("Add to state buffer")), - "[+]")); - output.append(Text.of(TextColors.GRAY, "[-]")); - } - output.append(Text.of(" ")); + FGUtil.genStatePrefix(output, region, source); } output.append(Text.of(FGUtil.getColorForObject(region), - TextActions.runCommand("/foxguard detail region " + FGUtil.genWorldFlag(region) + region.getName()), + TextActions.runCommand("/foxguard detail r " + FGUtil.genWorldFlag(region) + region.getFullName()), TextActions.showText(Text.of("View details")), - FGUtil.getRegionName(region, false))); + FGUtil.getObjectDisplayName(region, false, null, source))); if (regionListIterator.hasNext()) output.append(Text.NEW_LINE); } flag = true; @@ -178,59 +165,33 @@ public CommandResult process(CommandSource source, String arguments) throws Comm if (!parse.flags.containsKey("region") || parse.flags.containsKey("handler")) { if (flag) output.append(Text.NEW_LINE); - regionList.forEach(region -> region.getHandlers().stream() + regionList.forEach(region -> region.getLinks().stream() .filter(handler -> !handlerList.contains(handler)) .forEach(handlerList::add)); + boolean hasControllers = false; + for(IHandler handler: handlerList){ + if(handler instanceof IController){ + hasControllers = true; + break; + } + } output.append(Text.of(TextColors.GREEN, "------- Handlers Located Here -------\n")); if (parse.flags.containsKey("priority")) { - Collections.sort(handlerList, (o1, o2) -> o2.getPriority() - o1.getPriority()); + handlerList.sort(IHandler.PRIORITY); hudConfig.priority = true; } else { - Collections.sort(handlerList, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); + handlerList.sort((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); } ListIterator handlerListIterator = handlerList.listIterator(); while (handlerListIterator.hasNext()) { IHandler handler = handlerListIterator.next(); if (source instanceof Player) { - List selectedHandlers = FGUtil.getSelectedHandlers(source); - List selectedControllers = FGUtil.getSelectedControllers(source); - if (selectedHandlers.contains(handler)) { - output.append(Text.of(TextColors.GRAY, "[h+]")); - output.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s h remove " + handler.getName()), - TextActions.showText(Text.of("Remove from handler state buffer")), - "[h-]")); - } else { - output.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s h add " + handler.getName()), - TextActions.showText(Text.of("Add to handler state buffer")), - "[h+]")); - output.append(Text.of(TextColors.GRAY, "[h-]")); - } - if (handler instanceof IController) { - IController controller = ((IController) handler); - if (selectedControllers.contains(controller)) { - output.append(Text.of(TextColors.GRAY, "[c+]")); - output.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s c remove " + controller.getName()), - TextActions.showText(Text.of("Remove from controller state buffer")), - "[c-]")); - } else { - output.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s c add " + controller.getName()), - TextActions.showText(Text.of("Add to controller state buffer")), - "[c+]")); - output.append(Text.of(TextColors.GRAY, "[c-]")); - } - } else { - output.append(Text.of(TextColors.DARK_GRAY, "[c+][c-]")); - } - output.append(Text.of(" ")); + FGUtil.genStatePrefix(output, handler, source, hasControllers); } output.append(Text.of(FGUtil.getColorForObject(handler), - TextActions.runCommand("/foxguard detail handler " + handler.getName()), + TextActions.runCommand("/foxguard detail handler " + handler.getFullName()), TextActions.showText(Text.of("View details")), - handler.getShortTypeName() + " : " + handler.getName())); + FGUtil.getObjectDisplayName(handler, false, null, source))); if (handlerListIterator.hasNext()) output.append(Text.NEW_LINE); } hudConfig.handlers = true; @@ -239,7 +200,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm if (hud) { Player player = (Player) source; if (CommandHUD.instance().getIsHUDEnabled().get(player)) { - PlayerMoveListenerNew instance = PlayerMoveListenerNew.getInstance(); + PlayerMoveListener instance = PlayerMoveListener.getInstance(); instance.getHudConfigMap().put(player, hudConfig); instance.renderHUD(player, regionList, handlerList, hudConfig); instance.showScoreboard(player); @@ -248,6 +209,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm return CommandResult.empty(); } + @SuppressWarnings("Duplicates") @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { if (!testPermission(source)) return ImmutableList.of(); @@ -260,12 +222,12 @@ public List getSuggestions(CommandSource source, String arguments, @Null if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT) && parse.current.index < 3 && parse.current.token.isEmpty()) { return ImmutableList.of(parse.current.prefix + "~"); } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.SHORTFLAG)) { - return ImmutableList.of("r", "h", "p").stream() + return Stream.of("r", "h", "p") .filter(flag -> !parse.flags.containsKey(flag)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world", "regions", "handlers", "priority").stream() + return Stream.of("world", "regions", "handlers", "priority") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandLink.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandLink.java index 32b6dbb..c250aea 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandLink.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandLink.java @@ -33,8 +33,9 @@ import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.handler.GlobalHandler; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.UUIDOwner; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.state.HandlersStateField; import net.foxdenstudio.sponge.foxguard.plugin.state.RegionsStateField; @@ -43,7 +44,6 @@ import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.util.GuavaCollectors; @@ -55,6 +55,7 @@ import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.WORLD_ALIASES; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.isIn; @@ -94,30 +95,14 @@ public CommandResult process(CommandSource source, String arguments) throws Comm FCStateManager.instance().getStateMap().get(source).flush(RegionsStateField.ID, HandlersStateField.ID); return CommandResult.builder().successCount(successes[0]).build(); } else { - IRegion region = FGManager.getInstance().getRegion(parse.args[0]); - World world = null; - if (region == null) { - String worldName = parse.flags.get("world"); - if (source instanceof Locatable) world = ((Locatable) source).getWorld(); - if (!worldName.isEmpty()) { - Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); - if (optWorld.isPresent()) { - world = optWorld.get(); - } else { - if (world == null) - throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); - } - } - if (world == null) throw new CommandException(Text.of("Must specify a world!")); - region = FGManager.getInstance().getWorldRegion(world, parse.args[0]); - } - if (region == null) - throw new CommandException(Text.of("No region with name \"" + parse.args[0] + "\" in world \"" + world.getName() + "\"!")); + FGUtil.OwnerResult regionOwnerResult = FGUtil.processUserInput(parse.args[0]); + IRegion region = FGUtil.getRegionFromCommand(source, regionOwnerResult, parse.flags.containsKey("world"), parse.flags.get("world")); + if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a handler!")); - IHandler handler = FGManager.getInstance().gethandler(parse.args[1]); - if (handler == null) - throw new CommandException(Text.of("No handler with name \"" + parse.args[1] + "\"!")); - if (region.getHandlers().contains(handler)) + FGUtil.OwnerResult handlerOwnerResult = FGUtil.processUserInput(parse.args[1]); + IHandler handler = FGUtil.getHandlerFromCommand(handlerOwnerResult); + + if (region.getLinks().contains(handler)) throw new CommandException(Text.of("Already linked!")); boolean success = FGManager.getInstance().link(region, handler); if (success) { @@ -142,7 +127,15 @@ public List getSuggestions(CommandSource source, String arguments, @Null .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) { + FGUtil.OwnerTabResult result = FGUtil.getOwnerSuggestions(parse.current.token); + if (result.isComplete()) { + return result.getSuggestions().stream() + .map(str -> parse.current.prefix + str) + .collect(GuavaCollectors.toImmutableList()); + } + String worldName = parse.flags.get("world"); + boolean key = parse.flags.containsKey("world"); World world = null; if (source instanceof Locatable) world = ((Locatable) source).getWorld(); if (!worldName.isEmpty()) { @@ -151,52 +144,52 @@ public List getSuggestions(CommandSource source, String arguments, @Null world = optWorld.get(); } } - if (world == null) return FGManager.getInstance().getRegions().stream() - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); - else return FGManager.getInstance().getAllRegions(world).stream() - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); + if (key && world != null) { + return FGManager.getInstance().getAllRegions(world, new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } else { + return FGManager.getInstance().getAllRegionsWithUniqueNames(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner()), world).stream() + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } } else if (parse.current.index == 1) { - IRegion region = FGManager.getInstance().getRegion(parse.args[0]); - if (region == null) { - String worldName = parse.flags.get("world"); - World world = null; - if (source instanceof Locatable) world = ((Locatable) source).getWorld(); - if (!worldName.isEmpty()) { - Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); - if (optWorld.isPresent()) { - world = optWorld.get(); - } - } - if (world != null) { - region = FGManager.getInstance().getWorldRegion(world, parse.args[0]); - } + FGUtil.OwnerTabResult tabResult = FGUtil.getOwnerSuggestions(parse.current.token); + if (tabResult.isComplete()) { + return tabResult.getSuggestions().stream() + .map(str -> parse.current.prefix + str) + .collect(GuavaCollectors.toImmutableList()); } + IRegion region = null; + try { + FGUtil.OwnerResult regionOwnerResult = FGUtil.processUserInput(parse.args[0]); + region = FGUtil.getRegionFromCommand(source, regionOwnerResult, parse.flags.containsKey("world"), parse.flags.get("world")); + } catch (CommandException ignored) { + } if (region != null) { IRegion finalRegion = region; - return FGManager.getInstance().getHandlers().stream() - .filter(handler -> !finalRegion.getHandlers().contains(handler) && !(handler instanceof IGlobal)) - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) + return FGManager.getInstance().getHandlers(new UUIDOwner(UUIDOwner.USER_GROUP, tabResult.getOwner())).stream() + .filter(handler -> !finalRegion.getLinks().contains(handler) && !(handler instanceof IGlobal)) + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(tabResult.getToken())) + .map(args -> parse.current.prefix + tabResult.getPrefix() + args) .collect(GuavaCollectors.toImmutableList()); } - return FGManager.getInstance().getHandlers().stream() + return FGManager.getInstance().getHandlers(new UUIDOwner(UUIDOwner.USER_GROUP, tabResult.getOwner())).stream() .filter(handler -> !(handler instanceof IGlobal)) - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .map(args -> parse.current.prefix + args) + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(tabResult.getToken())) + .map(args -> parse.current.prefix + tabResult.getPrefix() + args) .collect(GuavaCollectors.toImmutableList()); } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world").stream() + return Stream.of("world") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandLink2.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandLink2.java index da8046b..3bf5a72 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandLink2.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandLink2.java @@ -66,9 +66,9 @@ public CommandResult process(CommandSource source, String arguments) throws Comm int[] successes = {0}; set.forEach(entry -> { if (link) { - if (entry.linkable.addHandler(entry.handler)) successes[0]++; + if (entry.linkable.addLink(entry.handler)) successes[0]++; } else { - if (entry.linkable.removeHandler(entry.handler)) successes[0]++; + if (entry.linkable.removeLink(entry.handler)) successes[0]++; } }); if (successes[0] > 0) { diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandList.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandList.java index 4f333bb..dd7f2c4 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandList.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandList.java @@ -30,12 +30,11 @@ import net.foxdenstudio.sponge.foxcore.plugin.command.FCCommandBase; import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; import net.foxdenstudio.sponge.foxcore.plugin.command.util.FlagMapper; -import net.foxdenstudio.sponge.foxcore.plugin.util.Aliases; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; @@ -46,14 +45,17 @@ import org.spongepowered.api.text.Text; import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.format.TextStyles; import org.spongepowered.api.util.GuavaCollectors; import org.spongepowered.api.util.StartsWithPredicate; +import org.spongepowered.api.world.Locatable; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; import javax.annotation.Nullable; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; @@ -77,6 +79,191 @@ public class CommandList extends FCCommandBase { return true; }; + @SuppressWarnings("Duplicates") + @Override + public CommandResult process(CommandSource source, String arguments) throws CommandException { + if (!testPermission(source)) { + source.sendMessage(Text.of(TextColors.RED, "You don't have permission to use this command!")); + return CommandResult.empty(); + } + AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).flagMapper(MAPPER).parse(); + + if (parse.args.length == 0) { + source.sendMessage(Text.builder() + .append(Text.of(TextColors.GREEN, "Usage: ")) + .append(getUsage(source)) + .build()); + return CommandResult.empty(); + } else { + List objects = new ArrayList<>(); + FGCat cat = FGCat.from(parse.args[0]); + if (cat == null) throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); + + String title = "Objects"; + boolean hasControllers = false; + boolean dispWorld = false; + + switch (cat) { + case REGION: { + if (parse.flags.containsKey("world")) { + World world; + String worldName = parse.flags.get("world"); + if (!worldName.isEmpty()) { + Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); + if (optWorld.isPresent()) { + world = optWorld.get(); + } else { + throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); + } + } else if (source instanceof Locatable) { + world = ((Locatable) source).getWorld(); + } else { + throw new CommandException(Text.of("Must specify world name for flag!")); + } + objects.addAll(FGManager.getInstance().getWorldRegions(world)); + title = "Regions in World: " + world.getName(); + if (parse.flags.containsKey("super")) { + objects.addAll(FGManager.getInstance().getRegions()); + title = "All " + title; + } + } else { + if (parse.flags.containsKey("super")) { + objects.addAll(FGManager.getInstance().getRegions()); + title = "Super Regions"; + } else { + objects.addAll(FGManager.getInstance().getAllRegions()); + title = "All Regions"; + } + dispWorld = true; + } + } + break; + case HANDLER: { + boolean controllers = parse.flags.containsKey("all"); + Collection handlers = FGManager.getInstance().getHandlers(controllers); + objects.addAll(handlers); + title = "Handlers"; + if (controllers) { + title += " and Controllers"; + for (IHandler handler : handlers) { + if (handler instanceof IController) { + hasControllers = true; + break; + } + } + } + } + break; + case CONTROLLER: { + objects.addAll(FGManager.getInstance().getControllers()); + title = "Controllers"; + hasControllers = true; + } + break; + } + + if (parse.flags.containsKey("query")) { + String query = parse.flags.get("query"); + if (query.startsWith("/")) { + if (source.hasPermission("foxcore.danger.regex")) { + FCCUtil.FCPattern pattern = FCCUtil.parseUserRegex(query); + objects = objects.stream() + .filter(region -> pattern.matches(region.getName())) + .collect(Collectors.toList()); + } else { + throw new CommandException(Text.of("You don't have permission to use regular expressions!")); + } + } else { + objects = objects.stream() + .filter(region -> region.getName().toLowerCase().contains(query.toLowerCase())) + .collect(Collectors.toList()); + } + } + + int page, number; + if (parse.flags.containsKey("page")) { + try { + page = Integer.parseInt(parse.flags.get("page")); + } catch (NumberFormatException ignored) { + page = 1; + } + } else page = 1; + if (parse.flags.containsKey("number")) { + try { + number = Integer.parseInt(parse.flags.get("number")); + } catch (NumberFormatException ignored) { + if (source instanceof Player) number = 18; + else number = Integer.MAX_VALUE; + } + } else { + if (source instanceof Player) number = 18; + else number = Integer.MAX_VALUE; + } + if (number < 1) number = 1; + int maxPage = (Math.max(objects.size() - 1, 0) / number) + 1; + if (page < 1) page = 1; + else if (page > maxPage) page = maxPage; + int skip = (page - 1) * number; + + + Text.Builder builder = Text.builder() + .append(Text.of(TextColors.GOLD, "\n-----------------------------------------------------\n")) + .append(Text.of(TextColors.GREEN, "------- " + title + " -------\n")); + + objects.sort((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); + Iterator objectIterator = objects.iterator(); + for (int i = 0; i < skip; i++) { + objectIterator.next(); + } + int count = 0; + if(!objectIterator.hasNext()){ + builder.append(Text.of(TextColors.GRAY, TextStyles.ITALIC, "No objects found")); + } + while (objectIterator.hasNext() && count < number) { + IGuardObject object = objectIterator.next(); + String fullName = object.getFullName(); + if (source instanceof Player) { + FGUtil.genStatePrefix(builder, object, source, hasControllers); + } + builder.append(Text.of(FGUtil.getColorForObject(object), + TextActions.runCommand("/foxguard det " + cat.sName + " " + FGUtil.genWorldFlag(object) + fullName), + TextActions.showText(Text.of("View details")), + FGUtil.getObjectDisplayName(object, dispWorld, null, source))); + count++; + if (objectIterator.hasNext() && count < number) builder.append(Text.NEW_LINE); + } + if (maxPage > 1) + builder.append(Text.NEW_LINE).append(FCPUtil.pageFooter(page, maxPage, "/foxguard ls " + arguments, null)); + source.sendMessage(builder.build()); + + return CommandResult.empty(); + } + } + + private enum FGCat { + REGION(REGIONS_ALIASES, "r"), + HANDLER(HANDLERS_ALIASES, "h"), + CONTROLLER(CONTROLLERS_ALIASES, HANDLER.sName); + + public final String[] catAliases; + public final String lName = name().toLowerCase(); + public final String uName = FCCUtil.toCapitalCase(name()); + public final String sName; + + FGCat(String[] catAliases, String sName) { + this.catAliases = catAliases; + this.sName = sName; + } + + public static FGCat from(String category) { + for (FGCat cat : values()) { + if (isIn(cat.catAliases, category)) return cat; + } + return null; + } + } + + /*@SuppressWarnings("Duplicates") @Override public CommandResult process(CommandSource source, String arguments) throws CommandException { if (!testPermission(source)) { @@ -98,15 +285,15 @@ public CommandResult process(CommandSource source, String arguments) throws Comm if (!worldName.isEmpty()) { Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); if (optWorld.isPresent()) { - FGManager.getInstance().getWorldRegions(optWorld.get()).forEach(regionList::add); + regionList.addAll(FGManager.getInstance().getWorldRegions(optWorld.get())); if (parse.flags.containsKey("super")) - FGManager.getInstance().getRegions().forEach(regionList::add); + regionList.addAll(FGManager.getInstance().getRegions()); allFlag = false; } } if (allFlag) { - if (parse.flags.containsKey("super")) FGManager.getInstance().getRegions().forEach(regionList::add); - else FGManager.getInstance().getAllRegions().forEach(regionList::add); + if (parse.flags.containsKey("super")) regionList.addAll(FGManager.getInstance().getRegions()); + else regionList.addAll(FGManager.getInstance().getAllRegions()); } if (parse.flags.containsKey("query")) { String query = parse.flags.get("query"); @@ -150,7 +337,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm Text.Builder builder = Text.builder() .append(Text.of(TextColors.GOLD, "\n-----------------------------------------------------\n")) .append(Text.of(TextColors.GREEN, "------- Regions" + (allFlag ? "" : (" for World: \"" + worldName + "\"")) + " -------\n")); - Collections.sort(regionList, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); + regionList.sort((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); Iterator regionIterator = regionList.iterator(); for (int i = 0; i < skip; i++) { regionIterator.next(); @@ -158,6 +345,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm int count = 0; while (regionIterator.hasNext() && count < number) { IRegion region = regionIterator.next(); + String fullName = region.getOwner().toString() + ":" + region.getName(); if (source instanceof Player) { List selectedRegions = FGUtil.getSelectedRegions(source); if (selectedRegions.contains(region)) { @@ -165,14 +353,14 @@ public CommandResult process(CommandSource source, String arguments) throws Comm builder.append(Text.of(TextColors.RED, TextActions.runCommand("/foxguard s r remove " + FGUtil.genWorldFlag(region) + - region.getName()), + FGUtil.getFullName(region)), TextActions.showText(Text.of("Remove from state buffer")), "[-]")); } else { builder.append(Text.of(TextColors.GREEN, TextActions.runCommand("/foxguard s r add " + FGUtil.genWorldFlag(region) + - region.getName()), + FGUtil.getFullName(region)), TextActions.showText(Text.of("Add to state buffer")), "[+]")); builder.append(Text.of(TextColors.GRAY, "[-]")); @@ -180,20 +368,20 @@ public CommandResult process(CommandSource source, String arguments) throws Comm builder.append(Text.of(" ")); } builder.append(Text.of(FGUtil.getColorForObject(region), - TextActions.runCommand("/foxguard det r " + FGUtil.genWorldFlag(region) + region.getName()), + TextActions.runCommand("/foxguard det r " + FGUtil.genWorldFlag(region) + fullName), TextActions.showText(Text.of("View details")), - FGUtil.getRegionName(region, allFlag))); + FGUtil.getObjectDisplayName(region, allFlag, null, source))); count++; if (regionIterator.hasNext() && count < number) builder.append(Text.NEW_LINE); } if (maxPage > 1) - builder.append(Text.NEW_LINE).append(FCPUtil.pageFooter(page, maxPage, "/fg ls " + arguments, null)); + builder.append(Text.NEW_LINE).append(FCPUtil.pageFooter(page, maxPage, "/foxguard ls " + arguments, null)); source.sendMessage(builder.build()); //---------------------------------------------------------------------------------------------------------- } else if (isIn(Aliases.HANDLERS_ALIASES, parse.args[0])) { boolean controllers = parse.flags.containsKey("all"); - List handlerList = FGManager.getInstance().getHandlers(controllers).stream().collect(Collectors.toList()); + List handlerList = new ArrayList<>(FGManager.getInstance().getHandlers(controllers)); if (parse.flags.containsKey("query")) { String query = parse.flags.get("query"); if (query.startsWith("/")) { @@ -236,7 +424,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm Text.Builder builder = Text.builder() .append(Text.of(TextColors.GOLD, "\n-----------------------------------------------------\n")) .append(Text.of(TextColors.GREEN, "------- Handlers " + (controllers ? "and Controllers " : "") + "-------\n")); - Collections.sort(handlerList, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); + handlerList.sort((o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); Iterator handlerIterator = handlerList.iterator(); for (int i = 0; i < skip; i++) { handlerIterator.next(); @@ -244,6 +432,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm int count = 0; while (handlerIterator.hasNext() && count < number) { IHandler handler = handlerIterator.next(); + String fullName = handler.getOwner().toString() + ":" + handler.getName(); if (source instanceof Player) { List selectedHandlers = FGUtil.getSelectedHandlers(source); if (controllers) { @@ -251,12 +440,12 @@ public CommandResult process(CommandSource source, String arguments) throws Comm if (selectedHandlers.contains(handler)) { builder.append(Text.of(TextColors.GRAY, "[h+]")); builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s h remove " + handler.getName()), + TextActions.runCommand("/foxguard s h remove " + FGUtil.getFullName(handler)), TextActions.showText(Text.of("Remove from handler state buffer")), "[h-]")); } else { builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s h add " + handler.getName()), + TextActions.runCommand("/foxguard s h add " + FGUtil.getFullName(handler)), TextActions.showText(Text.of("Add to handler state buffer")), "[h+]")); builder.append(Text.of(TextColors.GRAY, "[h-]")); @@ -266,12 +455,12 @@ public CommandResult process(CommandSource source, String arguments) throws Comm if (selectedControllers.contains(controller)) { builder.append(Text.of(TextColors.GRAY, "[c+]")); builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s c remove " + controller.getName()), + TextActions.runCommand("/foxguard s c remove " + FGUtil.getFullName(controller)), TextActions.showText(Text.of("Remove from controller state buffer")), "[c-]")); } else { builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s c add " + controller.getName()), + TextActions.runCommand("/foxguard s c add " + FGUtil.getFullName(controller)), TextActions.showText(Text.of("Add to controller state buffer")), "[c+]")); builder.append(Text.of(TextColors.GRAY, "[c-]")); @@ -283,12 +472,12 @@ public CommandResult process(CommandSource source, String arguments) throws Comm if (selectedHandlers.contains(handler)) { builder.append(Text.of(TextColors.GRAY, "[+]")); builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s h remove " + handler.getName()), + TextActions.runCommand("/foxguard s h remove " + FGUtil.getFullName(handler)), TextActions.showText(Text.of("Remove from state buffer")), "[-]")); } else { builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s h add " + handler.getName()), + TextActions.runCommand("/foxguard s h add " + FGUtil.getFullName(handler)), TextActions.showText(Text.of("Add to state buffer")), "[+]")); builder.append(Text.of(TextColors.GRAY, "[-]")); @@ -297,18 +486,18 @@ public CommandResult process(CommandSource source, String arguments) throws Comm builder.append(Text.of(" ")); } builder.append(Text.of(FGUtil.getColorForObject(handler), - TextActions.runCommand("/foxguard det h " + handler.getName()), + TextActions.runCommand("/foxguard det h " + fullName), TextActions.showText(Text.of("View details")), handler.getShortTypeName() + " : " + handler.getName())); if (handlerIterator.hasNext() && count < number) builder.append(Text.NEW_LINE); } if (maxPage > 1) - builder.append(Text.NEW_LINE).append(FCPUtil.pageFooter(page, maxPage, "/fg ls " + arguments, null)); + builder.append(Text.NEW_LINE).append(FCPUtil.pageFooter(page, maxPage, "/foxguard ls " + arguments, null)); source.sendMessage(builder.build()); //---------------------------------------------------------------------------------------------------------- } else if (isIn(Aliases.CONTROLLERS_ALIASES, parse.args[0])) { - List controllerList = FGManager.getInstance().getControllers().stream().collect(Collectors.toList()); + List controllerList = new ArrayList<>(FGManager.getInstance().getControllers()); if (parse.flags.containsKey("query")) { String query = parse.flags.get("query"); if (query.startsWith("/")) { @@ -364,12 +553,12 @@ public CommandResult process(CommandSource source, String arguments) throws Comm if (selectedHandlers.contains(controller)) { builder.append(Text.of(TextColors.GRAY, "[h+]")); builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s h remove " + controller.getName()), + TextActions.runCommand("/foxguard s h remove " + FGUtil.getFullName(controller)), TextActions.showText(Text.of("Remove from handler state buffer")), "[h-]")); } else { builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s h add " + controller.getName()), + TextActions.runCommand("/foxguard s h add " + FGUtil.getFullName(controller)), TextActions.showText(Text.of("Add to handler state buffer")), "[h+]")); builder.append(Text.of(TextColors.GRAY, "[h-]")); @@ -377,12 +566,12 @@ public CommandResult process(CommandSource source, String arguments) throws Comm if (selectedControllers.contains(controller)) { builder.append(Text.of(TextColors.GRAY, "[c+]")); builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s c remove " + controller.getName()), + TextActions.runCommand("/foxguard s c remove " + FGUtil.getFullName(controller)), TextActions.showText(Text.of("Remove from controller state buffer")), "[c-]")); } else { builder.append(Text.of(TextColors.GREEN, - TextActions.runCommand("/foxguard s c add " + controller.getName()), + TextActions.runCommand("/foxguard s c add " + FGUtil.getFullName(controller)), TextActions.showText(Text.of("Add to controller state buffer")), "[c+]")); builder.append(Text.of(TextColors.GRAY, "[c-]")); @@ -390,21 +579,21 @@ public CommandResult process(CommandSource source, String arguments) throws Comm builder.append(Text.of(" ")); } builder.append(Text.of(FGUtil.getColorForObject(controller), - TextActions.runCommand("/foxguard det h " + controller.getName()), + TextActions.runCommand("/foxguard det h " + FGUtil.getFullName(controller)), TextActions.showText(Text.of("View details")), controller.getShortTypeName() + " : " + controller.getName())); count++; if (controllerIterator.hasNext() && count < number) builder.append(Text.NEW_LINE); } if (maxPage > 1) - builder.append(Text.NEW_LINE).append(FCPUtil.pageFooter(page, maxPage, "/fg ls " + arguments, null)); + builder.append(Text.NEW_LINE).append(FCPUtil.pageFooter(page, maxPage, "/foxguard ls " + arguments, null)); source.sendMessage(builder.build()); } else { throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); } return CommandResult.empty(); - } + }*/ @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { @@ -418,12 +607,12 @@ public List getSuggestions(CommandSource source, String arguments, @Null .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) - return Arrays.asList("regions", "handlers", "controllers").stream() + return Stream.of("regions", "handlers", "controllers") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world").stream() + return Stream.of("world") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandModify.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandModify.java index bed9b09..f73f041 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandModify.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandModify.java @@ -32,17 +32,19 @@ import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.UUIDOwner; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; +import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.command.args.ArgumentParseException; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColor; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.util.GuavaCollectors; import org.spongepowered.api.util.StartsWithPredicate; @@ -50,9 +52,11 @@ import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; -import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; + +import javax.annotation.Nullable; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; @@ -83,89 +87,57 @@ public CommandResult process(CommandSource source, String arguments) throws Comm .append(getUsage(source)) .build()); return CommandResult.empty(); - } else if (isIn(REGIONS_ALIASES, parse.args[0])) { - if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a region name!")); - IRegion region = null; - if (!parse.flags.keySet().contains("world")) - region = FGManager.getInstance().getRegion(parse.args[1]); - if (region == null) { - String worldName = parse.flags.get("world"); - World world = null; - if (source instanceof Locatable) world = ((Locatable) source).getWorld(); - if (!worldName.isEmpty()) { - Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); - if (optWorld.isPresent()) { - world = optWorld.get(); - } else { - if (world == null) - throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); - } - } - if (world == null) throw new CommandException(Text.of("Must specify a world!")); - region = FGManager.getInstance().getWorldRegion(world, parse.args[1]); + } else { + String category = parse.args[0]; + FGCat fgCat = FGCat.from(category); + if (fgCat == null) throw new CommandException(Text.of("\"" + category + "\" is not a valid category!")); + + if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a name!")); + + FGUtil.OwnerResult ownerResult = FGUtil.processUserInput(parse.args[1]); + + IGuardObject object; + switch (fgCat) { + case REGION: + object = FGUtil.getRegionFromCommand(source, ownerResult, parse.flags.containsKey("world"), parse.flags.get("world")); + if (object instanceof IWorldRegion) fgCat = FGCat.WORLDREGION; + break; + case HANDLER: + object = FGUtil.getHandlerFromCommand(ownerResult); + if (object instanceof IController) fgCat = FGCat.CONTROLLER; + break; + default: + throw new CommandException(Text.of("Something went horribly wrong.")); } - if (region == null) - throw new ArgumentParseException(Text.of("No region exists with that name!"), parse.args[1], 1); - ProcessResult result = region.modify(source, parse.args.length < 3 ? "" : parse.args[2]); - Optional messageOptional = result.getMessage(); - if (result.isSuccess()) { - FGUtil.markRegionDirty(region); - if (messageOptional.isPresent()) { - if (!FCPUtil.hasColor(messageOptional.get())) { - source.sendMessage(messageOptional.get().toBuilder().color(TextColors.GREEN).build()); - } else { - source.sendMessage(messageOptional.get()); - } - } else { - source.sendMessage(Text.of(TextColors.GREEN, "Successfully modified region!")); - } + ProcessResult result = object.modify(source, parse.args.length < 3 ? "" : parse.args[2]); + Optional messageOptional = result.getMessage(); + boolean success = result.isSuccess(); + TextColor color; + if (success) { + color = TextColors.GREEN; + FGUtil.markDirty(object); } else { - if (messageOptional.isPresent()) { - if (!FCPUtil.hasColor(messageOptional.get())) { - source.sendMessage(messageOptional.get().toBuilder().color(TextColors.RED).build()); - } else { - source.sendMessage(messageOptional.get()); - } - } else { - source.sendMessage(Text.of(TextColors.RED, "Modification failed for region!")); - } + color = TextColors.RED; } - } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { - if (parse.args.length < 2) throw new CommandException(Text.of("Must specify a handler name!")); - IHandler handler = FGManager.getInstance().gethandler(parse.args[1]); - if (handler == null) - throw new CommandException(Text.of("No handler with name \"" + parse.args[1] + "\"!")); - ProcessResult result = handler.modify(source, parse.args.length < 3 ? "" : parse.args[2]); - Optional messageOptional = result.getMessage(); - if (result.isSuccess()) { - FGUtil.markHandlerDirty(handler); - if (messageOptional.isPresent()) { - if (!FCPUtil.hasColor(messageOptional.get())) { - source.sendMessage(messageOptional.get().toBuilder().color(TextColors.GREEN).build()); - } else { - source.sendMessage(messageOptional.get()); - } + + if (messageOptional.isPresent()) { + if (!FCPUtil.hasColor(messageOptional.get())) { + source.sendMessage(messageOptional.get().toBuilder().color(color).build()); } else { - source.sendMessage(Text.of(TextColors.GREEN, "Successfully modified handler!")); + source.sendMessage(messageOptional.get()); } } else { - if (messageOptional.isPresent()) { - if (!FCPUtil.hasColor(messageOptional.get())) { - source.sendMessage(messageOptional.get().toBuilder().color(TextColors.RED).build()); - } else { - source.sendMessage(messageOptional.get()); - } - } else { - source.sendMessage(Text.of(TextColors.RED, "Modification failed for handler!")); - } + source.sendMessage(Text.of(color, success ? + "Successfully modified " + fgCat.lName + "!" : + "Modification failed for " + fgCat.lName + "!")); } - } else { - throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); + + return CommandResult.empty(); } - return CommandResult.empty(); } + @SuppressWarnings("Duplicates") @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { if (!testPermission(source)) return ImmutableList.of(); @@ -179,13 +151,21 @@ public List getSuggestions(CommandSource source, String arguments, @Null .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) - return ImmutableList.of("region", "handler").stream() + return Stream.of("region", "handler") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); else if (parse.current.index == 1) { + FGUtil.OwnerTabResult result = FGUtil.getOwnerSuggestions(parse.current.token); + if (result.isComplete()) { + return result.getSuggestions().stream() + .map(str -> parse.current.prefix + str) + .collect(GuavaCollectors.toImmutableList()); + } + if (isIn(REGIONS_ALIASES, parse.args[0])) { String worldName = parse.flags.get("world"); + boolean key = parse.flags.containsKey("world"); World world = null; if (source instanceof Locatable) world = ((Locatable) source).getWorld(); if (!worldName.isEmpty()) { @@ -194,29 +174,29 @@ else if (parse.current.index == 1) { world = optWorld.get(); } } - if (world == null) return FGManager.getInstance().getRegions().stream() - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .sorted(String.CASE_INSENSITIVE_ORDER) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); - return FGManager.getInstance().getAllRegions(world).stream() - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .sorted(String.CASE_INSENSITIVE_ORDER) - .map(args -> parse.current.prefix + args) - .collect(GuavaCollectors.toImmutableList()); + if (key && world != null) { + return FGManager.getInstance().getAllRegions(world, new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } else { + return FGManager.getInstance().getAllRegionsWithUniqueNames(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner()), world).stream() + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) + .collect(GuavaCollectors.toImmutableList()); + } } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { - return FGManager.getInstance().getHandlers().stream() - .map(IFGObject::getName) - .filter(new StartsWithPredicate(parse.current.token)) - .sorted(String.CASE_INSENSITIVE_ORDER) - .map(args -> parse.current.prefix + args) + return FGManager.getInstance().getHandlers(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() + .map(IGuardObject::getName) + .filter(new StartsWithPredicate(result.getToken())) + .map(args -> parse.current.prefix + result.getPrefix() + args) .collect(GuavaCollectors.toImmutableList()); } } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world").stream() + return Stream.of("world") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -229,7 +209,7 @@ else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGF .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.FINAL)) { if (isIn(REGIONS_ALIASES, parse.args[0])) { - IRegion region = FGManager.getInstance().getRegion(parse.args[1]); + IRegion region = FGManager.getInstance().getRegion(parse.args[1]).orElse(null); if (region == null) { String worldName = parse.flags.get("world"); World world = null; @@ -241,7 +221,7 @@ else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGF } else return ImmutableList.of(); } if (world == null) return ImmutableList.of(); - region = FGManager.getInstance().getWorldRegion(world, parse.args[1]); + region = FGManager.getInstance().getWorldRegion(world, parse.args[1]).orElse(null); } if (region == null) return ImmutableList.of(); @@ -252,9 +232,9 @@ else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGF .collect(GuavaCollectors.toImmutableList()); } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { if (parse.args.length < 2) return ImmutableList.of(); - IHandler handler = FGManager.getInstance().gethandler(parse.args[1]); - if (handler == null) return ImmutableList.of(); - List suggestions = handler.modifySuggestions(source, parse.current.token, null); + Optional handlerOpt = FGManager.getInstance().getHandler(parse.args[1]); + if (!handlerOpt.isPresent()) return ImmutableList.of(); + List suggestions = handlerOpt.get().modifySuggestions(source, parse.current.token, null); if (suggestions == null) return ImmutableList.of(); return suggestions.stream() .map(args -> parse.current.prefix + args) @@ -284,4 +264,26 @@ public Optional getHelp(CommandSource source) { public Text getUsage(CommandSource source) { return Text.of("modify ] | handler> [args...]"); } + + private enum FGCat { + REGION(REGIONS_ALIASES), + WORLDREGION(null), + HANDLER(HANDLERS_ALIASES), + CONTROLLER(null); + + public final String[] catAliases; + public final String lName = name().toLowerCase(); + + FGCat(String[] catAliases) { + this.catAliases = catAliases; + + } + + public static FGCat from(String category) { + for (FGCat cat : values()) { + if (isIn(cat.catAliases, category)) return cat; + } + return null; + } + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandRename.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandMove.java similarity index 91% rename from src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandRename.java rename to src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandMove.java index efb5fff..3589437 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandRename.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandMove.java @@ -32,7 +32,7 @@ import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.handler.GlobalHandler; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.GlobalWorldRegion; @@ -42,7 +42,6 @@ import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.command.args.ArgumentParseException; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.util.GuavaCollectors; @@ -55,10 +54,11 @@ import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; -public class CommandRename extends FCCommandBase { +public class CommandMove extends FCCommandBase { private static final FlagMapper MAPPER = map -> key -> value -> { map.put(key, value); @@ -74,7 +74,11 @@ public CommandResult process(CommandSource source, String arguments) throws Comm source.sendMessage(Text.of(TextColors.RED, "You don't have permission to use this command!")); return CommandResult.empty(); } - AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).flagMapper(MAPPER).parse(); + AdvCmdParser.ParseResult parse = AdvCmdParser.builder() + .arguments(arguments) + .flagMapper(MAPPER) + .parse(); + if (parse.args.length == 0) { source.sendMessage(Text.builder() .append(Text.of(TextColors.GREEN, "Usage: ")) @@ -86,7 +90,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm IRegion region = null; World world = null; if (!parse.flags.keySet().contains("world")) - region = FGManager.getInstance().getRegion(parse.args[1]); + region = FGManager.getInstance().getRegion(parse.args[1]).orElse(null); if (region == null) { String worldName = parse.flags.get("world"); if (source instanceof Locatable) world = ((Locatable) source).getWorld(); @@ -100,7 +104,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm } } if (world == null) throw new CommandException(Text.of("Must specify a world!")); - region = FGManager.getInstance().getWorldRegion(world, parse.args[1]); + region = FGManager.getInstance().getWorldRegion(world, parse.args[1]).orElse(null); } if (region == null) throw new CommandException(Text.of("No region exists with the name \"" + parse.args[1] + "\"!")); @@ -122,13 +126,14 @@ public CommandResult process(CommandSource source, String arguments) throws Comm throw new CommandException(Text.of("There is already a region with the name \"" + parse.args[2] + "\"!")); } String oldName = region.getName(); - FGManager.getInstance().rename(region, parse.args[2]); + FGManager.getInstance().move(region, parse.args[2], null, null); source.sendMessage(Text.of(TextColors.GREEN, "Region \"" + oldName + "\" successfully renamed to \"" + parse.args[2] + "\"!")); } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { if (parse.args.length < 2) throw new CommandException(Text.of("You must specify a name!")); - IHandler handler = FGManager.getInstance().gethandler(parse.args[1]); - if (handler == null) + Optional handlerOpt = FGManager.getInstance().getHandler(parse.args[1]); + if (!handlerOpt.isPresent()) throw new CommandException(Text.of("No handler exists with the name \"" + parse.args[1] + "\"!")); + IHandler handler = handlerOpt.get(); if (handler instanceof GlobalHandler) { throw new CommandException(Text.of("You may not rename the global handler!")); } @@ -139,10 +144,10 @@ public CommandResult process(CommandSource source, String arguments) throws Comm throw new ArgumentParseException(Text.of("New name (\"" + parse.args[2] + "\") can't start with a number!"), parse.args[2], 1); if (handler.getName().equalsIgnoreCase(parse.args[2])) throw new CommandException(Text.of("You cannot rename a handler to its own name.")); - if (FGManager.getInstance().gethandler(parse.args[2]) != null) + if (FGManager.getInstance().getHandler(parse.args[2]).isPresent()) throw new CommandException(Text.of("There is already a handler with the name \"" + parse.args[2] + "\"!")); String oldName = handler.getName(); - FGManager.getInstance().rename(handler, parse.args[2]); + FGManager.getInstance().move(handler, parse.args[2], null, null); source.sendMessage(Text.of(TextColors.GREEN, "Handler \"" + oldName + "\" successfully renamed to \"" + parse.args[2] + "\"!")); } else throw new ArgumentParseException(Text.of("Not a valid category!"), parse.args[0], 0); return CommandResult.empty(); @@ -153,14 +158,13 @@ public List getSuggestions(CommandSource source, String arguments, @Null if (!testPermission(source)) return ImmutableList.of(); AdvCmdParser.ParseResult parse = AdvCmdParser.builder() .arguments(arguments) - .limit(2) .flagMapper(MAPPER) .excludeCurrent(true) .autoCloseQuotes(true) .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) - return ImmutableList.of("region", "handler").stream() + return Stream.of("region", "handler") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -177,20 +181,20 @@ else if (parse.current.index == 1) { } if (world == null) return FGManager.getInstance().getRegions().stream() .filter(region -> !(region instanceof GlobalWorldRegion)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); return FGManager.getInstance().getAllRegions(world).stream() .filter(region -> !(region instanceof GlobalWorldRegion)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (isIn(HANDLERS_ALIASES, parse.args[0])) { return FGManager.getInstance().getHandlers().stream() .filter(region -> !(region instanceof GlobalHandler)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -199,7 +203,7 @@ else if (parse.current.index == 1) { Tristate available = null; if (isIn(REGIONS_ALIASES, parse.args[0]) || isIn(WORLDREGIONS_ALIASES, parse.args[0])) { World world = null; - IRegion region = FGManager.getInstance().getRegion(parse.args[1]); + IRegion region = FGManager.getInstance().getRegion(parse.args[1]).orElse(null); if (region == null) { String worldName = parse.flags.get("world"); if (source instanceof Locatable) world = ((Locatable) source).getWorld(); @@ -210,7 +214,7 @@ else if (parse.current.index == 1) { } } if (world == null) return ImmutableList.of(); - region = FGManager.getInstance().getWorldRegion(world, parse.args[1]); + region = FGManager.getInstance().getWorldRegion(world, parse.args[1]).orElse(null); } if (region == null || region instanceof IGlobal) return ImmutableList.of(); if (region instanceof IWorldRegion) { @@ -219,7 +223,8 @@ else if (parse.current.index == 1) { available = Tristate.fromBoolean(FGManager.getInstance().isRegionNameAvailable(parse.current.token)); } } else if (isIn(HANDLERS_ALIASES, parse.args[0]) || isIn(CONTROLLERS_ALIASES, parse.args[0])) { - available = Tristate.fromBoolean(FGManager.getInstance().gethandler(parse.current.token) == null); + available = Tristate.fromBoolean(!FGManager.getInstance().getHandler(parse.current.token).isPresent()); + System.out.println("asdjfkasdkfjasdlfj"); } if (available != null) { switch (available) { @@ -236,7 +241,7 @@ else if (parse.current.index == 1) { } } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world").stream() + return Stream.of("world") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandPriority.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandPriority.java index 0320d3e..f4085b9 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandPriority.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandPriority.java @@ -31,8 +31,9 @@ import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.handler.GlobalHandler; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.UUIDOwner; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; @@ -72,17 +73,18 @@ public CommandResult process(CommandSource source, String arguments) throws Comm int successes = 0; int failures = 0; List handlers = new ArrayList<>(); - FGUtil.getSelectedHandlers(source).forEach(handlers::add); + handlers.addAll(FGUtil.getSelectedHandlers(source)); PriorityMachine machine = null; for (String arg : parse.args) { try { PriorityMachine temp = new PriorityMachine(arg); if (machine == null) machine = temp; } catch (NumberFormatException ignored) { - IHandler handler = FGManager.getInstance().gethandler(arg); - if (handler != null && !handlers.contains(handler)) { + try { + FGUtil.OwnerResult ownerResult = FGUtil.processUserInput(arg); + IHandler handler = FGUtil.getHandlerFromCommand(ownerResult); handlers.add(handler); - } else { + } catch (CommandException ignored2) { failures++; } } @@ -113,13 +115,20 @@ public List getSuggestions(CommandSource source, String arguments, @Null .autoCloseQuotes(true) .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { + FGUtil.OwnerTabResult result = FGUtil.getOwnerSuggestions(parse.current.token); + if (result.isComplete()) { + return result.getSuggestions().stream() + .map(str -> parse.current.prefix + str) + .collect(GuavaCollectors.toImmutableList()); + } + List selected = ImmutableList.copyOf(FGUtil.getSelectedHandlers(source)); - return FGManager.getInstance().getHandlers().stream() + return FGManager.getInstance().getHandlers(new UUIDOwner(UUIDOwner.USER_GROUP, result.getOwner())).stream() .filter(handler -> !selected.contains(handler) && !(handler instanceof IGlobal)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .filter(alias -> !isIn(parse.args, alias)) - .map(args -> parse.current.prefix + args) + .map(args -> parse.current.prefix + result.getPrefix() + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.COMPLETE)) return ImmutableList.of(parse.current.prefix + " "); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandSave.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandSave.java index cbe8d7c..f5561ed 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandSave.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandSave.java @@ -29,8 +29,10 @@ import net.foxdenstudio.sponge.foxcore.plugin.command.FCCommandBase; import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; import net.foxdenstudio.sponge.foxcore.plugin.command.util.FlagMapper; -import net.foxdenstudio.sponge.foxguard.plugin.FGStorageManager; +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGStorageManagerNew; +import org.slf4j.Logger; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; @@ -40,10 +42,11 @@ import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; -import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import javax.annotation.Nullable; + import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.FORCE_ALIASES; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.isIn; @@ -69,9 +72,27 @@ public CommandResult process(CommandSource source, String arguments) throws Comm boolean force = parse.flags.containsKey("force"); FoxGuardMain.instance().getLogger().info(force ? "Force saving objects" : "Saving objects"); - FGStorageManager.getInstance().saveRegions(force); - Sponge.getServer().getWorlds().forEach(world -> FGStorageManager.getInstance().saveWorldRegions(world, force)); - FGStorageManager.getInstance().saveHandlers(force); + //FGStorageManager.getInstance().saveRegions(force); + //Sponge.getServer().getWorlds().forEach(world -> FGStorageManager.getInstance().saveWorldRegions(world, force)); + //FGStorageManager.getInstance().saveHandlers(force); + + Logger logger = FoxGuardMain.instance().getLogger(); + + FGStorageManagerNew storage = FGStorageManagerNew.getInstance(); + storage.saveRegionIndex(); + Sponge.getServer().getWorlds().forEach(storage::saveWorldRegionIndex); + storage.saveHandlerIndex(); + + FGManager manager = FGManager.getInstance(); + logger.info("Saving regions"); + storage.saveObjects(manager.getRegions(), force); + Sponge.getServer().getWorlds().forEach(world -> { + logger.info("Saving worldregions for world: " + world.getName()); + storage.saveObjects(manager.getWorldRegions(world), force); + }); + logger.info("Saving handlers"); + storage.saveObjects(manager.getHandlers(), force); + source.sendMessage(Text.of(TextColors.GREEN, "Successfully saved!")); return CommandResult.success(); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandTest.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandTest.java index a5885a7..5b52c0d 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandTest.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandTest.java @@ -26,20 +26,36 @@ package net.foxdenstudio.sponge.foxguard.plugin.command; +import com.flowpowered.math.vector.Vector2i; import com.google.common.collect.ImmutableList; import net.foxdenstudio.sponge.foxcore.plugin.command.FCCommandBase; +import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; +import net.foxdenstudio.sponge.foxcore.plugin.command.util.FlagMapper; +import net.foxdenstudio.sponge.foxcore.plugin.util.BoundingBox2; +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.FoxPath; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; +import net.foxdenstudio.sponge.foxguard.plugin.region.world.RectangularRegion; +import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.world.Locatable; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; -import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import javax.annotation.Nullable; + +import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.WORLD_ALIASES; +import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.isIn; + public class CommandTest extends FCCommandBase { /* @@ -115,20 +131,90 @@ public Text getUsage(CommandSource source) { return Text.of("test [mystery args]..."); } + private static final FlagMapper MAPPER = map -> key -> value -> { + map.put(key, value); + if (isIn(WORLD_ALIASES, key) && !map.containsKey("world")) { + map.put("world", value); + } + return true; + }; + @Override public CommandResult process(CommandSource source, String arguments) throws CommandException { + +// Optional ownerOpt = FoxPath.getOwner(arguments, source); +// +// source.sendMessage(Text.of(ownerOpt)); + + + + return CommandResult.empty(); + } + + /*@Override + public CommandResult process(CommandSource source, String arguments) throws CommandException { if (!testPermission(source)) { source.sendMessage(Text.of(TextColors.RED, "You don't have permission to use this " + "command!")); return CommandResult.empty(); } - return CommandResult.empty(); - } + + AdvCmdParser.ParseResult parse = AdvCmdParser.builder() + .arguments(arguments) + .flagMapper(MAPPER) + .parse(); + + String worldName = parse.flags.get("world"); + World world = null; + + if (source instanceof Locatable) world = ((Locatable) source).getWorld(); + if (!worldName.isEmpty()) { + Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); + if (optWorld.isPresent()) { + world = optWorld.get(); + } else { + if (world == null) + throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); + } + } + if (world == null) throw new CommandException(Text.of("Must specify a world!")); + + if (parse.args.length == 0) return CommandResult.empty(); + int amount; + try { + amount = Integer.parseInt(parse.args[0]); + } catch (NumberFormatException e) { + return CommandResult.empty(); + } + int counter = 1; + String name; + if (parse.args.length > 1) { + name = parse.args[1]; + } else name = "region"; + + FGManager manager = FGManager.getInstance(); + + for (int i = 1; i <= amount; ) { + String numberName = name + counter; + if (manager.isWorldRegionNameAvailable(numberName, world)) { + FGObjectData data = new FGObjectData(); + data.setName(numberName); + IWorldRegion region = new RectangularRegion(data, new BoundingBox2(new Vector2i(-i, -i), new Vector2i(i, i))); + manager.addWorldRegion(region, world); + i++; + } + counter++; + } + + source.sendMessage(Text.of(TextColors.GREEN, "Successfully created " + amount + " regions!")); + return CommandResult.success(); + }*/ @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { - return ImmutableList.of(); + Thread.dumpStack(); + return ImmutableList.of("b", "c", "a", "d"); } /*@Override diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandUnlink.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandUnlink.java index 8afe867..f2f59b0 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandUnlink.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/CommandUnlink.java @@ -81,7 +81,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm FGUtil.getSelectedRegions(source).forEach( region -> { List handlers = new ArrayList<>(); - region.getHandlers().stream() + region.getLinks().stream() .filter(handler -> !(handler instanceof GlobalHandler)) .forEach(handlers::add); handlers.forEach(handler -> count[0] += FGManager.getInstance().unlink(region, handler) ? 1 : 0); @@ -98,7 +98,7 @@ public CommandResult process(CommandSource source, String arguments) throws Comm FGManager.getInstance().getAllRegions().forEach( region -> { List handlers = new ArrayList<>(); - region.getHandlers().stream() + region.getLinks().stream() .filter(handler -> !(handler instanceof GlobalHandler)) .forEach(handlers::add); handlers.stream().forEach(handler -> count[0] += FGManager.getInstance().unlink(region, handler) ? 1 : 0); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/link/IExpression.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/link/IExpression.java index 48da4a4..883aa9f 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/link/IExpression.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/link/IExpression.java @@ -25,7 +25,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.command.link; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import java.util.Set; @@ -34,7 +34,7 @@ */ public interface IExpression { - Set getValue(); + Set getValue(); Set getLinks(); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/link/LinkageParser.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/link/LinkageParser.java index a486f94..1f60b94 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/link/LinkageParser.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/command/link/LinkageParser.java @@ -32,14 +32,13 @@ import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.ILinkable; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.util.StartsWithPredicate; import org.spongepowered.api.world.Locatable; @@ -49,6 +48,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Created by Fox on 4/19/2016. @@ -60,6 +60,12 @@ public final class LinkageParser { private World currentWorld; + private LinkageParser(CommandSource source) { + if (source instanceof Locatable) { + currentWorld = ((Locatable) source).getWorld(); + } + } + public static Set parseLinkageExpression(String expression, CommandSource source) throws CommandException { return new LinkageParser(source).parse(expression, source); } @@ -92,19 +98,19 @@ else if (match.startsWith("%")) { } else if (expressionString.endsWith(" ")) { if (stage == Stage.START) { return FGManager.getInstance().getAllRegions(world).stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .sorted() .collect(Collectors.toList()); } else { return FGManager.getInstance().getHandlers().stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .sorted() .collect(Collectors.toList()); } } else if (expressionString.endsWith(token)) { if (token.startsWith("^")) { return FGManager.getInstance().getControllers().stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(token.substring(1))) .sorted() .map(str -> endPart + str.substring(token.length() - 1)) @@ -116,21 +122,21 @@ else if (match.startsWith("%")) { .map(str -> endPart + str.substring(token.length() - 1)) .collect(Collectors.toList()); } else if (token.startsWith("$")) { - return ImmutableList.of("regions", "handlers", "controllers").stream() + return Stream.of("regions", "handlers", "controllers") .filter(new StartsWithPredicate(token.substring(1))) .map(str -> endPart + str.substring(token.length() - 1)) .collect(Collectors.toList()); } else { if (stage == Stage.START) { return FGManager.getInstance().getAllRegions(world).stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(token)) .sorted() .map(str -> endPart + str.substring(token.length())) .collect(Collectors.toList()); } else { return FGManager.getInstance().getHandlers().stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(token)) .sorted() .map(str -> endPart + str.substring(token.length())) @@ -140,17 +146,27 @@ else if (match.startsWith("%")) { } } else { return FGManager.getInstance().getAllRegions(world).stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .sorted() .collect(Collectors.toList()); } return ImmutableList.of(); } - private LinkageParser(CommandSource source) { - if (source instanceof Locatable) { - currentWorld = ((Locatable) source).getWorld(); + private static boolean checkParentheses(String expression) { + Pattern leftPattern = Pattern.compile("\\("); + Matcher leftMatcher = leftPattern.matcher(expression); + int leftCount = 0; + while (leftMatcher.find()) { + leftCount++; } + Pattern rightPattern = Pattern.compile("\\)"); + Matcher rightMatcher = rightPattern.matcher(expression); + int rightCount = 0; + while (rightMatcher.find()) { + rightCount++; + } + return leftCount == rightCount; } private Set parse(String expressionString, CommandSource source) throws CommandException { @@ -166,20 +182,8 @@ private Set parse(String expressionString, CommandSource source) thro return ImmutableSet.copyOf(set); } - private static boolean checkParentheses(String expression) { - Pattern leftPattern = Pattern.compile("\\("); - Matcher leftMatcher = leftPattern.matcher(expression); - int leftCount = 0; - while (leftMatcher.find()) { - leftCount++; - } - Pattern rightPattern = Pattern.compile("\\)"); - Matcher rightMatcher = rightPattern.matcher(expression); - int rightCount = 0; - while (rightMatcher.find()) { - rightCount++; - } - return leftCount == rightCount; + private enum Stage { + START, REST } public class Expression implements IExpression { @@ -206,7 +210,7 @@ else if (matcher.group().equals(">") && parentheses == 0) { private Set parseSegment(String segmentString, CommandSource source) { Set set = new LinkedHashSet<>(); - Set stubObjects = new LinkedHashSet<>(); + Set stubObjects = new LinkedHashSet<>(); Matcher matcher = PATTERN.matcher(segmentString); while (matcher.find()) { if (matcher.group().equals("(")) { @@ -222,7 +226,7 @@ private Set parseSegment(String segmentString, CommandSource source if (!token.startsWith("-")) { if (token.startsWith("%")) { Optional worldOptional = Sponge.getServer().getWorld(token.substring(1)); - if (worldOptional.isPresent()) currentWorld = worldOptional.get(); + worldOptional.ifPresent(world -> currentWorld = world); } else if (token.startsWith("$")) { String name = token.substring(1); if (Aliases.isIn(Aliases.REGIONS_ALIASES, name)) { @@ -233,14 +237,26 @@ private Set parseSegment(String segmentString, CommandSource source set.add(new ExpressionStub(ImmutableSet.copyOf(FGUtil.getSelectedControllers(source)))); } } else if (token.startsWith("^")) { - IController controller = FGManager.getInstance().getController(token.substring(1)); - if (controller != null) stubObjects.add(controller); + try { + FGUtil.OwnerResult ownerResult = FGUtil.processUserInput(token.substring(1)); + Optional controllerOpt = FGManager.getInstance().getController(ownerResult.getName(), ownerResult.getOwner()); + controllerOpt.ifPresent(stubObjects::add); + } catch (CommandException ignored) { + } } else if (stage == Stage.START) { - IRegion region = FGManager.getInstance().getRegionFromWorld(currentWorld, token); - if (region != null) stubObjects.add(region); + try { + FGUtil.OwnerResult ownerResult = FGUtil.processUserInput(token); + Optional regionOpt = FGManager.getInstance().getRegionFromWorld(currentWorld, ownerResult.getName(), ownerResult.getOwner()); + regionOpt.ifPresent(stubObjects::add); + } catch (CommandException ignored) { + } } else { - IHandler handler = FGManager.getInstance().gethandler(token); - if (handler != null) stubObjects.add(handler); + try { + FGUtil.OwnerResult ownerResult = FGUtil.processUserInput(token); + Optional handlerOpt = FGManager.getInstance().getHandler(ownerResult.getName(), ownerResult.getOwner()); + handlerOpt.ifPresent(stubObjects::add); + } catch (CommandException ignored) { + } } } } @@ -250,9 +266,9 @@ private Set parseSegment(String segmentString, CommandSource source } @Override - public Set getValue() { + public Set getValue() { if (contents.size() > 0) { - Set set = new LinkedHashSet<>(); + Set set = new LinkedHashSet<>(); for (IExpression expression : contents.get(0)) { set.addAll(expression.getValue()); } @@ -304,13 +320,13 @@ public class Result { public class ExpressionStub implements IExpression { - Set set; + Set set; - public ExpressionStub(Set set) { + public ExpressionStub(Set set) { this.set = set; } - public Set getValue() { + public Set getValue() { return set; } @@ -320,8 +336,4 @@ public Set getLinks() { } } - - private enum Stage { - START, REST - } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/compat/djxy/pm/FGCompat.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/compat/djxy/pm/FGCompat.java index c0ae8b8..6a94b39 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/compat/djxy/pm/FGCompat.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/compat/djxy/pm/FGCompat.java @@ -30,6 +30,8 @@ import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.world.World; +import java.util.Optional; + /** * Created by Fox on 8/21/2016. */ @@ -37,8 +39,8 @@ public class FGCompat { public static boolean isPlayerInRegion(Player player, String regionName) { World world = player.getWorld(); - IRegion region = FGManager.getInstance().getRegionFromWorld(world, regionName); - return region != null && region.contains(player.getLocation().getPosition(), world); + Optional regionOpt = FGManager.getInstance().getRegionFromWorld(world, regionName); + return regionOpt.isPresent() && regionOpt.get().contains(player.getLocation().getPosition(), world); } public static int getCompatVersion() { diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/config/FGConfigManager.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/config/FGConfigManager.java index e700dda..e47e9ee 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/config/FGConfigManager.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/config/FGConfigManager.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.EnumMap; import java.util.Map; @@ -41,12 +42,34 @@ public final class FGConfigManager { private static FGConfigManager instance; - private boolean cleanupFiles = true; - private boolean saveInWorldFolder = true; - private boolean saveWorldRegionsInWorldFolders = true; - private boolean useConfigFolder = false; - private int nameLengthLimit = 24; + // general + private int nameLengthLimit; + // storage + private boolean gcAndFinalize; + + // storage/cleanup + private boolean cleanOnDelete; + private boolean cleanOnError; + + // storage/json + private boolean prettyPrint; + private int prettyPrintIndent; + + // storage/location + private boolean saveInWorldDirectory; + private boolean saveWorldRegionsInWorldDirectories; + private boolean ownerFirst; + private boolean useConfigDirectory; + private boolean useCustomDirectory; + private Path customDirectory; + + // storage/database + private boolean lockDatabaseFiles; + private boolean useMMappedFiles; + private boolean gcCleanerHack; + + // modules private Map modules = new EnumMap<>(ListenerModule.class); private FGConfigManager() { @@ -77,34 +100,110 @@ public void save() { } //-------------------------------------------------------------------------------------------------------------- - root.getNode("storage", "cleanupFiles").setComment("Sets whether to aggressively delete files that are no longer used. Default: true\n" + - "This is meant to keep the file store clean and free of clutter. It also improves load times.\n" + - "The caveat is that objects that fail to load are deleted without warning. This normally isn't an issue, even in server crashes.\n" + - "However, modifying databases and moving the files around can trigger the cleanup.\n" + - "If force loading is off or the plugin simply fails to load the database, it would just be discarded.\n" + - "Setting this option to false will prevent databases from being deleted.\n" + - "However, they will still be overwritten if a new database is made with the same name.") - .setValue(cleanupFiles); - - root.getNode("storage", "saveInWorldFolder").setComment("Whether or not FoxGuard should save object information in the world folder.\n" + - "This includes super-regions, handlers, and controllers, but does not include world-regions.") - .setValue(saveInWorldFolder); - - root.getNode("storage", "saveWorldRegionsInWorldFolders").setComment("Whether or not FoxGuard should save world-region information in the world folder.\n" + - "In this case, the files are kept with their corresponding world/dimension.\n" + - "This makes it easier to copy and paste world data without causing de-synchronization between the world data and FoxGuard data.") - .setValue(saveWorldRegionsInWorldFolders); - root.getNode("storage", "useConfigFolder").setComment("Whether or not to place the foxguard folder inside the config folder.\n" + - "Only applies if files are not kept inside the world folder.") - .setValue(useConfigFolder); - root.getNode("general", "nameLengthLimit").setComment("The length limit for object names. Use 0 or lower for no limit.\n" + - "Extremely long names can cause a variety of unfixable issues. You have been warned.") - .setValue(nameLengthLimit); + // general + root.getNode("general", "nameLengthLimit") + .setValue(nameLengthLimit) + .setComment("The length limit for object names. Use 0 or lower for no limit.\n" + + "Extremely long names can cause a variety of un-fixable issues. You have been warned."); + + // storage + root.getNode("storage", "gcAndFinalize") + .setValue(gcAndFinalize) + .setComment("Whether to run try running gc and finalization when deleting things.\n" + + "This may drastically slow down the deletion of objects.\n" + + "Use only if you are having trouble deleting things from in game.\n" + + "This really only makes a difference on Windows, so you can leave this alone on Unix based operating systems."); + + // storage/cleanup + root.getNode("storage", "cleanup", "cleanOnDelete") + .setValue(cleanOnDelete) + .setComment("Sets whether to delete object files when objects are deleted. Default: true\n" + + "This is meant to keep the file store clean and free of clutter.\n" + + "If set to false, files will be left intact when deleting objects.\n" + + "However if a new object is made with the same name, the files will be deleted to make space."); + + root.getNode("storage", "cleanup", "cleanOnError") + .setValue(cleanOnError) + .setComment("Sets whether to delete object files if they fail to load. Default: false\n" + + "This is also meant to keep the file store clean and free of clutter.\n" + + "However it is usually left off because it may be undesirable to delete files if they are still recoverable."); + + // storage/json + root.getNode("storage", "json", "prettyPrint") + .setValue(prettyPrint) + .setComment("Enables formatted json in .foxcf files when set to true. Otherwise leaves json minified when set to false." + + "Default: false"); + + root.getNode("storage", "json", "prettyPrintIndent") + .setValue(prettyPrintIndent) + .setComment("Sets the indent for pretty printing when applicable." + + "Default: 4"); + + // storage/location + root.getNode("storage", "location") + .setComment("These options control where FoxGuard objects are stored.\n" + + "BE WARNED that changing these settings will not automatically move files to a new location.\n" + + "YOU MUST do that move yourself. It is advised that you do the move at the same time you change these settings."); + + root.getNode("storage", "location", "saveInWorldDirectory") + .setValue(saveInWorldDirectory) + .setComment("Whether or not FoxGuard should save object information in the world directory. Default: true\n" + + "This includes super-regions, handlers, and controllers, but does not include world-regions.\n" + + "If set to false, files will be placed in a directory in the server root directory."); + + root.getNode("storage", "location", "saveWorldRegionsInWorldDirectories") + .setValue(saveWorldRegionsInWorldDirectories) + .setComment("Whether or not FoxGuard should save world-region information in the world directory. Default: true\n" + + "In this case, the files are kept with their corresponding world/dimension.\n" + + "This makes it easier to copy and paste world data without causing de-synchronization between the world data and FoxGuard data."); + root.getNode("storage", "location", "ownerFirst") + .setValue(ownerFirst) + .setComment("Whether to sort by owners first and then category. Default: true\n" + + "When set to true, object will be stored like \"foxguard/owners/uuid/handlers/myhandler\".\n" + + "When set to false, objects will instead be stored like \"foxguard/handlers/owners/uuid/myhandler\".\n" + + "This does not affect objects without an owner, which are still stored like \"foxguard/handlers/myhandler\"."); + + root.getNode("storage", "location", "useConfigDirectory") + .setValue(useConfigDirectory) + .setComment("Whether or not to place the foxguard directory inside the config directory. Default: false\n" + + "Only applies if files are not kept inside the world directory."); + + root.getNode("storage", "location", "useCustomDirectory") + .setValue(useCustomDirectory) + .setComment("Whether or not to set the foxguard directory to a custom path. Default false:\n" + + "Only applies if files are not kept inside the world folder.\n" + + "This setting overrides the other location settings.\n" + + "The working directory is the saves directory, which is the root directory on a Minecraft server."); + + root.getNode("storage", "location", "customDirectory") + .setValue(customDirectory.normalize().toString()) + .setComment("The custom foxguard directory path."); + + // storage/database + root.getNode("storage", "database", "lockDatabaseFiles") + .setValue(lockDatabaseFiles) + .setComment("Whether to put a lock on database files while accessing them.\n" + + "Locking is known to cause Java to hang on Unix based operating systems running on a NFS (Networked File System) that does not properly support locking.\n" + + "This is often the case if you are using a server host, so be very cautious.\n" + + "If your server hangs and crashes from the Minecraft watchdog, try setting this to false."); + root.getNode("storage", "database", "useMMappedFiles") + .setValue(useMMappedFiles) + .setComment("Whether to enable memory mapping for database files.\n" + + "This has the potential to greatly speed up saving and loading from database files." + + "This is known to cause some issues on Windows.\n" + + "This may be correctable with gcCleanerHack."); + root.getNode("storage", "database", "gcCleanerHack") + .setValue(gcCleanerHack) + .setComment("Whether to enable MapDB's gcCleanerHack functionality.\n" + + "This is meant for fixing issues with databases being un-deletable on Windows when memory mapping is enabled.\n" + + "This only makes a difference if memory mapping is enabled, and can potentially decrease performance."); + + // modules for (ListenerModule m : ListenerModule.values()) { CommentedConfigurationNode node = root.getNode("module", m.getName()).setValue(this.modules.get(m)); String comment = m.getComment(); - if(comment != null) node.setComment(comment); + if (comment != null) node.setComment(comment); } @@ -133,44 +232,122 @@ private void load() { } //-------------------------------------------------------------------------------------------------------------- - cleanupFiles = root.getNode("storage", "cleanupFiles").getBoolean(true); - saveInWorldFolder = root.getNode("storage", "saveInWorldFolder").getBoolean(true); - saveWorldRegionsInWorldFolders = root.getNode("storage", "saveWorldRegionsInWorldFolders").getBoolean(true); - useConfigFolder = root.getNode("storage", "useConfigFolder").getBoolean(false); + // general nameLengthLimit = root.getNode("general", "nameLengthLimit").getInt(24); + + // storage + gcAndFinalize = root.getNode("storage", "gcAndFinalize").getBoolean(false); + + // storage/cleaup + cleanOnDelete = root.getNode("storage", "cleanup", "cleanOnDelete").getBoolean(true); + cleanOnError = root.getNode("storage", "cleanup", "cleanOnError").getBoolean(false); + + // storage/json + prettyPrint = root.getNode("storage", "json", "prettyPrint").getBoolean(false); + prettyPrintIndent = root.getNode("storage", "json", "prettyPrintIndent").getInt(4); + + // storage/location + saveInWorldDirectory = root.getNode("storage", "location", "saveInWorldDirectory").getBoolean(true); + saveWorldRegionsInWorldDirectories = root.getNode("storage", "location", "saveWorldRegionsInWorldDirectories").getBoolean(true); + ownerFirst = root.getNode("storage", "location", "ownerFirst").getBoolean(true); + useConfigDirectory = root.getNode("storage", "location", "useConfigDirectory").getBoolean(false); + useCustomDirectory = root.getNode("storage", "location", "useCustomDirectory").getBoolean(false); + customDirectory = root.getNode("storage", "location", "customDirectory").getValue(o -> { + Path path = null; + if (o instanceof Path) path = (Path) o; + else if (o instanceof String) path = Paths.get((String) o); + if (path == null) return null; + if (Files.notExists(path) || Files.isDirectory(path)) return path.normalize(); + else return null; + }, Paths.get("foxguard")); + + // storage/database + lockDatabaseFiles = root.getNode("storage", "database", "lockDatabaseFiles").getBoolean(false); + useMMappedFiles = root.getNode("storage", "database", "useMMappedFiles").getBoolean(false); + gcCleanerHack = root.getNode("storage", "database", "gcCleanerHack").getBoolean(false); + + // modules for (ListenerModule m : ListenerModule.values()) { this.modules.put(m, root.getNode("module", m.getName()).getString(m.getDefaultValue())); } //-------------------------------------------------------------------------------------------------------------- + + //Path path = Sponge.getGame().getSavesDirectory(); } + // general + public int getNameLengthLimit() { + return nameLengthLimit; + } + + // storage + public boolean gcAndFinalize() { + return gcAndFinalize; + } + + // storage/cleanup + public boolean cleanOnDelete() { + return cleanOnDelete; + } + + public boolean cleanOnError() { + return cleanOnError; + } + + + // storage/json + public boolean prettyPrint() { + return prettyPrint; + } - public boolean cleanupFiles() { - return cleanupFiles; + public int prettyPrintIndent() { + return prettyPrintIndent; } - public boolean saveInWorldFolder() { - return saveInWorldFolder; + // storage/location + public boolean saveInWorldDirectory() { + return saveInWorldDirectory; } - public boolean saveWorldRegionsInWorldFolders() { - return saveWorldRegionsInWorldFolders; + public boolean saveWorldRegionsInWorldDirectories() { + return saveWorldRegionsInWorldDirectories; + } + + public boolean ownerFirst() { + return ownerFirst; } public boolean useConfigFolder() { - return useConfigFolder; + return useConfigDirectory; } - public int getNameLengthLimit() { - return nameLengthLimit; + public boolean useCustomDirectory() { + return useCustomDirectory; + } + + public Path customDirectory() { + return customDirectory; + } + + // storage/database + public boolean lockDatabaseFiles() { + return lockDatabaseFiles; + } + + public boolean useMMappedFiles() { + return useMMappedFiles; + } + + public boolean gcCleanerHack() { + return gcCleanerHack; } public Map getModules() { return this.modules; } - public void setupModule(ListenerModule module){ + public void setupModule(ListenerModule module) { module.setup(this.modules.get(module)); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/config/ListenerModule.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/config/ListenerModule.java index 0f8d2c2..fe0bf35 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/config/ListenerModule.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/config/ListenerModule.java @@ -1,7 +1,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.config; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; -import net.foxdenstudio.sponge.foxguard.plugin.listener.PlayerMoveListenerNew; +import net.foxdenstudio.sponge.foxguard.plugin.listener.PlayerMoveListener; import org.spongepowered.api.event.entity.MoveEntityEvent; import javax.annotation.Nonnull; @@ -25,7 +25,7 @@ public String setup(String setting) { setting = getDefaultValue(); full = true; } - PlayerMoveListenerNew pml = new PlayerMoveListenerNew(true); + PlayerMoveListener pml = new PlayerMoveListener(true); plugin.registerListener(MoveEntityEvent.class, pml); //plugin.registerListeners(pml.new Listeners()); return setting; diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/ControllerBase.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/ControllerBase.java index 3ed1e31..302b036 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/ControllerBase.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/ControllerBase.java @@ -28,11 +28,8 @@ import com.google.common.collect.ImmutableList; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.handler.HandlerBase; +import net.foxdenstudio.sponge.foxguard.plugin.handler.HandlerData; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; -import org.mapdb.DB; -import org.mapdb.DBMaker; -import org.mapdb.Serializer; import java.nio.file.Path; import java.util.ArrayList; @@ -40,54 +37,58 @@ public abstract class ControllerBase extends HandlerBase implements IController { - protected final List handlers; + protected final List links; - public ControllerBase(String name, boolean isEnabled, int priority) { - super(name, priority, isEnabled); - this.handlers = new ArrayList<>(); + public ControllerBase(HandlerData data) { + super(data); + this.links = new ArrayList<>(); } @Override - public List getHandlers() { - return ImmutableList.copyOf(this.handlers); + public List getLinks() { + return ImmutableList.copyOf(this.links); } @Override - public boolean addHandler(IHandler handler) { + public boolean addLink(IHandler handler) { if (!FGManager.getInstance().isRegistered(handler)) return false; int maxLinks = this.maxLinks(); - return !(maxLinks >= 0 && this.handlers.size() >= maxLinks) && this.handlers.add(handler); + return !(maxLinks >= 0 && this.links.size() >= maxLinks) && this.links.add(handler); } @Override - public boolean removeHandler(IHandler handler) { - return this.handlers.remove(handler); + public boolean removeLink(IHandler handler) { + return this.links.remove(handler); } @Override - public void clearHandlers() { - this.handlers.clear(); + public void clearLinks() { + this.links.clear(); } + /** + * Called when links are to be loaded. The new FoxGuard storage manager stores and loads links for you, but + * + * @param directory + * @param savedList + */ @Override - public void loadLinks(Path directory) { - try (DB linksDB = DBMaker.fileDB(directory.resolve("links.foxdb").normalize().toString()).make()) { - List linksList = linksDB.indexTreeList("links", Serializer.STRING).createOrOpen(); - handlers.clear(); - linksList.stream() - .filter(name -> !this.name.equalsIgnoreCase(name)) - .map(name -> FGManager.getInstance().gethandler(name)) - .filter(handler -> handler != null) - .forEach(handlers::add); - - } + public void loadLinks(Path directory, List savedList) { + links.clear(); + links.addAll(savedList); } + /** + * Stub method for controllers to put custom link saving code. This way, subclasses have something to call to save only links. + * I'm not sure why this is useful, if it's useful at all. I might end up removing it, or redoing controller save code entirely, + * cause array based serialization makes much less sense for controllers than regions. + *

+ * so actually, while i'm at it: + * TODO do something like map or arbitrary tree based serialization instea for controllers in a way that foxguard storage understands. + * + * @param directory the save directory of the controller + */ protected void saveLinks(Path directory) { - try (DB linksDB = DBMaker.fileDB(directory.resolve("links.foxdb").normalize().toString()).make()) { - List linksList = linksDB.indexTreeList("links", Serializer.STRING).createOrOpen(); - linksList.clear(); - handlers.stream().map(IFGObject::getName).forEach(linksList::add); - } + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/IController.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/IController.java index 370dde3..8f1a7de 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/IController.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/IController.java @@ -29,10 +29,14 @@ import net.foxdenstudio.sponge.foxguard.plugin.object.ILinkable; import java.nio.file.Path; +import java.util.List; public interface IController extends IHandler, ILinkable { - void loadLinks(Path directory); + @Override + List getLinks(); + + void loadLinks(Path directory, List savedList); /** * Method to get the maximum number of links the controller allows in a given configuration. @@ -49,4 +53,13 @@ default boolean canLinkToItself() { return false; } + @Override + default boolean saveLinks(){ + return false; + } + + @Override + default String getFilter() { + return "c"; + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/LogicController.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/LogicController.java index a1e485e..5daada9 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/LogicController.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/LogicController.java @@ -30,6 +30,7 @@ import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; +import net.foxdenstudio.sponge.foxguard.plugin.handler.HandlerData; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; import net.foxdenstudio.sponge.foxguard.plugin.object.factory.IControllerFactory; @@ -58,6 +59,7 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.List; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; import static org.spongepowered.api.text.format.TextColors.*; @@ -76,12 +78,12 @@ public class LogicController extends ControllerBase { private Tristate mode = UNDEFINED; private boolean shortCircuit = false; - public LogicController(String name, int priority) { - super(name, true, priority); + public LogicController(String name) { + super(new HandlerData().setName(name)); } - public LogicController(String name, boolean isEnabled, int priority, Operator operator, Tristate mode, boolean shortCircuit) { - super(name, isEnabled, priority); + public LogicController(HandlerData data, Operator operator, Tristate mode, boolean shortCircuit) { + super(data); this.operator = operator; this.mode = mode; this.shortCircuit = shortCircuit; @@ -89,7 +91,7 @@ public LogicController(String name, boolean isEnabled, int priority, Operator op @Override public EventResult handle(@Nullable User user, FlagSet flags, ExtraContext extra) { - return EventResult.of(operator.operate(this.handlers, mode, shortCircuit, user, flags, extra)); + return EventResult.of(operator.operate(this.links, mode, shortCircuit, user, flags, extra)); } @Override @@ -116,7 +118,7 @@ public String getUniqueTypeString() { public Text details(CommandSource source, String arguments) { Text.Builder builder = Text.builder(); builder.append(Text.of( - TextActions.suggestCommand("/foxguard md h " + this.name + " operator "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " operator "), TextActions.showText(Text.of(Text.of("Click to change operator"))), TextColors.GOLD, "Operator: ", operator.color, operator.toString() @@ -124,13 +126,13 @@ public Text details(CommandSource source, String arguments) { builder.append(Text.builder() .append(Text.of(TextColors.GOLD, "\nMode: ")) .append(FGUtil.readableTristateText(mode)) - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + " mode ")) + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " mode ")) .onHover(TextActions.showText(Text.of(Text.of("Click to change mode")))) .build()); builder.append(Text.builder() .append(Text.of(TextColors.GOLD, "\nShort Circuit: ")) .append(Text.of(FCPUtil.readableBooleanText(shortCircuit))) - .onClick(TextActions.runCommand("/foxguard md h " + this.name + " shortCircuit " + !shortCircuit)) + .onClick(TextActions.runCommand("/foxguard md h " + this.getFullName() + " shortCircuit " + !shortCircuit)) .onHover(TextActions.showText(Text.of(Text.of("Click to toggle short circuit")))) .build()); return builder.build(); @@ -200,7 +202,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N .parse(); if (parse.current.type == AdvCmdParser.CurrentElement.ElementType.ARGUMENT) { if (parse.current.index == 0) { - return ImmutableList.of("operator", "mode", "short").stream() + return Stream.of("operator", "mode", "short") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -213,12 +215,12 @@ public List modifySuggestions(CommandSource source, String arguments, @N .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (isIn(MODE_ALIASES, parse.args[0])) { - return ImmutableList.of("allow", "deny", "pass").stream() + return Stream.of("allow", "deny", "pass") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (isIn(SHORT_ALIASES, parse.args[0])) { - return ImmutableList.of("true", "false").stream() + return Stream.of("true", "false") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -380,6 +382,7 @@ public static Operator from(String name) { } return null; } + } public static final class Factory implements IControllerFactory { @@ -387,8 +390,8 @@ public static final class Factory implements IControllerFactory { public static final String[] LOGIC_ALIASES = {"logic", "logical"}; @Override - public IController create(String name, int priority, String arguments, CommandSource source) throws CommandException { - return new LogicController(name, priority); + public IController create(String name, String arguments, CommandSource source) throws CommandException { + return new LogicController(name); } @Override @@ -397,7 +400,7 @@ public List createSuggestions(CommandSource source, String arguments, St } @Override - public IController create(Path directory, String name, int priority, boolean isEnabled) { + public IController create(Path directory, HandlerData data) { Path configFile = directory.resolve("settings.cfg"); CommentedConfigurationNode root; ConfigurationLoader loader = @@ -419,7 +422,7 @@ public IController create(Path directory, String name, int priority, boolean isE else if (isIn(FALSE_ALIASES, modeName)) mode = FALSE; else mode = UNDEFINED; boolean shortCircuit = root.getNode("shortCircuit").getBoolean(false); - return new LogicController(name, isEnabled, priority, operator, mode, shortCircuit); + return new LogicController(data, operator, mode, shortCircuit); } @Override diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/message/MessageController.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/message/MessageController.java index d63ab11..c86d760 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/message/MessageController.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/controller/message/MessageController.java @@ -31,6 +31,7 @@ import net.foxdenstudio.sponge.foxguard.plugin.controller.ControllerBase; import net.foxdenstudio.sponge.foxguard.plugin.controller.util.HandlerWrapper; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; +import net.foxdenstudio.sponge.foxguard.plugin.handler.HandlerData; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; import net.foxdenstudio.sponge.foxguard.plugin.object.factory.IHandlerFactory; @@ -54,8 +55,8 @@ public class MessageController extends ControllerBase { private Map messages; - public MessageController(String name, boolean isEnabled, int priority) { - super(name, isEnabled, priority); + public MessageController(HandlerData data) { + super(data); slot = HandlerWrapper.PASSTHROUGH; messages = new HashMap<>(); } @@ -92,7 +93,7 @@ public void save(Path directory) { } @Override - public void loadLinks(Path directory) { + public void loadLinks(Path directory, List savedList) { } @@ -103,28 +104,28 @@ public int maxLinks() { @Override - public boolean addHandler(IHandler handler) { - if (this.handlers.size() < 1) { + public boolean addLink(IHandler handler) { + if (this.links.size() < 1) { slot = new HandlerWrapper(handler); - return super.addHandler(handler); + return super.addLink(handler); } else return false; } @Override - public boolean removeHandler(IHandler handler) { + public boolean removeLink(IHandler handler) { if (slot != null && slot.handler == handler) slot = HandlerWrapper.PASSTHROUGH; - return super.removeHandler(handler); + return super.removeLink(handler); } @Override - public void clearHandlers() { + public void clearLinks() { slot = HandlerWrapper.PASSTHROUGH; - super.clearHandlers(); + super.clearLinks(); } public IHandler getHandler() { - if (this.handlers.size() == 0) return null; - else return this.handlers.get(0); + if (this.links.size() == 0) return null; + else return this.links.get(0); } @Override @@ -176,12 +177,12 @@ public static class Factory implements IHandlerFactory { private static final String[] messageAliases = {"message", "mess", "msg"}; @Override - public IHandler create(String name, int priority, String arguments, CommandSource source) { + public IHandler create(String name, String arguments, CommandSource source) { return null; } @Override - public IHandler create(Path directory, String name, int priority, boolean isEnabled) { + public IHandler create(Path directory, HandlerData data) { return null; } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/event/FGUpdateObjectEvent.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/event/FGUpdateObjectEvent.java index 43f9e05..3b3c9ab 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/event/FGUpdateObjectEvent.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/event/FGUpdateObjectEvent.java @@ -25,10 +25,10 @@ package net.foxdenstudio.sponge.foxguard.plugin.event; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; public interface FGUpdateObjectEvent extends FGUpdateEvent { - IFGObject getTarget(); + IGuardObject getTarget(); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/BasicHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/BasicHandler.java index 413225d..f0eb22c 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/BasicHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/BasicHandler.java @@ -27,6 +27,11 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; import net.foxdenstudio.sponge.foxcore.common.util.CacheMap; import net.foxdenstudio.sponge.foxcore.common.util.FCCUtil; import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; @@ -34,7 +39,6 @@ import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; import net.foxdenstudio.sponge.foxcore.plugin.util.Aliases; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; -import net.foxdenstudio.sponge.foxguard.plugin.FGStorageManager; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.Flag; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; @@ -43,6 +47,8 @@ import net.foxdenstudio.sponge.foxguard.plugin.handler.util.TristateEntry; import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; import net.foxdenstudio.sponge.foxguard.plugin.object.factory.IHandlerFactory; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGSLegacyLoader; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGStorageManagerNew; import net.foxdenstudio.sponge.foxguard.plugin.util.EverythingSet; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; @@ -50,8 +56,8 @@ import ninja.leaping.configurate.hocon.HoconConfigurationLoader; import ninja.leaping.configurate.loader.ConfigurationLoader; import org.mapdb.DB; -import org.mapdb.DBMaker; import org.mapdb.Serializer; +import org.slf4j.Logger; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -70,9 +76,11 @@ import javax.annotation.Nullable; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; import static net.foxdenstudio.sponge.foxguard.plugin.flag.Flags.*; @@ -101,6 +109,7 @@ public class BasicHandler extends HandlerBase { private final Map defaultPermCache; private final Map, Map> groupSetPermCache; private final Map> userGroupCache; + private final Map> userPermCache; private PassiveSetting passiveSetting = PassiveSetting.PASSTHROUGH; @@ -108,20 +117,28 @@ public class BasicHandler extends HandlerBase { private Map passiveGroupCacheRef; private final Map passivePermCache; - public BasicHandler(String name, int priority) { - this(name, true, priority, + + public BasicHandler(String name) { + this(new HandlerData() + .setName(name) + .setEnabled(true) + .setPriority(0)); + } + + public BasicHandler(HandlerData data) { + this(data, new ArrayList<>(), new HashMap<>(), new Group("default", EverythingSet.get(), TextColors.RED, "Default"), new ArrayList<>()); } - public BasicHandler(String name, boolean isEnabled, int priority, + public BasicHandler(HandlerData data, List groups, Map> groupPermissions, Group defaultGroup, List defaultPermissions) { - super(name, priority, isEnabled); + super(data); this.groups = groups; this.defaultGroup = defaultGroup; @@ -131,10 +148,11 @@ public BasicHandler(String name, boolean isEnabled, int priority, this.groupPermCache = new CacheMap<>((k1, m1) -> { if (k1 instanceof Group) { List entries = BasicHandler.this.groupPermissions.get(k1); + Map map = new CacheMap<>((k2, m2) -> { if (k2 instanceof FlagSet) { FlagSet flags = (FlagSet) k2; - Tristate state = null; + Tristate state = UNDEFINED; for (TristateEntry entry : entries) { if (flags.toFlagSet().containsAll(entry.set)) { state = entry.tristate; @@ -170,10 +188,10 @@ public BasicHandler(String name, boolean isEnabled, int priority, } Set set = (Set) k1; List list = new ArrayList<>(set); - Collections.sort(list, (g1, g2) -> this.groups.indexOf(g1) - this.groups.indexOf(g2)); + list.sort(Comparator.comparingInt(this.groups::indexOf)); Map map = new CacheMap<>((k2, m2) -> { if (k2 instanceof FlagSet) { - Tristate state = null; + Tristate state = UNDEFINED; FlagSet flags = (FlagSet) k2; for (Group group : list) { state = this.groupPermCache.get(group).get(flags); @@ -234,6 +252,12 @@ public BasicHandler(String name, boolean isEnabled, int priority, }); } + public static boolean isNameValid(String name) { + return !name.matches("^.*[ :\\.=;\"\'\\\\/\\{\\}\\(\\)\\[\\]<>#@\\|\\?\\*].*$") && + !name.equalsIgnoreCase("default") && + !isIn(FGStorageManagerNew.FS_ILLEGAL_NAMES, name); + } + public ProcessResult modify(CommandSource source, String arguments) throws CommandException { AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).flagMapper(MAPPER).parse(); @@ -560,7 +584,8 @@ public ProcessResult modify(CommandSource source, String arguments) throws Comma if (parse.args.length < 4) return ProcessResult.of(false, Text.of("Must specify flags or an index to remove!")); List permissions = getGroupPermissions(group); - if(permissions.isEmpty()) return ProcessResult.of(false, "There are no entries to remove in this group!"); + if (permissions.isEmpty()) + return ProcessResult.of(false, "There are no entries to remove in this group!"); try { int index = Integer.parseInt(parse.args[3]); if (index < 0) index = 0; @@ -594,7 +619,8 @@ public ProcessResult modify(CommandSource source, String arguments) throws Comma if (parse.args.length < 4) return ProcessResult.of(false, Text.of("Must specify an index or flags and then a tristate value!")); List permissions = getGroupPermissions(group); - if(permissions.isEmpty()) return ProcessResult.of(false, "There are no entries to set in this group!"); + if (permissions.isEmpty()) + return ProcessResult.of(false, "There are no entries to set in this group!"); try { int index = Integer.parseInt(parse.args[3]); if (index < 0) index = 0; @@ -688,7 +714,8 @@ public ProcessResult modify(CommandSource source, String arguments) throws Comma List permissions = getGroupPermissions(group); if (parse.args.length < 4) return ProcessResult.of(false, Text.of("Must specify flags or an index to move!")); - if(permissions.isEmpty()) return ProcessResult.of(false, "There are no entries to move in this group!"); + if (permissions.isEmpty()) + return ProcessResult.of(false, "There are no entries to move in this group!"); try { int from = Integer.parseInt(parse.args[3]); if (from < 0) from = 0; @@ -782,13 +809,13 @@ public List modifySuggestions(CommandSource source, String arguments, @N .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) { - return ImmutableList.of("groups", "users", "flags", "passive").stream() + return Stream.of("groups", "users", "flags", "passive") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.index == 1) { if (isIn(GROUPS_ALIASES, parse.args[0])) { - return ImmutableList.of("add", "remove", "modify", "rename", "move").stream() + return Stream.of("add", "remove", "modify", "rename", "move") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -807,7 +834,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N list.add("default"); return ImmutableList.copyOf(list); } else if (isIn(PASSIVE_ALIASES, parse.args[0])) { - return ImmutableList.of("allow", "deny", "pass", "group", "default").stream() + return Stream.of("allow", "deny", "pass", "group", "default") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -847,12 +874,12 @@ public List modifySuggestions(CommandSource source, String arguments, @N } } } else if (isIn(USERS_ALIASES, parse.args[0])) { - return ImmutableList.of("add", "remove", "set").stream() + return Stream.of("add", "remove", "set") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (isIn(FLAGS_ALIASES, parse.args[0])) { - return ImmutableList.of("add", "remove", "set", "move").stream() + return Stream.of("add", "remove", "set", "move") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -883,7 +910,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N switch (parse.args[2].toLowerCase()) { case "add": { if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass").stream() + return Stream.of("=allow", "=deny", "=pass") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -900,7 +927,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N case "set": { if (parse.current.index == 3) { if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass", "=clear").stream() + return Stream.of("=allow", "=deny", "=pass", "=clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -913,14 +940,14 @@ public List modifySuggestions(CommandSource source, String arguments, @N } } else if (parse.current.index == 4) try { Integer.parseInt(parse.args[3]); - return ImmutableList.of("allow", "deny", "pass", "clear").stream() + return Stream.of("allow", "deny", "pass", "clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } catch (NumberFormatException ignored) { } if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass", "=clear").stream() + return Stream.of("=allow", "=deny", "=pass", "=clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -994,12 +1021,12 @@ public List modifySuggestions(CommandSource source, String arguments, @N } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) { if (isIn(GROUPS_ALIASES, parse.args[0])) { - return ImmutableList.of("index", "color", "displayname").stream() + return Stream.of("index", "color", "displayname") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (isIn(FLAGS_ALIASES, parse.args[0])) { - ImmutableList.of("index").stream() + Stream.of("index") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -1049,17 +1076,17 @@ public Text details(CommandSource source, String arguments) { if (this.passiveSetting == PassiveSetting.GROUP) passiveBuilder.append(Text.of(passiveGroup.color, passiveGroup.displayName)); passiveBuilder - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + " passive ")) + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " passive ")) .onHover(TextActions.showText(Text.of("Click to change the passive config"))); builder.append(passiveBuilder.build()); builder.append(Text.NEW_LINE); builder.append(Text.of(TextColors.GOLD, - TextActions.suggestCommand("/foxguard md h " + this.getName() + " group add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " group add "), TextActions.showText(Text.of("Click to add a group")), "----- Group Members -----\n")); for (Group group : groups) { builder.append(Text.of(group.color, - TextActions.suggestCommand("/foxguard md h " + this.getName() + " users " + group.name + " add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " users " + group.name + " add "), TextActions.showText(Text.of("Click to add player(s) to \"", group.color, group.displayName, TextColors.RESET, "\"" + (group.name.equals(group.displayName) ? "" : " (" + group.name + ")"))), group.displayName, TextColors.RESET, ": ")); @@ -1074,32 +1101,32 @@ public Text details(CommandSource source, String arguments) { } } online.stream() - .sorted((u1, u2) -> u1.getName().compareTo(u2.getName())) + .sorted(Comparator.comparing(User::getName)) .forEach(user -> { TextColor color = TextColors.WHITE; if (source instanceof Player && ((Player) source).getUniqueId().equals(user.getUniqueId())) color = TextColors.YELLOW; builder.append(Text.of(color, - TextActions.suggestCommand("/foxguard md h " + this.getName() + " users " + group.name + " remove " + user.getName()), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " users " + group.name + " remove " + user.getName()), TextActions.showText(Text.of("Click to remove player \"" + user.getName() + "\" from \"", group.color, group.displayName, TextColors.RESET, "\"" + (group.name.equals(group.displayName) ? "" : " (" + group.name + ")"))), user.getName())).append(Text.of(" ")); }); offline.stream() - .sorted((u1, u2) -> u1.toString().compareTo(u2.toString())) + .sorted(Comparator.comparing(UUID::toString)) .forEach(uuid -> builder.append(Text.of(TextColors.RESET, - TextActions.suggestCommand("/foxguard md h " + this.getName() + " users " + group.name + " remove " + uuid.toString()), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " users " + group.name + " remove " + uuid.toString()), TextActions.showText(Text.of("Click to remove player \"" + uuid.toString() + "\" from \"", group.color, group.displayName, TextColors.RESET, "\"" + (group.name.equals(group.displayName) ? "" : " (" + group.name + ")"))), uuid.toString())).append(Text.of(" "))); builder.append(Text.NEW_LINE); } builder.append(Text.of(TextColors.GOLD, - TextActions.suggestCommand("/foxguard md h " + this.getName() + " groups add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " groups add "), TextActions.showText(Text.of("Click to add a group")), "----- Group Flags -----\n")); for (Group group : groups) { builder.append(Text.of(group.color, - TextActions.suggestCommand("/foxguard md h " + this.name + " flags " + group.name + " add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " flags " + group.name + " add "), TextActions.showText(Text.of("Click to add a flag entry")), group.displayName + ":\n")); int index = 0; @@ -1110,12 +1137,12 @@ public Text details(CommandSource source, String arguments) { entryBuilder.append(Text.of(" " + index + ": " + stringBuilder.toString(), TextColors.AQUA, ": ")) .append(FGUtil.readableTristateText(entry.tristate)) .onHover(TextActions.showText(Text.of("Click to change this flag entry"))) - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + " flags " + group.name + " set " + (index++) + " ")); + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " flags " + group.name + " set " + (index++) + " ")); builder.append(entryBuilder.build()).append(Text.NEW_LINE); } } builder.append(Text.of(this.defaultGroup.color, - TextActions.suggestCommand("/foxguard md h " + this.name + " flags default add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " flags default add "), TextActions.showText(Text.of("Click to add a flag entry")), this.defaultGroup.displayName + ":")); int index = 0; @@ -1126,7 +1153,7 @@ public Text details(CommandSource source, String arguments) { entryBuilder.append(Text.of(" " + index + ": " + stringBuilder.toString(), TextColors.AQUA, ": ")) .append(FGUtil.readableTristateText(entry.tristate)) .onHover(TextActions.showText(Text.of("Click to change this flag entry"))) - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + " flags default set " + (index++) + " ")); + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " flags default set " + (index++) + " ")); builder.append(Text.NEW_LINE).append(entryBuilder.build()); } return builder.build(); @@ -1139,14 +1166,16 @@ public List detailsSuggestions(CommandSource source, String arguments, @ @Override public void save(Path directory) { - FGStorageManager storageManager = FGStorageManager.getInstance(); + FGStorageManagerNew storageManager = FGStorageManagerNew.getInstance(); UserStorageService userStorageService = FoxGuardMain.instance().getUserStorage(); - try (DB flagMapDB = DBMaker.fileDB(directory.resolve("groups.foxdb").normalize().toString()).make()) { + Logger logger = FoxGuardMain.instance().getLogger(); + + /*try (DB flagMapDB = FGStorageManagerOld.openFoxDB(directory.resolve("groups.foxdb"))) { List groupNames = flagMapDB.indexTreeList("names", Serializer.STRING).createOrOpen(); groupNames.clear(); groupNames.addAll(this.groups.stream().map(group -> group.name).collect(Collectors.toList())); } - try (DB flagMapDB = DBMaker.fileDB(directory.resolve("flags.foxdb").normalize().toString()).make()) { + try (DB flagMapDB = FGStorageManagerOld.openFoxDB(directory.resolve("flags.foxdb"))) { for (Group group : this.groups) { List stringEntries = flagMapDB.indexTreeList(group.name, Serializer.STRING).createOrOpen(); stringEntries.clear(); @@ -1155,7 +1184,26 @@ public void save(Path directory) { List stringEntries = flagMapDB.indexTreeList("default", Serializer.STRING).createOrOpen(); stringEntries.clear(); stringEntries.addAll(this.defaultPermissions.stream().map(TristateEntry::serialize).collect(Collectors.toList())); + }*/ + + Path dataFile = directory.resolve("data.foxcf"); + GsonBuilder gsonBuilder = FGStorageManagerNew.getInstance().getGsonBuilder(); + gsonBuilder.registerTypeAdapter(TristateEntry.class, TristateEntry.ADAPTER); + Gson gson = gsonBuilder.create(); + + GsonData data = new GsonData(); + data.groups = new HashMap<>(); + for (Map.Entry> entry : this.groupPermissions.entrySet()) { + data.groups.put(entry.getKey().name, entry.getValue()); + } + data.defaultGroup = this.defaultPermissions; + + try (JsonWriter jsonWriter = storageManager.getJsonWriter(Files.newBufferedWriter(dataFile, FGStorageManagerNew.CHARSET))) { + gson.toJson(data, GsonData.class, jsonWriter); + } catch (IOException e) { + logger.error("Failed to open data file for writing: " + data, e); } + Path groupsDirectory = directory.resolve("groups"); storageManager.constructDirectory(groupsDirectory); for (Group group : this.groups) { @@ -1167,7 +1215,7 @@ public void save(Path directory) { for (UUID uuid : group.users) { Optional userOptional = userStorageService.get(uuid); Map map = new HashMap<>(); - if (userOptional.isPresent()) map.put("username", userOptional.get().getName()); + userOptional.ifPresent(user -> map.put("username", user.getName())); map.put("uuid", uuid.toString()); members.add(map); } @@ -1487,15 +1535,6 @@ private List getGroupPermissions(Group group) { else return this.groupPermissions.get(group); } - public static boolean isNameValid(String name) { - if (name.matches("^.*[ :\\.=;\"\'\\\\/\\{\\}\\(\\)\\[\\]<>#@\\|\\?\\*].*$")) return false; - if (name.equalsIgnoreCase("default")) return false; - for (String s : FGStorageManager.FS_ILLEGAL_NAMES) { - if (name.equalsIgnoreCase(s)) return false; - } - return true; - } - public enum PassiveSetting { ALLOW, DENY, PASSTHROUGH, GROUP, DEFAULT; @@ -1517,11 +1556,17 @@ public String toString() { } } + private static class GsonData { + Map> groups; + @SerializedName("default") + List defaultGroup; + } + public static class Group { + private final Set users; private String name; private String displayName; private TextColor color; - private final Set users; private Group(String name) { this(name, new HashSet<>()); @@ -1568,9 +1613,9 @@ public static class Factory implements IHandlerFactory { private static final String[] ALIASES = {"basic", "base"}; @Override - public IHandler create(String name, int priority, String arguments, CommandSource source) throws CommandException { + public IHandler create(String name, String arguments, CommandSource source) throws CommandException { AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).parse(); - BasicHandler handler = new BasicHandler(name, priority); + BasicHandler handler = new BasicHandler(name); if (parse.args.length > 0) { if (parse.args[0].equalsIgnoreCase("bare")) { return handler; @@ -1653,14 +1698,40 @@ public IHandler create(String name, int priority, String arguments, CommandSourc } @Override - public IHandler create(Path directory, String name, int priority, boolean isEnabled) { - FGStorageManager storageManager = FGStorageManager.getInstance(); + public IHandler create(Path directory, HandlerData data) { + Logger logger = FoxGuardMain.instance().getLogger(); + FGStorageManagerNew storageManagerNew = FGStorageManagerNew.getInstance(); + + GsonBuilder gsonBuilder = storageManagerNew.getGsonBuilder(); + gsonBuilder.registerTypeAdapter(TristateEntry.class, TristateEntry.ADAPTER); + Gson gson = gsonBuilder.create(); + + GsonData gsonData = null; + Path gsonDataFile = directory.resolve("data.foxcf"); + if (Files.exists(gsonDataFile) && !Files.isDirectory(gsonDataFile)) { + try (JsonReader jsonReader = new JsonReader(Files.newBufferedReader(gsonDataFile))) { + gsonData = gson.fromJson(jsonReader, GsonData.class); + if (gsonData == null) gsonData = new GsonData(); + if (gsonData.groups == null) gsonData.groups = new HashMap<>(); + if (gsonData.defaultGroup == null) gsonData.defaultGroup = new ArrayList<>(); + } catch (IOException e) { + logger.error("Failed to open data file for reading: " + data, e); + } + } + List groupNames = new ArrayList<>(); - try (DB flagMapDB = DBMaker.fileDB(directory.resolve("groups.foxdb").normalize().toString()).make()) { - groupNames.addAll(flagMapDB.indexTreeList("names", Serializer.STRING).createOrOpen()); + if (gsonData != null) { + groupNames.addAll(gsonData.groups.keySet()); + } else { + // Legacy code + Path dbFile = directory.resolve("groups.foxdb"); + if (Files.exists(dbFile) && !Files.isDirectory(dbFile)) + try (DB flagMapDB = FGSLegacyLoader.openFoxDB(dbFile)) { + groupNames.addAll(flagMapDB.indexTreeList("names", Serializer.STRING).createOrOpen()); + } } Path groupsDirectory = directory.resolve("groups"); - storageManager.constructDirectory(groupsDirectory); + storageManagerNew.constructDirectory(groupsDirectory); List groups = new ArrayList<>(); for (String groupName : groupNames) { Path groupFile = groupsDirectory.resolve(groupName + ".cfg"); @@ -1683,21 +1754,34 @@ public IHandler create(Path directory, String name, int priority, boolean isEnab } Map> groupPermissions = new HashMap<>(); List defaultPermissions; - try (DB flagMapDB = DBMaker.fileDB(directory.resolve("flags.foxdb").normalize().toString()).make()) { + if (gsonData != null) { for (Group group : groups) { - List stringEntries = flagMapDB.indexTreeList(group.name, Serializer.STRING).createOrOpen(); - groupPermissions.put(group, stringEntries.stream() - .map(TristateEntry::deserialize) - .filter(entry -> !entry.set.isEmpty()) - .distinct() - .collect(Collectors.toList())); + groupPermissions.put(group, gsonData.groups.get(group.name)); + } + defaultPermissions = gsonData.defaultGroup; + } else { + // Legacy Code + Path dbFile = directory.resolve("flags.foxdb"); + if (Files.exists(dbFile) && !Files.isDirectory(dbFile)) { + try (DB flagMapDB = FGSLegacyLoader.openFoxDB(dbFile)) { + for (Group group : groups) { + List stringEntries = flagMapDB.indexTreeList(group.name, Serializer.STRING).createOrOpen(); + groupPermissions.put(group, stringEntries.stream() + .map(TristateEntry::deserialize) + .filter(entry -> !entry.set.isEmpty()) + .distinct() + .collect(Collectors.toList())); + } + List stringEntries = flagMapDB.indexTreeList("default", Serializer.STRING).createOrOpen(); + defaultPermissions = stringEntries.stream() + .map(TristateEntry::deserialize) + .filter(entry -> !entry.set.isEmpty()) + .distinct() + .collect(Collectors.toList()); + } + } else { + defaultPermissions = new ArrayList<>(); } - List stringEntries = flagMapDB.indexTreeList("default", Serializer.STRING).createOrOpen(); - defaultPermissions = stringEntries.stream() - .map(TristateEntry::deserialize) - .filter(entry -> !entry.set.isEmpty()) - .distinct() - .collect(Collectors.toList()); } Path basicFile = directory.resolve("basic.cfg"); @@ -1708,7 +1792,7 @@ public IHandler create(Path directory, String name, int priority, boolean isEnab String defaultDisplayName = defaultNode.getNode("displayname").getString("Default"); TextColor defaultColor = Sponge.getRegistry().getType(TextColor.class, defaultNode.getNode("color").getString("red")).orElse(TextColors.RED); - BasicHandler handler = new BasicHandler(name, isEnabled, priority, + BasicHandler handler = new BasicHandler(data, groups, groupPermissions, new Group("default", EverythingSet.get(), defaultColor, defaultDisplayName), @@ -1760,7 +1844,7 @@ public List createSuggestions(CommandSource source, String arguments, St .parse(); if (parse.current.type == AdvCmdParser.CurrentElement.ElementType.ARGUMENT && parse.current.index == 0) { - return ImmutableList.of("bare", "skeleton", "default", "easy", "plugandplay").stream() + return Stream.of("bare", "skeleton", "default", "easy", "plugandplay") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/DebugHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/DebugHandler.java index aa789be..eb235b5 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/DebugHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/DebugHandler.java @@ -59,6 +59,7 @@ import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; @@ -71,12 +72,12 @@ public class DebugHandler extends HandlerBase { public boolean console; private TextColor color = TextColors.WHITE; - public DebugHandler(String name, int priority) { - this(name, true, priority, new HashSet<>(), false, TextColors.WHITE); + public DebugHandler(HandlerData data) { + this(data, new HashSet<>(), false, TextColors.WHITE); } - public DebugHandler(String name, boolean isEnabled, int priority, Set members, boolean console, TextColor color) { - super(name, priority, isEnabled); + public DebugHandler(HandlerData data, Set members, boolean console, TextColor color) { + super(data); this.members = members; this.console = console; this.color = color; @@ -303,18 +304,18 @@ public List modifySuggestions(CommandSource source, String arguments, @N .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) { - return ImmutableList.of("members", "console", "color").stream() + return Stream.of("members", "console", "color") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.index == 1) { if (parse.args[0].equalsIgnoreCase("members")) { - return ImmutableList.of("add", "remove", "set").stream() + return Stream.of("add", "remove", "set") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.args[0].equalsIgnoreCase("console")) { - return ImmutableList.of("true", "false", "color").stream() + return Stream.of("true", "false") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -390,15 +391,15 @@ public static class Factory implements IHandlerFactory { private static final String[] ALIASES = {"debug", "debugger", "info"}; @Override - public IHandler create(String name, int priority, String arguments, CommandSource source) throws CommandException { - DebugHandler handler = new DebugHandler(name, priority); + public IHandler create(String name, String arguments, CommandSource source) throws CommandException { + DebugHandler handler = new DebugHandler(new HandlerData().setName(name)); if (source instanceof Player) handler.members.add(((Player) source).getUniqueId()); else if (source instanceof ConsoleSource) handler.console = true; return handler; } @Override - public IHandler create(Path directory, String name, int priority, boolean isEnabled) { + public IHandler create(Path directory, HandlerData data) { UserStorageService userStorageService = FoxGuardMain.instance().getUserStorage(); Path configFile = directory.resolve("config.cfg"); ConfigurationLoader loader = @@ -416,7 +417,7 @@ public IHandler create(Path directory, String name, int priority, boolean isEnab .collect(Collectors.toSet()); boolean console = root.getNode("console").getBoolean(false); TextColor color = Sponge.getRegistry().getType(TextColor.class, root.getNode("color").getString("white")).orElse(TextColors.WHITE); - return new DebugHandler(name, isEnabled, priority, members, console, color); + return new DebugHandler(data, members, console, color); } @Override diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/EconomyHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/EconomyHandler.java index 71ee472..e1a6de9 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/EconomyHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/EconomyHandler.java @@ -47,8 +47,8 @@ public class EconomyHandler extends HandlerBase { - public EconomyHandler(String name, boolean isEnabled, int priority) { - super(name, priority, isEnabled); + public EconomyHandler(HandlerData data) { + super(data); } @Override @@ -99,12 +99,12 @@ public List modifySuggestions(CommandSource source, String arguments, @N public static class Factory implements IHandlerFactory { @Override - public IHandler create(String name, int priority, String arguments, CommandSource source) throws CommandException { + public IHandler create(String name, String arguments, CommandSource source) throws CommandException { return null; } @Override - public IHandler create(Path directory, String name, int priority, boolean isEnabled) { + public IHandler create(Path directory, HandlerData data) { return null; } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/GlobalHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/GlobalHandler.java index f48b56e..774a4d2 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/GlobalHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/GlobalHandler.java @@ -31,8 +31,10 @@ public class GlobalHandler extends StaticHandler implements IGlobal { public static final String NAME = "_global"; + private static final HandlerData DATA = new HandlerData().setName(NAME).setPriority(Integer.MIN_VALUE / 2).setEnabled(true); + public GlobalHandler() { - super(NAME, Integer.MIN_VALUE / 2, true); + super(DATA); } @Override @@ -67,8 +69,8 @@ public boolean isEnabled() { } @Override - public void setIsEnabled(boolean state) { - this.isEnabled = true; + public void setEnabled(boolean state) { + this.enabled = true; } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/GroupHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/GroupHandler.java index 54015e9..165a7f8 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/GroupHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/GroupHandler.java @@ -26,6 +26,11 @@ package net.foxdenstudio.sponge.foxguard.plugin.handler; import com.google.common.collect.ImmutableList; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; import net.foxdenstudio.sponge.foxcore.common.util.CacheMap; import net.foxdenstudio.sponge.foxcore.common.util.FCCUtil; import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; @@ -33,22 +38,24 @@ import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; import net.foxdenstudio.sponge.foxcore.plugin.util.Aliases; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; -import net.foxdenstudio.sponge.foxguard.plugin.FGStorageManager; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.Flag; -import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagRegistry; +import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.handler.util.Operation; import net.foxdenstudio.sponge.foxguard.plugin.handler.util.TristateEntry; import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; import net.foxdenstudio.sponge.foxguard.plugin.object.factory.IHandlerFactory; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGSLegacyLoader; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGStorageManagerNew; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import ninja.leaping.configurate.commented.CommentedConfigurationNode; import ninja.leaping.configurate.hocon.HoconConfigurationLoader; import ninja.leaping.configurate.loader.ConfigurationLoader; import org.mapdb.DB; -import org.mapdb.DBMaker; import org.mapdb.Serializer; +import org.slf4j.Logger; import org.spongepowered.api.Sponge; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -65,11 +72,14 @@ import javax.annotation.Nullable; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; +import static org.spongepowered.api.util.Tristate.UNDEFINED; public class GroupHandler extends HandlerBase { @@ -98,20 +108,20 @@ public class GroupHandler extends HandlerBase { private final Map defaultPermCache; private final Map, Map> groupSetPermCache; - public GroupHandler(String name, int priority) { - this(name, true, priority, + public GroupHandler(HandlerData data) { + this(data, new ArrayList<>(), new HashMap<>(), new Group("default", "", TextColors.RED, "Default"), new ArrayList<>()); } - public GroupHandler(String name, boolean isEnabled, int priority, + public GroupHandler(HandlerData data, List groups, Map> groupPermissions, Group defaultGroup, List defaultPermissions) { - super(name, priority, isEnabled); + super(data); this.groups = groups; this.defaultGroup = defaultGroup; @@ -121,10 +131,11 @@ public GroupHandler(String name, boolean isEnabled, int priority, this.groupPermCache = new CacheMap<>((k1, m1) -> { if (k1 instanceof Group) { List entries = GroupHandler.this.groupPermissions.get(k1); + Map map = new CacheMap<>((k2, m2) -> { if (k2 instanceof FlagSet) { FlagSet flags = (FlagSet) k2; - Tristate state = null; + Tristate state = UNDEFINED; for (TristateEntry entry : entries) { if (flags.toFlagSet().containsAll(entry.set)) { state = entry.tristate; @@ -142,7 +153,7 @@ public GroupHandler(String name, boolean isEnabled, int priority, this.defaultPermCache = new CacheMap<>((k, m) -> { if (k instanceof FlagSet) { FlagSet flags = (FlagSet) k; - Tristate state = Tristate.UNDEFINED; + Tristate state = UNDEFINED; for (TristateEntry entry : GroupHandler.this.defaultPermissions) { if (flags.toFlagSet().containsAll(entry.set)) { state = entry.tristate; @@ -160,7 +171,7 @@ public GroupHandler(String name, boolean isEnabled, int priority, } Set set = (Set) k1; List list = new ArrayList<>(set); - Collections.sort(list, (g1, g2) -> this.groups.indexOf(g1) - this.groups.indexOf(g2)); + list.sort(Comparator.comparingInt(this.groups::indexOf)); Map map = new CacheMap<>((k2, m2) -> { if (k2 instanceof FlagSet) { Tristate state = null; @@ -180,6 +191,12 @@ public GroupHandler(String name, boolean isEnabled, int priority, }); } + public static boolean isNameValid(String name) { + return !name.matches("^.*[ :\\.=;\"\'\\\\/\\{\\}\\(\\)\\[\\]<>#@\\|\\?\\*].*$") && + !name.equalsIgnoreCase("default") && + !isIn(FGStorageManagerNew.FS_ILLEGAL_NAMES, name); + } + public ProcessResult modify(CommandSource source, String arguments) throws CommandException { AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).flagMapper(MAPPER).parse(); @@ -432,7 +449,8 @@ public ProcessResult modify(CommandSource source, String arguments) throws Comma if (parse.args.length < 4) return ProcessResult.of(false, Text.of("Must specify flags or an index to remove!")); List permissions = getGroupPermissions(group); - if(permissions.isEmpty()) return ProcessResult.of(false, "There are no entries to remove in this group!"); + if (permissions.isEmpty()) + return ProcessResult.of(false, "There are no entries to remove in this group!"); try { int index = Integer.parseInt(parse.args[3]); if (index < 0) index = 0; @@ -466,7 +484,8 @@ public ProcessResult modify(CommandSource source, String arguments) throws Comma if (parse.args.length < 4) return ProcessResult.of(false, Text.of("Must specify an index or flags and then a tristate value!")); List permissions = getGroupPermissions(group); - if(permissions.isEmpty()) return ProcessResult.of(false, "There are no entries to set in this group!"); + if (permissions.isEmpty()) + return ProcessResult.of(false, "There are no entries to set in this group!"); try { int index = Integer.parseInt(parse.args[3]); if (index < 0) index = 0; @@ -560,7 +579,8 @@ public ProcessResult modify(CommandSource source, String arguments) throws Comma List permissions = getGroupPermissions(group); if (parse.args.length < 4) return ProcessResult.of(false, Text.of("Must specify flags or an index to move!")); - if(permissions.isEmpty()) return ProcessResult.of(false, "There are no entries to move in this group!"); + if (permissions.isEmpty()) + return ProcessResult.of(false, "There are no entries to move in this group!"); try { int from = Integer.parseInt(parse.args[3]); if (from < 0) from = 0; @@ -631,13 +651,13 @@ public List modifySuggestions(CommandSource source, String arguments, @N .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) { - return ImmutableList.of("groups", "flags").stream() + return Stream.of("groups", "flags") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.index == 1) { if (isIn(GROUPS_ALIASES, parse.args[0])) { - return ImmutableList.of("add", "remove", "modify", "rename", "move").stream() + return Stream.of("add", "remove", "modify", "rename", "move") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -684,7 +704,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N } } } else if (isIn(FLAGS_ALIASES, parse.args[0])) { - return ImmutableList.of("add", "remove", "set", "move").stream() + return Stream.of("add", "remove", "set", "move") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -707,7 +727,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N switch (parse.args[2].toLowerCase()) { case "add": { if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass").stream() + return Stream.of("=allow", "=deny", "=pass") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -724,7 +744,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N case "set": { if (parse.current.index == 3) { if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass", "=clear").stream() + return Stream.of("=allow", "=deny", "=pass", "=clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -737,14 +757,14 @@ public List modifySuggestions(CommandSource source, String arguments, @N } } else if (parse.current.index == 4) try { Integer.parseInt(parse.args[3]); - return ImmutableList.of("allow", "deny", "pass", "clear").stream() + return Stream.of("allow", "deny", "pass", "clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } catch (NumberFormatException ignored) { } if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass", "=clear").stream() + return Stream.of("=allow", "=deny", "=pass", "=clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -773,12 +793,12 @@ public List modifySuggestions(CommandSource source, String arguments, @N } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) { if (isIn(GROUPS_ALIASES, parse.args[0])) { - return ImmutableList.of("index", "color", "displayname", "permission").stream() + return Stream.of("index", "color", "displayname", "permission") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (isIn(FLAGS_ALIASES, parse.args[0])) { - return ImmutableList.of("index").stream() + return Stream.of("index") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -833,12 +853,12 @@ public String getUniqueTypeString() { public Text details(CommandSource source, String arguments) { Text.Builder builder = Text.builder(); builder.append(Text.of(TextColors.GOLD, - TextActions.suggestCommand("/foxguard md h " + this.getName() + " group add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " group add "), TextActions.showText(Text.of("Click to add a group")), "----- Group Permission Strings -----\n")); for (Group group : groups) { builder.append(Text.of(group.color, - TextActions.suggestCommand("/foxguard md h " + this.getName() + " group modify " + group.name + " "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " group modify " + group.name + " "), TextActions.showText(Text.of("Click to modify \"", group.color, group.displayName, TextColors.RESET, "\"" + (group.name.equals(group.displayName) ? "" : " (" + group.name + ")"))), group.displayName, TextColors.RESET, ": ")); @@ -849,17 +869,17 @@ public Text details(CommandSource source, String arguments) { permBuilder.append(Text.of("foxguard.handler.", TextColors.YELLOW, this.name.toLowerCase(), TextColors.RESET, ".", group.color, group.name)); } permBuilder.onHover(TextActions.showText(Text.of("Click to modify the permissions string for \"", group.color, group.displayName, TextColors.RESET, "\"" + (group.name.equals(group.displayName) ? "" : " (" + group.name + ")")))); - permBuilder.onClick(TextActions.suggestCommand("/foxguard md h " + this.getName() + " group modify " + group.name + " --p:")); + permBuilder.onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " group modify " + group.name + " --p:")); builder.append(permBuilder.build()); builder.append(Text.NEW_LINE); } builder.append(Text.of(TextColors.GOLD, - TextActions.suggestCommand("/foxguard md h " + this.getName() + " groups add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " groups add "), TextActions.showText(Text.of("Click to add a group")), "----- Group Flags -----\n")); for (Group group : groups) { builder.append(Text.of(group.color, - TextActions.suggestCommand("/foxguard md h " + this.name + " flags " + group.name + " add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " flags " + group.name + " add "), TextActions.showText(Text.of("Click to add a flag entry")), group.displayName + ":\n")); int index = 0; @@ -870,12 +890,12 @@ public Text details(CommandSource source, String arguments) { entryBuilder.append(Text.of(" " + index + ": " + stringBuilder.toString(), TextColors.AQUA, ": ")) .append(FGUtil.readableTristateText(entry.tristate)) .onHover(TextActions.showText(Text.of("Click to change this flag entry"))) - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + " flags " + group.name + " set " + (index++) + " ")); + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " flags " + group.name + " set " + (index++) + " ")); builder.append(entryBuilder.build()).append(Text.NEW_LINE); } } builder.append(Text.of(this.defaultGroup.color, - TextActions.suggestCommand("/foxguard md h " + this.name + " flags default add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " flags default add "), TextActions.showText(Text.of("Click to add a flag entry")), this.defaultGroup.displayName + ":")); int index = 0; @@ -886,7 +906,7 @@ public Text details(CommandSource source, String arguments) { entryBuilder.append(Text.of(" " + index + ": " + stringBuilder.toString(), TextColors.AQUA, ": ")) .append(FGUtil.readableTristateText(entry.tristate)) .onHover(TextActions.showText(Text.of("Click to change this flag entry"))) - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + " flags default set " + (index++) + " ")); + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " flags default set " + (index++) + " ")); builder.append(Text.NEW_LINE).append(entryBuilder.build()); } return builder.build(); @@ -899,12 +919,14 @@ public List detailsSuggestions(CommandSource source, String arguments, @ @Override public void save(Path directory) { - try (DB flagMapDB = DBMaker.fileDB(directory.resolve("groups.foxdb").normalize().toString()).make()) { + FGStorageManagerNew storageManager = FGStorageManagerNew.getInstance(); + Logger logger = FoxGuardMain.instance().getLogger(); + /*try (DB flagMapDB = FGStorageManagerOld.openFoxDB(directory.resolve("groups.foxdb"))) { List groupNames = flagMapDB.indexTreeList("names", Serializer.STRING).createOrOpen(); groupNames.clear(); groupNames.addAll(this.groups.stream().map(group -> group.name).collect(Collectors.toList())); } - try (DB flagMapDB = DBMaker.fileDB(directory.resolve("flags.foxdb").normalize().toString()).make()) { + try (DB flagMapDB = FGStorageManagerOld.openFoxDB(directory.resolve("flags.foxdb"))) { for (Group group : this.groups) { List stringEntries = flagMapDB.indexTreeList(group.name, Serializer.STRING).createOrOpen(); stringEntries.clear(); @@ -913,27 +935,44 @@ public void save(Path directory) { List stringEntries = flagMapDB.indexTreeList("default", Serializer.STRING).createOrOpen(); stringEntries.clear(); stringEntries.addAll(this.defaultPermissions.stream().map(TristateEntry::serialize).collect(Collectors.toList())); + }*/ + + Path dataFile = directory.resolve("data.foxcf"); + GsonBuilder gsonBuilder = FGStorageManagerNew.getInstance().getGsonBuilder(); + gsonBuilder.registerTypeAdapter(TristateEntry.class, TristateEntry.ADAPTER); + Gson gson = gsonBuilder.create(); + + GsonData data = new GsonData(); + data.groups = new HashMap<>(); + for (Map.Entry> entry : this.groupPermissions.entrySet()) { + data.groups.put(entry.getKey().name, entry.getValue()); } - { - Path groupsFile = directory.resolve("groups.cfg"); - ConfigurationLoader loader = - HoconConfigurationLoader.builder().setPath(groupsFile).build(); - CommentedConfigurationNode root = FCPUtil.getHOCONConfiguration(groupsFile, loader); - CommentedConfigurationNode defaultNode = root.getNode("default"); - defaultNode.getNode("displayname").setValue(this.defaultGroup.displayName); - defaultNode.getNode("color").setValue(this.defaultGroup.color.getName()); - CommentedConfigurationNode groupsNode = root.getNode("groups"); - for (Group group : this.groups) { - CommentedConfigurationNode groupNode = groupsNode.getNode(group.name); - groupNode.getNode("displayname").setValue(group.displayName); - groupNode.getNode("color").setValue(group.color.getName()); - groupNode.getNode("permission").setValue(group.permission); - } - try { - loader.save(root); - } catch (IOException e) { - e.printStackTrace(); - } + data.defaultGroup = this.defaultPermissions; + + try (JsonWriter jsonWriter = storageManager.getJsonWriter(Files.newBufferedWriter(dataFile, FGStorageManagerNew.CHARSET))) { + gson.toJson(data, GsonData.class, jsonWriter); + } catch (IOException e) { + logger.error("Failed to open data file for writing: " + data, e); + } + + Path groupsFile = directory.resolve("groups.cfg"); + ConfigurationLoader loader = + HoconConfigurationLoader.builder().setPath(groupsFile).build(); + CommentedConfigurationNode root = FCPUtil.getHOCONConfiguration(groupsFile, loader); + CommentedConfigurationNode defaultNode = root.getNode("default"); + defaultNode.getNode("displayname").setValue(this.defaultGroup.displayName); + defaultNode.getNode("color").setValue(this.defaultGroup.color.getName()); + CommentedConfigurationNode groupsNode = root.getNode("groups"); + for (Group group : this.groups) { + CommentedConfigurationNode groupNode = groupsNode.getNode(group.name); + groupNode.getNode("displayname").setValue(group.displayName); + groupNode.getNode("color").setValue(group.color.getName()); + groupNode.getNode("permission").setValue(group.permission); + } + try { + loader.save(root); + } catch (IOException e) { + e.printStackTrace(); } } @@ -1165,13 +1204,10 @@ private boolean userFilter(Operation op, boolean isPresent) { } } - public static boolean isNameValid(String name) { - if (name.matches("^.*[ :\\.=;\"\'\\\\/\\{\\}\\(\\)\\[\\]<>#@\\|\\?\\*].*$")) return false; - if (name.equalsIgnoreCase("default")) return false; - for (String s : FGStorageManager.FS_ILLEGAL_NAMES) { - if (name.equalsIgnoreCase(s)) return false; - } - return true; + private static class GsonData { + Map> groups; + @SerializedName("default") + List defaultGroup; } public static class Group { @@ -1227,9 +1263,9 @@ public static class Factory implements IHandlerFactory { private static final String[] ALIASES = {"group", "permgroup"}; @Override - public IHandler create(String name, int priority, String arguments, CommandSource source) throws CommandException { + public IHandler create(String name, String arguments, CommandSource source) throws CommandException { AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).parse(); - GroupHandler handler = new GroupHandler(name, priority); + GroupHandler handler = new GroupHandler(new HandlerData().setName(name)); if (parse.args.length < 1 || !parse.args[0].equalsIgnoreCase("bare")) { Group members = handler.createGroup("members").get(); members.displayName = "Members"; @@ -1238,13 +1274,43 @@ public IHandler create(String name, int priority, String arguments, CommandSourc return handler; } + @SuppressWarnings("Duplicates") @Override - public IHandler create(Path directory, String name, int priority, boolean isEnabled) { + public IHandler create(Path directory, HandlerData data) { + Logger logger = FoxGuardMain.instance().getLogger(); + FGStorageManagerNew storageManagerNew = FGStorageManagerNew.getInstance(); + + GsonBuilder gsonBuilder = storageManagerNew.getGsonBuilder(); + gsonBuilder.registerTypeAdapter(TristateEntry.class, TristateEntry.ADAPTER); + Gson gson = gsonBuilder.create(); + + GsonData gsonData = null; + Path gsonDataFile = directory.resolve("data.foxcf"); + if (Files.exists(gsonDataFile) && !Files.isDirectory(gsonDataFile)) { + try (JsonReader jsonReader = new JsonReader(Files.newBufferedReader(gsonDataFile))) { + gsonData = gson.fromJson(jsonReader, GsonData.class); + if (gsonData == null) gsonData = new GsonData(); + if (gsonData.groups == null) gsonData.groups = new HashMap<>(); + if (gsonData.defaultGroup == null) gsonData.defaultGroup = new ArrayList<>(); + } catch (IOException e) { + logger.error("Failed to open data file for reading: " + data, e); + } + } + List groupNames = new ArrayList<>(); - try (DB flagMapDB = DBMaker.fileDB(directory.resolve("groups.foxdb").normalize().toString()).make()) { - groupNames.addAll(flagMapDB.indexTreeList("names", Serializer.STRING).createOrOpen()); + if (gsonData != null) { + groupNames.addAll(gsonData.groups.keySet()); + } else { + // Legacy Code + Path dbFile = directory.resolve("groups.foxdb"); + if (Files.exists(dbFile) && !Files.isDirectory(dbFile)) + try (DB flagMapDB = FGSLegacyLoader.openFoxDB(directory.resolve("groups.foxdb"))) { + groupNames.addAll(flagMapDB.indexTreeList("names", Serializer.STRING).createOrOpen()); + } } + List groups = new ArrayList<>(); + Path groupsFile = directory.resolve("groups.cfg"); ConfigurationLoader loader = HoconConfigurationLoader.builder().setPath(groupsFile).build(); @@ -1263,18 +1329,32 @@ public IHandler create(Path directory, String name, int priority, boolean isEnab Map> groupPermissions = new HashMap<>(); List defaultPermissions; - try (DB flagMapDB = DBMaker.fileDB(directory.resolve("flags.foxdb").normalize().toString()).make()) { + + if (gsonData != null) { for (Group group : groups) { - List stringEntries = flagMapDB.indexTreeList(group.name, Serializer.STRING).createOrOpen(); - groupPermissions.put(group, stringEntries.stream() - .map(TristateEntry::deserialize) - .collect(Collectors.toList())); + groupPermissions.put(group, gsonData.groups.get(group.name)); + } + defaultPermissions = gsonData.defaultGroup; + } else { + // Legacy Code + Path dbFile = directory.resolve("flags.foxdb"); + if (Files.exists(dbFile) && !Files.isDirectory(dbFile)) { + try (DB flagMapDB = FGSLegacyLoader.openFoxDB(dbFile)) { + for (Group group : groups) { + List stringEntries = flagMapDB.indexTreeList(group.name, Serializer.STRING).createOrOpen(); + groupPermissions.put(group, stringEntries.stream() + .map(TristateEntry::deserialize) + .collect(Collectors.toList())); + } + List stringEntries = flagMapDB.indexTreeList("default", Serializer.STRING).createOrOpen(); + defaultPermissions = stringEntries.stream().map(TristateEntry::deserialize).collect(Collectors.toList()); + } + } else { + defaultPermissions = new ArrayList<>(); } - List stringEntries = flagMapDB.indexTreeList("default", Serializer.STRING).createOrOpen(); - defaultPermissions = stringEntries.stream().map(TristateEntry::deserialize).collect(Collectors.toList()); } - return new GroupHandler(name, isEnabled, priority, + return new GroupHandler(data, groups, groupPermissions, new Group("default", "", defaultColor, defaultDisplayName), @@ -1305,7 +1385,7 @@ public List createSuggestions(CommandSource source, String arguments, St .parse(); if (parse.current.type == AdvCmdParser.CurrentElement.ElementType.ARGUMENT && parse.current.index == 0) { - return ImmutableList.of("bare").stream() + return Stream.of("bare") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/HandlerBase.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/HandlerBase.java index 6bc7501..0232fa9 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/HandlerBase.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/HandlerBase.java @@ -25,16 +25,16 @@ package net.foxdenstudio.sponge.foxguard.plugin.handler; -import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectBase; +import net.foxdenstudio.sponge.foxguard.plugin.object.GuardObjectBase; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; -public abstract class HandlerBase extends FGObjectBase implements IHandler { +public abstract class HandlerBase extends GuardObjectBase implements IHandler { int priority; - public HandlerBase(String name, int priority, boolean isEnabled) { - super(name, isEnabled); - setPriority(priority); + public HandlerBase(HandlerData data) { + super(data); + setPriority(data.getPriority()); } @Override @@ -46,23 +46,18 @@ public int getPriority() { public void setPriority(int priority) { if (priority < Integer.MIN_VALUE / 2 + 1) priority = Integer.MIN_VALUE / 2 + 1; else if (priority > Integer.MAX_VALUE / 2) priority = Integer.MAX_VALUE / 2; - this.priority = priority > Integer.MIN_VALUE ? priority : Integer.MIN_VALUE + 1; - } - - @Override - public int compareTo(IHandler o) { - return o.getPriority() - this.priority; + this.priority = priority; } public void markDirty() { - FGUtil.markHandlerDirty(this); + FGUtil.markDirty(this); } @Override public String toString() { return this.getClass().getSimpleName() + "{" + "name='" + name + '\'' + - ", isEnabled=" + isEnabled + + ", enabled=" + enabled + ", priority=" + priority + '}'; } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/HandlerData.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/HandlerData.java new file mode 100644 index 0000000..468997f --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/HandlerData.java @@ -0,0 +1,71 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.handler; + +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; + +import java.util.UUID; + +public class HandlerData extends FGObjectData { + + protected int priority = 0; + + public HandlerData() { + super(); + } + + public HandlerData(FGObjectData data, int priority) { + this.name = data.getName(); + this.owner = data.getOwner(); + this.enabled = data.isEnabled(); + this.priority = priority; + } + + public int getPriority() { + return priority; + } + + public HandlerData setPriority(int priority) { + this.priority = priority; + return this; + } + + @Override + public HandlerData setName(String name) { + return (HandlerData) super.setName(name); + } + + @Override + public HandlerData setOwner(IOwner owner) { + return (HandlerData) super.setOwner(owner); + } + + @Override + public HandlerData setEnabled(boolean enabled) { + return (HandlerData) super.setEnabled(enabled); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/IHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/IHandler.java index 45935fc..edcd1ad 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/IHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/IHandler.java @@ -27,13 +27,16 @@ import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import org.spongepowered.api.entity.living.player.User; import javax.annotation.Nullable; +import java.util.Comparator; -public interface IHandler extends IFGObject, Comparable { +public interface IHandler extends IGuardObject { + + Comparator PRIORITY = Comparator.comparingInt(IHandler::getPriority); EventResult handle(@Nullable User user, FlagSet flags, ExtraContext extra); @@ -41,4 +44,8 @@ public interface IHandler extends IFGObject, Comparable { void setPriority(int priority); + @Override + default String getFilter(){ + return "h"; + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/PermissionHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/PermissionHandler.java index c67b5b5..1b5f073 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/PermissionHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/PermissionHandler.java @@ -57,6 +57,7 @@ import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; @@ -66,16 +67,17 @@ public class PermissionHandler extends HandlerBase { private final List entries; + private String defaultPermission; private final Map> permCache; - public PermissionHandler(String name, int priority, boolean isEnabled) { - this(name, priority, isEnabled, + public PermissionHandler(HandlerData data) { + this(data, new ArrayList<>(), ""); } - public PermissionHandler(String name, int priority, boolean isEnabled, List entries, String defaultPermission) { - super(name, priority, isEnabled); + public PermissionHandler(HandlerData data, List entries, String defaultPermission) { + super(data); this.entries = entries; this.defaultPermission = defaultPermission; this.permCache = new CacheMap<>((k, m) -> { @@ -366,13 +368,13 @@ public List modifySuggestions(CommandSource source, String arguments, @N if (parse.current.type == AdvCmdParser.CurrentElement.ElementType.ARGUMENT) { if (parse.current.index == 0) { - return ImmutableList.of("entries", "default").stream() + return Stream.of("entries", "default") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (isIn(ENTRIES_ALIASES, parse.args[0]) || isIn(FLAGS_ALIASES, parse.args[0])) { if (parse.current.index == 1) { - return ImmutableList.of("add", "set", "remove", "move").stream() + return Stream.of("add", "set", "remove", "move") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -484,7 +486,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N public Text details(CommandSource source, String arguments) { Text.Builder builder = Text.builder(); - Text prefix = Text.of("foxguard.handler.", TextColors.GOLD, this.name); + Text prefix = Text.of("foxguard.handler.", TextColors.GOLD, this.name.toLowerCase()); Text postfix = Text.of(".", TextColors.AQUA, "<", TextColors.GREEN, "allow", @@ -495,7 +497,7 @@ public Text details(CommandSource source, String arguments) { TextColors.AQUA, ">"); builder.append(Text.of( TextActions.showText(Text.of("Click to add a permission entry")), - TextActions.suggestCommand("/foxguard md h " + this.name + " entries add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " entries add "), TextColors.GREEN, "Entries:" )); int index = 0; @@ -514,7 +516,7 @@ public Text details(CommandSource source, String arguments) { } entryBuilder.append(postfix) .onHover(TextActions.showText(Text.of("Click to change this entry"))) - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + "entries set " + (index++) + " ")); + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + "entries set " + (index++) + " ")); builder.append(Text.NEW_LINE).append(entryBuilder.build()); } Text.Builder entryBuilder = Text.builder(); @@ -529,7 +531,7 @@ public Text details(CommandSource source, String arguments) { } entryBuilder.append(postfix) .onHover(TextActions.showText(Text.of("Click to change this entry"))) - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + " default ")); + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " default ")); builder.append(Text.NEW_LINE).append(entryBuilder.build()); return builder.build(); @@ -559,6 +561,12 @@ public void save(Path directory) { } } + @Override + public void setName(String name) { + super.setName(name); + this.permCache.clear(); + } + public boolean addFlagEntry(PermissionEntry entry) { return addFlagEntry(0, entry); } @@ -658,7 +666,7 @@ private boolean checkPermissionString(String perm) { } private String expandPermission(String perm) { - if (perm.isEmpty() || perm.startsWith(".")) perm = "foxguard.handler." + this.name + perm; + if (perm.isEmpty() || perm.startsWith(".")) perm = "foxguard.handler." + this.name.toLowerCase() + perm; return perm; } @@ -667,12 +675,12 @@ public static class Factory implements IHandlerFactory { public static final String[] ALIASES = {"perm", "perms", "permission", "permissions"}; @Override - public IHandler create(String name, int priority, String arguments, CommandSource source) throws CommandException { - return new PermissionHandler(name, priority, true); + public IHandler create(String name, String arguments, CommandSource source) throws CommandException { + return new PermissionHandler(new HandlerData().setName(name)); } @Override - public IHandler create(Path directory, String name, int priority, boolean isEnabled) { + public IHandler create(Path directory, HandlerData data) { Path permissionsFile = directory.resolve("permissions.cfg"); ConfigurationLoader loader = HoconConfigurationLoader.builder().setPath(permissionsFile).build(); @@ -688,7 +696,7 @@ public IHandler create(Path directory, String name, int priority, boolean isEnab .map(PermissionEntry::deserialize) .collect(Collectors.toList()); String defaultPermission = root.getNode("default").getString(""); - return new PermissionHandler(name, priority, isEnabled, entries, defaultPermission); + return new PermissionHandler(data, entries, defaultPermission); } @Override diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/StaticHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/StaticHandler.java index 4a9964c..ca032f1 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/StaticHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/StaticHandler.java @@ -61,6 +61,7 @@ import java.nio.file.Path; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; @@ -77,12 +78,15 @@ public class StaticHandler extends HandlerBase { private final List entries; private final Map permCache; - public StaticHandler(String name, int priority) { - this(name, priority, true); + public StaticHandler(String name) { + this(new HandlerData() + .setName(name) + .setEnabled(true) + .setPriority(0)); } - public StaticHandler(String name, int priority, boolean isEnabled) { - super(name, priority, isEnabled); + public StaticHandler(HandlerData data) { + super(data); this.entries = new ArrayList<>(); this.permCache = new CacheMap<>((k, m) -> { if (k instanceof FlagSet) { @@ -187,7 +191,7 @@ public ProcessResult modify(CommandSource source, String arguments) throws Comma case "remove": { if (parse.args.length < 2) return ProcessResult.of(false, Text.of("Must specify flags or an index to remove!")); - if(this.entries.isEmpty()) return ProcessResult.of(false, "There are no entries to remove!"); + if (this.entries.isEmpty()) return ProcessResult.of(false, "There are no entries to remove!"); try { int index = Integer.parseInt(parse.args[1]); if (index < 0) index = 0; @@ -377,7 +381,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) { - return ImmutableList.of("add", "set", "remove", "move").stream() + return Stream.of("add", "set", "remove", "move") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -385,7 +389,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N switch (parse.args[0].toLowerCase()) { case "add": { if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass").stream() + return Stream.of("=allow", "=deny", "=pass") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -402,7 +406,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N case "set": { if (parse.current.index == 1) { if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass", "=clear").stream() + return Stream.of("=allow", "=deny", "=pass", "=clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -415,14 +419,14 @@ public List modifySuggestions(CommandSource source, String arguments, @N } } else if (parse.current.index == 2) try { Integer.parseInt(parse.args[1]); - return ImmutableList.of("allow", "deny", "pass", "clear").stream() + return Stream.of("allow", "deny", "pass", "clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } catch (NumberFormatException ignored) { } if (parse.current.token.startsWith("=")) { - return ImmutableList.of("=allow", "=deny", "=pass", "=clear").stream() + return Stream.of("=allow", "=deny", "=pass", "=clear") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -457,7 +461,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N public Text details(CommandSource source, String arguments) { Text.Builder builder = Text.builder(); builder.append(Text.of(TextColors.AQUA, - TextActions.suggestCommand("/foxguard md h " + this.name + " add "), + TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " add "), TextActions.showText(Text.of("Click to add a flag entry")), "Flags:")); int index = 0; @@ -468,7 +472,7 @@ public Text details(CommandSource source, String arguments) { entryBuilder.append(Text.of(" " + index + ": " + stringBuilder.toString(), TextColors.AQUA, ": ")) .append(FGUtil.readableTristateText(entry.tristate)) .onHover(TextActions.showText(Text.of("Click to change this flag entry"))) - .onClick(TextActions.suggestCommand("/foxguard md h " + this.name + " set " + (index++) + " ")); + .onClick(TextActions.suggestCommand("/foxguard md h " + this.getFullName() + " set " + (index++) + " ")); builder.append(Text.NEW_LINE).append(entryBuilder.build()); } return builder.build(); @@ -613,13 +617,13 @@ public static class Factory implements IHandlerFactory { public static final String[] ALIASES = {"static", "stub", "blind"}; @Override - public IHandler create(String name, int priority, String arguments, CommandSource source) throws CommandException { - return new StaticHandler(name, priority); + public IHandler create(String name, String arguments, CommandSource source) throws CommandException { + return new StaticHandler(name); } @Override - public IHandler create(Path directory, String name, int priority, boolean isEnabled) { - StaticHandler handler = new StaticHandler(name, priority, isEnabled); + public IHandler create(Path directory, HandlerData data) { + StaticHandler handler = new StaticHandler(data); handler.load(directory); return handler; } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/WelcomeHandler.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/WelcomeHandler.java index 740cd9c..1e97656 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/WelcomeHandler.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/WelcomeHandler.java @@ -26,55 +26,122 @@ package net.foxdenstudio.sponge.foxguard.plugin.handler; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; +import net.foxdenstudio.sponge.foxguard.plugin.flag.Flags; import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.factory.IHandlerFactory; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import ninja.leaping.configurate.commented.CommentedConfigurationNode; import ninja.leaping.configurate.hocon.HoconConfigurationLoader; import ninja.leaping.configurate.loader.ConfigurationLoader; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.TextTemplate; +import org.spongepowered.api.text.format.TextColor; import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.text.format.TextStyle; +import org.spongepowered.api.text.format.TextStyles; +import org.spongepowered.api.util.GuavaCollectors; +import org.spongepowered.api.util.StartsWithPredicate; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; import javax.annotation.Nullable; +import java.io.IOException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; /** * Created by Fox on 11/5/2016. */ public class WelcomeHandler extends HandlerBase { - TextTemplate enterTemplate = TextTemplate.EMPTY; - TextTemplate exitTemplate = TextTemplate.EMPTY; + private static final Pattern PATTERN = Pattern.compile("&[0-9a-fk-or]|%|(?:\\.|&(?![0-9a-fk-or%])|[^&%])+"); - public WelcomeHandler(String name, int priority) { - this(name, true, priority); + private boolean enter; + private boolean exit; + private String enterString = ""; + private String exitString = ""; + private TextTemplate enterTemplate = TextTemplate.EMPTY; + private TextTemplate exitTemplate = TextTemplate.EMPTY; + + + public WelcomeHandler(HandlerData data) { + this(data, "", ""); } - public WelcomeHandler(String name, boolean isEnabled, int priority) { - super(name, priority, isEnabled); + public WelcomeHandler(HandlerData data, String enterString, String exitString) { + super(data); + this.setEnter(enterString); + this.setExit(exitString); } @Override public ProcessResult modify(CommandSource source, String arguments) throws CommandException { - return null; + AdvCmdParser.ParseResult parse = AdvCmdParser.builder() + .arguments(arguments) + .limit(1) + .leaveFinalAsIs(true) + .parse(); + + if (parse.args.length < 1) return ProcessResult.of(false, Text.of("Must specify a command!")); + + if (parse.args.length < 2) return ProcessResult.failure(); + + if (parse.args[0].equalsIgnoreCase("enter")) this.setEnter(parse.args[1]); + else if (parse.args[0].equalsIgnoreCase("exit")) this.setExit(parse.args[1]); + else ProcessResult.of(false, "Invalid Command!"); + + return ProcessResult.success(); } @Override public List modifySuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { - return null; + AdvCmdParser.ParseResult parse = AdvCmdParser.builder() + .arguments(arguments) + .limit(1) + .leaveFinalAsIs(true) + .autoCloseQuotes(true) + .excludeCurrent(true) + .parse(); + if (parse.current.type == AdvCmdParser.CurrentElement.ElementType.ARGUMENT) { + if (parse.current.index == 0) { + return Stream.of("enter", "exit") + .filter(new StartsWithPredicate(parse.current.token)) + .map(args -> parse.current.prefix + args) + .collect(GuavaCollectors.toImmutableList()); + } + } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.COMPLETE)) + return ImmutableList.of(parse.current.prefix + " "); + return ImmutableList.of(); } + @SuppressWarnings("ConstantConditions") @Override public EventResult handle(@Nullable User user, FlagSet flags, ExtraContext extra) { + if (flags.get(Flags.MOVE)) { + Player player = (Player) user; + Map input = ImmutableMap.of("player", player.getName()); + if (flags.get(Flags.ENTER)) { + player.sendMessage(enterTemplate.apply(input).build()); + //player.sendMessage(enterTemplate.toText()); + } else if (flags.get(Flags.EXIT)) { + player.sendMessage(exitTemplate.apply(input).build()); + } + } return EventResult.pass(); } @@ -95,11 +162,12 @@ public String getUniqueTypeString() { @Override public Text details(CommandSource source, String arguments) { + final Text quote = Text.of(TextColors.AQUA, "\""); Text.Builder builder = Text.builder(); - builder.append(Text.of(TextColors.GREEN, "Enter:\n")); - builder.append(enterTemplate.toText()); - builder.append(Text.of(TextColors.GOLD, "Exit:\n")); - builder.append(exitTemplate.toText()); + builder.append(Text.of(TextColors.GREEN, "Enter:\n ")); + builder.append(quote).append(enterTemplate.toText()).append(quote); + builder.append(Text.of(TextColors.GOLD, "\nExit:\n ")); + builder.append(quote).append(exitTemplate.toText()).append(quote); return builder.build(); } @@ -114,7 +182,96 @@ public void save(Path directory) { ConfigurationLoader loader = HoconConfigurationLoader.builder().setPath(file).build(); CommentedConfigurationNode root = FCPUtil.getHOCONConfiguration(file, loader); - root.getNode("enter").setValue(enterTemplate); - root.getNode("exit").setValue(exitTemplate); + root.getNode("enter").setValue(enterString); + root.getNode("exit").setValue(exitString); + try { + loader.save(root); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void setEnter(String enterString) { + this.enter = !enterString.isEmpty(); + this.enterString = enterString; + this.enterTemplate = fromString(enterString); + } + + public void setExit(String exitString) { + this.exit = !exitString.isEmpty(); + this.exitString = exitString; + this.exitTemplate = fromString(exitString); + } + + private static TextTemplate fromString(String string) { + List elements = new ArrayList<>(); + Matcher matcher = PATTERN.matcher(string); + + TextColor curColor = TextColors.RESET; + TextStyle curStyle = TextStyles.RESET; + while (matcher.find()) { + String str = matcher.group(); + + if (str.equals("%")) { + elements.add(TextTemplate.arg("player") + .color(curColor) + .style(curStyle) + .build()); + } else if (str.matches("&[0-9a-fk-or]")) { + str = str.substring(1); + if (str.matches("[0-9a-f]")) { + Optional colorOpt = FCPUtil.textColorFromHex(str); + if (colorOpt.isPresent()) curColor = colorOpt.get(); + } else { + Optional styleOpt = FCPUtil.textStyleFromCode(str); + if (styleOpt.isPresent()) curStyle = styleOpt.get(); + } + } else { + elements.add(Text.of(curColor, curStyle, str)); + } + } + + return TextTemplate.of(elements.toArray()); + } + + public static class Factory implements IHandlerFactory { + + private static final String[] ALIASES = {"welcome"}; + + @Override + public IHandler create(String name, String arguments, CommandSource source) throws CommandException { + return new WelcomeHandler(new HandlerData().setName(name)); + } + + @Override + public IHandler create(Path directory, HandlerData data) { + Path file = directory.resolve("messages.cfg"); + ConfigurationLoader loader = + HoconConfigurationLoader.builder().setPath(file).build(); + CommentedConfigurationNode root = FCPUtil.getHOCONConfiguration(file, loader); + String enterString = root.getNode("enter").getString(""); + String exitString = root.getNode("enter").getString(""); + return new WelcomeHandler(data, enterString, exitString); + } + + @Override + public String[] getAliases() { + return ALIASES; + } + + @Override + public String getType() { + return "welcome"; + } + + @Override + public String getPrimaryAlias() { + return "welcome"; + } + + @Override + public List createSuggestions(CommandSource source, String arguments, String type, @Nullable Location targetPosition) throws CommandException { + return ImmutableList.of(); + } } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/Entry.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/Entry.java index 661ed29..b146adb 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/Entry.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/Entry.java @@ -27,12 +27,8 @@ import com.google.common.collect.ImmutableSet; import net.foxdenstudio.sponge.foxguard.plugin.flag.Flag; -import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagRegistry; -import org.spongepowered.api.util.Tristate; -import java.util.HashSet; import java.util.Iterator; -import java.util.Optional; import java.util.Set; /** diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/PermissionEntry.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/PermissionEntry.java index 7ff21df..a01797e 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/PermissionEntry.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/PermissionEntry.java @@ -25,9 +25,17 @@ package net.foxdenstudio.sponge.foxguard.plugin.handler.util; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.Flag; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagRegistry; +import org.slf4j.Logger; +import org.spongepowered.api.util.Tristate; +import java.io.IOException; import java.util.HashSet; import java.util.Optional; import java.util.Set; @@ -37,25 +45,21 @@ */ public class PermissionEntry extends Entry { + public static final TypeAdapter ADAPTER = new PermissionEntryAdapter().nullSafe(); public String permission; public boolean relative; public PermissionEntry(Set set, String permission) { super(set); - this.permission = permission; + this.permission = permission.toLowerCase(); } public PermissionEntry(String permission, Flag... flags) { super(flags); - this.permission = permission; + this.permission = permission.toLowerCase(); } - @Override - public String serializeValue() { - return permission; - } - - public static PermissionEntry deserialize(String string){ + public static PermissionEntry deserialize(String string) { FlagRegistry registry = FlagRegistry.getInstance(); String[] parts = string.split(":"); String[] flags = parts[0].split(",", 2); @@ -68,4 +72,82 @@ public static PermissionEntry deserialize(String string){ } return new PermissionEntry(flagSet, parts[1]); } + + @Override + public String serializeValue() { + return permission; + } + + @SuppressWarnings("Duplicates") + public static class PermissionEntryAdapter extends TypeAdapter { + + private PermissionEntryAdapter() { + } + + @Override + public void write(JsonWriter out, PermissionEntry value) throws IOException { + out.beginObject(); + out.name("set"); + out.beginArray(); + for (Flag flag : value.set) { + out.value(flag.getName()); + } + out.endArray(); + out.name("value"); + out.value(value.serializeValue()); + out.endObject(); + } + + @Override + public PermissionEntry read(JsonReader in) throws IOException { + FlagRegistry registry = FlagRegistry.getInstance(); + Logger logger = FoxGuardMain.instance().getLogger(); + + in.beginObject(); + Set set = new HashSet<>(); + String permission = null; + while (in.peek() != JsonToken.END_OBJECT) { + String name = in.nextName(); + switch (name) { + case "set": { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + break; + } + in.beginArray(); + while (in.peek() != JsonToken.END_ARRAY) { + if(in.peek() == JsonToken.NULL) { + in.nextNull(); + continue; + } + Optional flagOptional = registry.getFlag(in.nextString()); + flagOptional.ifPresent(set::add); + } + in.endArray(); + } + break; + case "value": { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + break; + } + permission = in.nextString(); + } + break; + } + } + in.endObject(); + if (set.isEmpty()) { + // TODO add custom exception for stacktrace + logger.error("Tried to deserialize a TristateEntry with an empty flag set!", new RuntimeException("Error deserializing TristateEntry")); + return null; + } + if (permission == null) { + logger.warn("Deserialized a TristateEntry with a null tristate! Replacing with UNDEFINED."); + permission = "undefined"; + } + + return new PermissionEntry(set, permission); + } + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/TristateEntry.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/TristateEntry.java index bc10f95..c56f23f 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/TristateEntry.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/handler/util/TristateEntry.java @@ -25,10 +25,17 @@ package net.foxdenstudio.sponge.foxguard.plugin.handler.util; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.Flag; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagRegistry; +import org.slf4j.Logger; import org.spongepowered.api.util.Tristate; +import java.io.IOException; import java.util.HashSet; import java.util.Objects; import java.util.Optional; @@ -39,20 +46,23 @@ */ public class TristateEntry extends Entry { + public static final TypeAdapter ADAPTER = new TristateEntryAdapter().nullSafe(); public Tristate tristate; public TristateEntry(Set set, Tristate tristate) { super(set); - this.tristate = tristate; + if (tristate == null) { + FoxGuardMain.instance().getLogger().warn("Tried to instantiate tristate entry with null tristate! Substituting default value UNDEFINED"); + this.tristate = Tristate.UNDEFINED; + } else this.tristate = tristate; } public TristateEntry(Tristate tristate, Flag... flags) { super(flags); - this.tristate = tristate; - } - - public String serializeValue(){ - return tristate.name(); + if (tristate == null) { + FoxGuardMain.instance().getLogger().warn("Tried to instantiate tristate entry with null tristate! Substituting default value UNDEFINED"); + this.tristate = Tristate.UNDEFINED; + } else this.tristate = tristate; } public static TristateEntry deserialize(String string) { @@ -62,11 +72,93 @@ public static TristateEntry deserialize(String string) { Set flagSet = new HashSet<>(); for (String flagName : flags) { Optional flagOptional = registry.getFlag(flagName); - if (flagOptional.isPresent()) { - flagSet.add(flagOptional.get()); + flagOptional.ifPresent(flagSet::add); + } + Tristate tristate; + try { + tristate = Tristate.valueOf(parts[1]); + } catch (IllegalArgumentException e) { + FoxGuardMain.instance().getLogger().error("Error deserializing tristate value \"" + parts[1] + "\"!", e); + FoxGuardMain.instance().getLogger().warn("Substituting default value UNDEFINED"); + tristate = Tristate.UNDEFINED; + } + return new TristateEntry(flagSet, tristate); + } + + public String serializeValue() { + return tristate.name(); + } + + public static class TristateEntryAdapter extends TypeAdapter { + + private TristateEntryAdapter() { + } + + @Override + public void write(JsonWriter out, TristateEntry value) throws IOException { + out.beginObject(); + out.name("set"); + out.beginArray(); + for (Flag flag : value.set) { + out.value(flag.getName()); + } + out.endArray(); + out.name("value"); + out.value(value.serializeValue()); + out.endObject(); + } + + @Override + public TristateEntry read(JsonReader in) throws IOException { + FlagRegistry registry = FlagRegistry.getInstance(); + Logger logger = FoxGuardMain.instance().getLogger(); + + in.beginObject(); + Set set = new HashSet<>(); + Tristate tristate = null; + while (in.peek() != JsonToken.END_OBJECT) { + String name = in.nextName(); + switch (name) { + case "set": { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + break; + } + in.beginArray(); + while (in.peek() != JsonToken.END_ARRAY) { + if(in.peek() == JsonToken.NULL) { + in.nextNull(); + continue; + } + Optional flagOptional = registry.getFlag(in.nextString()); + flagOptional.ifPresent(set::add); + } + in.endArray(); + } + break; + case "value": { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + break; + } + tristate = Tristate.valueOf(in.nextString()); + } + break; + } + } + in.endObject(); + if (set.isEmpty()) { + // TODO add custom exception for stacktrace + logger.error("Tried to deserialize a TristateEntry with an empty flag set!", new RuntimeException("Error deserializing TristateEntry")); + return null; } + if (tristate == null) { + logger.warn("Deserialized a TristateEntry with a null tristate! Replacing with UNDEFINED."); + tristate = Tristate.UNDEFINED; + } + + return new TristateEntry(set, tristate); } - return new TristateEntry(flagSet, Tristate.valueOf(parts[1])); } @Override diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/BlockChangeListener.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/BlockChangeListener.java index 28701ad..21e90a7 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/BlockChangeListener.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/BlockChangeListener.java @@ -28,9 +28,13 @@ import com.flowpowered.math.vector.Vector3i; import net.foxdenstudio.sponge.foxcore.plugin.command.CommandDebug; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; + +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; +import net.foxdenstudio.sponge.foxguard.plugin.util.DebugManager; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.block.BlockSnapshot; @@ -67,6 +71,9 @@ public void handle(ChangeBlockEvent event) throws Exception { || tr.getOriginal().getState().getType().equals(BlockTypes.GRASS) && tr.getFinal().getState().getType().equals(BlockTypes.DIRT)) return; } + + DebugManager.INSTANCE.printEvent(event); + //DebugHelper.printBlockEvent(event); /*FlagOld typeFlag; if (event instanceof ChangeBlockEvent.Modify) typeFlag = FlagOld.BLOCK_MODIFY; @@ -89,8 +96,8 @@ public void handle(ChangeBlockEvent event) throws Exception { FGManager.getInstance().getRegionsInChunkAtPos(world, pos).stream() .filter(region -> region.contains(pos, world)) - .forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) + .forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) .forEach(handlerSet::add)); } else { FGManager.getInstance().getRegionsAtMultiLocI( @@ -99,11 +106,12 @@ public void handle(ChangeBlockEvent event) throws Exception { .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()) - ).forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) + ).forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) .forEach(handlerSet::add)); } - if(handlerSet.size() == 0) return; + if(handlerSet.isEmpty()) return; + User user; if (event.getCause().containsType(Player.class)) { @@ -114,6 +122,8 @@ public void handle(ChangeBlockEvent event) throws Exception { user = null; } + + boolean[] flags = BASE_FLAG_SET.clone(); if (event instanceof ChangeBlockEvent.Modify) flags[MODIFY.id] = true; @@ -125,19 +135,24 @@ public void handle(ChangeBlockEvent event) throws Exception { FlagSet flagSet = new FlagSet(flags); + + Tristate flagState = UNDEFINED; List handlerList = new ArrayList<>(handlerSet); - Collections.sort(handlerList); + handlerList.sort(IHandler.PRIORITY); int currPriority = handlerList.get(0).getPriority(); - Tristate flagState = UNDEFINED; for (IHandler handler : handlerList) { if (handler.getPriority() < currPriority && flagState != UNDEFINED) { break; } - //flagState = flagState.and(handler.handle(user, typeFlag, Optional.of(event)).getState()); - flagState = flagState.and(handler.handle(user, flagSet, ExtraContext.of(event)).getState()); + EventResult result = handler.handle(user, flagSet, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" of type \"" + handler.getUniqueTypeString() + "\" returned null!"); + } currPriority = handler.getPriority(); } -// if(flagState == UNDEFINED) flagState = TRUE; + if (flagState == FALSE) { if (user instanceof Player) { diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/DamageListener.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/DamageListener.java index eb917b0..c24ae95 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/DamageListener.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/DamageListener.java @@ -26,20 +26,18 @@ package net.foxdenstudio.sponge.foxguard.plugin.listener; import com.flowpowered.math.vector.Vector3d; +import com.google.common.collect.ImmutableList; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; -import net.foxdenstudio.sponge.foxguard.plugin.flag.Flag; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.listener.util.FGListenerUtil; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EntityFlagCalculator; +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.entity.hanging.Hanging; -import org.spongepowered.api.entity.living.*; +import org.spongepowered.api.entity.living.Living; import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.entity.vehicle.Boat; -import org.spongepowered.api.entity.vehicle.minecart.Minecart; import org.spongepowered.api.event.EventListener; import org.spongepowered.api.event.cause.Cause; import org.spongepowered.api.event.cause.entity.damage.DamageModifier; @@ -54,8 +52,9 @@ import javax.annotation.Nullable; import java.util.ArrayList; -import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static net.foxdenstudio.sponge.foxguard.plugin.flag.Flags.*; import static org.spongepowered.api.util.Tristate.*; @@ -65,6 +64,7 @@ */ public class DamageListener implements EventListener { + private static final EntityFlagCalculator ENTITY_FLAG_CALCULATOR = EntityFlagCalculator.getInstance(); private static final boolean[] BASE_FLAGS_SOURCE = FlagSet.arrayFromFlags(ROOT, DEBUFF, DAMAGE, ENTITY); private static final boolean[] INVINCIBLE_FLAGS = FlagSet.arrayFromFlags(ROOT, BUFF, INVINCIBLE); private static final FlagSet INVINCIBLE_FLAG_SET = new FlagSet(INVINCIBLE_FLAGS); @@ -80,28 +80,38 @@ public void handle(DamageEntityEvent event) throws Exception { Vector3d pos = event.getTargetEntity().getLocation().getPosition(); Entity entity = event.getTargetEntity(); - List handlerList = new ArrayList<>(); + Set handlerSet = new HashSet<>(); FGManager.getInstance().getRegionsInChunkAtPos(world, pos).stream() .filter(region -> region.contains(pos, world)) - .forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) - .filter(handler -> !handlerList.contains(handler)) - .forEach(handlerList::add)); - - Collections.sort(handlerList); - int currPriority; + .forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) + .forEach(handlerSet::add)); Tristate flagState = UNDEFINED; boolean invincible = false; + + if (handlerSet.isEmpty()) { + FoxGuardMain.instance().getLogger().error("Handlers list is empty for event: " + event); + } + + List handlerList = new ArrayList<>(handlerSet); + handlerList.sort(IHandler.PRIORITY); + + int currPriority; if (entity instanceof Player) { currPriority = handlerList.get(0).getPriority(); for (IHandler handler : handlerList) { if (handler.getPriority() < currPriority && flagState != UNDEFINED) { break; } - flagState = flagState.and(handler.handle((Player) entity, INVINCIBLE_FLAG_SET, ExtraContext.of(event)).getState()); + EventResult result = handler.handle((Player) entity, INVINCIBLE_FLAG_SET, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" of type \"" + handler.getUniqueTypeString() + "\" returned null!"); + } currPriority = handler.getPriority(); } -// if(flagState == UNDEFINED) flagState = FALSE; + if (flagState == TRUE) { invincible = true; flagState = FALSE; @@ -115,7 +125,9 @@ public void handle(DamageEntityEvent event) throws Exception { flags = BASE_FLAGS_SOURCE.clone(); - FGListenerUtil.applyEntityFlags(entity, flags); + //FGListenerUtil.applyEntityFlags(entity, flags); + ENTITY_FLAG_CALCULATOR.applyEntityFlags(ImmutableList.of(entity), flags); + flagSet = new FlagSet(flags); currPriority = handlerList.get(0).getPriority(); @@ -124,7 +136,12 @@ public void handle(DamageEntityEvent event) throws Exception { if (handler.getPriority() < currPriority && flagState != UNDEFINED) { break; } - flagState = flagState.and(handler.handle(player, flagSet, ExtraContext.of(event)).getState()); + EventResult result = handler.handle(player, flagSet, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" of type \"" + handler.getUniqueTypeString() + "\" returned null!"); + } currPriority = handler.getPriority(); } // if(flagState == UNDEFINED) flagState = TRUE; @@ -144,7 +161,12 @@ public void handle(DamageEntityEvent event) throws Exception { if (handler.getPriority() < currPriority && flagState != UNDEFINED) { break; } - flagState = flagState.and(handler.handle((Player) entity, UNDYING_FLAG_SET, ExtraContext.of(event)).getState()); + EventResult result = handler.handle(player, UNDYING_FLAG_SET, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" of type \"" + handler.getUniqueTypeString() + "\" returned null!"); + } currPriority = handler.getPriority(); } // if(flagState == UNDEFINED) flagState = FALSE; @@ -164,7 +186,12 @@ public void handle(DamageEntityEvent event) throws Exception { if (handler.getPriority() < currPriority && flagState != UNDEFINED) { break; } - flagState = flagState.and(handler.handle(player, flagSet, ExtraContext.of(event)).getState()); + EventResult result = handler.handle(player, flagSet, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" of type \"" + handler.getUniqueTypeString() + "\" returned null!"); + } currPriority = handler.getPriority(); } // if(flagState == UNDEFINED) flagState = TRUE; diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/ExplosionListener.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/ExplosionListener.java index 0f5b854..b9ad0d8 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/ExplosionListener.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/ExplosionListener.java @@ -30,7 +30,8 @@ import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.data.Transaction; @@ -61,21 +62,20 @@ public class ExplosionListener implements EventListener { public void handle(ExplosionEvent event) throws Exception { if (!(event instanceof Cancellable) || ((Cancellable) event).isCancelled()) return; - boolean[] flags = FLAG_SET.clone(); Set handlerSet = new HashSet<>(); if (event instanceof ExplosionEvent.Post) { ExplosionEvent.Post postEvent = (ExplosionEvent.Post) event; List> transactions = postEvent.getTransactions(); - if(transactions.size() == 0) return; + if (transactions.size() == 0) return; FGManager.getInstance().getRegionsAtMultiLocI( transactions.stream() .map(trans -> trans.getOriginal().getLocation().get()) .collect(Collectors.toList()) - ).forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) + ).forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) .forEach(handlerSet::add)); flags[POST.id] = true; @@ -84,11 +84,11 @@ public void handle(ExplosionEvent event) throws Exception { } else if (event instanceof ExplosionEvent.Detonate) { ExplosionEvent.Detonate detonateEvent = ((ExplosionEvent.Detonate) event); List> locations = detonateEvent.getAffectedLocations(); - if(locations.size() == 0) return; + if (locations.isEmpty()) return; FGManager.getInstance().getRegionsAtMultiLocI(locations) - .forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) + .forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) .forEach(handlerSet::add)); flags[DETONATE.id] = true; @@ -98,13 +98,13 @@ public void handle(ExplosionEvent event) throws Exception { World world = loc.getExtent(); FGManager.getInstance().getRegionsInChunkAtPos(world, pos).stream() .filter(region -> region.contains(pos, world)) - .forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) + .forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) .forEach(handlerSet::add)); flags[PRE.id] = true; } - if(handlerSet.size() == 0){ + if (handlerSet.isEmpty()) { FoxGuardMain.instance().getLogger().warn("Handlers were empty for explosion listener!"); return; } @@ -115,6 +115,7 @@ public void handle(ExplosionEvent event) throws Exception { } else if (event.getCause().containsType(User.class)) { user = event.getCause().first(User.class).get(); } else { + // Duct tape: Optional explosiveOptional = event.getExplosion().getSourceExplosive(); if (explosiveOptional.isPresent()) { Explosive explosive = explosiveOptional.get(); @@ -128,18 +129,29 @@ public void handle(ExplosionEvent event) throws Exception { } List handlerList = new ArrayList<>(handlerSet); + handlerList.sort(IHandler.PRIORITY); - Collections.sort(handlerList); int currPriority = handlerList.get(0).getPriority(); + Tristate flagState = Tristate.UNDEFINED; FlagSet flagSet = new FlagSet(flags); + for (IHandler handler : handlerList) { if (handler.getPriority() < currPriority && flagState != Tristate.UNDEFINED) { break; } - flagState = flagState.and(handler.handle(user, flagSet, ExtraContext.of(event)).getState()); + + EventResult result = handler.handle(user, flagSet, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" of type \"" + handler.getUniqueTypeString() + "\" returned null!"); + } + currPriority = handler.getPriority(); } + + if (flagState == Tristate.FALSE) { if (user instanceof Player) ((Player) user).sendMessage(ChatTypes.ACTION_BAR, Text.of("You don't have permission!")); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/InteractBlockListener.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/InteractBlockListener.java index 68ab8ea..46ab840 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/InteractBlockListener.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/InteractBlockListener.java @@ -30,7 +30,8 @@ import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import org.spongepowered.api.block.BlockSnapshot; import org.spongepowered.api.block.BlockTypes; @@ -68,8 +69,8 @@ public void handle(InteractBlockEvent event) throws Exception { Set handlerSet = new HashSet<>(); FGManager.getInstance().getRegionsInChunkAtPos(world, pos).stream() .filter(region -> region.contains(pos, world)) - .forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) + .forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) .forEach(handlerSet::add)); if (handlerSet.isEmpty()) { @@ -100,18 +101,23 @@ public void handle(InteractBlockEvent event) throws Exception { FlagSet flagSet = new FlagSet(flags); List handlerList = new ArrayList<>(handlerSet); - Collections.sort(handlerList); + handlerList.sort(IHandler.PRIORITY); + int currPriority = handlerList.get(0).getPriority(); Tristate flagState = UNDEFINED; for (IHandler handler : handlerList) { if (handler.getPriority() < currPriority && flagState != UNDEFINED) { break; } - //flagState = flagState.and(handler.handle(user, typeFlag, Optional.of(event)).getState()); - flagState = flagState.and(handler.handle(user, flagSet, ExtraContext.of(event)).getState()); + + EventResult result = handler.handle(user, flagSet, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" of type \"" + handler.getUniqueTypeString() + "\" returned null!"); + } currPriority = handler.getPriority(); } -// if (flagState == UNDEFINED) flagState = TRUE; if (flagState == FALSE) { if (user instanceof Player) ((Player) user).sendMessage(ChatTypes.ACTION_BAR, Text.of("You don't have permission!")); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/InteractEntityListener.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/InteractEntityListener.java index 0e70da3..aa08b80 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/InteractEntityListener.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/InteractEntityListener.java @@ -26,14 +26,15 @@ package net.foxdenstudio.sponge.foxguard.plugin.listener; import com.flowpowered.math.vector.Vector3d; +import com.google.common.collect.ImmutableList; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.listener.util.FGListenerUtil; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EntityFlagCalculator; +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; -import org.spongepowered.api.entity.Entity; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.event.EventListener; @@ -43,7 +44,10 @@ import org.spongepowered.api.util.Tristate; import org.spongepowered.api.world.World; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import static net.foxdenstudio.sponge.foxguard.plugin.flag.Flags.*; import static org.spongepowered.api.util.Tristate.FALSE; @@ -51,6 +55,7 @@ public class InteractEntityListener implements EventListener { + private static final EntityFlagCalculator ENTITY_FLAG_CALCULATOR = EntityFlagCalculator.getInstance(); private static final boolean[] BASE_FLAG_SET = FlagSet.arrayFromFlags(ROOT, DEBUFF, INTERACT, ENTITY); @Override @@ -63,8 +68,8 @@ public void handle(InteractEntityEvent event) throws Exception { Set handlerSet = new HashSet<>(); FGManager.getInstance().getRegionsInChunkAtPos(world, pos).stream() .filter(region -> region.contains(pos, world)) - .forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) + .forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) .forEach(handlerSet::add)); if (handlerSet.isEmpty()) { @@ -91,23 +96,29 @@ public void handle(InteractEntityEvent event) throws Exception { if (event instanceof InteractEntityEvent.Secondary.MainHand) flags[MAIN.id] = true; else if (event instanceof InteractEntityEvent.Secondary.OffHand) flags[OFF.id] = true; } - Entity entity = event.getTargetEntity(); - FGListenerUtil.applyEntityFlags(entity, flags); + + ENTITY_FLAG_CALCULATOR.applyEntityFlags(ImmutableList.of(event.getTargetEntity()), flags); + FlagSet flagSet = new FlagSet(flags); List handlerList = new ArrayList<>(handlerSet); - Collections.sort(handlerList); + handlerList.sort(IHandler.PRIORITY); + int currPriority = handlerList.get(0).getPriority(); Tristate flagState = UNDEFINED; - for (IHandler handler : handlerList) { + for (IHandler handler : handlerSet) { if (handler.getPriority() < currPriority && flagState != UNDEFINED) { break; } - //flagState = flagState.and(handler.handle(user, typeFlag, Optional.of(event)).getState()); - flagState = flagState.and(handler.handle(user, flagSet, ExtraContext.of(event)).getState()); + + EventResult result = handler.handle(user, flagSet, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" of type \"" + handler.getUniqueTypeString() + "\" returned null!"); + } currPriority = handler.getPriority(); } -// if(flagState == UNDEFINED) flagState = TRUE; if (flagState == FALSE) { if (user instanceof Player) ((Player) user).sendMessage(ChatTypes.ACTION_BAR, Text.of("You don't have permission!")); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/PlayerMoveListenerNew.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/PlayerMoveListener.java similarity index 96% rename from src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/PlayerMoveListenerNew.java rename to src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/PlayerMoveListener.java index d7eb237..f51b7e4 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/PlayerMoveListenerNew.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/PlayerMoveListener.java @@ -61,11 +61,11 @@ * Created by Fox on 1/4/2016. * Project: SpongeForge */ -public class PlayerMoveListenerNew implements EventListener { +public class PlayerMoveListener implements EventListener { private static final boolean[] BASE_FLAG_SET = FlagSet.arrayFromFlags(ROOT, DEBUFF, MOVE); - private static PlayerMoveListenerNew instance; + private static PlayerMoveListener instance; public final boolean full; @@ -84,7 +84,7 @@ public class PlayerMoveListenerNew implements EventListener { }); private final Map hudConfigMap = new WeakCacheMap<>((k, m) -> new HUDConfig()); - public PlayerMoveListenerNew(boolean full) { + public PlayerMoveListener(boolean full) { this.full = full; if (instance == null) instance = this; } @@ -153,7 +153,7 @@ public void handle(@Nonnull MoveEntityEvent event) { if (noToRegions && initialRegions.size() == matchedRegionsCount) return; finalHandlers = finalRegions.stream() - .flatMap(region -> region.getHandlers().stream()) + .flatMap(region -> region.getLinks().stream()) .collect(Collectors.toSet()); for (Player player : passengerStack) { @@ -169,7 +169,7 @@ public void handle(@Nonnull MoveEntityEvent event) { Set fromHandlers, toHandlers = new HashSet<>(); fromHandlers = initialRegions.stream() - .flatMap(region -> region.getHandlers().stream()) + .flatMap(region -> region.getLinks().stream()) .collect(Collectors.toSet()); finalHandlers.forEach(handler -> { if (!fromHandlers.remove(handler)) toHandlers.add(handler); @@ -268,7 +268,7 @@ public HandlerWrapper(@Nonnull IHandler handler, @Nonnull Type type) { @Override public int compareTo(HandlerWrapper w) { - int val = handler.compareTo(w.handler); + int val = IHandler.PRIORITY.compare(handler, w.handler); return val != 0 ? val : type.compareTo(w.type); } @@ -306,7 +306,7 @@ public void renderHUD(Player player, Collection regions, Collection regions, Collection { - - private static final boolean[] ENTER_FLAGS = FlagSet.arrayFromFlags(ROOT, DEBUFF, MOVE, ENTER); - private static final FlagSet ENTER_FLAG_SET = new FlagSet(ENTER_FLAGS); - private static final boolean[] EXIT_FLAGS = FlagSet.arrayFromFlags(ROOT, DEBUFF, MOVE, EXIT); - private static final FlagSet EXIT_FLAG_SET = new FlagSet(EXIT_FLAGS); - - private static final LastWrapper EMPTY_LAST_WRAPPER = new LastWrapper(null, null); - - private static PlayerMoveListenerOld instance; - - public final boolean full; - - private final Map last = new CacheMap<>((key, map) -> EMPTY_LAST_WRAPPER); - private final Map scoreboardMap = new CacheMap<>((k, m) -> { - if (k instanceof Player) { - Scoreboard s = Scoreboard.builder().build(); - Objective o = Objective.builder().criterion(Criteria.DUMMY).name("foxguardhere").displayName(Text.EMPTY).build(); - s.addObjective(o); - s.updateDisplaySlot(o, DisplaySlots.SIDEBAR); - m.put((Player) k, s); - return s; - } else return null; - }); - private final Map hudConfigMap = new CacheMap<>((k, m) -> new HUDConfig()); - - public PlayerMoveListenerOld(boolean full) { - this.full = full; - if (instance == null) instance = this; - } - - @Override - public void handle(@Nonnull MoveEntityEvent event) throws Exception { - - if (event.isCancelled() || event.getTargetEntity().getVehicle().isPresent()) return; - - World world = event.getTargetEntity().getWorld(); - //boolean cancel = false; - - getPassengerStack(event.getTargetEntity()).stream() - .filter(entity -> entity instanceof Player) - .map(entity -> (Player) entity) - .forEach(player -> { - final boolean hud = player.getScoreboard() == scoreboardMap.get(player) && CommandHUD.instance().getIsHUDEnabled().get(player); - final HUDConfig config = this.hudConfigMap.get(player); - final boolean regionHUD = hud && config.regions; - - List fromList = last.get(player).list, toList = new ArrayList<>(); - List regionList = new ArrayList<>(); - Vector3d to = event.getToTransform().getPosition().add(0, 0.1, 0); - if (fromList == null) { - fromList = new ArrayList<>(); - final List temp = fromList; - Vector3d from = event.getFromTransform().getPosition().add(0, 0.1, 0); - FGManager.getInstance().getRegionsInChunkAtPos(world, from).stream() - .filter(region -> region.contains(from, world)) - .forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) - .filter(handler -> !temp.contains(handler)) - .forEach(temp::add)); - } else { - fromList = new ArrayList<>(fromList); - } - FGManager.getInstance().getRegionsInChunkAtPos(world, to).stream() - .filter(region -> region.contains(to, world)) - .forEach(region -> { - if (regionHUD) regionList.add(region); - region.getHandlers().stream() - .filter(IFGObject::isEnabled) - .filter(handler -> !toList.contains(handler)) - .forEach(toList::add); - }); - - final List toComplete = new ArrayList<>(toList); - - final List temp = fromList; - ImmutableList.copyOf(fromList).stream() - .filter(toList::contains) - .forEach(handler -> { - temp.remove(handler); - toList.remove(handler); - }); - List finalList = new ArrayList<>(); - fromList.stream() - .map(handler -> new HandlerWrapper(handler, Type.FROM)) - .forEach(finalList::add); - toList.stream() - .map(handler -> new HandlerWrapper(handler, Type.TO)) - .forEach(finalList::add); - - if (finalList.size() == 0) { - this.last.put(player, new LastWrapper(toComplete, event.getToTransform().getPosition())); - return; - } - - if (full) { - Collections.sort(finalList); - int currPriority = finalList.get(0).handler.getPriority(); - Tristate flagState = Tristate.UNDEFINED; - for (HandlerWrapper wrap : finalList) { - if (wrap.handler.getPriority() < currPriority && flagState != Tristate.UNDEFINED) { - break; - } - EventResult result; - if (wrap.type == Type.FROM) { - result = wrap.handler.handle(player, EXIT_FLAG_SET, ExtraContext.of(event)); - } else - result = wrap.handler.handle(player, ENTER_FLAG_SET, ExtraContext.of(event)); - flagState = flagState.and(result.getState()); - currPriority = wrap.handler.getPriority(); - } - - if (flagState == Tristate.FALSE) { - player.sendMessage(ChatTypes.ACTION_BAR, Text.of("You don't have permission to pass!")); - Vector3d position = this.last.get(player).position; - if (position == null) position = event.getFromTransform().getPosition(); - event.setToTransform(event.getToTransform().setPosition(position)); - } else { - this.last.put(player, new LastWrapper(toComplete, event.getToTransform().getPosition())); - //makes sure that handlers are unable to cancel the event directly. - event.setCancelled(false); - if (hud) { - renderHUD(player, regionList, toComplete, config); - player.setScoreboard(this.scoreboardMap.get(player)); - } - } - } else if (hud) { - renderHUD(player, regionList, toComplete, config); - player.setScoreboard(this.scoreboardMap.get(player)); - } - }); - } - - public void renderHUD(Player player, List regions, List handlers, HUDConfig config) { - this.scoreboardMap.remove(player); - Scoreboard scoreboard = this.scoreboardMap.get(player); - Objective objective = scoreboard.getObjective("foxguardhere").get(); - if (config.regions) { - Collections.sort(regions, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); - if (config.handlers) { - if (config.priority) { - Collections.sort(handlers, (o1, o2) -> o2.getPriority() - o1.getPriority()); - } else { - Collections.sort(handlers, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); - } - objective.setDisplayName(Text.of(TextColors.GOLD, " Regions and Handlers Here ")); - final int total = regions.size() + handlers.size(); - final int regionCount = (int) Math.round(13.0 * regions.size() / total); - final int handlerCount = (int) Math.round(13.0 * handlers.size() / total); - int slot = Math.min(15, total + 2); - Score regionsScore = objective.getOrCreateScore(Text.of(TextColors.GREEN, "Regions (" + player.getWorld().getName() + ") ", - TextColors.YELLOW, "(" + regions.size() + ")")); - regionsScore.setScore(slot--); - for (int i = 0; i < regionCount && i < regions.size(); i++) { - IRegion region = regions.get(i); - Score score = objective.getOrCreateScore(Text.of(FGUtil.getColorForObject(region), - " " + FGUtil.getRegionName(region, false))); - score.setScore(slot--); - } - Score handlersScore = objective.getOrCreateScore(Text.of(TextColors.GREEN, "Handlers " + (config.priority ? "by Priority " : ""), - TextColors.YELLOW, "(" + handlers.size() + ")")); - handlersScore.setScore(slot--); - for (int i = 0; i < handlerCount && i < handlers.size(); i++) { - IHandler handler = handlers.get(i); - Score score = objective.getOrCreateScore(Text.of(FGUtil.getColorForObject(handler), - " " + handler.getShortTypeName() + " : " + handler.getName())); - score.setScore(slot--); - } - - } else { - int slot = regions.size(); - objective.setDisplayName(Text.of(TextColors.GOLD, " Regions Here (" + player.getWorld().getName() + ") ")); - for (IRegion region : regions) { - Score score = objective.getOrCreateScore(Text.of(FGUtil.getColorForObject(region), - " " + FGUtil.getRegionName(region, false))); - score.setScore(slot--); - if (slot <= 0) break; - } - } - } else if (config.handlers) { - if (config.priority) { - objective.setDisplayName(Text.of(TextColors.GOLD, " Handlers Here by Priority ")); - for (IHandler handler : handlers) { - Score score = objective.getOrCreateScore(Text.of(FGUtil.getColorForObject(handler), - " " + handler.getShortTypeName() + " : " + handler.getName())); - score.setScore(handler.getPriority()); - } - } else { - int slot = handlers.size(); - objective.setDisplayName(Text.of(TextColors.GOLD, " Handlers Here ")); - Collections.sort(handlers, (o1, o2) -> o1.getName().compareToIgnoreCase(o2.getName())); - for (IHandler handler : handlers) { - Score score = objective.getOrCreateScore(Text.of(FGUtil.getColorForObject(handler), - " " + handler.getShortTypeName() + " : " + handler.getName())); - score.setScore(slot--); - if (slot <= 0) break; - } - } - } - } - - public Map getHudConfigMap() { - return hudConfigMap; - } - - public void showScoreboard(Player player) { - player.setScoreboard(this.scoreboardMap.get(player)); - } - - public static PlayerMoveListenerOld getInstance() { - return instance; - } - - private static Set getPassengerStack(Entity e) { - Set set = new HashSet<>(); - set.add(e); - List po = e.getPassengers(); - if (!po.isEmpty()) { - for (Entity ent : po) { - set.add(ent); - } - } - return set; - } - - private enum Type { - FROM, TO - } - - private class HandlerWrapper implements Comparable { - public IHandler handler; - public Type type; - - public HandlerWrapper(IHandler handler, Type type) { - this.handler = handler; - this.type = type; - } - - @Override - public int compareTo(HandlerWrapper w) { - int val = handler.compareTo(w.handler); - return val != 0 ? val : type.compareTo(w.type); - } - - @Override - public String toString() { - return this.type + ":" + this.handler; - } - } - - private static class LastWrapper { - public List list; - public Vector3d position; - - public LastWrapper(List list, Vector3d position) { - this.list = list; - this.position = position; - } - } - - public static class HUDConfig { - public boolean regions; - public boolean handlers; - public boolean priority; - - public HUDConfig() { - this(true, true, false); - } - - public HUDConfig(boolean regions, boolean handlers, boolean priority) { - this.regions = regions; - this.handlers = handlers; - this.priority = priority; - } - } - - public class Listeners { - @Listener - public void onJoin(ClientConnectionEvent.Join event) { - last.put(event.getTargetEntity(), new LastWrapper(null, event.getTargetEntity().getTransform().getPosition())); - } - - /*@Listener - public void onPlayerChangeWorld() { - - }*/ - - @Listener - public void onChange(FGUpdateEvent event) { - last.clear(); - } - } -} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/SpawnEntityListener.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/SpawnEntityListener.java index 6d68854..fb911d8 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/SpawnEntityListener.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/SpawnEntityListener.java @@ -27,17 +27,14 @@ import com.flowpowered.math.vector.Vector3d; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; -import net.foxdenstudio.sponge.foxguard.plugin.flag.Flag; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.flag.FlagSet; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EntityFlagCalculator; +import net.foxdenstudio.sponge.foxguard.plugin.listener.util.EventResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.ExtraContext; import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.entity.hanging.Hanging; -import org.spongepowered.api.entity.living.Agent; -import org.spongepowered.api.entity.living.Hostile; -import org.spongepowered.api.entity.living.Human; -import org.spongepowered.api.entity.living.Living; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.entity.living.player.User; import org.spongepowered.api.event.EventListener; @@ -48,31 +45,29 @@ import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import static net.foxdenstudio.sponge.foxguard.plugin.flag.Flags.*; public class SpawnEntityListener implements EventListener { + private static final EntityFlagCalculator ENTITY_FLAG_CALCULATOR = EntityFlagCalculator.getInstance(); private static final boolean[] BASE_FLAG_SET = FlagSet.arrayFromFlags(ROOT, DEBUFF, SPAWN, ENTITY); @Override public void handle(SpawnEntityEvent event) throws Exception { if (event.isCancelled()) return; - if (event.getEntities().isEmpty()) return; - for (Entity entity : event.getEntities()) { + List entities = event.getEntities(); + if (entities.isEmpty()) return; + + for (Entity entity : entities) { if (entity instanceof Player) return; } - User user; - if (event.getCause().containsType(Player.class)) { - user = event.getCause().first(Player.class).get(); - } else if (event.getCause().containsType(User.class)) { - user = event.getCause().first(User.class).get(); - } else { - user = null; - } - Entity oneEntity = event.getEntities().get(0); + //Entity oneEntity = event.getEntities().get(0); /*if (oneEntity instanceof Arrow) { Optional creator = oneEntity.getCreator(), notifier = oneEntity.getNotifier(); @@ -89,54 +84,62 @@ public void handle(SpawnEntityEvent event) throws Exception { } }*/ - boolean[] flags = BASE_FLAG_SET.clone(); - - if (oneEntity instanceof Living) { - flags[LIVING.id] = true; - if (oneEntity instanceof Agent) { - flags[AGENT.id] = true; - if (oneEntity instanceof Hostile) { - flags[HOSTILE.id] = true; - } else if (oneEntity instanceof Human) { - flags[HUMAN.id] = true; - } else { - flags[PASSIVE.id] = true; - } - } - } else if (oneEntity instanceof Hanging) { - flags[HANGING.id] = true; - } - - FlagSet flagSet = new FlagSet(flags); Set handlerSet = new HashSet<>(); - for (Entity entity : event.getEntities()) { + for (Entity entity : entities) { Location loc = entity.getLocation(); Vector3d pos = loc.getPosition(); World world = loc.getExtent(); FGManager.getInstance().getRegionsInChunkAtPos(world, pos).stream() .filter(region -> region.contains(pos, world)) - .forEach(region -> region.getHandlers().stream() - .filter(IFGObject::isEnabled) + .forEach(region -> region.getLinks().stream() + .filter(IGuardObject::isEnabled) .forEach(handlerSet::add)); } + if (handlerSet.isEmpty()) { + FoxGuardMain.instance().getLogger().warn("Handler set is empty for spawn entity listener!"); + return; + } + + User user; + if (event.getCause().containsType(Player.class)) { + user = event.getCause().first(Player.class).get(); + } else if (event.getCause().containsType(User.class)) { + user = event.getCause().first(User.class).get(); + } else { + user = null; + } + + boolean[] flags = BASE_FLAG_SET.clone(); + + ENTITY_FLAG_CALCULATOR.applyEntityFlags(entities, flags); + + FlagSet flagSet = new FlagSet(flags); - //TODO maybe throw a warning - if(handlerSet.size() == 0) return; - ArrayList handlerList = new ArrayList<>(handlerSet); - Collections.sort(handlerList); + List handlerList = new ArrayList<>(handlerSet); + handlerList.sort(IHandler.PRIORITY); int currPriority = handlerList.get(0).getPriority(); Tristate flagState = Tristate.UNDEFINED; + + for (IHandler handler : handlerList) { if (handler.getPriority() < currPriority && flagState != Tristate.UNDEFINED) { break; } - flagState = flagState.and(handler.handle(user, flagSet, ExtraContext.of(event)).getState()); + + EventResult result = handler.handle(user, flagSet, ExtraContext.of(event)); + if (result != null) { + flagState = flagState.and(result.getState()); + } else { + FoxGuardMain.instance().getLogger().error("Handler \"" + handler.getName() + "\" returned null!"); + } + currPriority = handler.getPriority(); } + if (flagState == Tristate.FALSE) { if (user instanceof Player) ((Player) user).sendMessage(ChatTypes.ACTION_BAR, Text.of("You don't have permission!")); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/EntityFlagCalculator.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/EntityFlagCalculator.java index e82828b..9857e8c 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/EntityFlagCalculator.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/EntityFlagCalculator.java @@ -51,7 +51,6 @@ public void applyEntityFlags(Collection entities, boolean[] flags) { mini.apply(flags); } - @SuppressWarnings("Duplicates") private MiniFlagSet getMiniFlag(Map, Entity> types) { MiniFlagSet mini = new MiniFlagSet(); Set totalFlags = new HashSet<>(); @@ -210,7 +209,7 @@ public void apply(boolean[] flagset) { } } - public static void main(String[] args) { + /*public static void main(String[] args) { EntityFlagCalculator calculator = EntityFlagCalculator.getInstance(); FlagRegistry registry = FlagRegistry.getInstance(); Entity entity = (Entity) Proxy.newProxyInstance(EntityFlagCalculator.class.getClassLoader(), @@ -220,5 +219,5 @@ public static void main(String[] args) { for (Flag flag : flags) { System.out.println(flag.name); } - } + }*/ } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/EventResult.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/EventResult.java index ddc6d79..68caff0 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/EventResult.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/EventResult.java @@ -25,6 +25,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.listener.util; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import org.spongepowered.api.util.Tristate; public final class EventResult { @@ -37,7 +38,10 @@ public final class EventResult { private final boolean displayDefaultMessage; private EventResult(Tristate success, boolean displayDefaultMessage) { - this.state = success; + if (success == null) { + FoxGuardMain.instance().getLogger().warn("Tried to instantiate event result with null tristate! Substituting default value UNDEFINED"); + this.state = Tristate.UNDEFINED; + } else this.state = success; this.displayDefaultMessage = displayDefaultMessage; } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/FGListenerUtil.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/FGListenerUtil.java deleted file mode 100644 index 88f5d16..0000000 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/listener/util/FGListenerUtil.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.foxdenstudio.sponge.foxguard.plugin.listener.util; - -import org.spongepowered.api.entity.Entity; -import org.spongepowered.api.entity.hanging.Hanging; -import org.spongepowered.api.entity.living.*; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.entity.vehicle.Boat; -import org.spongepowered.api.entity.vehicle.minecart.Minecart; - -import java.util.Collection; - -import static net.foxdenstudio.sponge.foxguard.plugin.flag.Flags.*; - -public class FGListenerUtil { - - public static void applyEntityFlags(Entity entity, boolean[] flags){ - if (entity instanceof Living) { - flags[LIVING.id] = true; - if (entity instanceof Agent) { - flags[AGENT.id] = true; - if (entity instanceof Hostile) { - flags[HOSTILE.id] = true; - } else if (entity instanceof Human) { - flags[HUMAN.id] = true; - } else { - flags[PASSIVE.id] = true; - } - } else if (entity instanceof Player) { - flags[PLAYER.id] = true; - } else if (entity instanceof ArmorStand) { - flags[ARMORSTAND.id] = true; - } - } else if (entity instanceof Hanging) { - flags[HANGING.id] = true; - } else if (entity instanceof Boat) { - flags[BOAT.id] = true; - } else if (entity instanceof Minecart) { - flags[MINECART.id] = true; - } - } -} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/misc/FGContextCalculator.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/misc/FGContextCalculator.java index e31050e..4cadcb5 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/misc/FGContextCalculator.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/misc/FGContextCalculator.java @@ -26,6 +26,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.misc; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import org.spongepowered.api.Sponge; @@ -54,6 +55,8 @@ public void accumulateContexts(Subject calculable, Set accumulator) { StringBuilder builder = new StringBuilder(); for (Iterator iterator = regions.iterator(); iterator.hasNext(); ) { IRegion region = iterator.next(); + if (region instanceof IGlobal || !region.getOwner().equals(FGManager.SERVER_OWNER)) continue; + if (region instanceof IWorldRegion) { builder.append(((IWorldRegion) region).getWorld().getName()).append(":"); } @@ -76,15 +79,16 @@ public boolean matches(Context context, Subject subject) { String[] parts = regionName.split(":"); Optional worldOptional = Sponge.getServer().getWorld(parts[0]); if (worldOptional.isPresent()) { - IWorldRegion region = fgManager.getWorldRegion(worldOptional.get(), parts[1]); - if (region != null) { - if (!region.contains(player.getLocation().getPosition())) return false; + Optional regionOpt = fgManager.getWorldRegion(worldOptional.get(), parts[1]); + if (regionOpt.isPresent()) { + if (!regionOpt.get().contains(player.getLocation().getPosition())) return false; } else return false; } else return false; } else { - IRegion region = fgManager.getRegion(regionName); - if (region != null) { - if (!region.contains(player.getLocation().getPosition(), player.getWorld())) return false; + Optional regionOpt = fgManager.getRegion(regionName); + if (regionOpt.isPresent()) { + if (!regionOpt.get().contains(player.getLocation().getPosition(), player.getWorld())) + return false; } else return false; } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/FGObjectData.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/FGObjectData.java new file mode 100644 index 0000000..77c3db1 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/FGObjectData.java @@ -0,0 +1,75 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.object; + +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; + +import java.util.UUID; + +public class FGObjectData { + + protected String name; + protected IOwner owner; + protected boolean enabled; + + public FGObjectData(String name, IOwner owner, boolean enabled) { + setName(name).setOwner(owner).setEnabled(enabled); + } + + public FGObjectData() { + this("", FGManager.SERVER_OWNER, true); + } + + public String getName() { + return name; + } + + public FGObjectData setName(String name) { + if (name == null) this.name = ""; + else this.name = name; + return this; + } + + public IOwner getOwner() { + return owner; + } + + public FGObjectData setOwner(IOwner owner) { + if(owner == null) this.owner = FGManager.SERVER_OWNER; + else this.owner = owner; + return this; + } + + public boolean isEnabled() { + return enabled; + } + + public FGObjectData setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/FGObjectBase.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/GuardObjectBase.java similarity index 62% rename from src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/FGObjectBase.java rename to src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/GuardObjectBase.java index af0d462..4538684 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/FGObjectBase.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/GuardObjectBase.java @@ -25,14 +25,23 @@ package net.foxdenstudio.sponge.foxguard.plugin.object; -public abstract class FGObjectBase implements IFGObject { +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; + +import java.util.UUID; + +public abstract class GuardObjectBase implements IGuardObject { protected String name; - protected boolean isEnabled = true; + protected IOwner owner; + protected boolean enabled = true; - public FGObjectBase(String name, boolean isEnabled) { - this.name = name; - this.isEnabled = isEnabled; + public GuardObjectBase(FGObjectData data) { + String name = data.getName(); + this.name = (name == null || name.isEmpty()) ? "null" : name; + IOwner owner = data.getOwner(); + this.owner = owner == null ? FGManager.SERVER_OWNER : owner; + this.enabled = data.isEnabled(); } @Override @@ -45,23 +54,34 @@ public void setName(String name) { this.name = name; } + @Override + public IOwner getOwner() { + return owner; + } + + @Override + public void setOwner(IOwner owner) { + this.owner = owner == null ? FGManager.SERVER_OWNER : owner; + } + @Override public boolean isEnabled() { - return isEnabled; + return enabled; } @Override - public void setIsEnabled(boolean state) { - this.isEnabled = state; + public void setEnabled(boolean state) { + this.enabled = state; } public abstract void markDirty(); @Override public String toString() { - return this.getClass().getSimpleName() + "{" + + return "GuardObjectBase{" + "name='" + name + '\'' + - ", isEnabled=" + isEnabled + + ", owner=" + owner + + ", enabled=" + enabled + '}'; } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/IFGObject.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/IFGObject.java index e7c359f..5b493e4 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/IFGObject.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/IFGObject.java @@ -1,53 +1,19 @@ -/* - * This file is part of FoxGuard, licensed under the MIT License (MIT). - * - * Copyright (c) gravityfox - https://gravityfox.net/ - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - package net.foxdenstudio.sponge.foxguard.plugin.object; -import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; -import net.foxdenstudio.sponge.foxcore.plugin.util.IModifiable; -import net.foxdenstudio.sponge.foxguard.plugin.FGStorageManager; -import net.foxdenstudio.sponge.foxguard.plugin.command.CommandDetail; -import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; -import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; -import org.spongepowered.api.command.CommandException; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.text.Text; -import org.spongepowered.api.world.Location; -import org.spongepowered.api.world.World; +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; + +import javax.annotation.Nonnull; +import java.util.Comparator; +import java.util.UUID; -import javax.annotation.Nullable; -import java.nio.file.Path; -import java.util.List; +public interface IFGObject { -/** - * Interface for all FoxGuard Objects. Inherited by {@link IRegion Regions}, {@link IWorldRegion World Regions}, - * and {@link IHandler Handlers}. - * Essentially the core of the code, this is the most used interface. - */ -public interface IFGObject extends IModifiable { + Comparator OWNER_AND_NAME = (o1, o2) -> { + int ret = o1.getOwner().compareTo(o2.getOwner()); + if (ret != 0) return ret; + return o1.getName().compareToIgnoreCase(o2.getName()); + }; /** * Gets the name of the object. It should be alphanumeric with limited use of special characters. @@ -63,107 +29,17 @@ public interface IFGObject extends IModifiable { */ void setName(String name); - /** - * Gets the short direction name for this object. It should be around four letters. It should be human readable. - * It is used in object lists, such as when using the list or detail commands. - * - * @return The human readable short direction name. - */ - String getShortTypeName(); - - /** - * Gets the long direction name for this object. It should be human readable. Avoid abbreviating. - * It is used in the general information section of the detail command. - * - * @return The human readable long direction name. - */ - String getLongTypeName(); - - /** - * Gets the unique ID for this object. It should be alphabetic only. This return must be static. - * This is used for SQL storage. It is the same identifier used in the object factories. This return should be static. - * - * @return The unique identifier for this direction of object. - */ - String getUniqueTypeString(); - - /** - * Returns whether this object is enabled or disabled. - * - * @return Enable status. - */ - boolean isEnabled(); - - /** - * Sets the enable status of this object. - * - * @param state - */ - void setIsEnabled(boolean state); - - /** - * Gets the details for the object as a SpongeAPI {@link Text} Object. Used in the {@link CommandDetail Detail} command. - * Should be dynamically generated with formatted text. Multiple lines are allowed. - * Any arguments leftover from the detail command are passed to the detail method. - * This allows specific queries in case there is more data stored than can reasonably displayed. - * It is recommended to have click actions wherever possible to ease the configuration of objects. - * - * @param source - * @param arguments The extra arguments from the {@link CommandDetail Detail} command. Object should still return something meaningful if this is empty. - * @return A {@link Text} object that provides meaningful information about the object. - */ - Text details(CommandSource source, String arguments); - - List detailsSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition); + IOwner getOwner(); - /** - * Called when the object is being saved. - * It is completely up to the object how it wants to save itself. - * The only requirement is that it stays within its own directory and is able to load itself later. - * - * @param directory The directory for this object to save to. - */ - void save(Path directory); + void setOwner(IOwner owner); - /** - * Specifies whether FoxGuard should try saving this object. - * This simply involves saving the object to a list, creating a metadata file, - * and then calling {@link IFGObject#save(Path)} - *

- * This should be set to false only when an object already employs some other method of persistence, or simply does not require it. - * This will often be the case if another plugin is hooking into FoxGuard and using an object as a kind of API accessor. - * These object are either transient, or have their own methods of persistence. - *

- * When set to false, FoxGuard will save this object, meaning it will not be loaded on the next server start, - * which means the object must be re-added by some other means, or not at all. - * - * @return Whether FoxGuard should auto-save this object. - */ - @SuppressWarnings("SameReturnValue") - default boolean autoSave() { - return true; + default String getFullName(){ + IOwner owner = getOwner(); + if(owner == null) owner = FGManager.SERVER_OWNER; + return owner.getCommandPath() + ":" + getFilter() + ":" + getName(); } - /** - * This method is called when the modify command is used to try to modify an object. - * This method is essentially a command handler that does a specific job. - *

- * The only really important thing to note is that it is (REALLY) important that an object report a modify result of success if and only if the object was actually modified. - * "Actually modified" implies that the object needs to be saved again. - *

- * This contract is less important if an object implements the {@link IFGObject#shouldSave()} method. - * - * @param source The {@link CommandSource} of the modify command - * @param arguments The {@link String} arguments specifically for this object - * @return the result of the operation. The success flag should be true if and only if the object was changed in some way. - * @throws CommandException If there is an issue parsing the command. - */ - - @Override - ProcessResult modify(CommandSource source, String arguments) throws CommandException; - - default boolean shouldSave() { - return FGStorageManager.getInstance().defaultModifiedMap.get(this); - } + String getFilter(); + boolean stillExists(); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/IGuardObject.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/IGuardObject.java new file mode 100644 index 0000000..16fef0a --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/IGuardObject.java @@ -0,0 +1,163 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.object; + +import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; +import net.foxdenstudio.sponge.foxcore.plugin.util.IModifiable; +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.command.CommandDetail; +import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; +import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGStorageManagerNew; +import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; + +import javax.annotation.Nullable; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.List; +import java.util.UUID; + +/** + * Interface for all FoxGuard Objects. Inherited by {@link IRegion Regions}, {@link IWorldRegion World Regions}, + * and {@link IHandler Handlers}. + * Essentially the core of the code, this is the most used interface. + */ +public interface IGuardObject extends IModifiable, IFGObject { + + /** + * Gets the short direction name for this object. It should be around four letters. It should be human readable. + * It is used in object lists, such as when using the list or detail commands. + * + * @return The human readable short direction name. + */ + String getShortTypeName(); + + /** + * Gets the long direction name for this object. It should be human readable. Avoid abbreviating. + * It is used in the general information section of the detail command. + * + * @return The human readable long direction name. + */ + String getLongTypeName(); + + /** + * Gets the unique ID for this object. It should be alphabetic only. This return must be static. + * This is used for SQL storage. It is the same identifier used in the object factories. This return should be static. + * + * @return The unique identifier for this direction of object. + */ + String getUniqueTypeString(); + + /** + * Returns whether this object is enabled or disabled. + * + * @return Enable status. + */ + boolean isEnabled(); + + /** + * Sets the enable status of this object. + * + * @param state + */ + void setEnabled(boolean state); + + /** + * Gets the details for the object as a SpongeAPI {@link Text} Object. Used in the {@link CommandDetail Detail} command. + * Should be dynamically generated with formatted text. Multiple lines are allowed. + * Any arguments leftover from the detail command are passed to the detail method. + * This allows specific queries in case there is more data stored than can reasonably displayed. + * It is recommended to have click actions wherever possible to ease the configuration of objects. + * + * @param source + * @param arguments The extra arguments from the {@link CommandDetail Detail} command. Object should still return something meaningful if this is empty. + * @return A {@link Text} object that provides meaningful information about the object. + */ + Text details(CommandSource source, String arguments); + + List detailsSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition); + + /** + * Called when the object is being saved. + * It is completely up to the object how it wants to save itself. + * The only requirement is that it stays within its own directory and is able to load itself later. + * + * @param directory The directory for this object to save to. + */ + void save(Path directory); + + /** + * Specifies whether FoxGuard should try saving this object. + * This simply involves saving the object to a list, creating a metadata file, + * and then calling {@link IGuardObject#save(Path)} + *

+ * This should be set to false only when an object already employs some other method of persistence, or simply does not require it. + * This will often be the case if another plugin is hooking into FoxGuard and using an object as a kind of API accessor. + * These object are either transient, or have their own methods of persistence. + *

+ * When set to false, FoxGuard will save this object, meaning it will not be loaded on the next server start, + * which means the object must be re-added by some other means, or not at all. + * + * @return Whether FoxGuard should auto-save this object. + */ + default boolean autoSave() { + return true; + } + + /** + * This method is called when the modify command is used to try to modify an object. + * This method is essentially a command handler that does a specific job. + *

+ * The only really important thing to note is that it is (REALLY) important that an object report a modify result of success if and only if the object was actually modified. + * "Actually modified" implies that the object needs to be saved again. + *

+ * This contract is less important if an object implements the {@link IGuardObject#shouldSave()} method. + * + * @param source The {@link CommandSource} of the modify command + * @param arguments The {@link String} arguments specifically for this object + * @return the result of the operation. Should be true if and only if the object was changed in some way. + * @throws CommandException If there is an issue parsing the command. + */ + + @Override + ProcessResult modify(CommandSource source, String arguments) throws CommandException; + + default boolean shouldSave() { + return FGStorageManagerNew.getInstance().defaultModifiedMap.get(this); + } + + default boolean stillExists(){ + return FGManager.getInstance().contains(this); + } + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ILinkable.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ILinkable.java index e405d9a..9d85af9 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ILinkable.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ILinkable.java @@ -31,12 +31,13 @@ public interface ILinkable { - Collection getHandlers(); + Collection getLinks(); - boolean addHandler(IHandler handler); + boolean addLink(IHandler handler); - boolean removeHandler(IHandler handler); + boolean removeLink(IHandler handler); - void clearHandlers(); + void clearLinks(); + boolean saveLinks(); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/FGFactoryManager.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/FGFactoryManager.java index 8234183..9b4eaae 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/FGFactoryManager.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/FGFactoryManager.java @@ -27,7 +27,9 @@ import com.google.common.collect.ImmutableList; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; +import net.foxdenstudio.sponge.foxguard.plugin.handler.HandlerData; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import org.spongepowered.api.command.CommandException; @@ -70,10 +72,10 @@ public IRegion createRegion(String name, String type, String arguments, CommandS return null; } - public IRegion createRegion(Path directory, String name, String type, boolean isEnabled) { + public IRegion createRegion(Path directory, String type, FGObjectData data) { for (IRegionFactory rf : regionFactories) { if (rf.getType().equalsIgnoreCase(type)) { - IRegion region = rf.create(directory, name, isEnabled); + IRegion region = rf.create(directory, data); if (region != null) return region; } } @@ -90,10 +92,10 @@ public IWorldRegion createWorldRegion(String name, String type, String arguments return null; } - public IWorldRegion createWorldRegion(Path directory, String name, String type, boolean isEnabled) { + public IWorldRegion createWorldRegion(Path directory, String type, FGObjectData data) { for (IWorldRegionFactory wrf : worldRegionFactories) { if (wrf.getType().equalsIgnoreCase(type)) { - IWorldRegion region = wrf.create(directory, name, isEnabled); + IWorldRegion region = wrf.create(directory, data); if (region != null) return region; } } @@ -101,40 +103,40 @@ public IWorldRegion createWorldRegion(Path directory, String name, String type, } - public IHandler createHandler(String name, String type, int priority, String args, CommandSource source) throws CommandException { + public IHandler createHandler(String name, String type, String arguments, CommandSource source) throws CommandException { for (IHandlerFactory hf : handlerFactories) { if (isIn(hf.getAliases(), type)) { - IHandler handler = hf.create(name, priority, args, source); + IHandler handler = hf.create(name, arguments, source); if (handler != null) return handler; } } return null; } - public IHandler createHandler(Path directory, String name, String type, boolean isEnabled, int priority) { + public IHandler createHandler(Path directory, String type, HandlerData data) { for (IHandlerFactory hf : handlerFactories) { if (hf.getType().equalsIgnoreCase(type)) { - IHandler handler = hf.create(directory, name, priority, isEnabled); + IHandler handler = hf.create(directory, data); if (handler != null) return handler; } } return null; } - public IController createController(String name, String type, int priority, String args, CommandSource source) throws CommandException { + public IController createController(String name, String type, String arguments, CommandSource source) throws CommandException { for (IControllerFactory cf : controllerFactories) { if (isIn(cf.getAliases(), type)) { - IController controller = cf.create(name, priority, args, source); + IController controller = cf.create(name, arguments, source); if (controller != null) return controller; } } return null; } - public IController createController(Path directory, String name, String type, boolean isEnabled, int priority) { + public IController createController(Path directory, String type, HandlerData data) { for (IControllerFactory cf : controllerFactories) { if (cf.getType().equalsIgnoreCase(type)) { - IController controller = cf.create(directory, name, priority, isEnabled); + IController controller = cf.create(directory, data); if (controller != null) return controller; } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IControllerFactory.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IControllerFactory.java index 8b06186..9f70b24 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IControllerFactory.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IControllerFactory.java @@ -26,6 +26,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.object.factory; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; +import net.foxdenstudio.sponge.foxguard.plugin.handler.HandlerData; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -37,8 +38,8 @@ public interface IControllerFactory extends IHandlerFactory { @Override - IController create(String name, int priority, String arguments, CommandSource source) throws CommandException; + IController create(String name, String arguments, CommandSource source) throws CommandException; @Override - IController create(Path directory, String name, int priority, boolean isEnabled); + IController create(Path directory, HandlerData data); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IFGFactory.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IFGFactory.java index 62039c8..d85f9f2 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IFGFactory.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IFGFactory.java @@ -25,6 +25,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.object.factory; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.world.Location; @@ -35,6 +36,8 @@ public interface IFGFactory { + IGuardObject create(String name, String arguments, CommandSource source) throws CommandException; + String[] getAliases(); String getType(); diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IHandlerFactory.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IHandlerFactory.java index 6fbc1d9..5e042ca 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IHandlerFactory.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IHandlerFactory.java @@ -26,6 +26,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.object.factory; +import net.foxdenstudio.sponge.foxguard.plugin.handler.HandlerData; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -34,8 +35,9 @@ public interface IHandlerFactory extends IFGFactory { - IHandler create(String name, int priority, String arguments, CommandSource source) throws CommandException; + @Override + IHandler create(String name, String arguments, CommandSource source) throws CommandException; - IHandler create(Path directory, String name, int priority, boolean isEnabled); + IHandler create(Path directory, HandlerData data); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IRegionFactory.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IRegionFactory.java index bea6928..b31781f 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IRegionFactory.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IRegionFactory.java @@ -25,6 +25,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.object.factory; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -36,7 +37,8 @@ */ public interface IRegionFactory extends IFGFactory { + @Override IRegion create(String name, String arguments, CommandSource source) throws CommandException; - IRegion create(Path directory, String name, boolean isEnabled); + IRegion create(Path directory, FGObjectData data); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IWorldRegionFactory.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IWorldRegionFactory.java index 7359df6..e308d87 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IWorldRegionFactory.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/factory/IWorldRegionFactory.java @@ -25,6 +25,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.object.factory; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -33,8 +34,10 @@ public interface IWorldRegionFactory extends IRegionFactory { + @Override IWorldRegion create(String name, String arguments, CommandSource source) throws CommandException; - IWorldRegion create(Path directory, String name, boolean isEnabled); + @Override + IWorldRegion create(Path directory, FGObjectData data); } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/OwnerManager.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/OwnerManager.java new file mode 100644 index 0000000..f17340b --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/OwnerManager.java @@ -0,0 +1,150 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.object.ownerold; + +import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxcore.plugin.util.Aliases; +import net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.provider.*; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.text.Text; + +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; + +import javax.annotation.Nullable; + +/** + * Created by Fox on 12/22/2016. + */ +public class OwnerManager { + + private static OwnerManager instance; + private List ownerProviders; + + public OwnerManager() { + ownerProviders = new ArrayList<>(); + ownerProviders.add(UUIDProvider.getInstance()); + ownerProviders.add(new OnlinePlayerProvider()); + ownerProviders.add(new OfflineUserProvider()); + } + + public static OwnerManager getInstance() { + if (instance == null) instance = new OwnerManager(); + return instance; + } + + public boolean registerProvider(IOwnerProvider provider) { + return !ownerProviders.contains(provider) && ownerProviders.add(provider); + } + + public Optional getProvider(String type) { + for (IOwnerProvider provider : ownerProviders) { + if (Aliases.isIn(provider.getAliases(), type)) { + return Optional.of(provider); + } + } + return Optional.empty(); + } + + public List getProviders() { + return ImmutableList.copyOf(this.ownerProviders); + } + + public Optional getUUIDForOwner(@Nullable String providerType, @Nullable String qualifier) { + if (providerType == null || providerType.isEmpty()) { + if (qualifier == null || qualifier.isEmpty()) { + return Optional.empty();//return Optional.of(FGManager.SERVER_OWNER); + } else { + for (IOwnerProvider provider : ownerProviders) { + Optional ownerOpt = provider.getOwnerUUID(qualifier); + if (ownerOpt.isPresent()) return ownerOpt; + } + return Optional.empty(); + } + } else { + Optional providerOpt = getProvider(providerType); + return providerOpt.flatMap(provider -> provider.getOwnerUUID(qualifier)); + } + } + + public String getDisplayName(UUID owner, @Nullable String providerType, @Nullable CommandSource viewer) { + return getDisplayable(provider -> provider::getDisplayName, + owner.toString(), + owner, providerType, viewer); + } + + public Text getDisplayText(UUID owner, @Nullable String providerType, @Nullable CommandSource viewer) { + return getDisplayable(provider -> provider::getDisplayText, + Text.of(owner.toString()), + owner, providerType, viewer); + } + + public Text getHoverText(UUID owner, @Nullable String providerType, @Nullable CommandSource viewer) { + return getDisplayable(provider -> provider::getHoverText, + Text.of(owner.toString()), + owner, providerType, viewer); + } + + public String getKeyword(UUID owner, @Nullable String providerType) { + Optional keywordOpt = Optional.empty(); + if (providerType == null || providerType.isEmpty()) { + for (IOwnerProvider provider : ownerProviders) { + if (provider == UUIDProvider.getInstance()) continue; + keywordOpt = provider.getKeyword(owner); + if (keywordOpt.isPresent()) break; + } + } else { + keywordOpt = getProvider(providerType) + .flatMap(provider -> provider.getKeyword(owner)); + } + return keywordOpt.orElse(owner.toString()); + } + + private R getDisplayable(Function>> function, + R def, + UUID owner, + @Nullable String providerType, + @Nullable CommandSource viewer) { + Optional returnOpt = Optional.empty(); + if (providerType == null || providerType.isEmpty()) { + for (IOwnerProvider provider : ownerProviders) { + if (provider instanceof IDisplayableOwnerProvider) { + IDisplayableOwnerProvider displayableProvider = (IDisplayableOwnerProvider) provider; + returnOpt = function.apply(displayableProvider).apply(owner, viewer); + if (returnOpt.isPresent()) break; + } + } + } else { + returnOpt = getProvider(providerType) + .filter(provider -> provider instanceof IDisplayableOwnerProvider) + .map(provider -> (IDisplayableOwnerProvider) provider) + .flatMap(provider -> function.apply(provider).apply(owner, viewer)); + } + return returnOpt.orElse(def); + } + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/IDisplayableOwnerProvider.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/IDisplayableOwnerProvider.java new file mode 100644 index 0000000..058cd9b --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/IDisplayableOwnerProvider.java @@ -0,0 +1,57 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.provider; + +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.text.Text; + +import java.util.Optional; +import java.util.UUID; + +import javax.annotation.Nullable; + +/** + * Created by Fox on 8/28/2017. + * Project: SpongeForge + */ +public interface IDisplayableOwnerProvider extends IOwnerProvider { + + default Optional getDisplayName(UUID owner, @Nullable CommandSource viewer) { + if (viewer instanceof Player) + return getKeyword(owner); + else return getKeyword(owner).map(str->str + "(" + owner.toString() + ")"); + } + + default Optional getDisplayText(UUID owner, @Nullable CommandSource viewer) { + return getDisplayName(owner, viewer).map(Text::of); + } + + default Optional getHoverText(UUID owner, @Nullable CommandSource viewer) { + return Optional.of(Text.of(owner.toString())); + } + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/IOwnerProvider.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/IOwnerProvider.java new file mode 100644 index 0000000..196f207 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/IOwnerProvider.java @@ -0,0 +1,54 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.provider; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import javax.annotation.Nullable; + +/** + * Created by Fox on 12/21/2016. + */ +public interface IOwnerProvider { + + List getOwnerKeywords(); + + Optional getOwnerUUID(@Nullable String keyword); + + Optional getKeyword(UUID owner); + + String[] getAliases(); + + default String getPrimaryAlias() { + String[] aliases = getAliases(); + if (aliases.length > 0) { + return aliases[0]; + } else return ""; + } + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/OfflineUserProvider.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/OfflineUserProvider.java new file mode 100644 index 0000000..a3aeb8f --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/OfflineUserProvider.java @@ -0,0 +1,58 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.provider; + +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.profile.GameProfile; +import org.spongepowered.api.service.user.UserStorageService; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.util.GuavaCollectors; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import javax.annotation.Nullable; + +/** + * Created by Fox on 12/31/2016. + */ +public class OfflineUserProvider implements IDisplayableOwnerProvider { + + private static final String[] ALIASES = {"offline", "off", "o"}; + + private final UserStorageService service = FoxGuardMain.instance().getUserStorage(); + + @Override + public List getOwnerKeywords() { + return service.getAll().stream() + .map(GameProfile::getName) + .filter(Optional::isPresent) + .map(Optional::get) + .distinct() + .sorted(String.CASE_INSENSITIVE_ORDER) + .collect(GuavaCollectors.toImmutableList()); + } + + @Override + public Optional getOwnerUUID(@Nullable String keyword) { + if (keyword == null || keyword.isEmpty()) return Optional.empty(); + return service.get(keyword).map(User::getUniqueId); + } + + @Override + public Optional getKeyword(UUID owner) { + return service.get(owner).map(User::getName); + } + + @Override + public String[] getAliases() { + return ALIASES; + } + + @Override + public Optional getDisplayText(UUID owner, @Nullable CommandSource viewer) { + return getDisplayName(owner, viewer).map(name -> Text.of(TextColors.YELLOW, name)); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/OnlinePlayerProvider.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/OnlinePlayerProvider.java new file mode 100644 index 0000000..c9e7c7f --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/OnlinePlayerProvider.java @@ -0,0 +1,59 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.provider; + +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.format.TextColor; +import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.util.GuavaCollectors; +import org.spongepowered.api.util.Identifiable; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * Created by Fox on 12/31/2016. + */ +public class OnlinePlayerProvider implements IDisplayableOwnerProvider { + + private static final String[] ALIASES = {"player", "p"}; + + @Override + public List getOwnerKeywords() { + return Sponge.getServer().getOnlinePlayers().stream() + .map(Player::getName) + .sorted(String.CASE_INSENSITIVE_ORDER) + .collect(GuavaCollectors.toImmutableList()); + } + + @Override + public Optional getOwnerUUID(String keyword) { + if (keyword == null || keyword.isEmpty()) return Optional.empty(); + return Sponge.getServer().getPlayer(keyword).map(Player::getUniqueId); + } + + + @Override + public Optional getKeyword(UUID owner) { + return Sponge.getServer().getPlayer(owner).map(Player::getName); + } + + @Override + public String[] getAliases() { + return ALIASES; + } + + @Override + public Optional getDisplayText(UUID owner, @Nullable CommandSource viewer) { + return getDisplayName(owner, viewer) + .map(name->{ + TextColor color = TextColors.GREEN; + if (viewer instanceof Identifiable && ((Identifiable) viewer).getUniqueId().equals(owner)) + color = TextColors.AQUA; + return Text.of(color, name); + }); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/UUIDProvider.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/UUIDProvider.java new file mode 100644 index 0000000..5b60df7 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/ownerold/provider/UUIDProvider.java @@ -0,0 +1,82 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.provider; + +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +/** + * Created by Fox on 8/28/2017. + * Project: SpongeForge + */ +public class UUIDProvider implements IOwnerProvider { + + public static final String UUID_REGEX = "[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}"; + public static final UUIDProvider INSTANCE = new UUIDProvider(); + private static final String[] ALIASES = {"uuid", "id"}; + + private UUIDProvider() { + } + + public static UUIDProvider getInstance() { + return INSTANCE; + } + + @Override + public List getOwnerKeywords() { + return ImmutableList.of(); + } + + @Override + public Optional getOwnerUUID(String keyword) { + if (keyword == null || keyword.isEmpty()) return Optional.empty(); + if (keyword.matches(UUID_REGEX)) { + return Optional.of(UUID.fromString(keyword)); + } else { + keyword = keyword.replace("-", ""); + if (!keyword.matches("[\\da-f]{32}")) return Optional.empty(); + keyword = keyword.substring(0, 8) + "-" + + keyword.substring(8, 12) + "-" + + keyword.substring(12, 16) + "-" + + keyword.substring(16, 20) + "-" + + keyword.substring(20, 32); + return Optional.of(UUID.fromString(keyword)); + } + } + + @Override + public Optional getKeyword(UUID owner) { + return Optional.of(owner.toString()); + } + + @Override + public String[] getAliases() { + return ALIASES; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/FoxInvalidPathException.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/FoxInvalidPathException.java new file mode 100644 index 0000000..db9a6b2 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/FoxInvalidPathException.java @@ -0,0 +1,21 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path; + +import net.foxdenstudio.sponge.foxguard.plugin.util.FoxException; + +import java.util.List; + +public class FoxInvalidPathException extends FoxException { + + public FoxInvalidPathException(String element, String prefix, List path) { + super(); + } + + private static String message(String element, String prefix, List path){ + StringBuilder pathString = new StringBuilder(prefix).append(path.get(0)); + for (int i = 1; i < path.size(); i++) { + pathString.append("/").append(path.get(i)); + } + return "Element \"" + element+ "\" in path \"" + pathString.toString() + "\" " + + "is invalid" ; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/FoxPath.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/FoxPath.java new file mode 100644 index 0000000..cb364f1 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/FoxPath.java @@ -0,0 +1,251 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path; + +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.owner.DirectLocalOwnerElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.owner.IOwnerPathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.owner.OwnerPathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public final class FoxPath { + + public static final String LOCAL_ALT_CHAR = "~"; + + public static final String LITERAL_PREFIX = "::"; + public static final String DYNAMIC_PREFIX = ":"; + public static final String SERVER_OWNER_PREFIX = "://"; + public static final String LOCAL_OWNER_PREFIX = ":/"; + public static final String LOCAL_OWNER_PREFIX_ALT = ":" + LOCAL_ALT_CHAR + "/"; + public static final String SERVER_GROUP_PREFIX = "//"; + public static final String LOCAL_GROUP_PREFIX = "/"; + public static final String WORKING_PATH_PREFIX = "./"; + + private static final PathManager PATH_MANAGER = PathManager.getInstance(); + + public static final Root DEFAULT_ROOT = Root.SERVER_OWNER; + + private int depth = 0; + private Root root; + private List pathNames = new ArrayList<>(); + private List pathElements = new ArrayList<>(); + + FoxPath(@Nonnull Root rootPath, @Nullable CommandSource source) { + this(rootPath, rootPath.prefixes[0], source); + } + + FoxPath(@Nonnull String rootPrefix, @Nullable CommandSource source) { + this(Root.from(rootPrefix), rootPrefix, source); + } + + private FoxPath(@Nonnull Root rootPath, @Nonnull String prefix, @Nullable CommandSource source) { + this.root = rootPath; + this.pathElements.add(rootPath.apply(source)); + this.pathNames.add(prefix); + } + + @Nonnull + public ResolveResult resolve(@Nonnull String element) { + if (element.equals(".")) return ResolveResult.SUCCESS; + else if (element.equals("..")) { + goUp(); + return ResolveResult.SUCCESS; + } else if (element.startsWith(".")) return ResolveResult.FAILED; + + IPathElement currentElement = this.pathElements.get(depth); + if (currentElement == null) return ResolveResult.FAILED; + + Optional newElementOpt = currentElement.resolve(element); + if (newElementOpt.isPresent()) { + this.pathElements.add(newElementOpt.get()); + this.pathNames.add(element); + this.depth++; + return ResolveResult.SUCCESS; + } else { + this.pathElements.add(null); + this.pathNames.add(element); + this.depth++; + return ResolveResult.PHANTOM; + } + } + + public IPathElement getCurrentElement() { + return this.pathElements.get(this.depth); + } + + + public static Optional getObjects(@Nonnull String input, @Nullable CommandSource source) { + if (input.isEmpty()) return Optional.empty(); + Root rootPath = Root.from(input); + + boolean explicitPath; + if (rootPath == null) { + explicitPath = false; + rootPath = Root.getDefault(); + } else { + explicitPath = true; + input = rootPath.trimPrefix(input); + } + + if (input.isEmpty()) return Optional.empty(); + String[] sections = input.split(":+", explicitPath ? 3 : 2); + if (sections.length == 0) return Optional.empty(); + + String pathStr; + String filterStr; + String name; + + int count = sections.length; + if (explicitPath) { + pathStr = sections[0]; + --count; + } else { + pathStr = null; + } + + if (count != 0) { + name = sections[sections.length - 1]; + --count; + } else { + name = null; + } + + if (count != 0) { + filterStr = sections[sections.length - 2]; + } else { + filterStr = null; + } + + FoxPath foxPath = new FoxPath(rootPath, source); + + if (explicitPath) { + String[] pathParts = pathStr.split("/+"); + ResolveResult resolveResult = ResolveResult.SUCCESS; + for (String part : pathParts) { + if (part.isEmpty()) continue; + resolveResult = foxPath.resolve(part); + } + if (resolveResult != ResolveResult.SUCCESS) { + if (resolveResult == ResolveResult.PHANTOM && name == null) { + name = pathParts[pathParts.length - 1]; + foxPath.goUp(); + } + return Optional.empty(); + } + } + + + return Optional.empty(); + } + + public static Optional getOwner(@Nonnull String input, @Nullable CommandSource source) { + if (input.isEmpty()) return Optional.empty(); + Root rootPath = Root.from(input); + if (rootPath == null) { + rootPath = Root.getDefault(); + } else { + input = rootPath.trimPrefix(input); + } + + //if (input.endsWith(":")) input = input.substring(0, input.length() - 1); + String[] parts = input.split("[/:]+"); + + FoxPath foxPath = new FoxPath(rootPath, source); + IPathElement element; + Optional owner = Optional.empty(); + for (String part : parts) { + if (part.isEmpty()) continue; + element = foxPath.getCurrentElement(); + if (element instanceof IOwnerPathElement) { + IOwnerPathElement ownerElement = ((IOwnerPathElement) element); + Optional newOwner; + if (ownerElement.isFinished()) { + newOwner = ownerElement.getOwner(); + if (newOwner.isPresent()) return newOwner; + } else if (ownerElement.isValid()) { + newOwner = ownerElement.getOwner(); + if (newOwner.isPresent()) owner = newOwner; + } + } + foxPath.resolve(part); + } + element = foxPath.getCurrentElement(); + if (element instanceof IOwnerPathElement && ((IOwnerPathElement) element).isValid()) { + Optional newOwner = ((IOwnerPathElement) element).getOwner(); + if (newOwner.isPresent()) owner = newOwner; + } + + return owner; + } + + private void goUp() { + if (depth == 0) return; + + pathNames.remove(depth); + pathElements.remove(depth); + depth--; + } + + enum ResolveResult { + SUCCESS, FAILED, PHANTOM + } + + public enum Root implements Function { + + SERVER_OWNER(new DirectLocalOwnerElement.Suppier(true), SERVER_OWNER_PREFIX), // -> :// + LOCAL_OWNER(new DirectLocalOwnerElement.Suppier(false), LOCAL_OWNER_PREFIX, LOCAL_OWNER_PREFIX_ALT), // -> :/ :~/ + LITERAL_OWNER(source -> new OwnerPathElement.Literal(LITERAL_PREFIX), LITERAL_PREFIX), // -> :: + DYNAMIC_OWNER(source -> new OwnerPathElement.Dynamic(DYNAMIC_PREFIX, source), DYNAMIC_PREFIX, LOCAL_ALT_CHAR + DYNAMIC_PREFIX), // -> : ~: + SERVER_GROUP(source -> PATH_MANAGER.getServerGroup(), SERVER_GROUP_PREFIX), // -> // + LOCAL_GROUP(PATH_MANAGER::getLocalGroup, LOCAL_GROUP_PREFIX, LOCAL_ALT_CHAR + LOCAL_GROUP_PREFIX), // -> / ~/ + //WORKING_PATH(), + ; + + public final String[] prefixes; + private final Function rootProvider; + + Root(Function rootProvider, String... prefixes) { + this.rootProvider = rootProvider; + this.prefixes = prefixes; + } + + + public String getPrefix(String input) { + for (String prefix : this.prefixes) { + if (input.startsWith(prefix)) return prefix; + } + return ""; + } + + public String trimPrefix(String input) { + return input.substring(getPrefix(input).length()); + } + + public static Root from(String input) { + if (input == null) return null; + for (Root root : values()) { + for (String prefix : root.prefixes) { + if (input.startsWith(prefix)) return root; + } + } + return null; + } + + public static Root getDefault() { + return SERVER_OWNER; + } + + @Override + public IPathElement apply(@Nullable CommandSource source) { + return rootProvider.apply(source); + } + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/PathManager.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/PathManager.java new file mode 100644 index 0000000..f4ab819 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/PathManager.java @@ -0,0 +1,165 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path; + +import com.google.common.collect.ImmutableMap; +import net.foxdenstudio.sponge.foxcore.common.util.CacheMap; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.group.LocalGroupElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.group.ServerGroupElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.OwnerAdapterFactory; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.provider.PathOwnerProvider; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.*; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.User; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Function; + +/** + * Created by fox on 3/7/18. + */ +public class PathManager { + private static PathManager ourInstance = new PathManager(); + private Map> typeClassMap = new HashMap<>(); + private Map, OwnerAdapterFactory> adapterMap = new HashMap<>(); + private Map, PathOwnerProvider.Literal.Factory> literalPathProviderMap = new HashMap<>(); + private Map> dynamicPathProviderMap = new HashMap<>(); + + private Map userLocalGroups = new CacheMap<>((key, map) -> { + if (key instanceof UUID) { + UUID user = ((UUID) key); + LocalGroupElement element = new LocalGroupElement(user); + map.put(user, element); + return element; + } else return null; + }); + private LocalGroupElement serverLocalGroup = new LocalGroupElement(null); + private ServerGroupElement serverGroup = new ServerGroupElement(); + + private Map serverGroupExtensions = new HashMap<>(); + private Map> localGroupExtensions = new HashMap<>(); + + private PathManager() { + registerOwnerType(UUIDOwner.TYPE, UUIDOwner.class, + UUIDOwner.Adapter::new, + UUIDOwner.LiteralPathOwnerProvider::new); + registerOwnerType(NameOwner.TYPE, NameOwner.class, + NameOwner.Adapter::new, + NameOwner.LiteralPathOwnerProvider::new); + registerOwnerType(NumberOwner.TYPE, NumberOwner.class, + NumberOwner.Adapter::new, + NumberOwner.LiteralPathOwnerProvider::new); + + registerServerGroupExtension("s", this.serverLocalGroup); + registerServerGroupExtension("p", new ServerGroupElement.PlayerAccessNameElement()); + registerServerGroupExtension("o", new ServerGroupElement.PlayerAccessOfflineElement()); + registerServerGroupExtension("u", new ServerGroupElement.PlayerAccessUUIDElement()); + } + + public static PathManager getInstance() { + return ourInstance; + } + + public boolean registerOwnerType( + String type, + Class tClass, + OwnerAdapterFactory adapterFactory, + PathOwnerProvider.Literal.Factory pathProviderFactory) { + if (this.typeClassMap.containsKey(type)) return false; + this.typeClassMap.put(type, tClass); + this.adapterMap.put(tClass, adapterFactory); + this.literalPathProviderMap.put(tClass, pathProviderFactory); + return true; + } + + public boolean registerServerGroupExtension(String name, IPathElement provider) { + if (this.serverGroupExtensions.containsKey(name)) return false; + this.serverGroupExtensions.put(name, provider); + return true; + } + + public boolean registerLocalGroupExtension(String name, Function provider) { + if (this.localGroupExtensions.containsKey(name)) return false; + this.localGroupExtensions.put(name, provider); + return true; + } + + @SuppressWarnings("unchecked") + public OwnerAdapterFactory getOwnerTypeAdapterFactory(Class tClass) { + return (OwnerAdapterFactory) this.adapterMap.get(tClass); + } + + public OwnerAdapterFactory getOwnerTypeAdapter(String type) { + return this.adapterMap.get(this.typeClassMap.get(type)); + } + + public Class getTypeClass(String type) { + return this.typeClassMap.get(type); + } + + @SuppressWarnings("unchecked") + public PathOwnerProvider.Literal.Factory getLiteralPathOwnerProvider(Class tClass) { + return (PathOwnerProvider.Literal.Factory) this.literalPathProviderMap.get(tClass); + } + + public PathOwnerProvider.Literal.Factory getLiteralPathOwnerProvider(String type) { + return this.getLiteralPathOwnerProvider(this.typeClassMap.get(type)); + } + + public PathOwnerProvider.Dynamic.Factory getDynamicPathOwnerProvider(String type) { + return this.dynamicPathProviderMap.get(type); + } + + public LocalGroupElement getServerLocalGroup() { + return serverLocalGroup; + } + + public ServerGroupElement getServerGroup() { + return serverGroup; + } + + public LocalGroupElement getUserLocalGroup(@Nonnull UUID user) { + return this.userLocalGroups.get(user); + } + + public LocalGroupElement getLocalGroup(@Nullable UUID user) { + return user == null ? getServerLocalGroup() : getUserLocalGroup(user); + } + + public LocalGroupElement getLocalGroup(@Nullable CommandSource source) { + return source instanceof User ? getUserLocalGroup(((User) source).getUniqueId()) : getServerLocalGroup(); + } + + public Optional getServerGroupExtension(String name) { + return Optional.ofNullable(this.serverGroupExtensions.get(name)); + } + + public Map getServerGroupExtensions() { + return ImmutableMap.copyOf(serverGroupExtensions); + } + + public Optional getLocalGroupExtension(String name, @Nullable UUID user) { + Function func = this.localGroupExtensions.get(name); + if (func != null) return Optional.ofNullable(func.apply(user)); + else return Optional.empty(); + } + + public Map> getLocalGroupExtensions() { + return ImmutableMap.copyOf(localGroupExtensions); + } + + public Map getLocalGroupExtensions(@Nullable UUID user) { + ImmutableMap.Builder map = ImmutableMap.builder(); + for (Map.Entry> entry : this.localGroupExtensions.entrySet()) { + IPathElement element = entry.getValue().apply(user); + if (element != null) { + map.put(entry.getKey(), element); + } + } + return map.build(); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IModifiablePathElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IModifiablePathElement.java new file mode 100644 index 0000000..8e0e383 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IModifiablePathElement.java @@ -0,0 +1,41 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element; + +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; + +import java.util.Optional; + +public interface IModifiablePathElement extends IPathElement { + + @Override + default Optional resolve(String name) { + return resolve(name, false); + } + + Optional resolve(String name, boolean create); + + boolean add(String name, IPathElement path); + + default boolean add(IFGObject object) { + return add(object, object.getName()); + } + + default boolean add(IFGObject object, String name) { + return add(object, name, true); + } + + /** + * Adds object to this path with alternate name. + * The genExtension flag controls whether the type extension should be automatically generated. + * + * @param object the object to add. + * @param name + * @param genExtension + * @return + */ + boolean add(IFGObject object, String name, boolean genExtension); + + boolean remove(IFGObject object); + + boolean remove(IPathElement path); + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IPathElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IPathElement.java new file mode 100644 index 0000000..dd3a9f3 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IPathElement.java @@ -0,0 +1,45 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element; + +import com.google.common.collect.ImmutableMap; +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +public interface IPathElement { + + Optional resolve(String name); + + Optional get(@Nonnull String name, @Nullable World world); + + Collection getPathSuggestions(); + + Map getObjects(); + + /*default Map getObjects(String extension){ + ImmutableMap.Builder builder = ImmutableMap.builder(); + + for(Map.Entry entry : getObjects().entrySet()){ + String name = entry.getKey(); + if(name.endsWith(extension)){ + builder.put(entry); + } + } + + return builder.build(); + }*/ + + /** + * Check whether this is still persistent. + * Paths that are no longer persistent don't lead to anything, + * and can be excluded from suggestions and serialization. + * + * @return Whether this path should continue to persist. + */ + boolean isPersistent(); + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IPathOnlyElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IPathOnlyElement.java new file mode 100644 index 0000000..3097374 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/IPathOnlyElement.java @@ -0,0 +1,28 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element; + +import com.google.common.collect.ImmutableMap; +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Optional; + +public interface IPathOnlyElement extends IPathElement { + + @Override + default Optional get(@Nonnull String name, @Nullable World world) { + return Optional.empty(); + } + + @Override + default Map getObjects() { + return ImmutableMap.of(); + } + + @Override + default boolean isPersistent() { + return false; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/ExtendedGroupElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/ExtendedGroupElement.java new file mode 100644 index 0000000..52d28a6 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/ExtendedGroupElement.java @@ -0,0 +1,21 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.group; + +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; + +import java.util.Map; +import java.util.Optional; + +public abstract class ExtendedGroupElement extends GroupElement { + + public Optional getExtension(String name){ + return Optional.ofNullable(this.getExtensions().get(name)); + } + + public abstract Map getExtensions(); + + @Override + public Optional resolve(String name, boolean create) { + if (name.startsWith(">")) return getExtension(name.substring(1)); + else return super.resolve(name, create); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/GroupElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/GroupElement.java new file mode 100644 index 0000000..78be169 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/GroupElement.java @@ -0,0 +1,100 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.group; + +import com.google.common.collect.ImmutableMap; +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IModifiablePathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; +import org.spongepowered.api.util.GuavaCollectors; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +public class GroupElement implements IModifiablePathElement { + + Map children; + Map objects; + + public GroupElement() { + + } + + @Override + public Optional resolve(String name, boolean create) { + IPathElement ret = this.children.get(name); + if (ret == null && create) { + ret = new GroupElement(); + } + return Optional.ofNullable(ret); + } + + @Override + public boolean add(String name, IPathElement path) { + if (name.startsWith(".")) return false; + + IPathElement prev = this.children.get(name); + if (prev != null) return prev == path; + + this.children.put(name, path); + return true; + } + + @Override + public Optional get(@Nonnull String name, @Nullable World world) { + IFGObject object = this.objects.get(name); + if (object != null) { + return Optional.of(object); + } else return Optional.empty(); + } + + @Override + public boolean add(IFGObject object, String name, boolean genExtension) { + String keyName = name; + if (genExtension) { + keyName += "." + object.getPathExtension(); + } + if (this.objects.containsKey(keyName)) return false; + + this.objects.put(keyName, object); + + return true; + } + + @Override + public boolean remove(IFGObject object) { + return this.objects.values().remove(object); + } + + @Override + public boolean remove(IPathElement path) { + return this.children.values().remove(path); + } + + @Override + public Collection getPathSuggestions() { + return this.children.entrySet().stream() + .filter(e -> e.getValue().isPersistent()) + .map(Map.Entry::getKey) + .sorted() + .collect(GuavaCollectors.toImmutableList()); + } + + @Override + public Map getObjects() { + return ImmutableMap.copyOf(this.objects); + } + + @Override + public boolean isPersistent() { + if (!this.objects.isEmpty()) return true; + + for (IPathElement child : this.children.values()) { + if (child.isPersistent()) return true; + } + return false; + } + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/LocalGroupElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/LocalGroupElement.java new file mode 100644 index 0000000..cf3959b --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/LocalGroupElement.java @@ -0,0 +1,28 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.group; + +import net.foxdenstudio.sponge.foxguard.plugin.object.path.PathManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public class LocalGroupElement extends ExtendedGroupElement { + + public final UUID user; + + public LocalGroupElement(@Nullable UUID user) { + this.user = user; + } + + @Override + public Optional getExtension(String name) { + return PathManager.getInstance().getLocalGroupExtension(name, user); + } + + @Override + public Map getExtensions() { + return PathManager.getInstance().getLocalGroupExtensions(this.user); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/ServerGroupElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/ServerGroupElement.java new file mode 100644 index 0000000..800f0b7 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/ServerGroupElement.java @@ -0,0 +1,124 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.group; + +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.PathManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathOnlyElement; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.profile.GameProfile; +import org.spongepowered.api.service.user.UserStorageService; +import org.spongepowered.api.util.GuavaCollectors; +import org.spongepowered.api.util.Identifiable; + +import java.util.*; + +public class ServerGroupElement extends ExtendedGroupElement { + + @Override + public Optional getExtension(String name) { + return PathManager.getInstance().getServerGroupExtension(name); + } + + @Override + public Map getExtensions() { + return PathManager.getInstance().getServerGroupExtensions(); + } + + public static class PlayerAccessNameElement implements IPathOnlyElement { + + @Override + public Optional resolve(String name) { + Optional playerOptional = Sponge.getServer().getPlayer(name); + + return playerOptional.map(player -> PathManager.getInstance().getUserLocalGroup(player.getUniqueId())); + } + + @Override + public Collection getPathSuggestions() { + return Sponge.getServer().getOnlinePlayers().stream() + .map(User::getName) + .sorted() + .collect(GuavaCollectors.toImmutableList()); + } + } + + public static class PlayerAccessOfflineElement implements IPathOnlyElement { + + @Override + public Optional resolve(String name) { + UserStorageService service = FoxGuardMain.instance().getUserStorage(); + Optional playerOptional = service.get(name); + + return playerOptional.map(player -> PathManager.getInstance().getUserLocalGroup(player.getUniqueId())); + } + + @Override + public Collection getPathSuggestions() { + UserStorageService service = FoxGuardMain.instance().getUserStorage(); + return service.getAll().stream() + .map(org.spongepowered.api.profile.GameProfile::getName) + .filter(Optional::isPresent) + .map(Optional::get) + .sorted() + .collect(GuavaCollectors.toImmutableList()); + } + } + + public static class PlayerAccessUUIDElement implements IPathOnlyElement { + + public static final String UUID_REGEX = "[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}"; + + @Override + public Optional resolve(String name) { + UUID uuid = null; + + if (name.matches(UUID_REGEX)) { + uuid = UUID.fromString(name); + } else { + name = name.replace("-", ""); + if (name.matches("[\\da-f]+")) { + if (name.length() == 32) { + name = name.substring(0, 8) + "-" + + name.substring(8, 12) + "-" + + name.substring(12, 16) + "-" + + name.substring(16, 20) + "-" + + name.substring(20, 32); + uuid = UUID.fromString(name); + } else if (name.length() < 32) { + List candidates = getCandidates(name); + if (candidates.size() == 1) uuid = candidates.get(0); + } + } + } + if (uuid == null) return Optional.empty(); + return Optional.ofNullable(PathManager.getInstance().getUserLocalGroup(uuid)); + } + + @Override + public Collection getPathSuggestions() { + UserStorageService service = FoxGuardMain.instance().getUserStorage(); + + return service.getAll().stream() + .map(Identifiable::getUniqueId) + .map(UUID::toString) + .sorted() + .collect(GuavaCollectors.toImmutableList()); + } + + private List getCandidates(String name) { + UserStorageService service = FoxGuardMain.instance().getUserStorage(); + name = name.replace("-", ""); + + List candidates = new ArrayList<>(); + for (GameProfile profile : service.getAll()) { + UUID id = profile.getUniqueId(); + if (id.toString().replace("-", "").startsWith(name)) { + candidates.add(id); + } + } + return candidates; + } + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/StructuredGroupElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/StructuredGroupElement.java new file mode 100644 index 0000000..864ef9d --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/group/StructuredGroupElement.java @@ -0,0 +1,23 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.group; + +import com.google.common.collect.ImmutableMap; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; + +import java.util.HashMap; +import java.util.Map; + +public class StructuredGroupElement extends GroupElement { + + private Map fixedChildren; + + protected StructuredGroupElement(Map fixedChildren) { + this.children = new HashMap<>(fixedChildren); + this.fixedChildren = ImmutableMap.copyOf(fixedChildren); + } + + @Override + public boolean remove(IPathElement path) { + if (this.fixedChildren.containsValue(path)) return false; + return super.remove(path); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/DirectLocalOwnerElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/DirectLocalOwnerElement.java new file mode 100644 index 0000000..e65dbe0 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/DirectLocalOwnerElement.java @@ -0,0 +1,96 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.owner; + +import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxcore.common.util.CacheMap; +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.UUIDOwner; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Function; + +public class DirectLocalOwnerElement implements IOwnerPathElement { + + private final UUID uuid; + private final IOwner owner; + + public DirectLocalOwnerElement(@Nullable UUID uuid) { + this.uuid = uuid; + owner = uuid == null ? FGManager.SERVER_OWNER : new UUIDOwner(UUIDOwner.USER_GROUP, uuid); + } + + @Override + public Optional resolve(String name) { + return Optional.empty(); + } + + @Override + public Optional get(@Nonnull String name, @Nullable World world) { + //TODO fetch object from manager + return Optional.empty(); + } + + @Override + public Collection getPathSuggestions() { + return ImmutableList.of(); + } + + @Override + public Map getObjects() { + //TODO fetch objects from manager. + return null; + } + + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isValid() { + return true; + } + + public UUID getUuid() { + return uuid; + } + + @Override + public Optional getOwner() { + return Optional.of(owner); + } + + public static class Suppier implements Function { + + private final Map cache = new CacheMap<>((key, map) -> { + if (key == null || key instanceof UUID) { + UUID uuid = ((UUID) key); + DirectLocalOwnerElement element = new DirectLocalOwnerElement(uuid); + map.put(uuid, element); + return element; + } else return null; + }); + private final boolean server; + + public Suppier(boolean server) { + this.server = server; + } + + @Override + public IPathElement apply(CommandSource source) { + return !this.server && source instanceof User ? + cache.get(((User) source).getUniqueId()) : + cache.get(null); + } + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/DirectOwnerElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/DirectOwnerElement.java new file mode 100644 index 0000000..b41749a --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/DirectOwnerElement.java @@ -0,0 +1,57 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.owner; + +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +public class DirectOwnerElement implements IOwnerPathElement { + + @Nonnull + private final IOwner owner; + + public DirectOwnerElement(@Nonnull IOwner owner) { + this.owner = owner; + } + + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isValid() { + return true; + } + + @Override + public Optional getOwner() { + return Optional.of(owner); + } + + @Override + public Optional resolve(String name) { + return Optional.empty(); + } + + @Override + public Optional get(@Nonnull String name, @Nullable World world) { + return owner.getObject(name, world); + } + + @Override + public Collection getPathSuggestions() { + return null; + } + + @Override + public Map getObjects() { + return null; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/IOwnerPathElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/IOwnerPathElement.java new file mode 100644 index 0000000..5c6ead4 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/IOwnerPathElement.java @@ -0,0 +1,21 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.owner; + +import net.foxdenstudio.sponge.foxguard.plugin.object.path.element.IPathElement; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; + +import java.util.Optional; + +public interface IOwnerPathElement extends IPathElement { + + boolean isFinished(); + + boolean isValid(); + + @Override + default boolean isPersistent() { + return false; + } + + Optional getOwner(); + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/OwnerPathElement.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/OwnerPathElement.java new file mode 100644 index 0000000..365d243 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/element/owner/OwnerPathElement.java @@ -0,0 +1,164 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.element.owner; + +import com.google.common.collect.ImmutableMap; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.PathManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.provider.PathOwnerProvider; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.BaseOwner; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; + +public abstract class OwnerPathElement

> implements IOwnerPathElement { + + private static final PathManager MANAGER = PathManager.getInstance(); + + public final String prefix; + protected final OwnerPathElement

parent; + protected final List currentPath; + protected P provider; + + public OwnerPathElement(String prefix) { + this.prefix = prefix; + this.currentPath = new ArrayList<>(); + this.parent = null; + this.provider = null; + } + + private OwnerPathElement(OwnerPathElement

parent, String next) { + this.prefix = parent.prefix; + this.parent = parent; + this.currentPath = new ArrayList<>(parent.currentPath); + this.currentPath.add(next); + } + + @Override + public Optional get(@Nonnull String name, @Nullable World world) { + if (name.isEmpty() || !this.provider.isValid()) return Optional.empty(); + + if (this.parent != null) { + if (name.startsWith(".")) { + String current = this.currentPath.get(this.currentPath.size() - 1); + return this.parent.get(current + name, null); + } + } + IOwner owner = provider.getOwner().orElse(null); + + + // TODO actually lookup the object + + return Optional.empty(); + } + + + @Override + public abstract Optional resolve(String name); + + @Override + public Collection getPathSuggestions() { + return this.provider.getSuggestions(); + } + + @Override + public Map getObjects() { + if (!this.provider.isValid()) return ImmutableMap.of(); + + // TODO actually lookup the object + + return ImmutableMap.of(); + } + + @Override + public boolean isFinished() { + return this.provider != null && this.provider.isFinished(); + } + + @Override + public boolean isValid() { + return this.provider != null && this.provider.isValid(); + } + + @Override + public Optional getOwner() { + return provider.getOwner(); + } + + public static class Literal extends OwnerPathElement> { + + public final String group; + public final String type; + + public Literal(String prefix) { + super(prefix); + this.group = null; + this.type = null; + } + + private Literal(Literal parent, String next) { + super(parent, next); + int size = this.currentPath.size(); + this.group = size > 0 ? this.currentPath.get(0) : null; + this.type = size > 1 ? this.currentPath.get(1) : null; + if (size > 1) { + PathOwnerProvider.Literal.Factory providerFactory = MANAGER.getLiteralPathOwnerProvider(this.type); + if (providerFactory != null) { + this.provider = providerFactory.get(); + this.provider.setGroup(group); + for (int i = 2; i < size; i++) { + String element = this.currentPath.get(i); + this.provider.apply(element); + } + } + } else this.provider = null; + } + + @Override + public Optional resolve(String name) { + //System.out.println(name); + if (name == null || name.isEmpty()) return Optional.empty(); + else return Optional.of(new Literal(this, name)); + } + } + + public static class Dynamic extends OwnerPathElement> { + + public final String type; + public final CommandSource source; + + public Dynamic(String prefix, CommandSource source) { + super(prefix); + this.type = null; + this.source = source; + } + + private Dynamic(Dynamic parent, String next) { + super(parent, next); + this.source = parent.source; + int size = this.currentPath.size(); + + this.type = size > 0 ? this.currentPath.get(0) : null; + + if (size > 0) { + PathOwnerProvider.Dynamic.Factory providerFactory = MANAGER.getDynamicPathOwnerProvider(this.type); + if (providerFactory != null) { + this.provider = providerFactory.get(); + this.provider.setSource(source); + for (int i = 1; i < size; i++) { + String element = this.currentPath.get(i); + this.provider.apply(element); + } + } + } else this.provider = null; + } + + @Override + public Optional resolve(String name) { + if (name == null || name.isEmpty()) return Optional.empty(); + else return Optional.of(new Dynamic(this, name)); + } + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/OwnerAdapterFactory.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/OwnerAdapterFactory.java new file mode 100644 index 0000000..2c08e3c --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/OwnerAdapterFactory.java @@ -0,0 +1,20 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.BaseOwner; + +import java.util.function.BiFunction; + +/** + * Interface for adapter factory. This class does not normally need to be fully implemented, + * as a method reference to a single {@code String} arg constructor is usually sufficient. + * + * @param The type of the owner this factory is supposed to generate adapters for + */ +public interface OwnerAdapterFactory extends BiFunction> { + + @Override + OwnerTypeAdapter apply(String group, Gson gson); + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/OwnerTypeAdapter.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/OwnerTypeAdapter.java new file mode 100644 index 0000000..e6fea23 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/OwnerTypeAdapter.java @@ -0,0 +1,22 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.BaseOwner; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; + +import javax.annotation.Nonnull; + +public abstract class OwnerTypeAdapter extends TypeAdapter { + + public final String group; + protected final Gson gson; + + protected OwnerTypeAdapter(@Nonnull String group, @Nonnull Gson gson) { + this.group = group; + this.gson = gson; + } + + + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/DynamicPathOwnerProviderBase.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/DynamicPathOwnerProviderBase.java new file mode 100644 index 0000000..722dab5 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/DynamicPathOwnerProviderBase.java @@ -0,0 +1,22 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.provider; + +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.BaseOwner; +import org.spongepowered.api.command.CommandSource; + +import javax.annotation.Nullable; +import java.util.Optional; + +public abstract class DynamicPathOwnerProviderBase implements PathOwnerProvider.Dynamic { + + protected CommandSource source; + + @Override + public void setSource(@Nullable CommandSource source) { + this.source = source; + } + + @Override + public Optional getSource() { + return Optional.ofNullable(source); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/LiteralPathOwnerProviderBase.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/LiteralPathOwnerProviderBase.java new file mode 100644 index 0000000..578db09 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/LiteralPathOwnerProviderBase.java @@ -0,0 +1,22 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.provider; + +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.BaseOwner; + +import javax.annotation.Nonnull; + +public abstract class LiteralPathOwnerProviderBase implements PathOwnerProvider.Literal { + + protected String group = "null"; + + @Override + public boolean setGroup(@Nonnull String group) { + if (group.isEmpty()) return false; + this.group = group; + return true; + } + + @Override + public String getGroup() { + return this.group; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/PathOwnerProvider.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/PathOwnerProvider.java new file mode 100644 index 0000000..3ac5556 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/provider/PathOwnerProvider.java @@ -0,0 +1,73 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.provider; + +import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.BaseOwner; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import org.spongepowered.api.command.CommandSource; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +public interface PathOwnerProvider { + boolean apply(String element); + + default Collection getSuggestions() { + return ImmutableList.of(); + } + + int numApplied(); + + boolean isValid(); + + boolean isFinished(); + + int minimumElements(); + + Optional getOwner(); + + interface Dynamic extends PathOwnerProvider{ + + void setSource(@Nullable CommandSource source); + + Optional getSource(); + + /** + * Interface for Provider factory. This class does not normally need to be fully implemented, + * as a method reference to a single arg constructor of type {@code CommandSource} is usually sufficient. + * + * @param The particular type of {@code IOwner} this factory generates providers for. + */ + + interface Factory extends Supplier< Dynamic> { + + @Override + Dynamic get(); + } + } + + interface Literal extends PathOwnerProvider { + + boolean setGroup(@Nonnull String group); + + String getGroup(); + + /** + * Interface for a Literal Provider factory. This class does not normally need to be fully implemented, + * as a method reference to a no-args constructor is usually sufficient. + * + * @param The particular type of {@code BaseOwner} this factory generates providers for. + */ + + interface Factory extends Supplier> { + + @Override + Literal get(); + + } + } + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/BaseOwner.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/BaseOwner.java new file mode 100644 index 0000000..e90d3d8 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/BaseOwner.java @@ -0,0 +1,174 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.PathManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.OwnerAdapterFactory; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.OwnerTypeAdapter; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGStorageManagerNew; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; + +/** + * Created by fox on 3/4/18. + */ +public abstract class BaseOwner implements IOwner { + + public static final String DEFAULT_GROUP = "unknown"; + + protected final String group; + protected final String type; + + protected BaseOwner(@Nonnull String type, @Nonnull String group) { + this.type = type; + this.group = group.isEmpty() ? DEFAULT_GROUP : group; + } + + public String getType() { + return this.type; + } + + public String getGroup() { + return this.group; + } + + @Override + public final Path getDirectory() { + return Paths.get(FGStorageManagerNew.OWNERS_DIR_NAME, group, type).resolve(getPartialDirectory()); + } + + @Override + public String getCommandPath() { + return "::" + this.group + "/" + this.type + "/" + getPartialCommandPath(); + } + + protected abstract Path getPartialDirectory(); + + protected abstract String getPartialCommandPath(); + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BaseOwner baseOwner = (BaseOwner) o; + return Objects.equals(type, baseOwner.type) && + Objects.equals(group, baseOwner.group); + } + + @Override + public int hashCode() { + return Objects.hash(type, group); + } + + @Override + public int compareTo(@Nonnull IOwner o) { + if (o == ServerOwner.SERVER) return 1; + if (o instanceof BaseOwner) { + BaseOwner baseOwner = ((BaseOwner) o); + int compare = this.group.compareTo(baseOwner.group); + if (compare != 0) return compare; + compare = this.type.compareTo(baseOwner.type); + return compare; + } else return 0; + } + + @Override + public String toString() { + return "BaseOwner{" + group + ", " + type + '}'; + } + + public static class Adapter extends TypeAdapter { + + public static final String GROUP_KEY = "group"; + public static final String TYPE_KEY = "type"; + public static final String DATA_KEY = "data"; + + private final TypeAdapter jsonElementTypeAdapter; + private final Gson gson; + + public Adapter(TypeAdapter jsonElementTypeAdapter, Gson gson) { + this.jsonElementTypeAdapter = jsonElementTypeAdapter; + this.gson = gson; + } + + @SuppressWarnings("unchecked") + @Override + public void write(JsonWriter out, BaseOwner value) throws IOException { + if (value == null) { + out.nullValue(); + return; + } + out.beginObject(); + out.name(GROUP_KEY); + out.value(value.group); + out.name(TYPE_KEY); + out.value(value.type); + out.name(DATA_KEY); + + OwnerAdapterFactory factory = PathManager.getInstance().getOwnerTypeAdapterFactory(value.getClass()); + OwnerTypeAdapter adapter = factory.apply(value.group, gson); + adapter.write(out, value); + out.endObject(); + } + + @Override + public BaseOwner read(JsonReader in) throws IOException { + if(in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + String group = null, type = null; + JsonElement tree = null; + BaseOwner owner = null; + + in.beginObject(); + + while (in.hasNext() && in.peek() != JsonToken.END_OBJECT) { + String name = in.nextName(); + switch (name) { + case GROUP_KEY: + group = in.nextString(); + break; + case TYPE_KEY: + type = in.nextString(); + break; + case DATA_KEY: + if (group == null || group.isEmpty() || type == null || type.isEmpty()) { + tree = jsonElementTypeAdapter.read(in); + } else { + OwnerAdapterFactory factory = PathManager.getInstance().getOwnerTypeAdapter(type); + OwnerTypeAdapter adapter = factory.apply(group, gson); + owner = adapter.read(in); + } + + + } + } + in.endObject(); + + if (owner != null) return owner; + + if (group == null || group.isEmpty() || type == null || type.isEmpty()) return null; + + if (tree != null) { + OwnerAdapterFactory factory = PathManager.getInstance().getOwnerTypeAdapter(type); + OwnerTypeAdapter adapter = factory.apply(group, gson); + owner = adapter.fromJsonTree(tree); + } + + return owner; + } + + } + +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/IOwner.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/IOwner.java new file mode 100644 index 0000000..6f820d2 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/IOwner.java @@ -0,0 +1,103 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Optional; + +public interface IOwner extends Comparable { + + Path getDirectory(); + + @Override + String toString(); + + /** + * Get the absolute string to reference this owner, including prefix + * @return + */ + String getCommandPath(); + + @Override + boolean equals(Object owner); + + @Override + int hashCode(); + + default Optional getObject(@Nonnull String name, @Nullable World world) { + FGManager manager = FGManager.getInstance(); + + + + return Optional.empty(); + } + + class Adapter extends TypeAdapter { + + private final TypeAdapter baseOwnerTypeAdapter; + private final Gson gson; + + public Adapter(TypeAdapter baseOwnerTypeAdapter, Gson gson) { + this.baseOwnerTypeAdapter = baseOwnerTypeAdapter; + this.gson = gson; + } + + @Override + public void write(JsonWriter out, IOwner value) throws IOException { + if (value == null || value instanceof ServerOwner) { + out.nullValue(); + } else if (value instanceof BaseOwner) { + baseOwnerTypeAdapter.write(out, (BaseOwner) value); + } else { + out.nullValue(); + FoxGuardMain.instance().getLogger().warn("Failed to serialize an IOwner that isn't a BaseOwner or ServerOwner. Defaulting to server owner"); + } + } + + @Override + public IOwner read(JsonReader in) throws IOException { + if(in.peek() == JsonToken.NULL){ + in.nextNull(); + return ServerOwner.SERVER; + } else { + return baseOwnerTypeAdapter.read(in); + } + } + } + + class Factory implements TypeAdapterFactory { + + public static final Factory INSTANCE = new Factory(); + + private Factory() { + } + + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (BaseOwner.class.isAssignableFrom(type.getRawType())) { + TypeAdapter jsonElementTypeAdapter = gson.getAdapter(JsonElement.class); + BaseOwner.Adapter adapter = new BaseOwner.Adapter(jsonElementTypeAdapter, gson); + return (TypeAdapter) adapter; + } else if (IOwner.class.equals(type.getRawType()) || ServerOwner.class.equals(type.getRawType())) { + TypeAdapter baseOwnerAdapter = gson.getAdapter(BaseOwner.class); + IOwner.Adapter adapter = new IOwner.Adapter(baseOwnerAdapter, gson); + return (TypeAdapter) adapter; + } else return null; + } + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/NameOwner.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/NameOwner.java new file mode 100644 index 0000000..0eb4b29 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/NameOwner.java @@ -0,0 +1,67 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types; + +import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.OwnerTypeAdapter; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; + +public class NameOwner extends SingleKeyComparableOwner { + + public static final String TYPE = "name"; + + protected NameOwner(@Nonnull String group, @Nonnull String name) { + super(TYPE, group, name); + } + + @Override + public Path getPartialDirectory() { + return Paths.get(key); + } + + @Override + protected String getPartialCommandPath() { + return key; + } + + @Override + public String toString() { + return "NameOwner{" + this.group + ", " + this.key + '}'; + } + + public static class Adapter extends OwnerTypeAdapter { + + public Adapter(String group, Gson gson) { + super(group, gson); + } + + @Override + public void write(JsonWriter out, NameOwner value) { + gson.toJson(value.key, value.key.getClass(), out); + } + + @Override + public NameOwner read(JsonReader in) throws IOException { + String name = gson.fromJson(in, String.class); + return new NameOwner(group, name); + } + } + + public static class LiteralPathOwnerProvider extends SingleKeyOwner.LiteralPathOwnerProvider { + + @Override + protected String process(String element) { + return element; + } + + @Override + public Optional getOwner() { + return this.valid ? Optional.of(new NameOwner(group, key)) : Optional.empty(); + } + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/NumberOwner.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/NumberOwner.java new file mode 100644 index 0000000..78d7b3e --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/NumberOwner.java @@ -0,0 +1,72 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types; + +import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.OwnerTypeAdapter; + +import javax.annotation.Nonnull; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; + +public class NumberOwner extends SingleKeyComparableOwner { + + public static final String TYPE = "number"; + + protected NumberOwner(@Nonnull String group, @Nonnull Integer key) { + super(TYPE, group, key); + } + + @Override + protected Path getPartialDirectory() { + return Paths.get(key.toString()); + } + + @Override + protected String getPartialCommandPath() { + return key.toString(); + } + + @Override + public String toString() { + return "NumberOwner{" + this.group + ", " + this.key + '}'; + } + + public static class Adapter extends OwnerTypeAdapter { + + public Adapter(String group, Gson gson) { + super(group, gson); + } + + @Override + public void write(JsonWriter out, NumberOwner value) { + gson.toJson(value.key, value.key.getClass(), out); + } + + @Override + public NumberOwner read(JsonReader in) { + Integer uuid = gson.fromJson(in, Integer.class); + return new NumberOwner(group, uuid); + } + } + + + public static class LiteralPathOwnerProvider extends SingleKeyOwner.LiteralPathOwnerProvider { + + @Override + protected Integer process(String element) { + Integer number = null; + try { + number = Integer.parseInt(element); + } catch (NumberFormatException ignored) { + } + return number; + } + + @Override + public Optional getOwner() { + return this.valid ? Optional.of(new NumberOwner(group, key)) : Optional.empty(); + } + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/ServerOwner.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/ServerOwner.java new file mode 100644 index 0000000..df0505e --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/ServerOwner.java @@ -0,0 +1,40 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types; + +import net.foxdenstudio.sponge.foxguard.plugin.object.path.FoxPath; + +import javax.annotation.Nonnull; +import java.nio.file.Path; +import java.nio.file.Paths; + +public final class ServerOwner implements IOwner { + + public static final ServerOwner SERVER = new ServerOwner(); + + private ServerOwner() { + } + + @Override + public Path getDirectory() { + return Paths.get("."); + } + + @Override + public String toString() { + return "Server-Owner"; + } + + @Override + public String getCommandPath() { + return FoxPath.SERVER_OWNER_PREFIX; + } + + @Override + public int compareTo(@Nonnull IOwner o) { + return equals(o) ? 0 : -1; + } + + @Override + public int hashCode() { + return 42; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/SingleKeyComparableOwner.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/SingleKeyComparableOwner.java new file mode 100644 index 0000000..5ac512b --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/SingleKeyComparableOwner.java @@ -0,0 +1,33 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types; + +import javax.annotation.Nonnull; + +public abstract class SingleKeyComparableOwner> extends SingleKeyOwner { + + protected SingleKeyComparableOwner(@Nonnull String type, @Nonnull String group, @Nonnull T key) { + super(type, group, key); + } + + @Override + public int compareTo(@Nonnull IOwner o) { + if (o == ServerOwner.SERVER) return 1; + if (o instanceof BaseOwner) { + BaseOwner baseOwner = ((BaseOwner) o); + int compare = super.compareTo(baseOwner); + if (compare != 0) return compare; + if (o instanceof SingleKeyComparableOwner) { + SingleKeyComparableOwner comparableOwner = ((SingleKeyComparableOwner) o); + if (this.key.getClass() == comparableOwner.key.getClass()) { + //noinspection unchecked + return this.key.compareTo((T) comparableOwner.key); + } else throw new IllegalStateException("Can't compare two keys of different types! " + + "Expected: " + this.key.getClass() + + ", Actual: " + comparableOwner.key.getClass()); + } else + throw new IllegalStateException("All owners of same type must be the same class! Type-id: \"" + this.type + + "\", Expected-class: " + this.getClass() + + ", Actual-class: " + o.getClass()); + } else + throw new IllegalStateException("All IOwner instances that aren't the server owner must extend BaseOwner"); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/SingleKeyOwner.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/SingleKeyOwner.java new file mode 100644 index 0000000..4a518a7 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/SingleKeyOwner.java @@ -0,0 +1,86 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types; + +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.provider.LiteralPathOwnerProviderBase; + +import javax.annotation.Nonnull; +import java.util.Objects; +import java.util.Optional; + +public abstract class SingleKeyOwner extends BaseOwner { + + protected T key; + + protected SingleKeyOwner(@Nonnull String type, @Nonnull String group, @Nonnull T key) { + super(type, group); + this.key = key; + } + + public T getKey() { + return this.key; + } + + @Override + public String toString() { + return "SingleKeyOwner{" + this.group + ", " + this.type + ", " + this.key + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + SingleKeyOwner owner = (SingleKeyOwner) o; + return Objects.equals(this.key, owner.key); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), this.key); + } + + public static abstract class LiteralPathOwnerProvider extends LiteralPathOwnerProviderBase { + + T key = null; + boolean valid = false; + int count = 0; + + @Override + public boolean apply(String element) { + valid = true; + if (count++ == 0 && element != null && !element.isEmpty()) { + T result = this.process(element); + if (result != null) { + key = result; + return true; + } + } + valid = false; + return false; + } + + protected abstract T process(String element); + + @Override + public int numApplied() { + return count; + } + + @Override + public boolean isValid() { + return this.valid; + } + + @Override + public boolean isFinished() { + return this.valid; + } + + @Override + public int minimumElements() { + return 1; + } + + @Override + public abstract Optional getOwner(); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/UUIDOwner.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/UUIDOwner.java new file mode 100644 index 0000000..3ea7496 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/path/owner/types/UUIDOwner.java @@ -0,0 +1,87 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types; + +import com.google.gson.Gson; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.OwnerTypeAdapter; +import org.spongepowered.api.entity.living.player.User; + +import javax.annotation.Nonnull; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; +import java.util.UUID; + +public class UUIDOwner extends SingleKeyComparableOwner { + + public static final String USER_GROUP = "user"; + public static final String TYPE = "uuid"; + public static final String UUID_REGEX = "[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}"; + + public UUIDOwner(@Nonnull String group, @Nonnull UUID uuid) { + super(TYPE, group, uuid); + } + + public UUIDOwner(User user) { + this(USER_GROUP, user.getUniqueId()); + } + + @Override + public Path getPartialDirectory() { + return Paths.get(key.toString()); + } + + @Override + protected String getPartialCommandPath() { + return key.toString(); + } + + @Override + public String toString() { + return "UUIDOwner{" + this.group + ", " + this.key + '}'; + } + + public static class Adapter extends OwnerTypeAdapter { + + public Adapter(String group, Gson gson) { + super(group, gson); + } + + @Override + public void write(JsonWriter out, UUIDOwner value) { + gson.toJson(value.key, value.key.getClass(), out); + } + + @Override + public UUIDOwner read(JsonReader in) { + UUID uuid = gson.fromJson(in, UUID.class); + return new UUIDOwner(group, uuid); + } + } + + public static class LiteralPathOwnerProvider extends SingleKeyOwner.LiteralPathOwnerProvider { + + @Override + protected UUID process(String element) { + if (element.matches(UUID_REGEX)) { + return UUID.fromString(element); + } else { + element = element.replace("-", ""); + if (element.matches("[\\da-f]{32}")) { + element = element.substring(0, 8) + "-" + + element.substring(8, 12) + "-" + + element.substring(12, 16) + "-" + + element.substring(16, 20) + "-" + + element.substring(20, 32); + return UUID.fromString(element); + } + } + return null; + } + + @Override + public Optional getOwner() { + return this.valid ? Optional.of(new UUIDOwner(group, key)) : Optional.empty(); + } + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/provider/FGBaseProvider.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/provider/FGBaseProvider.java new file mode 100644 index 0000000..9e50737 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/provider/FGBaseProvider.java @@ -0,0 +1,81 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.provider; + +import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; +import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; +import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.util.GuavaCollectors; +import org.spongepowered.api.util.StartsWithPredicate; +import org.spongepowered.api.world.World; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.stream.Stream; + +public class FGBaseProvider implements IObjectProvider { + + public static final String[] PREFIXES = {"r", "wr", "sr", "h", "c"}; + + + @Override + public Collection filter(@Nonnull Collection objects, @Nonnull String prefix, @Nonnull String[] args, @Nonnull CommandSource source) { + Stream stream = objects.stream(); + + switch (prefix) { + case "r": + stream = stream.filter((ifgObject -> { + if (ifgObject instanceof IRegion) { + if (ifgObject instanceof IWorldRegion && args.length > 0 && !args[0].isEmpty()) { + return ((IWorldRegion) ifgObject).getWorld().getName().equalsIgnoreCase(args[0]); + } + return true; + } else return false; + })); + break; + case "wr": + stream = stream.filter((ifgObject -> { + if (ifgObject instanceof IWorldRegion) { + if (args.length > 0 && !args[0].isEmpty()) { + return ((IWorldRegion) ifgObject).getWorld().getName().equalsIgnoreCase(args[0]); + } + return true; + } else return false; + })); + break; + case "sr": + stream = stream.filter((ifgObject -> { + if (ifgObject instanceof IRegion) { + return !(ifgObject instanceof IWorldRegion); + } else return false; + })); + break; + case "h": + stream = stream.filter((ifgObject -> ifgObject instanceof IHandler)); + break; + case "c": + stream = stream.filter((ifgObject -> ifgObject instanceof IController)); + break; + } + + return stream.collect(GuavaCollectors.toImmutableList()); + } + + @Override + public Collection getFilterSuggestions(@Nonnull String prefix, @Nonnull String[] args, @Nonnull CommandSource source) { + if (args.length == 1 && (prefix.equalsIgnoreCase("r") || prefix.equalsIgnoreCase("wr"))) { + return Sponge.getServer().getWorlds().stream() + .map(World::getName) + .filter(new StartsWithPredicate(args[0])) + .collect(GuavaCollectors.toImmutableList()); + } else return ImmutableList.of(); + } + + @Override + public String[] getPrefixes() { + return PREFIXES; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/provider/IObjectProvider.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/provider/IObjectProvider.java new file mode 100644 index 0000000..cd2a239 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/object/provider/IObjectProvider.java @@ -0,0 +1,26 @@ +package net.foxdenstudio.sponge.foxguard.plugin.object.provider; + +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import org.spongepowered.api.command.CommandSource; + +import javax.annotation.Nonnull; +import java.util.Collection; + +public interface IObjectProvider { + + /** + * Method for filtering out objects by filter query. + * + * @param objects the collection to filter. + * @param args the filter arguments + * @param source the command source of the command. + * @return + */ + Collection filter(@Nonnull Collection objects, @Nonnull String prefix, @Nonnull String[] args, @Nonnull CommandSource source); + + + + Collection getFilterSuggestions(@Nonnull String prefix, @Nonnull String[] args, @Nonnull CommandSource source); + + String[] getPrefixes(); +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/GlobalRegion.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/GlobalRegion.java index b4cc93f..7b00150 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/GlobalRegion.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/GlobalRegion.java @@ -29,6 +29,7 @@ import com.flowpowered.math.vector.Vector3i; import com.google.common.collect.ImmutableList; import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -40,14 +41,18 @@ import java.nio.file.Path; import java.util.List; +import static java.lang.Boolean.TRUE; + /** * Created by Fox on 4/2/2016. */ public class GlobalRegion extends RegionBase implements IGlobal { public static final String NAME = "_sglobal"; + private static final FGObjectData DATA = new FGObjectData().setName(NAME).setEnabled(true); + public GlobalRegion() { - super(NAME, true); + super(DATA); } @Override @@ -101,8 +106,8 @@ public boolean isEnabled() { } @Override - public void setIsEnabled(boolean state) { - this.isEnabled = true; + public void setEnabled(boolean state) { + this.enabled = true; } @Override diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/IRegion.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/IRegion.java index a5652b0..d279c81 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/IRegion.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/IRegion.java @@ -26,16 +26,27 @@ package net.foxdenstudio.sponge.foxguard.plugin.region; import net.foxdenstudio.sponge.foxcore.plugin.util.IBounded; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.object.ILinkable; +import java.util.Set; + /** * Created by Fox on 3/29/2016. */ -public interface IRegion extends IFGObject, ILinkable, IBounded { +public interface IRegion extends IGuardObject, ILinkable, IBounded { + + @Override + Set getLinks(); + @Override default boolean saveLinks() { return true; } + @Override + default String getFilter(){ + return "r"; + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/RegionBase.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/RegionBase.java index 6fcc4de..69ef2eb 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/RegionBase.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/RegionBase.java @@ -25,54 +25,54 @@ package net.foxdenstudio.sponge.foxguard.plugin.region; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectBase; +import net.foxdenstudio.sponge.foxguard.plugin.object.GuardObjectBase; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import net.foxdenstudio.sponge.foxguard.plugin.util.RegionCache; import java.util.HashSet; -import java.util.List; import java.util.Set; -public abstract class RegionBase extends FGObjectBase implements IRegion { +public abstract class RegionBase extends GuardObjectBase implements IRegion { private final Set handlers; - protected RegionBase(String name, boolean isEnabled) { - super(name, isEnabled); + protected RegionBase(FGObjectData data) { + super(data); this.handlers = new HashSet<>(); } @Override - public void setIsEnabled(boolean state) { - super.setIsEnabled(state); + public void setEnabled(boolean state) { + super.setEnabled(state); FGManager.getInstance().markDirty(this, RegionCache.DirtyType.MODIFIED); } @Override - public List getHandlers() { - return ImmutableList.copyOf(this.handlers); + public Set getLinks() { + return ImmutableSet.copyOf(this.handlers); } @Override - public boolean addHandler(IHandler handler) { + public boolean addLink(IHandler handler) { return FGManager.getInstance().isRegistered(handler) && this.handlers.add(handler); } @Override - public boolean removeHandler(IHandler handler) { + public boolean removeLink(IHandler handler) { return this.handlers.remove(handler); } @Override - public void clearHandlers() { + public void clearLinks() { this.handlers.clear(); } public void markDirty() { - FGUtil.markRegionDirty(this); + FGUtil.markDirty(this); } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/CuboidRegion.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/CuboidRegion.java index 4a2e4b5..2227cf8 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/CuboidRegion.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/CuboidRegion.java @@ -33,6 +33,7 @@ import net.foxdenstudio.sponge.foxcore.plugin.selection.CuboidSelection; import net.foxdenstudio.sponge.foxcore.plugin.util.BoundingBox3; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.object.factory.IWorldRegionFactory; import net.foxdenstudio.sponge.foxguard.plugin.region.IIterableRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.ISelectableRegion; @@ -43,7 +44,6 @@ import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.command.args.ArgumentParseException; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.world.Locatable; @@ -63,14 +63,14 @@ public class CuboidRegion extends WorldRegionBase implements IIterableRegion, IS private BoundingBox3 boundingBox; - public CuboidRegion(String name, boolean isEnabled, BoundingBox3 boundingBox) { - super(name, isEnabled); + public CuboidRegion(FGObjectData data, BoundingBox3 boundingBox) { + super(data); this.boundingBox = boundingBox; } - public CuboidRegion(String name, List positions, String[] args, CommandSource source) + public CuboidRegion(FGObjectData data, List positions, String[] args, CommandSource source) throws CommandException { - super(name, true); + super(data); List allPositions = new ArrayList<>(positions); Vector3i sourcePos = source instanceof Locatable ? ((Locatable) source).getLocation().getBlockPosition() : Vector3i.ZERO; for (int i = 0; i < args.length - 2; i += 3) { @@ -215,21 +215,6 @@ public CuboidSelection toSelection() { return new CuboidSelection(this.boundingBox); } - private class RegionIterator implements Iterator> { - - Iterator bbIterator = boundingBox.iterator(); - - @Override - public boolean hasNext() { - return bbIterator.hasNext(); - } - - @Override - public Location next() { - return new Location<>(world, bbIterator.next()); - } - } - public static class Factory implements IWorldRegionFactory { private static final String[] cuboidAliases = {"box", "cube", "cuboid", "cuboidal", "rectangularprism", "rectangleprism", "rectprism"}; @@ -239,11 +224,11 @@ public IWorldRegion create(String name, String arguments, CommandSource source) AdvCmdParser.ParseResult parse = AdvCmdParser.builder() .arguments(arguments) .parse(); - return new CuboidRegion(name, FCPUtil.getPositions(source), parse.args, source); + return new CuboidRegion(new FGObjectData().setName(name), FCPUtil.getPositions(source), parse.args, source); } @Override - public IWorldRegion create(Path directory, String name, boolean isEnabled) { + public IWorldRegion create(Path directory, FGObjectData data) { Path boundsFile = directory.resolve("bounds.cfg"); CommentedConfigurationNode root; ConfigurationLoader loader = @@ -263,8 +248,7 @@ public IWorldRegion create(Path directory, String name, boolean isEnabled) { int x2 = root.getNode("upperX").getInt(0); int y2 = root.getNode("upperY").getInt(0); int z2 = root.getNode("upperZ").getInt(0); - return new CuboidRegion(name, isEnabled, new BoundingBox3(new Vector3i(x1, y1, z1), new Vector3i(x2, y2, z2))); - + return new CuboidRegion(data, new BoundingBox3(new Vector3i(x1, y1, z1), new Vector3i(x2, y2, z2))); } @Override @@ -292,4 +276,19 @@ public List createSuggestions(CommandSource source, String arguments, St return ImmutableList.of(parse.current.prefix + "~"); } } + + private class RegionIterator implements Iterator> { + + Iterator bbIterator = boundingBox.iterator(); + + @Override + public boolean hasNext() { + return bbIterator.hasNext(); + } + + @Override + public Location next() { + return new Location<>(world, bbIterator.next()); + } + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/ElevationRegion.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/ElevationRegion.java index b8d9edc..cd2e841 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/ElevationRegion.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/ElevationRegion.java @@ -31,6 +31,7 @@ import net.foxdenstudio.sponge.foxcore.plugin.command.util.AdvCmdParser; import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.object.factory.IWorldRegionFactory; import ninja.leaping.configurate.ConfigurationOptions; import ninja.leaping.configurate.commented.CommentedConfigurationNode; @@ -57,15 +58,15 @@ public class ElevationRegion extends WorldRegionBase { private int upperBound; private int lowerBound; - public ElevationRegion(String name, boolean isEnabled, int lowerBound, int upperBound) { - super(name, isEnabled); + public ElevationRegion(FGObjectData data, int lowerBound, int upperBound) { + super(data); this.upperBound = upperBound; this.lowerBound = lowerBound; } - public ElevationRegion(String name, List positions, String[] args, CommandSource source) + public ElevationRegion(FGObjectData data, List positions, String[] args, CommandSource source) throws CommandException { - super(name, true); + super(data); List allPositions = new ArrayList<>(positions); int sourceY = source instanceof Locatable ? ((Locatable) source).getLocation().getBlockY() : 0; for (String arg : args) { @@ -195,11 +196,11 @@ public IWorldRegion create(String name, String arguments, CommandSource source) AdvCmdParser.ParseResult parse = AdvCmdParser.builder() .arguments(arguments) .parse(); - return new ElevationRegion(name, FCPUtil.getPositions(source), parse.args, source); + return new ElevationRegion(new FGObjectData().setName(name), FCPUtil.getPositions(source), parse.args, source); } @Override - public IWorldRegion create(Path directory, String name, boolean isEnabled) { + public IWorldRegion create(Path directory, FGObjectData data) { Path boundsFile = directory.resolve("bounds.cfg"); CommentedConfigurationNode root; ConfigurationLoader loader = @@ -215,7 +216,7 @@ public IWorldRegion create(Path directory, String name, boolean isEnabled) { } int lower = root.getNode("lower").getInt(0); int upper = root.getNode("upper").getInt(0); - return new ElevationRegion(name, isEnabled, lower, upper); + return new ElevationRegion(data, lower, upper); } @Override diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/EllipticalRegion.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/EllipticalRegion.java index 808fec2..220a635 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/EllipticalRegion.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/EllipticalRegion.java @@ -30,6 +30,7 @@ import com.google.common.collect.ImmutableList; import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; import net.foxdenstudio.sponge.foxcore.plugin.util.BoundingBox2; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.text.Text; @@ -50,8 +51,8 @@ public class EllipticalRegion extends WorldRegionBase { private final double centerX, centerY, width, height; private final double widthSq, heightSq; - public EllipticalRegion(String name, boolean isEnabled, double centerX, double centerY, double height, double width) { - super(name, isEnabled); + public EllipticalRegion(FGObjectData data, double centerX, double centerY, double height, double width) { + super(data); this.centerX = centerX; this.centerY = centerY; this.width = width; diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/GlobalWorldRegion.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/GlobalWorldRegion.java index c31033a..8e69459 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/GlobalWorldRegion.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/GlobalWorldRegion.java @@ -29,6 +29,7 @@ import com.flowpowered.math.vector.Vector3i; import com.google.common.collect.ImmutableList; import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.text.Text; @@ -39,13 +40,17 @@ import java.nio.file.Path; import java.util.List; +import static java.lang.Boolean.TRUE; + public class GlobalWorldRegion extends WorldRegionBase implements IGlobal { public static final String NAME = "_wglobal"; public static final String TYPE = "wglobal"; + private static final FGObjectData DATA = new FGObjectData().setName(NAME).setEnabled(true); + public GlobalWorldRegion() { - super(NAME, true); + super(DATA); } @Override @@ -89,8 +94,8 @@ public boolean isEnabled() { } @Override - public void setIsEnabled(boolean state) { - this.isEnabled = true; + public void setEnabled(boolean state) { + this.enabled = true; } @Override diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/IWorldRegion.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/IWorldRegion.java index e622df1..c3d8614 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/IWorldRegion.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/IWorldRegion.java @@ -35,4 +35,9 @@ public interface IWorldRegion extends IRegion, IWorldBounded { World getWorld(); void setWorld(World world); + + @Override + default String getFilter() { + return "wr/" + getWorld().getName(); + } } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/RectangularRegion.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/RectangularRegion.java index ed282b2..3f943e8 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/RectangularRegion.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/RectangularRegion.java @@ -33,6 +33,7 @@ import net.foxdenstudio.sponge.foxcore.plugin.command.util.ProcessResult; import net.foxdenstudio.sponge.foxcore.plugin.util.BoundingBox2; import net.foxdenstudio.sponge.foxcore.plugin.util.FCPUtil; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.object.factory.IWorldRegionFactory; import net.foxdenstudio.sponge.foxguard.plugin.region.IIterableRegion; import ninja.leaping.configurate.ConfigurationOptions; @@ -42,7 +43,6 @@ import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.command.args.ArgumentParseException; -import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.text.Text; import org.spongepowered.api.text.format.TextColors; import org.spongepowered.api.world.Locatable; @@ -62,14 +62,14 @@ public class RectangularRegion extends WorldRegionBase implements IIterableRegio private BoundingBox2 boundingBox; - public RectangularRegion(String name, boolean isEnabled, BoundingBox2 boundingBox) { - super(name, isEnabled); + public RectangularRegion(FGObjectData data, BoundingBox2 boundingBox) { + super(data); this.boundingBox = boundingBox; } - public RectangularRegion(String name, List positions, String[] args, CommandSource source) + public RectangularRegion(FGObjectData data, List positions, String[] args, CommandSource source) throws CommandException { - super(name, true); + super(data); List allPositions = new ArrayList<>(positions); Vector3i sourcePos = source instanceof Locatable ? ((Locatable) source).getLocation().getBlockPosition() : Vector3i.ZERO; for (int i = 0; i < args.length - 1; i += 2) { @@ -193,31 +193,6 @@ public Iterator> iterator() { return new RegionIterator(); } - private class RegionIterator implements Iterator> { - - Iterator bbIterator = boundingBox.iterator(); - Vector2i vec2 = bbIterator.next(); - int y = 0; - - @Override - public boolean hasNext() { - return vec2 != null; - } - - @Override - public Location next() { - if (hasNext()) { - Location loc = new Location<>(world, vec2.getX(), y, vec2.getY()); - y++; - if (y > 255) { - y = 0; - vec2 = bbIterator.next(); - } - return loc; - } else return null; - } - } - public static class Factory implements IWorldRegionFactory { private static final String[] rectAliases = {"square", "rectangular", "rectangle", "rect"}; @@ -227,11 +202,11 @@ public IWorldRegion create(String name, String arguments, CommandSource source) AdvCmdParser.ParseResult parse = AdvCmdParser.builder() .arguments(arguments) .parse(); - return new RectangularRegion(name, FCPUtil.getPositions(source), parse.args, source); + return new RectangularRegion(new FGObjectData().setName(name), FCPUtil.getPositions(source), parse.args, source); } @Override - public IWorldRegion create(Path directory, String name, boolean isEnabled) { + public IWorldRegion create(Path directory, FGObjectData data) { Path boundsFile = directory.resolve("bounds.cfg"); CommentedConfigurationNode root; ConfigurationLoader loader = @@ -249,7 +224,7 @@ public IWorldRegion create(Path directory, String name, boolean isEnabled) { int z1 = root.getNode("lowerZ").getInt(0); int x2 = root.getNode("upperX").getInt(0); int z2 = root.getNode("upperZ").getInt(0); - return new RectangularRegion(name, isEnabled, new BoundingBox2(new Vector2i(x1, z1), new Vector2i(x2, z2))); + return new RectangularRegion(data, new BoundingBox2(new Vector2i(x1, z1), new Vector2i(x2, z2))); } @Override @@ -278,4 +253,29 @@ public List createSuggestions(CommandSource source, String arguments, St } } + private class RegionIterator implements Iterator> { + + Iterator bbIterator = boundingBox.iterator(); + Vector2i vec2 = bbIterator.next(); + int y = 0; + + @Override + public boolean hasNext() { + return vec2 != null; + } + + @Override + public Location next() { + if (hasNext()) { + Location loc = new Location<>(world, vec2.getX(), y, vec2.getY()); + y++; + if (y > 255) { + y = 0; + vec2 = bbIterator.next(); + } + return loc; + } else return null; + } + } + } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/WorldRegionBase.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/WorldRegionBase.java index 340df3e..975abe1 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/WorldRegionBase.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/region/world/WorldRegionBase.java @@ -25,6 +25,7 @@ package net.foxdenstudio.sponge.foxguard.plugin.region.world; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; import net.foxdenstudio.sponge.foxguard.plugin.region.RegionBase; import org.spongepowered.api.world.World; @@ -32,8 +33,8 @@ public abstract class WorldRegionBase extends RegionBase implements IWorldRegion protected World world; - protected WorldRegionBase(String name, boolean isEnabled) { - super(name, isEnabled); + protected WorldRegionBase(FGObjectData data) { + super(data); } @Override @@ -43,16 +44,14 @@ public World getWorld() { @Override public void setWorld(World world) { - if (this.world == null) { - this.world = world; - } + this.world = world; } @Override public String toString() { return this.getClass().getSimpleName() + "{" + "name='" + name + '\'' + - ", isEnabled=" + isEnabled + + ", enabled=" + enabled + ", world=" + world.getName() + '}'; } diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/ControllersStateField.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/ControllersStateField.java index ae433f6..463e8ba 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/ControllersStateField.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/ControllersStateField.java @@ -32,7 +32,7 @@ import net.foxdenstudio.sponge.foxcore.plugin.state.SourceState; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -51,6 +51,7 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; public class ControllersStateField extends ListStateFieldBase { @@ -68,7 +69,7 @@ public Text currentState(CommandSource source) { IController controller = it.next(); if (source instanceof Player) { builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s c remove " + controller.getName()), + TextActions.runCommand("/foxguard s c remove " + controller.getFullName()), TextActions.showText(Text.of("Remove from Handler State Buffer")), " [-] ")); } @@ -113,21 +114,21 @@ public List modifySuggestions(CommandSource source, String arguments, @N .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) { - return ImmutableList.of("add", "remove").stream() + return Stream.of("add", "remove") .filter(new StartsWithPredicate(parse.current.token)) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.index == 1) { if (parse.args[0].equals("add")) { return FGManager.getInstance().getControllers().stream() .filter(handler -> !this.list.contains(handler)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .sorted(String.CASE_INSENSITIVE_ORDER) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.args[0].equals("remove")) { return this.list.stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -166,9 +167,10 @@ public ProcessResult add(CommandSource source, String arguments) throws CommandE AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).parse(); if (parse.args.length < 1) throw new CommandException(Text.of("Must specify a name!")); - IController controller = FGManager.getInstance().getController(parse.args[0]); - if (controller == null) + Optional controllerOpt = FGManager.getInstance().getController(parse.args[0]); + if (!controllerOpt.isPresent()) throw new ArgumentParseException(Text.of("No controllers with this name!"), parse.args[0], 1); + IController controller = controllerOpt.get(); if (this.list.contains(controller)) throw new ArgumentParseException(Text.of("Controller is already in your state buffer!"), parse.args[0], 1); this.list.add(controller); @@ -185,7 +187,7 @@ public ProcessResult remove(CommandSource source, String arguments) throws Comma int index = Integer.parseInt(parse.args[0]); controller = this.list.get(index - 1); } catch (NumberFormatException e) { - controller = FGManager.getInstance().getController(parse.args[0]); + controller = FGManager.getInstance().getController(parse.args[0]).orElse(null); } catch (IndexOutOfBoundsException e) { throw new ArgumentParseException(Text.of("Index out of bounds! (1 - " + this.list.size()), parse.args[0], 1); } @@ -203,7 +205,7 @@ public ProcessResult remove(CommandSource source, String arguments) throws Comma int index = Integer.parseInt(arg); controller = this.list.get(index - 1); } catch (NumberFormatException e) { - controller = FGManager.getInstance().getController(arg); + controller = FGManager.getInstance().getController(arg).orElse(null); } catch (IndexOutOfBoundsException e) { failures++; continue; @@ -238,7 +240,7 @@ public List removeSuggestions(CommandSource source, String arguments) th if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) return this.list.stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.COMPLETE)) diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/HandlersStateField.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/HandlersStateField.java index eae039b..5fba0f5 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/HandlersStateField.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/HandlersStateField.java @@ -32,7 +32,7 @@ import net.foxdenstudio.sponge.foxcore.plugin.state.SourceState; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; @@ -51,6 +51,7 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; public class HandlersStateField extends ListStateFieldBase { @@ -68,7 +69,7 @@ public Text currentState(CommandSource source) { IHandler handler = it.next(); if (source instanceof Player) { builder.append(Text.of(TextColors.RED, - TextActions.runCommand("/foxguard s h remove " + handler.getName()), + TextActions.runCommand("/foxguard s h remove " + handler.getFullName()), TextActions.showText(Text.of("Remove from Handler State Buffer")), " [-] ")); } @@ -113,21 +114,21 @@ public List modifySuggestions(CommandSource source, String arguments, @N .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) { - return ImmutableList.of("add", "remove").stream() + return Stream.of("add", "remove") .filter(new StartsWithPredicate(parse.current.token)) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.index == 1) { if (parse.args[0].equals("add")) { return FGManager.getInstance().getHandlers().stream() .filter(handler -> !this.list.contains(handler)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .sorted(String.CASE_INSENSITIVE_ORDER) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); } else if (parse.args[0].equals("remove")) { return this.list.stream() - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -167,9 +168,10 @@ public ProcessResult add(CommandSource source, String arguments) throws CommandE AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).parse(); if (parse.args.length < 1) throw new CommandException(Text.of("Must specify a name!")); - IHandler handler = FGManager.getInstance().gethandler(parse.args[0]); - if (handler == null) + Optional handlerOpt = FGManager.getInstance().getHandler(parse.args[0]); + if (!handlerOpt.isPresent()) throw new ArgumentParseException(Text.of("No handlers with this name!"), parse.args[0], 1); + IHandler handler = handlerOpt.get(); if (this.list.contains(handler)) throw new ArgumentParseException(Text.of("Handler is already in your state buffer!"), parse.args[0], 1); this.list.add(handler); @@ -186,7 +188,7 @@ public ProcessResult remove(CommandSource source, String arguments) throws Comma int index = Integer.parseInt(parse.args[0]); handler = this.list.get(index - 1); } catch (NumberFormatException e) { - handler = FGManager.getInstance().gethandler(parse.args[0]); + handler = FGManager.getInstance().getHandler(parse.args[0]).orElse(null); } catch (IndexOutOfBoundsException e) { throw new ArgumentParseException(Text.of("Index out of bounds! (1 - " + this.list.size()), parse.args[0], 1); } @@ -204,7 +206,7 @@ public ProcessResult remove(CommandSource source, String arguments) throws Comma int index = Integer.parseInt(arg); handler = this.list.get(index - 1); } catch (NumberFormatException e) { - handler = FGManager.getInstance().gethandler(arg); + handler = FGManager.getInstance().getHandler(arg).orElse(null); } catch (IndexOutOfBoundsException e) { failures++; continue; diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/RegionsStateField.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/RegionsStateField.java index a8d43b1..df50d97 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/RegionsStateField.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/state/RegionsStateField.java @@ -32,7 +32,7 @@ import net.foxdenstudio.sponge.foxcore.plugin.state.ListStateFieldBase; import net.foxdenstudio.sponge.foxcore.plugin.state.SourceState; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; @@ -54,6 +54,7 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.WORLD_ALIASES; import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.isIn; @@ -85,12 +86,12 @@ public Text currentState(CommandSource source) { builder.append(Text.of(TextColors.RED, TextActions.runCommand("/foxguard s r remove " + FGUtil.genWorldFlag(region) + - region.getName()), + region.getFullName()), TextActions.showText(Text.of("Remove from State Buffer")), " [-] ")); } builder.append(Text.of(FGUtil.getColorForObject(region), - (index++) + ": " + FGUtil.getRegionName(region, true))); + (index++) + ": " + FGUtil.getObjectDisplayName(region, true, null, source))); if (regionIterator.hasNext()) builder.append(Text.NEW_LINE); } return builder.build(); @@ -111,8 +112,8 @@ public ProcessResult modify(CommandSource source, String arguments) throws Comma .parseLastFlags(false) .leaveFinalAsIs(true) .parse(); - String newArgs = parse.args.length > 1 ? parse.args[1] : ""; if (parse.args.length > 0) { + String newArgs = parse.args.length > 1 ? parse.args[1] : ""; if (parse.args[0].equalsIgnoreCase("add")) { return add(source, newArgs); } else if (parse.args[0].equalsIgnoreCase("remove")) { @@ -134,7 +135,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N .parse(); if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.ARGUMENT)) { if (parse.current.index == 0) { - return ImmutableList.of("add", "remove").stream() + return Stream.of("add", "remove") .filter(new StartsWithPredicate(parse.current.token)) .collect(GuavaCollectors.toImmutableList()); } else if (parse.current.index == 1) { @@ -150,14 +151,14 @@ public List modifySuggestions(CommandSource source, String arguments, @N if (parse.args[0].equals("add")) { if (world == null) return FGManager.getInstance().getRegions().stream() .filter(region -> !this.list.contains(region)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .sorted(String.CASE_INSENSITIVE_ORDER) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); else return FGManager.getInstance().getAllRegions(world).stream() .filter(region -> !this.list.contains(region)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .sorted(String.CASE_INSENSITIVE_ORDER) .map(args -> parse.current.prefix + args) @@ -166,7 +167,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N final World finalWorld = world; return this.list.stream() .filter(region -> !(region instanceof IWorldRegion) || finalWorld != null && ((IWorldRegion) region).getWorld().equals(finalWorld)) - .map(IFGObject::getName) + .map(IGuardObject::getName) .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -174,7 +175,7 @@ public List modifySuggestions(CommandSource source, String arguments, @N } } else if (parse.current.type.equals(AdvCmdParser.CurrentElement.ElementType.LONGFLAGKEY)) - return ImmutableList.of("world").stream() + return Stream.of("world") .filter(new StartsWithPredicate(parse.current.token)) .map(args -> parse.current.prefix + args) .collect(GuavaCollectors.toImmutableList()); @@ -201,7 +202,7 @@ public List getScoreboardText() { int[] index = {1}; return this.list.stream() .map(region -> Text.of(FGUtil.getColorForObject(region), - " " + index[0]++ + ": " + FGUtil.getRegionName(region, true))) + " " + index[0]++ + ": " + FGUtil.getObjectDisplayName(region,true, FGManager.SERVER_OWNER, null))) .collect(Collectors.toList()); } @@ -216,10 +217,13 @@ public boolean prioritizeLast() { } public ProcessResult add(CommandSource source, String arguments) throws CommandException { - AdvCmdParser.ParseResult parse = AdvCmdParser.builder().arguments(arguments).flagMapper(MAPPER).parse(); + AdvCmdParser.ParseResult parse = AdvCmdParser.builder() + .arguments(arguments) + .flagMapper(MAPPER) + .parse(); if (parse.args.length < 1) throw new CommandException(Text.of("Must specify a name!")); - IRegion region = FGManager.getInstance().getRegion(parse.args[0]); + IRegion region = FGManager.getInstance().getRegion(parse.args[0]).orElse(null); if (region == null) { String worldName = parse.flags.get("world"); World world = null; @@ -231,7 +235,7 @@ public ProcessResult add(CommandSource source, String arguments) throws CommandE } } if (world == null) throw new CommandException(Text.of("Must specify a world!")); - region = FGManager.getInstance().getWorldRegion(world, parse.args[0]); + region = FGManager.getInstance().getWorldRegion(world, parse.args[0]).orElse(null); } if (region == null) throw new CommandException(Text.of("No regions with the name\"" + parse.args[0] + "\"!")); @@ -271,7 +275,7 @@ public ProcessResult remove(CommandSource source, String arguments) throws Comma } } if (world == null) throw new CommandException(Text.of("Must specify a world!")); - region = FGManager.getInstance().getWorldRegion(world, parse.args[0]); + region = FGManager.getInstance().getWorldRegion(world, parse.args[0]).orElse(null); } } catch (IndexOutOfBoundsException e) { throw new CommandException(Text.of("Index " + parse.args[0] + " out of bounds! (1 - " diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSLegacyLoader.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSLegacyLoader.java new file mode 100644 index 0000000..de24a6f --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSLegacyLoader.java @@ -0,0 +1,94 @@ +package net.foxdenstudio.sponge.foxguard.plugin.storage; + +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.config.FGConfigManager; +import org.mapdb.DB; +import org.mapdb.DBMaker; +import org.mapdb.Serializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +/** + * Created by fox on 12/6/17. + */ +public class FGSLegacyLoader { + + public static String LOGGER_NAME = FGStorageManagerNew.LOGGER_NAME + ".legacy"; + + private static final int VERSION = 1; + + private static FGSLegacyLoader instance = new FGSLegacyLoader(); + private final Logger logger = LoggerFactory.getLogger(LOGGER_NAME); + + public static FGSLegacyLoader getInstance() { + return instance; + } + + private FGSLegacyLoader() { + } + + public Optional getLegacyIndex(Path file) { + if (Files.notExists(file) || Files.isDirectory(file)) return Optional.empty(); + + logger.info("Loading legacy index: " + file); + + try (DB mainDB = openFoxDB(file)) { + List list = new ArrayList<>(); + + Map mainMap = mainDB.hashMap("main", Serializer.STRING, Serializer.STRING).createOrOpen(); + Map typeMap = mainDB.hashMap("types", Serializer.STRING, Serializer.STRING).createOrOpen(); + Map enabledMap = mainDB.hashMap("enabled", Serializer.STRING, Serializer.BOOLEAN).createOrOpen(); + Map priorityMap = mainDB.exists("priority") ? + mainDB.hashMap("priority", Serializer.STRING, Serializer.INTEGER).createOrOpen() : + null; + Map linksMap = mainDB.exists("links") ? + mainDB.hashMap("links", Serializer.STRING, Serializer.STRING).createOrOpen() : + null; + + mainMap.forEach((name, category) -> { + if (!typeMap.containsKey(name)) return; + String type = typeMap.get(name); + Boolean enabled = enabledMap.getOrDefault(name, true); + Integer priority = priorityMap != null ? priorityMap.getOrDefault(name, 0) : null; + List links = null; + if (linksMap != null) { + String handlerString = linksMap.getOrDefault(name, ""); + if (!handlerString.isEmpty()) { + links = new ArrayList<>(); + String[] parts = handlerString.split(","); + for (String part : parts) { + if (!part.isEmpty()) { + links.add(new FGSObjectPath(part, FGManager.SERVER_OWNER)); + } + } + } + } + FGSObjectIndex index = new FGSObjectIndex(name, null, category, type, enabled, priority, links); + list.add(index); + }); + if (list.isEmpty()) return Optional.empty(); + else return Optional.of(new FGStorageManagerNew.IndexConfig(list, VERSION)); + } + } + + public String getIndexDBName(String catFileName) { + return catFileName + ".foxdb"; + } + + @SuppressWarnings("Duplicates") + public static DB openFoxDB(Path path) { + FGConfigManager c = FGConfigManager.getInstance(); + DBMaker.Maker maker = DBMaker.fileDB(path.normalize().toFile()); + if (!c.lockDatabaseFiles()) maker.fileLockDisable(); + if (c.useMMappedFiles()) maker.fileMmapEnableIfSupported(); + if (c.gcCleanerHack()) maker.cleanerHackEnable(); + return maker.make(); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectIndex.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectIndex.java new file mode 100644 index 0000000..1034935 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectIndex.java @@ -0,0 +1,110 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.storage; + +import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.ILinkable; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Created by Fox on 7/9/2017. + * Project: SpongeForge + */ +public class FGSObjectIndex extends FGSObjectMeta { + + Boolean enabled; + Integer priority; + List links; + + public FGSObjectIndex(String name, IOwner owner, String category, String type, Boolean enabled, Integer priority, List links) { + super(name, owner, category, type); + this.enabled = enabled; + this.priority = priority; + this.links = links; + } + + public FGSObjectIndex() { + } + + public FGSObjectIndex(IGuardObject object) { + super(object); + this.enabled = object.isEnabled(); + if (object instanceof IHandler) { + this.priority = ((IHandler) object).getPriority(); + } + if (object instanceof ILinkable && ((ILinkable) object).saveLinks()) { + this.links = ((ILinkable) object).getLinks().stream() + .map(FGSObjectPath::new) + .collect(Collectors.toList()); + } + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Integer getPriority() { + return priority; + } + + public void setPriority(Integer priority) { + this.priority = priority; + } + + public List getLinks() { + return links; + } + + public void setLinks(List links) { + this.links = links; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + FGSObjectIndex that = (FGSObjectIndex) o; + return Objects.equals(enabled, that.enabled) && + Objects.equals(priority, that.priority) && + Objects.equals(links, that.links); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), enabled, priority, links); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectMeta.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectMeta.java new file mode 100644 index 0000000..45a2d1e --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectMeta.java @@ -0,0 +1,102 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.storage; + +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; + +import java.util.Objects; +import java.util.UUID; + +/** + * Created by Fox on 7/9/2017. + * Project: SpongeForge + */ +public class FGSObjectMeta extends FGSObjectPath { + + String category; + String type; + + public FGSObjectMeta(String name, IOwner owner, String category, String type) { + super(name, owner); + this.category = category; + this.type = type; + } + + public FGSObjectMeta() { + } + + public FGSObjectMeta(IGuardObject object) { + super(object); + this.category = FGUtil.getCategory(object); + this.type = object.getUniqueTypeString(); + this.object = object; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("FGSObjectMeta{"); + sb.append("category='").append(category).append("', "); + sb.append("type='").append(type).append("', "); + sb.append("name='").append(name).append("', "); + sb.append("owner='").append(owner).append("', "); + if (object != null) sb.append(", object=").append(object); + sb.append('}'); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + FGSObjectMeta that = (FGSObjectMeta) o; + return Objects.equals(category, that.category) && + Objects.equals(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), category, type); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectPath.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectPath.java new file mode 100644 index 0000000..98aa6c6 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGSObjectPath.java @@ -0,0 +1,90 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.storage; + +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; + +import java.util.Objects; +import java.util.UUID; + +/** + * Created by Fox on 8/28/2017. + * Project: SpongeForge + */ +public class FGSObjectPath { + String name; + IOwner owner; + transient IGuardObject object; + + public FGSObjectPath() { + this.owner = FGManager.SERVER_OWNER; + } + + public FGSObjectPath(String name, IOwner owner) { + this.name = name; + this.owner = owner == null ? FGManager.SERVER_OWNER : owner; + } + + public FGSObjectPath(IGuardObject object) { + this( + object.getName(), + object.getOwner() + ); + this.object = object; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public IOwner getOwner() { + return owner; + } + + public void setOwner(IOwner owner) { + this.owner = owner; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FGSObjectPath that = (FGSObjectPath) o; + return Objects.equals(name, that.name) && + Objects.equals(owner, that.owner); + } + + @Override + public int hashCode() { + return Objects.hash(name, owner); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGStorageManagerNew.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGStorageManagerNew.java new file mode 100644 index 0000000..abd9a60 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FGStorageManagerNew.java @@ -0,0 +1,1219 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.storage; + +import com.google.common.collect.ImmutableList; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import net.foxdenstudio.sponge.foxcore.common.util.CacheMap; +import net.foxdenstudio.sponge.foxcore.common.util.FCCUtil; +import net.foxdenstudio.sponge.foxcore.plugin.util.IWorldBound; +import net.foxdenstudio.sponge.foxguard.plugin.FGManager; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; +import net.foxdenstudio.sponge.foxguard.plugin.config.FGConfigManager; +import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; +import net.foxdenstudio.sponge.foxguard.plugin.handler.GlobalHandler; +import net.foxdenstudio.sponge.foxguard.plugin.handler.HandlerData; +import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; +import net.foxdenstudio.sponge.foxguard.plugin.object.FGObjectData; +import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.ILinkable; +import net.foxdenstudio.sponge.foxguard.plugin.object.factory.FGFactoryManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; +import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; +import net.foxdenstudio.sponge.foxguard.plugin.util.FGUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spongepowered.api.Server; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.service.user.UserStorageService; +import org.spongepowered.api.util.GuavaCollectors; +import org.spongepowered.api.util.Tristate; +import org.spongepowered.api.world.World; +import org.spongepowered.api.world.storage.WorldProperties; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; +import java.util.stream.Collectors; + +import static net.foxdenstudio.sponge.foxguard.plugin.FGManager.SERVER_OWNER; + +/** + * Created by Fox on 7/8/2017. + * Project: SpongeForge + */ +public class FGStorageManagerNew { + + private static final int VERSION = 2; + + public static final String[] FS_ILLEGAL_NAMES = {"con", "prn", "aux", "nul", + "com0", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", + "lpt0", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"}; + public static final String METADATA_FILE_NAME = "metadata.foxcf"; + public static final String OWNERS_DIR_NAME = "owners"; + public static final Charset CHARSET = StandardCharsets.UTF_8; + public static final String LOGGER_NAME = FoxGuardMain.LOGGER_NAME + ".storage"; + + private static final Type INDEX_LIST_TYPE = new TypeToken() { + }.getType(); + private static FGStorageManagerNew instance; + public final HashMap defaultModifiedMap; + private final FGConfigManager config; + private final UserStorageService userStorageService; + private final Logger logger = LoggerFactory.getLogger(LOGGER_NAME); + private final FGManager manager = FGManager.getInstance(); + private final Map worldDirectories; + private Gson gson; + private boolean prettyPrint; + private String gsonIndentString; + private Path fgDirectory; + private boolean serverLoaded = false; + private boolean reentry = false; + + private FGStorageManagerNew() { + config = FGConfigManager.getInstance(); + userStorageService = FoxGuardMain.instance().getUserStorage(); + defaultModifiedMap = new CacheMap<>((k, m) -> { + if (k instanceof IGuardObject) { + m.put((IGuardObject) k, true); + return true; + } else return null; + }); + worldDirectories = new HashMap<>(); + prettyPrint = config.prettyPrint(); + StringBuilder builder = new StringBuilder(); + int indent = config.prettyPrintIndent(); + for (int i = 0; i < indent; i++) { + builder.append(" "); + } + gsonIndentString = builder.toString(); + gson = getGsonBuilder().create(); + } + + public static FGStorageManagerNew getInstance() { + if (instance == null) instance = new FGStorageManagerNew(); + return instance; + } + + public static int getVersion() { + return VERSION; + } + + public void saveHandlerIndex() { + logger.info("Saving handler index"); + Path file = getFGDirectory().resolve(FGCat.HANDLER.getIndexFile()); + Set handlers = manager.getHandlers(); + saveIndex(handlers, file); + } + + public void saveRegionIndex() { + logger.info("Saving region index"); + Path file = getFGDirectory().resolve(FGCat.REGION.getIndexFile()); + Set regions = manager.getRegions(); + saveIndex(regions, file); + } + + public void saveWorldRegionIndex(World world) { + logger.info("Saving worldregion index for world: " + world.getName()); + Path file = getWorldDirectory(world).resolve(FGCat.WORLDREGION.getIndexFile()); + Set worldRegions = manager.getWorldRegions(world); + saveIndex(worldRegions, file); + } + + private void saveIndex(Set objects, Path file) { + List indexList = new ArrayList<>(); + objects.stream().sorted(IFGObject.OWNER_AND_NAME).forEach(object -> { + boolean saveLinks = (object instanceof ILinkable && ((ILinkable) object).saveLinks()); + boolean autoSave = object.autoSave(); + if (autoSave || saveLinks) { + FGSObjectIndex index = new FGSObjectIndex(object); + //if (index.owner.equals(SERVER_OWNER)) index.owner = null; + if (!autoSave) { + index.type = null; + index.enabled = null; + index.priority = null; + } + indexList.add(index); + } + }); + + IndexConfig data = new IndexConfig(indexList, getVersion()); + + try (JsonWriter jsonWriter = getJsonWriter(Files.newBufferedWriter(file, CHARSET))) { + gson.toJson(data, FoxConfig.class, jsonWriter); + } catch (IOException e) { + logger.error("Failed to open index for writing: " + file, e); + } + } + + private void updateIndexFor(IGuardObject object) { + if (object instanceof IHandler) { + saveHandlerIndex(); + } else if (object instanceof IRegion) { + if (object instanceof IWorldRegion) { + saveWorldRegionIndex(((IWorldRegion) object).getWorld()); + } else { + saveRegionIndex(); + } + } + } + + public void saveObject(IGuardObject object) { + saveObject(object, false); + } + + public void saveObject(IGuardObject object, boolean force) { + if (reentry) return; + FGCat type = getObjectType(object); + String logName = FGUtil.getLogName(object); + + //System.out.println(name +", " + owner + ", " + isOwned + ", " + userOwner + ", " + logName); + + if (object.autoSave()) { + + boolean shouldSave = object.shouldSave(); + if (force || shouldSave) { + Path directory = getObjectDirectory(object, true); + String category = FGUtil.getCategory(object); + logger.info((shouldSave ? "S" : "Force s") + "aving " + category + " " + logName + " in directory: " + directory); + try { + object.save(directory); + } catch (Exception e) { + logger.error("There was an error while saving " + FGUtil.getCategory(object) + " " + logName + "!", e); + } + + logger.info("Saving metadata for " + category + " " + logName); + FGSObjectMeta metadata = new FGSObjectMeta(object); + Path metadataFile = directory.resolve(METADATA_FILE_NAME); + try (JsonWriter jsonWriter = getJsonWriter(Files.newBufferedWriter(metadataFile, CHARSET))) { + gson.toJson(metadata, FGSObjectMeta.class, jsonWriter); + } catch (IOException e) { + logger.error("Failed to open metadata for writing: " + metadataFile, e); + } + } else { + logger.info(type.uName + " " + logName + " is already up to date. Skipping..."); + } + + defaultModifiedMap.put(object, false); + } else { + logger.info(type.uName + " " + logName + " does not need saving. Skipping..."); + } + } + + public void saveObjects(Set objects) { + saveObjects(objects, false); + } + + public void saveObjects(Set objects, boolean force) { + if (reentry) return; + objects.forEach(object -> saveObject(object, force)); + } + + public void addObject(IGuardObject object) { + if (reentry) return; + Path directory = getObjectDirectory(object, false); + if (Files.exists(directory)) { + if (Files.isDirectory(directory)) { + deleteDirectory(directory, true); + } else { + logger.warn("Found file instead of directory. Deleting."); + try { + Files.delete(directory); + } catch (IOException e) { + logger.error("Unable to delete file: " + directory, e); + return; + } + } + } + saveObject(object); + updateIndexFor(object); + } + + public void removeObject(IGuardObject object) { + if (reentry) return; + Path directory = getObjectDirectory(object, false); + if (config.cleanOnDelete()) { + if (Files.exists(directory)) { + if (Files.isDirectory(directory)) { + deleteDirectory(directory); + } else { + try { + Files.delete(directory); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + updateIndexFor(object); + } + + public void loadServer() { + if (serverLoaded) return; + boolean oldReentry = reentry; + reentry = true; + + FGManager manager = FGManager.getInstance(); + FGSLegacyLoader legacyLoader = FGSLegacyLoader.getInstance(); + + logger.info("Loading regions"); + Path regionIndexFile = getFGDirectory().resolve(FGCat.REGION.getIndexFile()); + Optional regionConfigOpt = loadIndex(regionIndexFile); + if (!regionConfigOpt.isPresent()) { + regionIndexFile = getFGDirectory().resolve(legacyLoader.getIndexDBName(FGCat.REGION.pathName)); + regionConfigOpt = legacyLoader.getLegacyIndex(regionIndexFile); + } + class RegionEntry { + private IRegion region; + private FGSObjectIndex index; + + private RegionEntry(IRegion region, FGSObjectIndex index) { + this.region = region; + this.index = index; + } + } + List loadedRegions = new ArrayList<>(); + List extraRegionLinks = new ArrayList<>(); + if (regionConfigOpt.isPresent()) { + FoxConfig> regionConfig = regionConfigOpt.get(); + if (regionConfig.data != null) { + for (FGSObjectIndex index : regionConfig.data) { + FGCat fgCat = FGCat.from(index.category); + if (fgCat == FGCat.REGION) { + Path directory = getObjectDirectory(index, null, false); + Optional fgObjectOptional = loadObject(directory, index, null); + if (fgObjectOptional.isPresent()) { + IGuardObject fgObject = fgObjectOptional.get(); + if (fgObject instanceof IRegion) { + IRegion region = (IRegion) fgObject; + manager.addRegion(region); + loadedRegions.add(new RegionEntry(region, index)); + } + } else if (index.links != null && !index.links.isEmpty()) { + extraRegionLinks.add(index); + } + } else { + logger.warn("Found an entry of incorrect category. Expected region, found: " + index.category); + } + } + } + } + + logger.info("Loading handlers"); + Path handlerIndexFile = getFGDirectory().resolve(FGCat.HANDLER.getIndexFile()); + Optional handlerConfigOpt = loadIndex(handlerIndexFile); + if (!handlerConfigOpt.isPresent()) { + handlerIndexFile = getFGDirectory().resolve(legacyLoader.getIndexDBName(FGCat.HANDLER.pathName)); + handlerConfigOpt = legacyLoader.getLegacyIndex(handlerIndexFile); + } + class ControllerEntry { + private IController controller; + private FGSObjectIndex index; + private Path directory; + + private ControllerEntry(IController controller, FGSObjectIndex index, Path directory) { + this.controller = controller; + this.index = index; + this.directory = directory; + } + } + List loadedControllers = new ArrayList<>(); + if (handlerConfigOpt.isPresent()) { + IndexConfig handlerConfig = handlerConfigOpt.get(); + for (FGSObjectIndex index : handlerConfig.data) { + FGCat fgCat = FGCat.from(index.category); + if (fgCat == FGCat.HANDLER || fgCat == FGCat.CONTROLLER) { + Path directory = getObjectDirectory(index, null, false); + Optional fgObjectOptional = loadObject(directory, index, null); + if (fgObjectOptional.isPresent()) { + IGuardObject fgObject = fgObjectOptional.get(); + if (fgObject instanceof IHandler) { + IHandler handler = (IHandler) fgObject; + manager.addHandler(handler); + if (handler instanceof IController) { + loadedControllers.add(new ControllerEntry(((IController) handler), index, directory)); + } + } + } + } else { + logger.warn("Found an entry of incorrect category. Expected handler or controller, found: " + index.category); + } + } + } + + logger.info("Loading global handler"); + manager.getGlobalHandler().load( + getFGDirectory() + .resolve(FGCat.HANDLER.pathName) + .resolve(GlobalHandler.NAME.toLowerCase()) + ); + + logger.info("Loading region links"); + for (RegionEntry entry : loadedRegions) { + if (entry.index.links != null) { + Set handlers = entry.index.links.stream() + .map(path -> manager.getHandler(path.name, path.owner)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + handlers.forEach(entry.region::addLink); + StringBuilder logMessage = new StringBuilder("Linked region "); + logMessage.append(FGUtil.getLogName(entry.region)); + logMessage.append(" to handlers: "); + for (Iterator handlerIterator = handlers.iterator(); handlerIterator.hasNext(); ) { + IHandler handler = handlerIterator.next(); + logMessage.append(FGUtil.getLogName(handler)); + if (handlerIterator.hasNext()) { + logMessage.append(", "); + } + } + + logger.info(logMessage.toString()); + } + } + + logger.info("Loading controller links"); + for (ControllerEntry entry : loadedControllers) { + List handlers; + if (entry.index.links != null) { + handlers = entry.index.links.stream() + .map(path -> manager.getHandler(path.name, path.owner)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(GuavaCollectors.toImmutableList()); + } else handlers = ImmutableList.of(); + + entry.controller.loadLinks(entry.directory, handlers); + } + + + reentry = oldReentry; + serverLoaded = true; + } + + public void loadWorld(World world) { + boolean oldReentry = reentry; + reentry = true; + + FGManager manager = FGManager.getInstance(); + FGSLegacyLoader legacyLoader = FGSLegacyLoader.getInstance(); + + logger.info("Loading worldregions for world: " + world.getName()); + Path regionIndexFile = getWorldDirectory(world).resolve(FGCat.WORLDREGION.getIndexFile()); + Optional worldRegionConfigOpt = loadIndex(regionIndexFile); + if (!worldRegionConfigOpt.isPresent()) { + regionIndexFile = getWorldDirectory(world).resolve(legacyLoader.getIndexDBName(FGCat.WORLDREGION.pathName)); + worldRegionConfigOpt = legacyLoader.getLegacyIndex(regionIndexFile); + } + if (worldRegionConfigOpt.isPresent()) { + IndexConfig worldRegionConfig = worldRegionConfigOpt.get(); + for (FGSObjectIndex index : worldRegionConfig.data) { + FGCat fgCat = FGCat.from(index.category); + if (fgCat == FGCat.WORLDREGION) { + Path directory = getObjectDirectory(index, world, false); + Optional fgObjectOptional = loadObject(directory, index, world); + if (fgObjectOptional.isPresent()) { + IGuardObject fgObject = fgObjectOptional.get(); + if (fgObject instanceof IWorldRegion) { + IWorldRegion worldRegion = (IWorldRegion) fgObject; + manager.addWorldRegion(worldRegion, world); + if (index.links != null) { + Set handlers = index.links.stream() + .map(path -> manager.getHandler(path.name, path.owner)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + handlers.forEach(worldRegion::addLink); + StringBuilder logMessage = new StringBuilder("Linked worldregion "); + logMessage.append(FGUtil.getLogName(worldRegion)); + logMessage.append(" to handlers: "); + for (Iterator handlerIterator = handlers.iterator(); handlerIterator.hasNext(); ) { + IHandler handler = handlerIterator.next(); + logMessage.append(FGUtil.getLogName(handler)); + if (handlerIterator.hasNext()) { + logMessage.append(", "); + } + } + + logger.info(logMessage.toString()); + } + } + } + } else { + logger.warn("Found an entry of incorrect category. Expected worldregion, found: " + index.category); + } + } + } + + reentry = oldReentry; + } + + public Optional loadIndex(Path indexFile) { + IndexConfig index = null; + if (Files.exists(indexFile) && !Files.isDirectory(indexFile)) { + try (JsonReader jsonReader = new JsonReader(Files.newBufferedReader(indexFile))) { + index = gson.fromJson(jsonReader, INDEX_LIST_TYPE); + } catch (IOException e) { + logger.error("Failed to open index for reading: " + indexFile, e); + } catch (JsonParseException e) { + logger.error("Failed to parse index JSON: " + indexFile, e); + } + } else { + logger.warn("Index file does not exist: " + indexFile); + } + return Optional.ofNullable(index); + } + + public Optional loadObject(Path directory, @Nullable FGSObjectIndex index, @Nullable World world) { + if (!Files.exists(directory) || !Files.isDirectory(directory)) return Optional.empty(); + + FGSObjectMeta metadata = null; + Path metadataFile = directory.resolve(METADATA_FILE_NAME); + if (Files.exists(metadataFile) && !Files.isDirectory(metadataFile)) { + try (JsonReader jsonReader = new JsonReader(Files.newBufferedReader(metadataFile))) { + metadata = gson.fromJson(jsonReader, FGSObjectMeta.class); + } catch (IOException e) { + logger.error("Failed to open metadata for reading: " + metadataFile, e); + } catch (JsonParseException e) { + logger.error("Failed to parse metadata JSON: " + metadataFile, e); + } + } + + String name = null; + String category = null; + String type = null; + if (index != null) { + name = index.name; + category = index.category; + type = index.type; + } + if (metadata != null) { + if (name == null || name.isEmpty()) name = metadata.name; + if (category == null || category.isEmpty()) category = metadata.category; + if (type == null || type.isEmpty()) type = metadata.type; + } + + if (category == null || category.isEmpty() || type == null || type.isEmpty()) return Optional.empty(); + + + FGCat fgCat = FGCat.from(category); + if (fgCat == null || fgCat == FGCat.OBJECT) return Optional.empty(); + + if (isGlobal(fgCat, type, name)) { + logger.info("Found global " + fgCat.lName + ". Skipping..."); + return Optional.empty(); + } + + IOwner owner = null; + if (index != null) owner = index.owner; + if (owner == null) owner = SERVER_OWNER; + + boolean isOwned = !owner.equals(SERVER_OWNER); + Optional userOwner = isOwned ? FGUtil.getUserFromOwner(owner) : Optional.empty(); + IOwner finalOwner = owner; + String ownerName = (userOwner.map(user -> user.getName() + ":" + finalOwner).orElse("None")); + + + if (name == null || name.isEmpty()) { + name = category + "-" + type; + logger.warn("No name for loaded " + fgCat.lName + ". Using generated name: " + name); + } + if (!fgCat.isNameAvailable(name, owner, world)) { + String oldName = name; + String nameBase = name + "-"; + int id = 1; + do { + name = nameBase + id; + id++; + } while (!fgCat.isNameAvailable(name, owner, world)); + logger.warn("Name " + oldName + " for " + fgCat.lName + " already in use. Changed to: " + name); + } + + FGObjectData data; + if (fgCat == FGCat.HANDLER || fgCat == FGCat.CONTROLLER) { + HandlerData handlerData = new HandlerData(); + if (index != null && index.priority != null) + handlerData.setPriority(index.priority); + data = handlerData; + } else data = new FGObjectData(); + data.setName(name); + data.setOwner(owner); + if (index != null && index.enabled != null) + data.setEnabled(index.enabled); + + StringBuilder infoMessage = new StringBuilder(); + infoMessage.append("FoxGuard object info loaded! Category: \"").append(category).append("\", "); + infoMessage.append("Type: \"").append(type).append("\", "); + infoMessage.append("Name: \"").append(name).append("\", "); + if (isOwned) infoMessage.append("Owner: \"").append(ownerName).append("\", "); + infoMessage.append("Enabled: \"").append(data.isEnabled()).append("\""); + logger.info(infoMessage.toString()); + + IGuardObject fgObject = null; + try { + fgObject = fgCat.loadInstance(directory, type, data); + } catch (Exception e) { + logger.error("There was an error creating the " + fgCat.lName, e); + } + + if (fgObject == null) { + logger.warn("The " + fgCat.lName + " was unable to be created."); + cleanup(directory, true); + } + + return Optional.ofNullable(fgObject); + } + + public GsonBuilder getGsonBuilder() { + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapterFactory(IOwner.Factory.INSTANCE); + if (prettyPrint) builder.setPrettyPrinting(); + + return builder; + } + + public JsonWriter getJsonWriter(Writer out) { + JsonWriter writer = new JsonWriter(out); + if (this.prettyPrint) writer.setIndent(this.gsonIndentString); + + return writer; + } + + /*public String getGsonIndent() { + return gsonIndentString; + }*/ + + private void cleanup(Path directory, boolean errored) { + FGConfigManager manager = FGConfigManager.getInstance(); + if (errored) { + if (!manager.cleanOnError()) return; + logger.warn("Cleaning up errored object directory: " + directory); + } else { + if (!manager.cleanOnDelete()) return; + logger.info("Cleaning up directory of deleted object: " + directory); + } + autoPath(directory, false, true, true); + } + + private Path getFGDirectory() { + if (fgDirectory != null) { + constructDirectories(fgDirectory); + return fgDirectory; + } + Path path = Sponge.getGame().getSavesDirectory(); + if (FGConfigManager.getInstance().saveInWorldDirectory()) { + path = path.resolve(Sponge.getServer().getDefaultWorldName()); + } else if (FGConfigManager.getInstance().useConfigFolder()) { + path = FoxGuardMain.instance().getConfigDirectory(); + } + path = path.resolve("foxguard"); + constructDirectories(path); + fgDirectory = path; + return path; + } + + private Path getWorldDirectory(World world) { + if (worldDirectories.containsKey(world)) { + Path directory = worldDirectories.get(world); + constructDirectories(directory); + return directory; + } + FGConfigManager manager = FGConfigManager.getInstance(); + Path path; + if (manager.saveWorldRegionsInWorldDirectories()) { + path = world.getDirectory(); + path = path.resolve("foxguard"); + } else { + if (manager.useCustomDirectory()) { + path = manager.customDirectory(); + } else { + path = getFGDirectory(); + } + path = path.resolve("worlds").resolve(world.getName()); + } + constructDirectories(path); + worldDirectories.put(world, path); + return path; + } + + public boolean autoPath(Path path, boolean create, boolean empty, boolean force) { + boolean exists = Files.exists(path); + boolean notExists = Files.notExists(path); + + if (exists == notExists) { + logger.error("There was an unknown file IO error trying to access path: " + path); + return false; + } + + if (exists) { + boolean isDirectory = Files.isDirectory(path); + if (isDirectory) { + boolean isEmpty = isEmptyDirectory(path); + if (create) { + if (!empty || isEmpty) return true; + } else if (isEmpty) { + return tryOp(FileOp.DELETE_DIR, path); + } + try { + Files.walkFileTree(path, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + tryOpEx(FileOp.DELETE_FILE, file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (exc == null && !(create && Files.isSameFile(dir, path))) { + tryOpEx(FileOp.DELETE_DIR, dir); + } + return FileVisitResult.CONTINUE; + } + }); + return true; + } catch (IOException e) { + logger.error("There was an error while trying to recursively " + (create ? "clear" : "delete") + " the directory: " + path, e); + return false; + } + } else { + if (create) { + if (force) { + logger.warn("Replacing file with directory: " + path); + } else { + logger.error("Unable to create directory because there is a file at the path: " + path); + return false; + } + } else logger.info("Deleting file: " + path); + + boolean success = tryOp(FileOp.DELETE_FILE, path); + if (create && success) { + success = tryOp(FileOp.CREATE, path); + } + return success; + } + } else { + if (!create) return true; + + boolean multiple = false; + + Path parent = path.normalize().getParent(); + while (parent != null && Files.notExists(parent)) { + parent = parent.getParent(); + multiple = true; + } + if (parent != null && !Files.exists(parent)) { + logger.error("There was an unknown file IO error trying to access path: " + parent); + return false; + } + if (parent != null && Files.exists(parent) && !Files.isDirectory(parent)) { + if (force) { + logger.warn("Deleting file: " + parent + + "\nthat is in the way of directories: " + path); + } else { + logger.error("Unable to create directories: " + path + + "\nbecause there is a file at the path: " + parent); + return false; + } + tryOp(FileOp.DELETE_FILE, parent); + multiple = true; + } + if (multiple) { + tryOp(FileOp.CREATE_MULTI, path); + } else { + tryOp(FileOp.CREATE, path); + } + + + } + + +// boolean isDirectory = Files.isDirectory(path); +// +// if (!empty && exists && isDirectory && create) { +// return true; +// } +// +// boolean isEmpty = isEmptyDirectory(path); +// +// if (exists && isDirectory && create && isEmpty) { +// return true; +// } + return false; + } + + private boolean tryOp(FileOp op, Path path) { + try { + tryOpUnsafe(op, path); + return true; + } catch (IOException e) { + logger.error("There was an IO error " + op.message3 + ": " + path, e); + return false; + } + } + + private void tryOpEx(FileOp op, Path path) throws IOException { + try { + tryOpUnsafe(op, path); + } catch (IOException e) { + throw new IOException("There was an IO error " + op.message3 + ": " + path, e); + } + } + + private void tryOpUnsafe(FileOp op, Path path) throws IOException { + int counter = 1; + float time = 0.25f; + while (true) { + try { + op.operate(path); + break; + } catch (AccessDeniedException e) { + if (counter > 5) { + logger.error("Access denied while trying to " + op.message1 + ": " + path, e); + throw e; + } else { + logger.warn("Access denied while trying to " + op.message1 + ": " + path + " Trying again in " + time + " second(s)"); + try { + Thread.sleep((long) (1000 * time)); + } catch (InterruptedException e1) { + logger.warn("Thread sleep was interrupted: ", e); + } + } + } + counter++; + time *= 2; + } + logger.info(op.message2 + ": " + path); + } + + private enum FileOp { + CREATE("create directory", "Created directory", "creating the directory") { + @Override + public void operate(Path path) throws IOException { + Files.createDirectory(path); + } + }, CREATE_MULTI("create directories", "Created directories", "creating the directories") { + @Override + public void operate(Path path) throws IOException { + Files.createDirectories(path); + } + }, DELETE_DIR("delete directory", "Deleted directory", "deleting the directory") { + @Override + public void operate(Path path) throws IOException { + Files.delete(path); + } + }, DELETE_FILE("delete file", "Deleted file", "deleting the file") { + @Override + public void operate(Path path) throws IOException { + DELETE_DIR.operate(path); + } + }; + + String message1, message2, message3; + + FileOp(String message1, String message2, String message3) { + this.message1 = message1; + this.message2 = message2; + this.message3 = message3; + } + + abstract public void operate(Path path) throws IOException; + } + + public void constructDirectories(Path directory) { + LinkedList stack = new LinkedList<>(); + Path dir = directory.normalize(); + while (true) { + if (Files.notExists(dir) || !Files.isDirectory(dir)) { + stack.push(dir); + Path parent = dir.getParent(); + if (parent != null) { + dir = parent; + continue; + } + } + break; + } + + while (!stack.isEmpty()) { + Path path = stack.pop(); + constructDirectory(path); + } + } + + public void constructDirectory(Path directory) { + if (Files.exists(directory)) { + if (Files.isDirectory(directory)) return; + else { + logger.warn("There is a file at " + directory + " where a directory was expected. Deleting and replacing with a directory..."); + try { + Files.delete(directory); + } catch (IOException e) { + logger.error("Error deleting the file: " + directory, e); + return; + } + } + } + + try { + int counter = 1; + float time = 0.25f; + while (true) { + try { + Files.createDirectories(directory); + break; + } catch (AccessDeniedException e) { + if (counter > 5) throw e; + else { + logger.error("Unable to create directory: " + directory + " Trying again in " + time + " second(s)", e); + try { + Thread.sleep((long) (1000 * time)); + } catch (InterruptedException e1) { + logger.warn("Thread sleep was interrupted: ", e); + } + } + } + counter++; + time *= 2; + } + logger.info("Created directory: " + directory); + } catch (IOException e) { + logger.error("There was an error creating the directory: " + directory, e); + } + } + + private void deleteDirectory(Path directory) { + deleteDirectory(directory, false); + } + + /** + * Deletes a directory recursively. + *

+ * If the boolean flag is set, this method attempts to return after leaving the filesystem + * with an empty directory at the parameter specified path. + * This includes doing functions such as deleting files and creating the directory if it doesn't already exist. + * + * @param directory the path at which to delete or prepare an empty directory + * @param makeEmpty whether to delete the directory or prepare and clear it (make it an empty directory). + */ + private void deleteDirectory(Path directory, boolean makeEmpty) { + if (Files.exists(directory)) { + if (makeEmpty && isEmptyDirectory(directory)) return; + FoxGuardMain.instance().getLogger().info((makeEmpty ? "Clearing" : "Deleting") + " directory: " + directory); + + if (Files.isDirectory(directory)) try { + Files.walkFileTree(directory, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + try { + Files.delete(file); + logger.info("Deleted file: " + file); + } catch (IOException e) { + logger.error("There was an error deleting the file: " + file, e); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + if (exc == null && !(makeEmpty && Files.isSameFile(dir, directory))) { + try { + Files.delete(dir); + logger.info("Deleted directory: " + dir); + } catch (IOException e) { + logger.error("There was an error deleting the directory: " + dir, e); + } + } + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + logger.error("There was an error while trying to recursively " + (makeEmpty ? "clear" : "delete") + " the directory: " + directory, e); + } + else { + logger.warn(directory + "is a file. A directory was expected. Deleting..."); + try { + Files.delete(directory); + if (makeEmpty) { + logger.warn("Replacing file with empty directory instead."); + constructDirectory(directory); + } + } catch (IOException e) { + logger.error("There was an error deleting the file: " + directory, e); + } + + } + } else if (makeEmpty) { + constructDirectory(directory); + } + } + + private boolean isEmptyDirectory(Path directory) { + if (Files.notExists(directory)) return true; + if (!Files.isDirectory(directory)) return false; + try { + DirectoryStream stream = Files.newDirectoryStream(directory); + return !stream.iterator().hasNext(); + } catch (IOException e) { + logger.error("Could not read contents of directory: " + directory, e); + return false; + } + } + + private Path getObjectDirectory(IGuardObject object, boolean construct) { + World world = null; + boolean flag = false; + if (object instanceof IWorldBound) { + world = ((IWorldBound) object).getWorld(); + flag = true; + } + return getObjectDirectory(getObjectType(object), + object.getOwner(), + object.getName(), + flag, + world, + construct); + } + + private Path getObjectDirectory(FGSObjectMeta meta, @Nullable World world, boolean construct) { + FGCat fgCat = FGCat.from(meta.category); + return getObjectDirectory(fgCat, + meta.owner, + meta.name, + fgCat == FGCat.WORLDREGION, + world, + construct); + } + + private Path getObjectDirectory(FGCat fgCat, IOwner owner, String name, boolean inWorld, @Nullable World world, boolean construct) { + if (fgCat == null) fgCat = FGCat.OBJECT; + Path dir; + if (inWorld) { + if (world == null) + world = getDefaultWorld(); + dir = getWorldDirectory(world); + } else { + dir = getFGDirectory(); + } + + boolean ownerFirst = FGConfigManager.getInstance().ownerFirst(); + + if (!ownerFirst) dir = dir.resolve(fgCat.pathName); + if (owner != null && !owner.equals(SERVER_OWNER)) { + dir = dir.resolve(owner.getDirectory()); + } + if (ownerFirst) dir = dir.resolve(fgCat.pathName); + + dir = dir.resolve(name.toLowerCase()); + if (construct) + constructDirectories(dir); + return dir; + } + + private World getDefaultWorld() { + Server server = Sponge.getServer(); + World world = null; + Optional worldPropertiesOpt = server.getDefaultWorld(); + if (worldPropertiesOpt.isPresent()) { + WorldProperties worldProperties = worldPropertiesOpt.get(); + Optional worldOpt = server.getWorld(worldProperties.getUniqueId()); + if (!worldOpt.isPresent()) + worldOpt = server.getWorld(worldProperties.getWorldName()); + if (worldOpt.isPresent()) + world = worldOpt.get(); + } + if (world == null) { + String worldName = server.getDefaultWorldName(); + Optional worldOpt = server.getWorld(worldName); + if (worldOpt.isPresent()) world = worldOpt.get(); + } + if (world == null) { + Collection worlds = server.getWorlds(); + Iterator worldIterator = worlds.iterator(); + if (worldIterator.hasNext()) { + world = worldIterator.next(); + } else { + logger.error("Could not find default world! There are no worlds loaded!"); + } + } + return world; + } + + private boolean isGlobal(FGCat fgCat, String type, String name) { + switch (fgCat) { + case REGION: + if (type.equals("sglobal") || name.equals("_sglobal")) return true; + break; + case WORLDREGION: + if (type.equals("wglobal") || name.equals("_wglobal")) return true; + break; + case HANDLER: + if (type.equals("global") || name.equals("_global")) return true; + break; + } + return false; + } + + private FGCat getObjectType(IGuardObject object) { + if (object instanceof IRegion) { + if (object instanceof IWorldRegion) { + return FGCat.WORLDREGION; + } + return FGCat.REGION; + } else if (object instanceof IHandler) { + if (object instanceof IController) { + return FGCat.CONTROLLER; + } + return FGCat.HANDLER; + } + return FGCat.OBJECT; + } + + private enum FGCat { + REGION("regions") { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + return FGManager.getInstance().isRegionNameAvailable(name, owner); + } + + @Override + public IGuardObject loadInstance(Path directory, String type, FGObjectData data) { + return FGFactoryManager.getInstance().createRegion(directory, type, data); + } + }, + WORLDREGION("wregions") { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + if (world == null) + return FGManager.getInstance().isWorldRegionNameAvailable(name, owner) == Tristate.TRUE; + else return FGManager.getInstance().isWorldRegionNameAvailable(name, owner, world); + } + + @Override + public IGuardObject loadInstance(Path directory, String type, FGObjectData data) { + return FGFactoryManager.getInstance().createWorldRegion(directory, type, data); + } + }, + HANDLER("handlers") { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + return FGManager.getInstance().isHandlerNameAvailable(name, owner); + } + + @Override + public IGuardObject loadInstance(Path directory, String type, FGObjectData data) { + HandlerData handlerData; + if (data instanceof HandlerData) { + handlerData = (HandlerData) data; + } else { + handlerData = new HandlerData(data, 0); + } + return FGFactoryManager.getInstance().createHandler(directory, type, handlerData); + } + }, + CONTROLLER(HANDLER.pathName) { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + return HANDLER.isNameAvailable(name, owner, world); + } + + @Override + public IGuardObject loadInstance(Path directory, String type, FGObjectData data) { + HandlerData handlerData; + if (data instanceof HandlerData) { + handlerData = (HandlerData) data; + } else { + handlerData = new HandlerData(data, 0); + } + return FGFactoryManager.getInstance().createController(directory, type, handlerData); + } + }, + OBJECT("objects") { + @Override + public boolean isNameAvailable(String name, IOwner owner, @Nullable World world) { + return true; + } + + @Override + public IGuardObject loadInstance(Path directory, String type, FGObjectData data) { + return null; + } + }; + + String lName = name().toLowerCase(); + String uName = FCCUtil.toCapitalCase(name()); + String pathName; + + FGCat(String pathName) { + this.pathName = pathName; + } + + public static FGCat from(String name) { + for (FGCat type : values()) { + if (type.lName.equals(name)) return type; + } + return null; + } + + public String getIndexFile() { + return pathName + ".foxcf"; + } + + public abstract boolean isNameAvailable(String name, IOwner owner, @Nullable World world); + + public abstract IGuardObject loadInstance(Path directory, String type, FGObjectData data); + } + + public static class IndexConfig extends FoxConfig> { + public IndexConfig() { + } + + public IndexConfig(List data, Integer version) { + super(data, version); + } + } + + /*private void setPrettyPrint(boolean prettyPrint) { + if (this.prettyPrint == prettyPrint) return; + this.prettyPrint = prettyPrint; + GsonBuilder builder = new GsonBuilder(); + if (prettyPrint) builder.setPrettyPrinting(); + this.gson = builder.create(); + }*/ +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FoxConfig.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FoxConfig.java new file mode 100644 index 0000000..64e0390 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FoxConfig.java @@ -0,0 +1,14 @@ +package net.foxdenstudio.sponge.foxguard.plugin.storage; + +public class FoxConfig extends FoxConfigStub{ + public T data; + + public FoxConfig() { + } + + public FoxConfig(T data, Integer version) { + super(version); + this.data = data; + this.hash = data.hashCode(); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FoxConfigStub.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FoxConfigStub.java new file mode 100644 index 0000000..bc4a976 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/storage/FoxConfigStub.java @@ -0,0 +1,13 @@ +package net.foxdenstudio.sponge.foxguard.plugin.storage; + +public class FoxConfigStub { + public Integer version; + public Integer hash; + + public FoxConfigStub() { + } + + public FoxConfigStub(Integer version) { + this.version = version; + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/DebugHelper.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/DebugHelper.java deleted file mode 100644 index d6f6ad6..0000000 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/DebugHelper.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of FoxGuard, licensed under the MIT License (MIT). - * - * Copyright (c) gravityfox - https://gravityfox.net/ - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package net.foxdenstudio.sponge.foxguard.plugin.util; - -import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; -import org.spongepowered.api.data.Transaction; -import org.spongepowered.api.event.Event; -import org.spongepowered.api.event.block.ChangeBlockEvent; - -public class DebugHelper { - - public static void printEvent(Event event) { - StringBuilder sb = new StringBuilder().append("-----------------------------------\n"); - sb.append(event.getClass()).append("\n\n"); - for (Object o : event.getCause().all()) { - sb.append(o).append("\n"); - } - FoxGuardMain.instance().getLogger().info(sb.toString()); - } - - public static void printBlockEvent(ChangeBlockEvent event) { - StringBuilder sb = new StringBuilder().append("-----------------------------------\n"); - sb.append(event.getClass()).append("\n"); - for (Transaction t : event.getTransactions()) { - sb.append(t).append("\n"); - } - sb.append("\n"); - for (Object o : event.getCause().all()) { - sb.append(o).append("\n"); - } - sb.append("\n"); - event.getCause().getNamedCauses().forEach((k, v) -> sb.append(k).append("::").append(v).append("\n")); - FoxGuardMain.instance().getLogger().info(sb.toString()); - } -} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/DebugManager.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/DebugManager.java new file mode 100644 index 0000000..c802992 --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/DebugManager.java @@ -0,0 +1,135 @@ +/* + * This file is part of FoxGuard, licensed under the MIT License (MIT). + * + * Copyright (c) gravityfox - https://gravityfox.net/ + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package net.foxdenstudio.sponge.foxguard.plugin.util; + +import net.foxdenstudio.sponge.foxcore.plugin.command.FCCommandBase; +import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.data.Transaction; +import org.spongepowered.api.event.Event; +import org.spongepowered.api.event.block.ChangeBlockEvent; +import org.spongepowered.api.event.cause.EventContextKey; +import org.spongepowered.api.text.Text; + +import java.util.Map; + +public class DebugManager extends FCCommandBase { + + public static final DebugManager INSTANCE = new DebugManager(); + + private boolean enabled = false; + private int armCount = 0; + + @Override + public CommandResult process(CommandSource source, String arguments) throws CommandException { + String[] parts = arguments.split(" +"); + if (parts.length == 0) { + source.sendMessage(getUsage(source)); + return CommandResult.empty(); + } + + switch (parts[0]) { + case "on": + enabled = true; + armCount = 0; + source.sendMessage(Text.of("Enabled printing")); + break; + case "off": + enabled = false; + armCount = 0; + source.sendMessage(Text.of("Disabled printing")); + case "arm": + enabled = true; + int count = 1; + if (parts.length > 1) { + try { + count = Integer.parseInt(parts[1]); + } catch (NumberFormatException ignored) { + } + } + armCount = count; + source.sendMessage(Text.of("Armed for " + count + " prints")); + default: + return CommandResult.empty(); + } + return CommandResult.empty(); + } + + @Override + public boolean testPermission(CommandSource source) { + return source.hasPermission("foxguard.command.debug"); + } + + private boolean print() { + boolean ret = enabled; + if (armCount > 0) { + if (--armCount == 0) enabled = false; + } + return ret; + } + + public void printEvent(Event event) { + if (print()) { + StringBuilder sb = new StringBuilder().append("-----------------------------------\n"); + sb.append(event.getClass()).append("\n\n"); + + for (Object o : event.getCause().all()) { + sb.append(o).append("\n"); + } + + sb.append("\n"); + + for (Map.Entry, Object> entry : event.getContext().asMap().entrySet()) { + sb.append(entry).append("\n"); + } + FoxGuardMain.instance().getLogger().info(sb.toString()); + } + } + + public void printBlockEvent(ChangeBlockEvent event) { + if (print()) { + StringBuilder sb = new StringBuilder().append("-----------------------------------\n"); + sb.append(event.getClass()).append("\n"); + for (Transaction t : event.getTransactions()) { + sb.append(t).append("\n"); + } + sb.append("\n"); + for (Object o : event.getCause().all()) { + sb.append(o).append("\n"); + } + sb.append("\n"); + event.getContext().asMap().forEach((k, v) -> sb.append(k).append("::").append(v).append("\n")); + FoxGuardMain.instance().getLogger().info(sb.toString()); + } + } + + @Override + public Text getUsage(CommandSource source) { + return Text.of("debug "); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/ExtraContext.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/ExtraContext.java index 9b983df..6129ad7 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/ExtraContext.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/ExtraContext.java @@ -53,6 +53,7 @@ public boolean present(Class clazz) { return false; } + @SuppressWarnings("unchecked") public Optional first(Class clazz) { for (Object o : objects) { if (clazz.isInstance(o)) { diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/FGUtil.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/FGUtil.java index b6cfe45..1b57c61 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/FGUtil.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/FGUtil.java @@ -25,39 +25,60 @@ package net.foxdenstudio.sponge.foxguard.plugin.util; +import com.google.common.collect.ImmutableList; +import net.foxdenstudio.sponge.foxcore.common.util.FCCUtil; import net.foxdenstudio.sponge.foxcore.plugin.state.FCStateManager; +import net.foxdenstudio.sponge.foxcore.plugin.util.IWorldBound; import net.foxdenstudio.sponge.foxguard.plugin.FGManager; -import net.foxdenstudio.sponge.foxguard.plugin.FGStorageManager; import net.foxdenstudio.sponge.foxguard.plugin.FoxGuardMain; import net.foxdenstudio.sponge.foxguard.plugin.controller.IController; import net.foxdenstudio.sponge.foxguard.plugin.event.factory.FGEventFactory; import net.foxdenstudio.sponge.foxguard.plugin.handler.IHandler; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; import net.foxdenstudio.sponge.foxguard.plugin.object.IGlobal; +import net.foxdenstudio.sponge.foxguard.plugin.object.IGuardObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.OwnerManager; +import net.foxdenstudio.sponge.foxguard.plugin.object.ownerold.provider.IOwnerProvider; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.UUIDOwner; import net.foxdenstudio.sponge.foxguard.plugin.region.GlobalRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import net.foxdenstudio.sponge.foxguard.plugin.state.ControllersStateField; import net.foxdenstudio.sponge.foxguard.plugin.state.HandlersStateField; import net.foxdenstudio.sponge.foxguard.plugin.state.RegionsStateField; +import net.foxdenstudio.sponge.foxguard.plugin.storage.FGStorageManagerNew; import org.slf4j.Logger; import org.spongepowered.api.Sponge; import org.spongepowered.api.block.BlockSnapshot; +import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandSource; import org.spongepowered.api.data.Transaction; +import org.spongepowered.api.entity.living.player.User; +import org.spongepowered.api.service.user.UserStorageService; import org.spongepowered.api.text.Text; +import org.spongepowered.api.text.action.TextActions; import org.spongepowered.api.text.format.TextColor; import org.spongepowered.api.text.format.TextColors; +import org.spongepowered.api.util.StartsWithPredicate; import org.spongepowered.api.util.Tristate; +import org.spongepowered.api.world.Locatable; import org.spongepowered.api.world.Location; import org.spongepowered.api.world.World; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.List; import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +import static net.foxdenstudio.sponge.foxcore.plugin.util.Aliases.*; public final class FGUtil { - public static TextColor getColorForObject(IFGObject object) { + private static UserStorageService userStorageService; + + public static TextColor getColorForObject(IGuardObject object) { if (object instanceof GlobalRegion) return TextColors.LIGHT_PURPLE; else if (object instanceof IGlobal) return TextColors.YELLOW; else if (!object.isEnabled()) return TextColors.GRAY; @@ -66,7 +87,6 @@ public static TextColor getColorForObject(IFGObject object) { else return TextColors.WHITE; } - @SuppressWarnings("unchecked") public static List getSelectedRegions(CommandSource source) { return ((RegionsStateField) FCStateManager.instance().getStateMap().get(source).getOrCreate(RegionsStateField.ID).get()).getList(); @@ -82,11 +102,54 @@ public static List getSelectedControllers(CommandSource source) { return ((ControllersStateField) FCStateManager.instance().getStateMap().get(source).getOrCreate(ControllersStateField.ID).get()).getList(); } - public static String getRegionName(IRegion region, boolean dispWorld) { - return region.getShortTypeName() + " : " + (dispWorld && region instanceof IWorldRegion ? ((IWorldRegion) region).getWorld().getName() + " : " : "") + region.getName(); + public static String getObjectDisplayName(IGuardObject object, boolean dispWorld, @Nullable IOwner owner, @Nullable CommandSource viewer) { + if (owner == null) owner = object.getOwner(); + boolean hasOwner; + hasOwner = (owner != null && !owner.equals(FGManager.SERVER_OWNER)); + return object.getShortTypeName() + + " : " + + (dispWorld && object instanceof IWorldBound ? ((IWorldBound) object).getWorld().getName() + " : " : "") + // TODO make better display name thing + + (hasOwner ? owner.toString() + " : " : "") + + object.getName(); + } + + public static Text getObjectDisplayTest(IGuardObject object, boolean dispWorld, @Nullable IOwner owner, @Nullable CommandSource viewer) { + if (owner == null) owner = object.getOwner(); + boolean hasOwner; + hasOwner = (owner != null && !owner.equals(FGManager.SERVER_OWNER)); + Text.Builder builder = Text.builder(); + + // TODO finish display text + + return builder.build(); + } + + public static String getLogName(IGuardObject object) { + if (userStorageService == null) userStorageService = FoxGuardMain.instance().getUserStorage(); + IOwner owner = object.getOwner(); + boolean isOwned = !owner.equals(FGManager.SERVER_OWNER); + // TODO come up with better logname impl + Optional userOwner = isOwned ? Optional.of(owner) + .filter(o -> o instanceof UUIDOwner) + .map(o -> (UUIDOwner) o) + .filter(o -> o.getGroup().equals(UUIDOwner.USER_GROUP)) + .flatMap(o -> userStorageService.get(o.getKey())) : + Optional.empty(); + return (userOwner.map(user -> user.getName() + ":").orElse("")) + (isOwned ? owner + ":" : "") + object.getName(); } - public static String getCategory(IFGObject object) { + public static Optional getUserFromOwner(IOwner owner) { + return owner == null || owner.equals(FGManager.SERVER_OWNER) ? Optional.empty() : + Optional.of(owner) + .filter(o -> o instanceof UUIDOwner) + .map(o -> (UUIDOwner) o) + .filter(o -> o.getGroup().equals(UUIDOwner.USER_GROUP)) + .flatMap(o -> userStorageService.get(o.getKey())); + } + + + public static String getCategory(IGuardObject object) { if (object instanceof IRegion) { if (object instanceof IWorldRegion) return "worldregion"; else return "region"; @@ -96,8 +159,8 @@ public static String getCategory(IFGObject object) { } else return "object"; } - public static String genWorldFlag(IRegion region) { - return region instanceof IWorldRegion ? "--w:" + ((IWorldRegion) region).getWorld().getName() + " " : ""; + public static String genWorldFlag(IGuardObject object) { + return object instanceof IWorldBound ? "--w:" + ((IWorldBound) object).getWorld().getName() + " " : ""; } public static Text readableTristateText(Tristate state) { @@ -113,15 +176,380 @@ public static Text readableTristateText(Tristate state) { } } - public static void markRegionDirty(IRegion region) { - FGManager.getInstance().markDirty(region, RegionCache.DirtyType.MODIFIED); - FGStorageManager.getInstance().defaultModifiedMap.put(region, true); - Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), region)); + public static void markDirty(IGuardObject object) { + if (object instanceof IRegion) { + FGManager.getInstance().markDirty(((IRegion) object), RegionCache.DirtyType.MODIFIED); + } + FGStorageManagerNew.getInstance().defaultModifiedMap.put(object, true); + Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), object)); + } + + @Nonnull + public static IHandler getHandlerFromCommand(OwnerResult qualifier) throws CommandException { + String name = qualifier.getName(); + IOwner owner = qualifier.getOwner(); + Optional handlerOpt; + + handlerOpt = FGManager.getInstance().getHandler(name, owner); + + if (!handlerOpt.isPresent()) { + StringBuilder builder = new StringBuilder(); + builder.append("No handler exists with the name \"").append(name).append("\""); + if (!owner.equals(FGManager.SERVER_OWNER)) { + builder.append(" and owner \"").append(qualifier.getOwnerName()).append("\""); + } + builder.append("!"); + + throw new CommandException(Text.of(builder.toString())); + } + return handlerOpt.get(); + } + + @Nonnull + public static IRegion getRegionFromCommand(CommandSource source, OwnerResult qualifier, boolean worldFlag, @Nullable String worldName) throws CommandException { + String name = qualifier.getName(); + IOwner owner = qualifier.getOwner(); + + IRegion returnRegion = null; + /*Optional regionOpt = FGManager.getInstance().getRegion(name, owner); + if (!regionOpt.isPresent()) { + World world = null; + if (source instanceof Locatable) world = ((Locatable) source).getWorld(); + if (!worldName.isEmpty()) { + Optional optWorld = Sponge.getServer().getWorld(worldName); + if (optWorld.isPresent()) { + world = optWorld.get(); + } else { + if (world == null) + throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); + } + } + if (world == null) throw new CommandException(Text.of("Must specify a world!")); + regionOpt = FGManager.getInstance().getWorldRegion(world, name, owner); + }*/ + + Set regions = FGManager.getInstance().getAllRegions(qualifier.getName(), qualifier.getOwner()); + World world = null; + if (source instanceof Locatable) world = ((Locatable) source).getWorld(); + if (worldFlag) { + if (worldName != null && !worldName.isEmpty()) { + Optional optWorld = Sponge.getGame().getServer().getWorld(worldName); + if (optWorld.isPresent()) { + world = optWorld.get(); + } else { + throw new CommandException(Text.of("No world exists with name \"" + worldName + "\"!")); + } + } + if (world == null) + throw new CommandException(Text.of("Must specify a world with the world flag!")); + Optional regionOpt = FGManager.getInstance().getWorldRegion(world, qualifier.getName(), qualifier.getOwner()); + if (regionOpt.isPresent()) { + returnRegion = regionOpt.get(); + } + } else { + if (regions.size() == 1) { + returnRegion = regions.iterator().next(); + } else if (regions.size() > 1) { + for (IRegion region : regions) { + if (region instanceof IWorldRegion) { + if (world == null) continue; + if (((IWorldRegion) region).getWorld() == world) returnRegion = region; + } else { + returnRegion = region; + break; + } + } + if (returnRegion == null && world == null) + throw new CommandException(Text.of("Multiple regions exist !")); + } + } + if (returnRegion == null) { + StringBuilder builder = new StringBuilder(); + builder.append("No region exists with the name \"").append(name).append("\""); + if (!owner.equals(FGManager.SERVER_OWNER)) { + builder.append(" and owner \"").append(qualifier.getOwnerName()).append("\""); + } + if (world != null && regions.size() > 0) { + builder.append(" in world \"").append(world.getName()).append("\""); + } + builder.append("!"); + + throw new CommandException(Text.of(builder.toString())); + } + return returnRegion; + } + + + public static OwnerResult processUserInput(String input) throws CommandException { + + return new OwnerResult(input, FGManager.SERVER_OWNER, FGManager.SERVER_OWNER.toString()); + + /*if (input.startsWith(":")) input = input.substring(1); + String[] parts = input.split(":", 3); + + String name = null; + String ownerQualifier = null; + String provider = null; + switch (parts.length) { + case 1: + name = parts[0]; + break; + case 2: + ownerQualifier = parts[0]; + name = parts[1]; + break; + case 3: + provider = parts[0]; + ownerQualifier = parts[1]; + name = parts[2]; + break; + } + + if (name == null) + throw new CommandException(Text.of("Name must not be... null?")); + else if (name.isEmpty()) + throw new CommandException(Text.of("Name must not be empty!")); + + Optional ownerOpt = OwnerManager.getInstance().getUUIDForOwner(provider, ownerQualifier); + if (!ownerOpt.isPresent()) { + String errorName = (provider != null ? provider + ":" : "") + ownerQualifier; + throw new CommandException(Text.of("\"" + errorName + "\" is not a valid owner!")); + } + return new OwnerResult(name, new UUIDOwner(UUIDOwner.USER_GROUP, ownerOpt.get()), ownerQualifier);*/ + } + + public static OwnerTabResult getOwnerSuggestions(String input) { + boolean prefixed = false; + if (input.startsWith(":")) { + input = input.substring(1); + prefixed = true; + } + String[] parts = input.split(":", 3); + if (parts.length == 1) { + if (prefixed) { + List list = OwnerManager.getInstance().getProviders().stream() + .map(IOwnerProvider::getPrimaryAlias) + .filter(str -> str != null && !str.isEmpty()) + .filter(new StartsWithPredicate(parts[0])) + .map(str -> ":" + str) + .collect(ImmutableList.toImmutableList()); + if (list.size() == 1) { + list = ImmutableList.of(list.get(0).substring(1) + ":"); + } + return new OwnerTabResult(list); + } else { + return new OwnerTabResult("", parts[0], FGManager.SERVER_UUID_DEPRECATED); + } + } else if (parts.length == 2) { + OwnerManager registry = OwnerManager.getInstance(); + Optional providerOpt = registry.getProvider(parts[0]); + if (providerOpt.isPresent()) { + IOwnerProvider provider = providerOpt.get(); + List list = provider.getOwnerKeywords().stream() + .filter(str -> str != null && !str.isEmpty()) + .filter(new StartsWithPredicate(parts[1])) + .map(str -> parts[0] + ":" + str) + .collect(ImmutableList.toImmutableList()); + int size = list.size(); + if (size == 0) { + if (prefixed) { + list = ImmutableList.of(parts[0] + ":" + parts[1]); + } + } else if (size == 1) { + ImmutableList.of(list.get(0) + ":"); + } + return new OwnerTabResult(list); + } else { + Optional ownerOpt = registry.getUUIDForOwner(null, parts[0]); + return ownerOpt.map(uuid -> new OwnerTabResult(parts[0] + ":", parts[1], uuid)) + .orElseGet(OwnerTabResult::new); + + } + } else if (parts.length == 3) { + Optional providerOpt = OwnerManager.getInstance().getProvider(parts[0]); + if (providerOpt.isPresent()) { + IOwnerProvider provider = providerOpt.get(); + Optional ownerOpt = provider.getOwnerUUID(parts[1]); + return ownerOpt.map(uuid -> new OwnerTabResult(parts[0] + ":" + parts[1] + ":", parts[2], uuid)) + .orElseGet(OwnerTabResult::new); + } + + } + return new OwnerTabResult(); + } + + public static void genStatePrefix(Text.Builder builder, IGuardObject object, CommandSource source) { + genStatePrefix(builder, object, source, false); } - public static void markHandlerDirty(IHandler handler) { - FGStorageManager.getInstance().defaultModifiedMap.put(handler, true); - Sponge.getGame().getEventManager().post(FGEventFactory.createFGUpdateObjectEvent(FoxGuardMain.getCause(), handler)); + public static void genStatePrefix(Text.Builder builder, IGuardObject object, CommandSource source, boolean controllerPadding) { + FGCat cat = FGCat.from(object); + if (cat == null) return; + if (cat == FGCat.WORLDREGION) cat = FGCat.REGION; + boolean contains; + if (cat == FGCat.REGION) { + contains = getSelectedRegions(source).contains(object); + controllerPadding = false; + } else { + contains = getSelectedHandlers(source).contains(object); + if (cat == FGCat.CONTROLLER) { + genStateButtons(builder, FGCat.HANDLER, object, contains); + contains = getSelectedControllers(source).contains(object); + controllerPadding = false; + } + } + genStateButtons(builder, cat, object, contains); + if (controllerPadding) + builder.append(Text.of(TextColors.DARK_GRAY, "[c+][c-]")); + builder.append(Text.of(" ")); + } + + private static void genStateButtons(Text.Builder builder, FGCat cat, IGuardObject object, boolean contains) { + String plus = "[" + cat.sName + "+]"; + String minus = "[" + cat.sName + "-]"; + if (contains) { + builder.append(Text.of(TextColors.GRAY, plus)); + builder.append(Text.of(TextColors.RED, + TextActions.runCommand("/foxguard s " + cat.sName + " remove " + genWorldFlag(object) + object.getFullName()), + TextActions.showText(Text.of("Remove from " + cat.lName + " state buffer")), + minus)); + } else { + builder.append(Text.of(TextColors.GREEN, + TextActions.runCommand("/foxguard s " + cat.sName + " add " + genWorldFlag(object) + object.getFullName()), + TextActions.showText(Text.of("Add to " + cat.lName + " state buffer")), + plus)); + builder.append(Text.of(TextColors.GRAY, minus)); + } + } + + private enum FGCat { + REGION(REGIONS_ALIASES, "r"), + WORLDREGION(null, REGION.sName), + HANDLER(HANDLERS_ALIASES, "h"), + CONTROLLER(null, HANDLER.sName); + + public final String[] catAliases; + public final String lName = name().toLowerCase(); + public final String uName = FCCUtil.toCapitalCase(name()); + public final String sName; + + FGCat(String[] catAliases, String sName) { + this.catAliases = catAliases; + this.sName = sName; + } + + public static FGCat from(String category) { + for (FGCat cat : values()) { + if (isIn(cat.catAliases, category)) return cat; + } + return null; + } + + public static FGCat from(IGuardObject object) { + if (object instanceof IRegion) { + if (object instanceof IWorldRegion) { + return WORLDREGION; + } else { + return REGION; + } + } else if (object instanceof IHandler) { + if (object instanceof IController) { + return CONTROLLER; + } else { + return HANDLER; + } + } + return null; + } + } + + public static class OwnerTabResult { + private boolean complete; + private List suggestions; + private String prefix; + private String token; + private UUID owner; + + public OwnerTabResult() { + this.complete = true; + this.suggestions = ImmutableList.of(); + } + + public OwnerTabResult(List suggestions) { + this.complete = true; + this.suggestions = suggestions; + } + + public OwnerTabResult(String prefix, String token, UUID owner) { + this.complete = false; + this.prefix = prefix; + this.token = token; + this.owner = owner; + } + + public boolean isComplete() { + return complete; + } + + public List getSuggestions() { + return suggestions; + } + + public String getPrefix() { + return prefix; + } + + public String getToken() { + return token; + } + + public UUID getOwner() { + return owner; + } + + @Override + public String toString() { + return "OwnerTabResult{" + + "complete=" + complete + + ", suggestions=" + suggestions + + ", prefix='" + prefix + '\'' + + ", token='" + token + '\'' + + ", owner=" + owner + + '}'; + } + } + + public static class OwnerResult { + private String name; + private IOwner owner; + private String ownerName; + + private OwnerResult(String name, IOwner owner, String ownerName) { + this.name = name; + this.owner = owner; + this.ownerName = ownerName; + } + + public String getName() { + return name; + } + + public IOwner getOwner() { + return owner; + } + + public String getOwnerName() { + return ownerName; + } + + @Override + public String toString() { + return "OwnerResult{" + + "name='" + name + '\'' + + ", owner=" + owner + + ", ownerName='" + ownerName + '\'' + + '}'; + } } public static Optional> getLocation(Transaction transaction) { diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/FoxException.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/FoxException.java new file mode 100644 index 0000000..925f8fc --- /dev/null +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/FoxException.java @@ -0,0 +1,23 @@ +package net.foxdenstudio.sponge.foxguard.plugin.util; + +public class FoxException extends Exception { + + public FoxException() { + } + + public FoxException(String message) { + super(message); + } + + public FoxException(String message, Throwable cause) { + super(message, cause); + } + + public FoxException(Throwable cause) { + super(cause); + } + + public FoxException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/RegionCache.java b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/RegionCache.java index c64450f..1758a68 100644 --- a/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/RegionCache.java +++ b/src/main/java/net/foxdenstudio/sponge/foxguard/plugin/util/RegionCache.java @@ -27,16 +27,14 @@ import com.flowpowered.math.vector.Vector3i; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Multimap; import net.foxdenstudio.sponge.foxcore.common.util.CacheMap; -import net.foxdenstudio.sponge.foxguard.plugin.object.IFGObject; +import net.foxdenstudio.sponge.foxguard.plugin.object.path.owner.types.IOwner; import net.foxdenstudio.sponge.foxguard.plugin.region.IRegion; import net.foxdenstudio.sponge.foxguard.plugin.region.world.IWorldRegion; import org.spongepowered.api.world.World; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Created by Fox on 3/30/2016. @@ -44,12 +42,12 @@ public class RegionCache { - private final Map> worldRegions; - private final Set regions; + private final Map> worldRegions; + private final Multimap regions; private final Map> chunks; - public RegionCache(Set regions, Map> worldRegions) { + public RegionCache(Multimap regions, Map> worldRegions) { this.worldRegions = worldRegions; this.regions = regions; chunks = new CacheMap<>((world, worldDataMap) -> { @@ -89,6 +87,10 @@ public ChunkData getData(World world, Vector3i chunk) { return this.chunks.get(world).get(chunk); } + public enum DirtyType { + ADDED, MODIFIED, REMOVED + } + public class ChunkData { private final World world; @@ -105,23 +107,40 @@ public ChunkData(World world, Vector3i chunk) { this.chunk = chunk; this.dirty = new HashMap<>(); this.contains = new HashSet<>(); - worldRegions.get(world).stream() - .filter(IFGObject::isEnabled) + this.disabled = new HashSet<>(); + + for (IWorldRegion region : worldRegions.get(world).values()) { + if (!region.isInChunk(chunk)) continue; + if (region.isEnabled()) { + contains.add(region); + } else { + disabled.add(region); + } + } + for (IRegion region : regions.values()) { + if (!region.isInChunk(chunk, world)) continue; + if (region.isEnabled()) { + contains.add(region); + } else { + disabled.add(region); + } + } + /*worldRegions.get(world).values().stream() + .filter(IFGObject::enabled) .filter(r -> r.isInChunk(chunk)) .forEach(contains::add); - regions.stream() - .filter(IFGObject::isEnabled) + regions.values().stream() + .filter(IFGObject::enabled) .filter(r -> r.isInChunk(chunk, world)) .forEach(contains::add); - this.disabled = new HashSet<>(); - worldRegions.get(world).stream() - .filter(r -> !r.isEnabled()) + worldRegions.get(world).values().stream() + .filter(r -> !r.enabled()) .filter(r -> r.isInChunk(chunk)) .forEach(disabled::add); - regions.stream() - .filter(IFGObject::isEnabled) + regions.values().stream() + .filter(IFGObject::enabled) .filter(r -> r.isInChunk(chunk, world)) - .forEach(disabled::add); + .forEach(disabled::add);*/ } public Set getRegions(boolean includeDisabled) { @@ -171,8 +190,4 @@ public void markDirty(IRegion region, DirtyType type) { } } - - public enum DirtyType { - ADDED, MODIFIED, REMOVED - } }