Skip to content

Commit

Permalink
Adding in via most direct path optional multiple world support. Exist…
Browse files Browse the repository at this point in the history
…ing configs will continue to work with no change; or, admins can add in multiple world block config settings by world name or uuid.
  • Loading branch information
ProgrammerDan committed Jul 18, 2018
1 parent 5660b54 commit fd82fc1
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 69 deletions.
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2016 Devoted
Copyright (c) 2016-2018 Devoted

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,26 @@ You can specify custom messages for specific types of drops, allowing "uber"-fin

You can turn on or off the debug using `/hiddenore debug true` or `false`. Be warned, if people are digging, this will spam the console _very_ badly.

Supports saving and loading of the tracking database, and fully adheres to /reload with no difficulties.
Supports saving and loading of the tracking database, and fully adheres to /reload with no difficulties.

As of 1.4.2, full multiple world support, via name or UUID.

I'm probably missing some other details but that's it for now.

### TODO / In progress features:

* Full multiworld support

* Configure which tool to "use" for cave dusting. Default right now is Diamond Pickaxe.

* Better documentation

* Minecraft 1.13 support (will be 1.5.0)

### Feature Augment List:

**v1.4.1** Live use of new tracker shows its disk use is much increased. Added a configuration option to explicity disable it. Added config example of Command "drops" and some fixes.
**v1.4.2** Added full multiple world support. Standard config is used as default for any world that does not have a specific config. A new section, `worlds`
can be specified, each subsection is either the UUID or name of the world with a specific config. A single `blocks` subsection under the world identifier contains all the block configurations for that world. It is configured like the default, within that subsection. Check the configs for examples.

**v1.4.1** Live use of new tracker shows its disk use is much increased. Added a configuration option to explicitly disable it. Added config example of Command "drops" and some fixes.

**v1.4.0** New exploit tracker that tracks the actual blocks broken or exposed. This will fully prevent the "but I already checked that block" problem. Heuristic tracking is, for now, still active.

Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.github.devotedmc</groupId>
<artifactId>hiddenore</artifactId>
<version>1.4.1</version>
<version>1.4.2</version>
<name>HiddenOre</name>

<repositories>
Expand Down
48 changes: 35 additions & 13 deletions src/main/java/com/github/devotedmc/hiddenore/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.inventory.ItemStack;

