add block inspector for ops

* adds /inspect (or /ins) as a /co i replacement command for OPs. container and sign logging are still a WIP for this command.
* replaces "Rank must be Trial Mod or higher." with "Rank must be Admin or higher." in slconfig
* replaces "scripthead is the owner of TotalFreedom." with "Wild1145 is the owner of TotalFreedom." in the config
This commit is contained in:
speed 2020-11-30 18:17:27 -05:00
parent 6cd995ff52
commit c1d4e126a3
8 changed files with 350 additions and 12 deletions

View File

@ -6,16 +6,30 @@ import java.sql.DriverManager;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import me.totalfreedom.totalfreedommod.FreedomService; import me.totalfreedom.totalfreedommod.FreedomService;
import me.totalfreedom.totalfreedommod.config.ConfigEntry; import me.totalfreedom.totalfreedommod.config.ConfigEntry;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import me.totalfreedom.totalfreedommod.util.FLog; import me.totalfreedom.totalfreedommod.util.FLog;
import me.totalfreedom.totalfreedommod.util.FUtil;
import net.coreprotect.CoreProtect; import net.coreprotect.CoreProtect;
import net.coreprotect.CoreProtectAPI; import net.coreprotect.CoreProtectAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask; import org.bukkit.scheduler.BukkitTask;
@ -26,6 +40,10 @@ public class CoreProtectBridge extends FreedomService
private final List<String> tables = Arrays.asList("co_sign", "co_session", "co_container", "co_block"); private final List<String> tables = Arrays.asList("co_sign", "co_session", "co_container", "co_block");
private final HashMap<String, Long> cooldown = new HashMap<>();
public static Map<Player, FUtil.PaginationList<String>> HISTORY_MAP = new HashMap<>();
private BukkitTask wiper; private BukkitTask wiper;
@Override @Override
@ -218,4 +236,211 @@ public class CoreProtectBridge extends FreedomService
server.shutdown(); server.shutdown();
} }
} }
public static Long getSecondsLeft(long prevTime, int timeAdd)
{
return prevTime / 1000L + timeAdd - System.currentTimeMillis() / 1000L;
}
// Unix timestamp converter taken from Functions class in CoreProtect, not my code
public static String getTimeAgo(int logTime, int currentTime)
{
StringBuilder message = new StringBuilder();
double timeSince = (double)currentTime - ((double)logTime + 0.0D);
timeSince /= 60.0D;
if (timeSince < 60.0D)
{
message.append((new DecimalFormat("0.00")).format(timeSince)).append("/m ago");
}
if (message.length() == 0)
{
timeSince /= 60.0D;
if (timeSince < 24.0D)
{
message.append((new DecimalFormat("0.00")).format(timeSince)).append("/h ago");
}
}
if (message.length() == 0)
{
timeSince /= 24.0D;
message.append((new DecimalFormat("0.00")).format(timeSince)).append("/d ago");
}
return message.toString();
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerInteract(PlayerInteractEvent event)
{
Player player = event.getPlayer();
PlayerData data = plugin.pl.getData(player);
Block block = event.getClickedBlock();
final CoreProtectAPI coreProtect = getCoreProtectAPI();
if (data.hasInspection())
{
if (event.getAction() == Action.LEFT_CLICK_BLOCK)
{
if (block != null)
{
event.setCancelled(true);
List<String[]> lookup = coreProtect.blockLookup(block, -1);
int cooldownTime = 3;
if (cooldown.containsKey(player.getName()))
{
long secondsLeft = getSecondsLeft(cooldown.get(player.getName()), cooldownTime);
if (secondsLeft > 0L)
{
event.setCancelled(true);
player.sendMessage(ChatColor.RED + String.valueOf(secondsLeft) + " seconds left before next query.");
return;
}
}
if (!plugin.sl.isStaff(player))
{
cooldown.put(player.getName(), System.currentTimeMillis());
}
if (lookup != null)
{
if (lookup.isEmpty())
{
player.sendMessage(net.md_5.bungee.api.ChatColor.of("#30ade4") + "Block Inspector " + ChatColor.WHITE + "- " + "No block data found for this location");
return;
}
HISTORY_MAP.remove(event.getPlayer());
HISTORY_MAP.put(event.getPlayer(), new FUtil.PaginationList<>(10));
FUtil.PaginationList<String> paged = HISTORY_MAP.get(event.getPlayer());
player.sendMessage("---- " + net.md_5.bungee.api.ChatColor.of("#30ade4") + "Block Inspector" + ChatColor.WHITE + " ---- " +
ChatColor.GRAY + "(x" + block.getX() + "/" + "y" + block.getY() + "/" + "z" + block.getZ() + ")");
for (String[] value : lookup)
{
CoreProtectAPI.ParseResult result = coreProtect.parseResult(value);
BlockData bl = result.getBlockData();
String s;
String st = "";
if (result.getActionString().equals("Placement"))
{
s = " placed ";
}
else
{
s = " broke ";
}
if (result.isRolledBack())
{
st += "§m";
}
int time = (int)(System.currentTimeMillis() / 1000L);
paged.add(ChatColor.GRAY + getTimeAgo(result.getTime(), time) + ChatColor.WHITE + " - " + net.md_5.bungee.api.ChatColor.of("#30ade4") +
st + result.getPlayer() + ChatColor.WHITE + st + s + net.md_5.bungee.api.ChatColor.of("#30ade4") + st + bl.getMaterial().toString().toLowerCase());
}
List<String> page = paged.getPage(1);
for (String entries : page)
{
player.sendMessage(entries);
}
player.sendMessage("Page 1/" + paged.getPageCount() + " | To index through the pages, type " + net.md_5.bungee.api.ChatColor.of("#30ade4") + "/ins history <page>");
}
}
}
else if (event.getAction() == Action.RIGHT_CLICK_BLOCK)
{
if (block != null)
{
if (data.hasInspection())
{
BlockState placedBlock = block.getRelative(event.getBlockFace()).getState();
event.setCancelled(true);
List<String[]> lookup = coreProtect.blockLookup(placedBlock.getBlock(), -1);
int cooldownTime = 3;
if (cooldown.containsKey(player.getName()))
{
long secondsLeft = getSecondsLeft(cooldown.get(player.getName()), cooldownTime);
if (secondsLeft > 0L)
{
event.setCancelled(true);
player.sendMessage(ChatColor.RED + String.valueOf(secondsLeft) + " seconds left before next query.");
return;
}
}
if (!plugin.sl.isStaff(player))
{
cooldown.put(player.getName(), System.currentTimeMillis());
}
if (lookup != null)
{
if (lookup.isEmpty())
{
player.sendMessage(net.md_5.bungee.api.ChatColor.of("#30ade4") + "Block Inspector " + ChatColor.WHITE + "- " + "No block data found for this location");
return;
}
HISTORY_MAP.remove(event.getPlayer());
HISTORY_MAP.put(event.getPlayer(), new FUtil.PaginationList<>(10));
FUtil.PaginationList<String> paged = HISTORY_MAP.get(event.getPlayer());
player.sendMessage("---- " + net.md_5.bungee.api.ChatColor.of("#30ade4") + "Block Inspector" + ChatColor.WHITE + " ---- " +
ChatColor.GRAY + "(x" + block.getX() + "/" + "y" + block.getY() + "/" + "z" + block.getZ() + ")");
for (String[] value : lookup)
{
CoreProtectAPI.ParseResult result = coreProtect.parseResult(value);
BlockData bl = result.getBlockData();
String s;
String st = "";
if (result.getActionString().equals("Placement"))
{
s = " placed ";
}
else
{
s = " broke ";
}
if (result.isRolledBack())
{
st += "§m";
}
int time = (int)(System.currentTimeMillis() / 1000L);
paged.add(ChatColor.GRAY + getTimeAgo(result.getTime(), time) + ChatColor.WHITE + " - " + net.md_5.bungee.api.ChatColor.of("#30ade4") +
st + result.getPlayer() + ChatColor.WHITE + st + s + net.md_5.bungee.api.ChatColor.of("#30ade4") + st + bl.getMaterial().toString().toLowerCase());
}
List<String> page = paged.getPage(1);
for (String entries : page)
{
player.sendMessage(entries);
}
player.sendMessage("Page 1/" + paged.getPageCount() + " | To index through the pages, type " + net.md_5.bungee.api.ChatColor.of("#30ade4") + "/ins history <page>");
}
}
}
}
}
}
} }

