196 lines
7.1 KiB
Java

package net.knarcraft.permissionsigns.manager;
import net.knarcraft.permissionsigns.PermissionSigns;
import net.knarcraft.permissionsigns.container.PermissionSign;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.logging.Level;
/**
* A manager for keeping track of known signs
*/
public final class SignManager {
private static Map<Location, PermissionSign> managedSigns = new HashMap<>();
private static final File signsFile = new File(PermissionSigns.getInstance().getDataFolder(), "data.yml");
private SignManager() {
}
/**
* Gets the permission sign at the given location
*
* @param signLocation <p>The location of the permission sign to get</p>
* @return <p>The permission sign at the given location, or null if no such sign exists</p>
*/
public static PermissionSign getSign(Location signLocation) {
return managedSigns.get(signLocation);
}
/**
* Adds a sign
*
* @param sign <p>The sign to add</p>
*/
public static void addSign(PermissionSign sign) {
managedSigns.put(sign.getSignLocation(), sign);
save();
}
/**
* Removes a sign
*
* @param location <p>The location of the sign to remove</p>
*/
public static void removeSign(Location location) {
managedSigns.remove(location);
save();
}
/**
* Saves all signs to the signs file
*
* @throws IOException <p>If unable to save to the signs file</p>
*/
public static void saveSigns() throws IOException {
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile);
ConfigurationSection signSection = configuration.createSection("signs");
for (Location signLocation : managedSigns.keySet()) {
String locationString = Objects.requireNonNull(signLocation.getWorld()).getUID() + "," +
signLocation.getBlockX() + "," + signLocation.getBlockY() + "," + signLocation.getBlockZ();
PermissionSign sign = managedSigns.get(signLocation);
signSection.set(locationString + ".name", sign.getName());
signSection.set(locationString + ".permissions", sign.getPermissionNodes());
signSection.set(locationString + ".duration", sign.getDuration());
signSection.set(locationString + ".cost", sign.getCost());
}
configuration.save(signsFile);
}
/**
* Loads all saved signs from disk
*/
public static void loadSigns() {
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile);
ConfigurationSection signSection = configuration.getConfigurationSection("signs");
managedSigns = new HashMap<>();
if (signSection == null) {
PermissionSigns.getInstance().getLogger().log(Level.WARNING, "Signs section not found in data.yml");
return;
}
for (String key : signSection.getKeys(false)) {
try {
loadSign(signSection, key);
} catch (InvalidConfigurationException e) {
PermissionSigns.getInstance().getLogger().log(Level.SEVERE, "Unable to load sign " + key + ": " +
e.getMessage());
}
}
//Re-draw all signs in a separate thread
redrawSigns();
}
/**
* Re-draws all loaded signs in case something changed
*/
private static void redrawSigns() {
Bukkit.getScheduler().scheduleSyncDelayedTask(PermissionSigns.getInstance(), () -> {
List<Location> invalidPermissionSigns = new ArrayList<>();
for (Location key : managedSigns.keySet()) {
PermissionSign permissionSign = managedSigns.get(key);
Block signBlock = key.getBlock();
BlockState state = signBlock.getState();
if (!(state instanceof Sign sign)) {
if (PermissionSigns.removePermissionSignIfMissing()) {
invalidPermissionSigns.add(permissionSign.getSignLocation());
}
continue;
}
String[] newLines = permissionSign.getSignLines();
if (Arrays.equals(sign.getLines(), newLines)) {
continue;
}
for (int i = 0; i < 4; i++) {
sign.setLine(i, newLines[i]);
}
sign.update();
}
for (Location signLocation : invalidPermissionSigns) {
SignManager.removeSign(signLocation);
}
});
}
/**
* Tries to save signs and handles any errors
*/
private static void save() {
try {
saveSigns();
} catch (IOException e) {
PermissionSigns.getInstance().getLogger().log(Level.SEVERE, "Unable to save signs: " + e.getMessage());
}
}
/**
* Loads a sign from the save file
*
* @param signSection <p>The configuration section containing signs</p>
* @param key <p>The sign key which is also the sign's location</p>
* @throws InvalidConfigurationException <p>If unable to load the sign</p>
*/
private static void loadSign(ConfigurationSection signSection, String key) throws InvalidConfigurationException {
String[] locationParts = key.split(",");
Location signLocation;
try {
signLocation = new Location(Bukkit.getWorld(UUID.fromString(locationParts[0])),
Double.parseDouble(locationParts[1]), Double.parseDouble(locationParts[2]),
Double.parseDouble(locationParts[3]));
} catch (NumberFormatException exception) {
throw new InvalidConfigurationException("Invalid sign coordinates");
}
String signName = signSection.getString(key + ".name");
if (signName == null) {
throw new IllegalArgumentException("Name missing from sign data");
}
List<String> permissionStrings = new ArrayList<>();
List<?> permissions = signSection.getList(key + ".permissions");
if (permissions == null) {
throw new IllegalArgumentException("Permission list missing from sign data");
}
permissions.forEach((item) -> {
if (item instanceof String) {
permissionStrings.add((String) item);
}
});
int duration = signSection.getInt(key + ".duration");
double cost = signSection.getDouble(key + ".cost");
PermissionSign loadedSign = new PermissionSign(signLocation, signName, permissionStrings, duration, cost);
managedSigns.put(signLocation, loadedSign);
}
}