/**
* Someday it might be nice to refactor this to be a proper object.
*
* For now, this holds the configs for HiddenOre, in an instance-backed semi-private collective.
*
* @author soexpso, programmerdan
*
*/
public final class Config {

public static Config instance;
Expand Down Expand Up @@ -176,24 +184,32 @@ public static void doLoad() {
UUID worlduid = null;
try {
worlduid = UUID.fromString(world);
if (HiddenOre.getPlugin().getServer().getWorld(worlduid) == null) {
System.err.println("Although it seems to be a UUID, " + world + " no match found yet.");
worlduid = null;
}
} catch (Exception e) {
System.out.println("World not defined by UUID");
worlduid = null;
}

try {
worlduid = HiddenOre.getPlugin().getServer().getWorld(world).getUID();
} catch (Exception f) {
System.out.println("World not defined by Name");
if (worlduid == null) {
try {
worlduid = HiddenOre.getPlugin().getServer().getWorld(world).getUID();
} catch (Exception f) {
System.out.println("World not defined by Name; unable to match " + world + " with actual world. Skipping.");
continue;
}
}

if (worlduid == null) {
System.err.println("Unable to match world " + world + " with actual spigot world. Skipping.");
System.err.println("Unable to match world " + world + " with actual world. Skipping.");
} else {
ConfigurationSection worldConfig = worlds.getConfigurationSection(world);
if (worldConfig != null) {
ConfigurationSection worldBlocks = worldConfig.getConfigurationSection("blocks");
if (worldBlocks != null) {
grabBlocks(worlduid, worldBlocks, i)
grabBlocks(worlduid, worldBlocks, i);
}
}
}
Expand All @@ -205,8 +221,12 @@ public static void doLoad() {

private static void grabBlocks(UUID world, ConfigurationSection blocks, Config i) {
if (blocks != null) {
Map<String, List<BlockConfig>> worldBlockConfigs = i.blockConfigs.get(world);
if (worldBlockConfigs == null) {
worldBlockConfigs = new HashMap<String, List<BlockConfig>>();
}
for (String sourceBlock : blocks.getKeys(false)) {
HiddenOre.getPlugin().getLogger().info("Loading config for " + sourceBlock);
HiddenOre.getPlugin().getLogger().info("Loading config for " + sourceBlock + " for world " + world);
ConfigurationSection block = blocks.getConfigurationSection(sourceBlock);

String cBlockName = block.getString("material");
Expand Down Expand Up @@ -262,14 +282,16 @@ private static void grabBlocks(UUID world, ConfigurationSection blocks, Config i

bc.addDropConfig(sourceDrop, dc);
}
List<BlockConfig> bclist = i.blockConfigs.get(cBlockName);//sourceBlock);
List<BlockConfig> bclist = worldBlockConfigs.get(cBlockName);//sourceBlock);
if (bclist == null) {
bclist = new LinkedList<BlockConfig>();
}
bclist.add(bc);

i.blockConfigs.put(cBlockName, bclist);//sourceBlock, bclist);
worldBlockConfigs.put(cBlockName, bclist);//sourceBlock, bclist);
}

i.blockConfigs.put(world, worldBlockConfigs);
} else {
HiddenOre.getPlugin().getLogger().info("No blocks specified (Why are you using this plugin?)");
}
Expand Down Expand Up @@ -320,8 +342,8 @@ private static DropLimitsConfig grabLimits(ConfigurationSection drop, DropLimits
return dlc;
}

public static BlockConfig isDropBlock(String block, byte subtype) {
List<BlockConfig> bcs = instance.blockConfigs.get(block);
public static BlockConfig isDropBlock(UUID world, String block, byte subtype) {
List<BlockConfig> bcs = instance.blockConfigs.getOrDefault(world, instance.blockConfigs.get(null)).get(block);
if (bcs != null && bcs.size() > 0) {
// return first match
for (BlockConfig bc : bcs) {
Expand All @@ -333,8 +355,8 @@ public static BlockConfig isDropBlock(String block, byte subtype) {
return null;
}

public static String getPrefix(String block, byte subtype, String drop) {
BlockConfig bc = isDropBlock(block, subtype);
public static String getPrefix(UUID world, String block, byte subtype, String drop) {
BlockConfig bc = isDropBlock(world, block, subtype);
String pref = (bc == null) ? instance.defaultPrefix : bc.getPrefix(drop);
return (pref == null ? instance.defaultPrefix : pref);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.github.devotedmc.hiddenore.commands;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.bukkit.Bukkit;
import org.bukkit.command.Command;
Expand All @@ -15,6 +17,11 @@
import com.github.devotedmc.hiddenore.DropItemConfig;
import com.github.devotedmc.hiddenore.HiddenOre;

/**
* Management and maintenance commands
*
* @author programmerdan
*/
public class CommandHandler implements CommandExecutor {

final HiddenOre plugin;
Expand Down Expand Up @@ -49,15 +56,21 @@ public boolean onCommand(CommandSender sender, Command cmd, String label, String
mult = Integer.parseInt(args[1]);
} catch (Exception e) {mult = 1;}
final double vmult = mult;
final UUID world = player.getWorld().getUID();

sender.sendMessage("Generating all drops, this could cause lag");

Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
long delay = 0l;
for (String blockConf : Config.instance.blockConfigs.keySet()) {
for (BlockConfig block : Config.instance.blockConfigs.get(blockConf)) {
Map<String, List<BlockConfig>> worldBlockConfigs = Config.instance.blockConfigs.getOrDefault(world, Config.instance.blockConfigs.get(null));
if (worldBlockConfigs == null) {
sender.sendMessage("No drops configured for blocks in this world.");
return;
}
for (String blockConf : worldBlockConfigs.keySet()) {
for (BlockConfig block : worldBlockConfigs.get(blockConf)) {
for (String dropConf : block.getDrops()) {
DropConfig drop = block.getDropConfig(dropConf);
for (DropItemConfig item : drop.drops) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.logging.Level;

import com.github.devotedmc.hiddenore.BlockConfig;
Expand All @@ -33,6 +34,11 @@
import com.github.devotedmc.hiddenore.events.HiddenOreGenerateEvent;
import com.github.devotedmc.hiddenore.util.FakePlayer;

/**
* Heart of ore generation, handles breaks.
*
* @author soerxpso, programmerdan
*/
public class BlockBreakListener implements Listener {
private final HiddenOre plugin;

Expand Down Expand Up @@ -69,8 +75,9 @@ private void doBlockBreak(BlockBreakEvent event) {
Block b = event.getBlock();
String blockName = b.getType().name();
Byte sb = b.getData();
UUID world = b.getWorld().getUID();

BlockConfig bc = Config.isDropBlock(blockName, sb);
BlockConfig bc = Config.isDropBlock(world, blockName, sb);

Player p = event.getPlayer();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;

import org.bukkit.Chunk;
Expand Down Expand Up @@ -30,12 +31,13 @@ public class WorldGenerationListener implements Listener {
Set<Material> toReplace = null;
Material replaceWith = null;
String worldName = null;
UUID worldUUID = null;

/**
* When creating, pass in a config with three sub-elements
* When creating, pass in a config with three sub-elements. Now supports UUID reference of world.
* <br/>
* <code>
* world: world_name
* world: world_name (or UUID)
* replace:
* - IRON_ORE
* - REDSTONE_ORE
Expand All @@ -51,6 +53,18 @@ public WorldGenerationListener(ConfigurationSection config) {
if (config.contains("world")) {
worldName = config.getString("world");
}
try {
if (worldName != null) {
World world = HiddenOre.getPlugin().getServer().getWorld(worldName);
if (world != null) {
worldUUID = world.getUID();
} else {
worldUUID = UUID.fromString(worldName);
}
}
} catch (IllegalArgumentException iae) {
worldUUID = null;
}
if (config.contains("replace")) {
toReplace = new HashSet<Material>();
for (String replace : config.getStringList("replace")) {
Expand Down Expand Up @@ -85,7 +99,7 @@ public void postGenerationOreClear(ChunkPopulateEvent event) {

World world = chunk.getWorld();

if (!world.getName().equalsIgnoreCase(worldName)) {
if (!world.getName().equalsIgnoreCase(worldName) && !world.getUID().equals(worldUUID)) {
return;
}

Expand Down Expand Up @@ -154,15 +168,18 @@ private void clear(Chunk chunk) {

static BlockFace[] faces = new BlockFace[] {BlockFace.UP,BlockFace.DOWN,BlockFace.NORTH,BlockFace.SOUTH,BlockFace.EAST,BlockFace.WEST};
private void generateCaveOres(Chunk chunk) {
UUID world = chunk.getWorld().getUID();
int xzmax = chunk.getWorld().getMaxHeight();
ItemStack breakItem = new ItemStack(Material.DIAMOND_PICKAXE);
for(int x = 0; x < 16; x++) {
for(int z = 0; z < 16; z++) {
for(int y = 0; y < chunk.getWorld().getMaxHeight(); y++) {
for(int y = 0; y < xzmax; y++) {
Block block = chunk.getBlock(x, y, z);
BlockConfig bc = Config.isDropBlock(block.getType().name(), block.getData());
BlockConfig bc = Config.isDropBlock(world, block.getType().name(), block.getData());
if(bc == null) continue;
for(BlockFace face : faces) {
if(block.getRelative(face).getType() == Material.AIR) {
BlockBreakListener.spoofBlockBreak(block.getLocation(), block, new ItemStack(Material.DIAMOND_PICKAXE));
BlockBreakListener.spoofBlockBreak(block.getLocation(), block, breakItem);
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@
import com.github.devotedmc.hiddenore.Config;
import com.github.devotedmc.hiddenore.HiddenOre;

/**
* A critical component of HiddenOre is preventing gaming of the ore generation system.
* This is done by circumspect tracking and suppressing of "repeat placements",
* generators, piston use, etc. It's quite effective; all known avenues of attack
* result in significantly reduced drop/genrates. It does <i>not</i> pay to cheat.
*
* @author soerxpso, programmerdan
*/
public class BreakTracking {
private static final int GEN = 1;
private static final int MAP = 0;
Expand Down Expand Up @@ -175,17 +183,21 @@ public void save() {
long s = System.currentTimeMillis();
HiddenOre.getPlugin().getLogger().info("Starting Break Tracking save");
File tf = Config.getTrackFile();
if (tf.exists()) {
File tfb = new File(tf.getAbsoluteFile() + ".backup");
if (tfb.exists()) {
if (!tfb.delete()) {
HiddenOre.getPlugin().getLogger().info("Couldn't remove old backup file - " + tfb);
try {
if (tf.exists()) {
File tfb = new File(tf.getAbsoluteFile() + ".backup");
if (tfb.exists()) {
if (!tfb.delete()) {
HiddenOre.getPlugin().getLogger().info("Couldn't remove old backup file - " + tfb);
} else {
tf.renameTo(tfb);
}
} else {
tf.renameTo(tfb);
}
} else {
tf.renameTo(tfb);
}
} catch (SecurityException se) {
HiddenOre.getPlugin().getLogger().log(Level.SEVERE, "Failed to manage old backup of break tracking.", se);
}
try {
if (tf.createNewFile()) {
Expand Down Expand Up @@ -230,17 +242,21 @@ public void saveMap() {
long s = System.currentTimeMillis();
HiddenOre.getPlugin().getLogger().info("Starting Break Map save");
File tf = Config.getMapFile();
if (tf.exists()) {
File tfb = new File(tf.getAbsoluteFile() + ".backup");
if (tfb.exists()) {
if (!tfb.delete()) {
HiddenOre.getPlugin().getLogger().info("Couldn't remove old map backup file - " + tfb);
try {
if (tf.exists()) {
File tfb = new File(tf.getAbsoluteFile() + ".backup");
if (tfb.exists()) {
if (!tfb.delete()) {
HiddenOre.getPlugin().getLogger().info("Couldn't remove old map backup file - " + tfb);
} else {
tf.renameTo(tfb);
}
} else {
tf.renameTo(tfb);
}
} else {
tf.renameTo(tfb);
}
} catch (SecurityException se) {
HiddenOre.getPlugin().getLogger().log(Level.SEVERE, "Failed to manage old break map backup.", se);
}
try {
if (tf.createNewFile()) {
Expand Down
Loading

0 comments on commit fd82fc1

Please sign in to comment.