View File

@ -32,7 +32,6 @@ public class Command_forcekill extends FreedomCommand
} }
player.setHealth(0); player.setHealth(0);
return true; return true;
} }
} }

View File

@ -0,0 +1,69 @@
package me.totalfreedom.totalfreedommod.command;
import java.util.List;
import me.totalfreedom.totalfreedommod.bridge.CoreProtectBridge;
import me.totalfreedom.totalfreedommod.player.PlayerData;
import me.totalfreedom.totalfreedommod.rank.Rank;
import me.totalfreedom.totalfreedommod.util.FUtil;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@CommandPermissions(level = Rank.OP, source = SourceType.ONLY_IN_GAME)
@CommandParameters(description = "Block inspector tool for operators", usage = "/<command> [history] <page>", aliases = "ins")
public class Command_inspect extends FreedomCommand
{
@Override
public boolean run(CommandSender sender, Player playerSender, Command cmd, String commandLabel, String[] args, boolean senderIsConsole)
{
if (args.length == 0)
{
PlayerData playerData = plugin.pl.getData(playerSender);
playerData.setInspect(!playerData.hasInspection());
plugin.pl.save(playerData);
msg("Block inspector " + (playerData.hasInspection() ? "enabled." : "disabled."));
return true;
}
if (args[0].equalsIgnoreCase("history"))
{
int pageIndex = 1;
if (args.length >= 2)
{
try
{
pageIndex = Integer.parseInt(args[1]);
}
catch (NumberFormatException e)
{
sender.sendMessage(ChatColor.RED + "Invalid number");
}
}
FUtil.PaginationList<String> paged = CoreProtectBridge.HISTORY_MAP.get(playerSender);
if (paged != null)
{
if (pageIndex < 1 || pageIndex > paged.getPageCount())
{
sender.sendMessage(ChatColor.RED + "Not a valid page number");
return true;
}
sender.sendMessage("---- " + net.md_5.bungee.api.ChatColor.of("#30ade4") + "Block Inspector" + ChatColor.WHITE + " ---- ");
List<String> page = paged.getPage(pageIndex);
for (String entries : page)
{
sender.sendMessage(entries);
}
sender.sendMessage("Page " + pageIndex + "/" + paged.getPageCount() + " | To index through the pages, type " + net.md_5.bungee.api.ChatColor.of("#30ade4") + "/ins history <page>");
return true;
}
}
return true;
}
}

View File

@ -85,7 +85,7 @@ public class Command_slconfig extends FreedomCommand
if (!rank.isAtLeast(Rank.ADMIN)) if (!rank.isAtLeast(Rank.ADMIN))
{ {
msg("Rank must be Trial Mod or higher.", ChatColor.RED); msg("Rank must be Admin or higher.", ChatColor.RED);
return true; return true;
} }

View File

@ -53,6 +53,8 @@ public class PlayerData
@Getter @Getter
@Setter @Setter
private String loginMessage; private String loginMessage;
@Setter
private Boolean inspect = false;
public PlayerData(ResultSet resultSet) public PlayerData(ResultSet resultSet)
{ {
@ -77,6 +79,7 @@ public class PlayerData
displayDiscord = resultSet.getBoolean("display_discord"); displayDiscord = resultSet.getBoolean("display_discord");
redditUsername = resultSet.getString("reddit_username"); redditUsername = resultSet.getString("reddit_username");
loginMessage = resultSet.getString("login_message"); loginMessage = resultSet.getString("login_message");
inspect = resultSet.getBoolean("inspect");
} }
catch (SQLException e) catch (SQLException e)
{ {
@ -231,6 +234,11 @@ public class PlayerData
return masterBuilder; return masterBuilder;
} }
public boolean hasInspection()
{
return inspect;
}
public Map<String, Object> toSQLStorable() public Map<String, Object> toSQLStorable()
{ {
Map<String, Object> map = new HashMap<String, Object>() Map<String, Object> map = new HashMap<String, Object>()
@ -250,6 +258,7 @@ public class PlayerData
put("display_discord", displayDiscord); put("display_discord", displayDiscord);
put("reddit_username", redditUsername); put("reddit_username", redditUsername);
put("login_message", loginMessage); put("login_message", loginMessage);
put("inspect", inspect);
}}; }};
return map; return map;
} }

View File

@ -93,7 +93,7 @@ public class SQLite extends FreedomService
{ {
try try
{ {
connection.createStatement().execute("CREATE TABLE `players` (`username` VARCHAR NOT NULL, `ips` VARCHAR NOT NULL, `notes` VARCHAR, `tag` VARCHAR, `discord_id` VARCHAR, `backup_codes` VARCHAR, `donator` BOOLEAN NOT NULL, `master_builder` BOOLEAN NOT NULL,`verification` BOOLEAN NOT NULL, `ride_mode` VARCHAR NOT NULL, `coins` INT, `items` VARCHAR, `total_votes` INT NOT NULL, `display_discord` BOOLEAN NOT NULL, `reddit_username` VARCHAR, `login_message` VARCHAR);"); connection.createStatement().execute("CREATE TABLE `players` (`username` VARCHAR NOT NULL, `ips` VARCHAR NOT NULL, `notes` VARCHAR, `tag` VARCHAR, `discord_id` VARCHAR, `backup_codes` VARCHAR, `master_builder` BOOLEAN NOT NULL,`verification` BOOLEAN NOT NULL, `ride_mode` VARCHAR NOT NULL, `coins` INT, `items` VARCHAR, `total_votes` INT NOT NULL, `display_discord` BOOLEAN NOT NULL, `reddit_username` VARCHAR, `login_message` VARCHAR, `inspect` BOOLEAN NOT NULL);");
} }
catch (SQLException e) catch (SQLException e)
{ {
@ -270,7 +270,7 @@ public class SQLite extends FreedomService
{ {
try try
{ {
PreparedStatement statement = connection.prepareStatement("INSERT INTO players VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PreparedStatement statement = connection.prepareStatement("INSERT INTO players VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
statement.setString(1, player.getName()); statement.setString(1, player.getName());
statement.setString(2, FUtil.listToString(player.getIps())); statement.setString(2, FUtil.listToString(player.getIps()));
statement.setString(3, FUtil.listToString(player.getNotes())); statement.setString(3, FUtil.listToString(player.getNotes()));
@ -286,6 +286,7 @@ public class SQLite extends FreedomService
statement.setBoolean(13, player.doesDisplayDiscord()); statement.setBoolean(13, player.doesDisplayDiscord());
statement.setString(14, player.getRedditUsername()); statement.setString(14, player.getRedditUsername());
statement.setString(15, player.getLoginMessage()); statement.setString(15, player.getLoginMessage());
statement.setBoolean(16, player.hasInspection());
statement.executeUpdate(); statement.executeUpdate();
} }
catch (SQLException e) catch (SQLException e)

View File

@ -190,8 +190,9 @@ public class FUtil
/** /**
* A way to get a sublist with a page index and a page size. * A way to get a sublist with a page index and a page size.
* @param list A list of objects that should be split into pages. *
* @param size The size of the pages. * @param list A list of objects that should be split into pages.
* @param size The size of the pages.
* @param index The page index, if outside of bounds error will be thrown. The page index starts at 0 as with all lists. * @param index The page index, if outside of bounds error will be thrown. The page index starts at 0 as with all lists.
* @return A list of objects that is the page that has been selected from the previous last parameter. * @return A list of objects that is the page that has been selected from the previous last parameter.
*/ */
@ -254,7 +255,7 @@ public class FUtil
return null; return null;
} }
public static Response sendRequest(String endpoint, String method, List<String>headers, String body) throws IOException public static Response sendRequest(String endpoint, String method, List<String> headers, String body) throws IOException
{ {
URL url = new URL(endpoint); URL url = new URL(endpoint);
HttpURLConnection connection = (HttpURLConnection)url.openConnection(); HttpURLConnection connection = (HttpURLConnection)url.openConnection();
@ -800,13 +801,13 @@ public class FUtil
{ {
c1values[i] = Math.round(c1values[i] + factor * (c2values[i] - c1values[i])); c1values[i] = Math.round(c1values[i] + factor * (c2values[i] - c1values[i]));
} }
return Color.fromRGB((int) c1values[0], (int) c1values[1], (int) c1values[2]); return Color.fromRGB((int)c1values[0], (int)c1values[1], (int)c1values[2]);
} }
public static boolean isValidIPv4(String ip) public static boolean isValidIPv4(String ip)
{ {
if (ip.matches("^([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))$") if (ip.matches("^([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))$")
|| ip.matches("^([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([*])\\.([*])$")) || ip.matches("^([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([0-9]|[1-9][0-9]|1([0-9][0-9])|2([0-4][0-9]|5[0-5]))\\.([*])\\.([*])$"))
{ {
return true; return true;
} }
@ -868,4 +869,38 @@ public class FUtil
} }
}.runTaskLater(TotalFreedomMod.getPlugin(), delay); }.runTaskLater(TotalFreedomMod.getPlugin(), delay);
} }
}
public static class PaginationList<T> extends ArrayList<T>
{
private final int epp;
public PaginationList(int epp)
{
super();
this.epp = epp;
}
@SafeVarargs
public PaginationList(int epp, T... elements)
{
super(Arrays.asList(elements));
this.epp = epp;
}
public int getPageCount()
{
return (int)Math.ceil((double)size() / (double)epp);
}
public List<T> getPage(int page)
{
if (page < 1 || page > getPageCount())
{
return null;
}
int startIndex = (page - 1) * epp;
int endIndex = Math.min(startIndex + (epp - 1), this.size() - 1);
return subList(startIndex, endIndex + 1);
}
}
}

View File

@ -418,7 +418,7 @@ announcer:
- 'Save your buildings via WorldEdit! http://totalfreedom.me for more information!' - 'Save your buildings via WorldEdit! http://totalfreedom.me for more information!'
- 'You may contact TotalFreedom support on Twitter! https://tiny.re/tfsupport' - 'You may contact TotalFreedom support on Twitter! https://tiny.re/tfsupport'
- 'You may download TotalFreedomMod here: https://tiny.re/tfm+' - 'You may download TotalFreedomMod here: https://tiny.re/tfm+'
- 'scripthead is the owner of TotalFreedom.' - 'Wild1145 is the owner of TotalFreedom.'
- 'markbyron is the founder of TotalFreedom.' - 'markbyron is the founder of TotalFreedom.'
- 'Server lagging? Check the lag via "/tps"' - 'Server lagging? Check the lag via "/tps"'
- 'You are allowed to record and stream videos on TotalFreedom.' - 'You are allowed to record and stream videos on TotalFreedom.'