Skip to content

Commit

Permalink
feat: add /huskhomes dump, improve config load warning
Browse files Browse the repository at this point in the history
  • Loading branch information
WiIIiam278 committed Feb 27, 2025
1 parent d023e4e commit 115dd1d
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 67 deletions.
2 changes: 2 additions & 0 deletions bukkit/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dependencies {
implementation 'io.papermc:paperlib:1.0.8'
implementation 'space.arim.morepaperlib:morepaperlib:0.4.4'
implementation 'net.kyori:adventure-platform-bukkit:4.3.4'
implementation 'net.william278.toilet:toilet-bukkit:1.0.12'

compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
compileOnly 'org.jetbrains:annotations:26.0.2'
Expand Down Expand Up @@ -42,6 +43,7 @@ shadowJar {
relocate 'com.zaxxer', 'net.william278.huskhomes.libraries'
relocate 'net.william278.paginedown', 'net.william278.huskhomes.libraries.paginedown'
relocate 'net.william278.desertwell', 'net.william278.huskhomes.libraries.desertwell'
relocate 'net.william278.toilet', 'net.william278.huskhomes.libraries.toilet'
relocate 'de.exlll', 'net.william278.huskhomes.libraries'
relocate 'org.json', 'net.william278.huskhomes.libraries.json'
relocate 'org.yaml.snakeyaml', 'net.william278.huskhomes.libraries.snakeyaml'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
import net.william278.huskhomes.util.BukkitSavePositionProvider;
import net.william278.huskhomes.util.BukkitTask;
import net.william278.huskhomes.util.UnsafeBlocks;
import net.william278.toilet.BukkitToilet;
import net.william278.toilet.Toilet;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
Expand Down Expand Up @@ -84,6 +86,7 @@ public class BukkitHuskHomes extends JavaPlugin implements HuskHomes, BukkitTask
private AsynchronousScheduler asyncScheduler;
private RegionalScheduler regionalScheduler;
private MorePaperLib morePaperLib;
private Toilet toilet;

private final Set<SavedUser> savedUsers = Sets.newHashSet();
private final Set<UUID> currentlyOnWarmup = Sets.newConcurrentHashSet();
Expand Down Expand Up @@ -132,6 +135,7 @@ public void onLoad() {
public void onEnable() {
this.audiences = BukkitAudiences.create(this);
this.morePaperLib = new MorePaperLib(this);
this.toilet = BukkitToilet.create(getDumpOptions());
this.enable();
this.loadCommands();
}
Expand Down
2 changes: 2 additions & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ dependencies {
exclude module: 'slf4j-api'
}

compileOnlyApi 'net.william278.toilet:toilet-common:1.0.12'

compileOnly 'org.jetbrains:annotations:26.0.2'
compileOnly 'com.google.guava:guava:33.4.0-jre'
compileOnly 'net.kyori:adventure-api:4.19.0'
Expand Down
8 changes: 7 additions & 1 deletion common/src/main/java/net/william278/huskhomes/HuskHomes.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package net.william278.huskhomes;

import com.google.common.collect.Sets;
import de.exlll.configlib.ConfigurationException;
import net.kyori.adventure.key.Key;
import net.william278.huskhomes.api.BaseHuskHomesAPI;
import net.william278.huskhomes.command.Command;
Expand Down Expand Up @@ -57,7 +58,7 @@
public interface HuskHomes extends Task.Supplier, EventDispatcher, SavePositionProvider, TransactionResolver,
ConfigProvider, DatabaseProvider, BrokerProvider, MetaProvider, HookProvider, RandomTeleportProvider,
AudiencesProvider, UserProvider, TextValidator, ManagerProvider, ListenerProvider, CommandProvider,
GsonProvider {
GsonProvider, DumpProvider {

int BSTATS_BUKKIT_PLUGIN_ID = 8430;

Expand All @@ -72,6 +73,11 @@ default void load() {
setHooks(Sets.newHashSet());
loadHooks(PluginHook.Register.ON_LOAD);
registerHooks(PluginHook.Register.ON_LOAD);
} catch (ConfigurationException e) {
log(Level.SEVERE, "Failed to load the HuskHomes config.yml file! HuskHomes will be disabled.\n" +
"Please regenerate your HuskHomes config.yml file (delete it and restart your server.)", e);
disablePlugin();
return;
} catch (Throwable e) {
log(Level.SEVERE, "An error occurred whilst loading HuskHomes", e);
disablePlugin();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
import de.themoep.minedown.adventure.MineDown;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.william278.desertwell.about.AboutMenu;
import net.william278.desertwell.util.UpdateChecker;
import net.william278.huskhomes.HuskHomes;
Expand All @@ -34,13 +36,12 @@
import net.william278.huskhomes.user.CommandUser;
import net.william278.huskhomes.user.SavedUser;
import net.william278.huskhomes.user.User;
import net.william278.huskhomes.util.StatusLine;
import net.william278.paginedown.PaginatedList;
import org.apache.commons.text.WordUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
Expand All @@ -52,6 +53,7 @@ public class HuskHomesCommand extends Command implements UserListTabCompletable
"help", false,
"reload", true,
"status", true,
"dump", true,
"homeslots", false,
"import", true,
"delete", true,
Expand Down Expand Up @@ -124,6 +126,20 @@ public void execute(@NotNull CommandUser executor, @NotNull String[] args) {
Arrays.stream(StatusLine.values()).map(s -> s.get(plugin)).toList()
));
}
case "dump" -> {
if (!parseStringArg(args, 0).map(s -> s.equals("confirm")).orElse(false)) {
getPlugin().getLocales().getLocale("system_dump_confirm").ifPresent(executor::sendMessage);
return;
}

getPlugin().getLocales().getLocale("system_dump_started").ifPresent(executor::sendMessage);
plugin.runAsync(() -> {
final String url = plugin.createDump(executor);
getPlugin().getLocales().getLocale("system_dump_ready").ifPresent(executor::sendMessage);
executor.sendMessage(Component.text(url).clickEvent(ClickEvent.openUrl(url))
.decorate(TextDecoration.UNDERLINED).color(NamedTextColor.GRAY));
});
}
case "homeslots" -> {
if (!plugin.isUsingEconomy() || args.length <= 1) {
plugin.getLocales().getLocale("error_invalid_syntax", getUsage())
Expand Down Expand Up @@ -415,6 +431,7 @@ public List<String> suggest(@NotNull CommandUser user, @NotNull String[] args) {
case 2 -> switch (args[0].toLowerCase()) {
case "help" -> IntStream.rangeClosed(1, getCommandList(user).getTotalPages())
.mapToObj(Integer::toString).toList();
case "dump" -> List.of("confirm");
case "homeslots" -> UserListTabCompletable.super.getUsernameList();
case "import" -> List.of("start", "list");
case "delete" -> List.of("player", "homes", "warps");
Expand All @@ -434,63 +451,4 @@ public List<String> suggest(@NotNull CommandUser user, @NotNull String[] args) {
};
}

private enum StatusLine {
PLUGIN_VERSION(plugin -> Component.text("v" + plugin.getPluginVersion().toStringWithoutMetadata())
.appendSpace().append(plugin.getPluginVersion().getMetadata().isBlank() ? Component.empty()
: Component.text("(build " + plugin.getPluginVersion().getMetadata() + ")"))),
SERVER_VERSION(plugin -> Component.text(plugin.getServerType())),
LANGUAGE(plugin -> Component.text(plugin.getSettings().getLanguage())),
MINECRAFT_VERSION(plugin -> Component.text(plugin.getMinecraftVersion().toString())),
JAVA_VERSION(plugin -> Component.text(System.getProperty("java.version"))),
JAVA_VENDOR(plugin -> Component.text(System.getProperty("java.vendor"))),
SERVER_NAME(plugin -> Component.text(plugin.getServerName())),
DATABASE_TYPE(plugin -> Component.text(plugin.getSettings().getDatabase().getType().getDisplayName())),
IS_DATABASE_LOCAL(plugin -> getLocalhostBoolean(plugin.getSettings().getDatabase().getCredentials().getHost())),
USING_REDIS_SENTINEL(plugin -> getBoolean(!plugin.getSettings().getCrossServer().getRedis().getSentinel()
.getMasterName().isBlank())),
USING_REDIS_PASSWORD(plugin -> getBoolean(!plugin.getSettings().getCrossServer().getRedis().getPassword()
.isBlank())),
REDIS_USING_SSL(plugin -> getBoolean(!plugin.getSettings().getCrossServer().getRedis().isUseSsl())),
IS_REDIS_LOCAL(plugin -> getLocalhostBoolean(plugin.getSettings().getCrossServer().getRedis().getHost())),
ECONOMY_MODE(plugin -> getBoolean(plugin.isUsingEconomy())),
LOADED_HOOKS(plugin -> Component.join(
JoinConfiguration.commas(true),
plugin.getHooks().stream().filter(hook -> !(hook instanceof Importer))
.map(hook -> Component.text(hook.getName())).toList()
)),
LOADED_IMPORTERS(plugin -> Component.join(
JoinConfiguration.commas(true),
plugin.getImporters().stream().map(hook -> Component.text(hook.getName())).toList()
));

private final Function<HuskHomes, Component> supplier;

StatusLine(@NotNull Function<HuskHomes, Component> supplier) {
this.supplier = supplier;
}

@NotNull
private Component get(@NotNull HuskHomes plugin) {
return Component
.text("•").appendSpace()
.append(Component.text(
WordUtils.capitalizeFully(name().replaceAll("_", " ")),
TextColor.color(0x848484)
))
.append(Component.text(':')).append(Component.space().color(NamedTextColor.WHITE))
.append(supplier.apply(plugin));
}

@NotNull
private static Component getBoolean(boolean value) {
return Component.text(value ? "Yes" : "No", value ? NamedTextColor.GREEN : NamedTextColor.RED);
}

@NotNull
private static Component getLocalhostBoolean(@NotNull String value) {
return getBoolean(value.equals("127.0.0.1") || value.equals("0.0.0.0")
|| value.equals("localhost") || value.equals("::1"));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@

package net.william278.huskhomes.config;

import de.exlll.configlib.NameFormatters;
import de.exlll.configlib.YamlConfigurationProperties;
import de.exlll.configlib.YamlConfigurationStore;
import de.exlll.configlib.YamlConfigurations;
import de.exlll.configlib.*;
import net.william278.huskhomes.HuskHomes;
import net.william278.huskhomes.position.Location;
import net.william278.huskhomes.util.UnsafeBlocks;
Expand Down
135 changes: 135 additions & 0 deletions common/src/main/java/net/william278/huskhomes/util/DumpProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* This file is part of HuskHomes, licensed under the Apache License 2.0.
*
* Copyright (c) William278 <will27528@gmail.com>
* Copyright (c) contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.william278.huskhomes.util;

import net.william278.huskhomes.HuskHomes;
import net.william278.huskhomes.hook.Hook;
import net.william278.huskhomes.user.CommandUser;
import net.william278.huskhomes.user.OnlineUser;
import net.william278.toilet.DumpOptions;
import net.william278.toilet.Toilet;
import net.william278.toilet.dump.DumpUser;
import net.william278.toilet.dump.PluginInfo;
import net.william278.toilet.dump.PluginStatus;
import net.william278.toilet.dump.ProjectMeta;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.NotNull;

import static net.william278.toilet.DumpOptions.*;

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

public interface DumpProvider {

@NotNull String BYTEBIN_URL = "https://bytebin.lucko.me";
@NotNull String VIEWER_URL = "https://william278.net/dump";

@NotNull
Toilet getToilet();

@NotNull
@Blocking
default String createDump(@NotNull CommandUser u) {
return getToilet().dump(getPluginStatus(), u instanceof OnlineUser o
? new DumpUser(o.getName(), o.getUuid()) : null).toString();
}

@NotNull
default DumpOptions getDumpOptions() {
return builder()
.bytebinUrl(BYTEBIN_URL)
.viewerUrl(VIEWER_URL)
.projectMeta(ProjectMeta.builder()
.id("huskhomes")
.name("HuskHomes")
.version(getPlugin().getPluginVersion().toString())
.md5("unknown")
.author("William278")
.sourceCode("https://github.com/WiIIiam278/HuskHomes")
.website("https://william278.net/project/huskhomes")
.support("https://discord.gg/tVYhJfyDWG")
.build())
.fileInclusionRules(List.of(
FileInclusionRule.configFile("config.yml", "Config File"),
FileInclusionRule.configFile("spawn.yml", "Spawn File"),
FileInclusionRule.configFile(getMessagesFile(), "Locales File")
))
.compatibilityRules(List.of(
getCompatibilityWarning("CMI", "CMI may cause compatibility issues with " +
"HuskHomes. If you're using Vault, ensure the CMI-compatible version is in use.")
))
.build();
}

@NotNull
@Blocking
private PluginStatus getPluginStatus() {
return PluginStatus.builder()
.blocks(List.of(getSystemStatus(), getHookStatus()))
.build();
}

@NotNull
@Blocking
private PluginStatus.MapStatusBlock getSystemStatus() {
return new PluginStatus.MapStatusBlock(
Map.ofEntries(
Map.entry("Language", StatusLine.LANGUAGE.getValue(getPlugin())),
Map.entry("Database Type", StatusLine.DATABASE_TYPE.getValue(getPlugin())),
Map.entry("Database Local", StatusLine.IS_DATABASE_LOCAL.getValue(getPlugin())),
Map.entry("Economy Mode", StatusLine.ECONOMY_MODE.getValue(getPlugin())),
Map.entry("Cross Server", StatusLine.IS_CROSS_SERVER.getValue(getPlugin())),
Map.entry("Server Name", StatusLine.SERVER_NAME.getValue(getPlugin())),
Map.entry("Message Broker", StatusLine.MESSAGE_BROKER_TYPE.getValue(getPlugin())),
Map.entry("Redis Sentinel", StatusLine.USING_REDIS_SENTINEL.getValue(getPlugin())),
Map.entry("Redis Password", StatusLine.USING_REDIS_PASSWORD.getValue(getPlugin())),
Map.entry("Redis SSL", StatusLine.REDIS_USING_SSL.getValue(getPlugin())),
Map.entry("Redis Local", StatusLine.IS_REDIS_LOCAL.getValue(getPlugin()))
), "Plugin Status", "fa6-solid:wrench"
);
}

@NotNull
@Blocking
private PluginStatus.ListStatusBlock getHookStatus() {
return new PluginStatus.ListStatusBlock(
getPlugin().getHooks().stream().map(Hook::getName).toList(),
"Loaded Hooks", "fa6-solid:plug"
);
}

@NotNull
@SuppressWarnings("SameParameterValue")
private CompatibilityRule getCompatibilityWarning(@NotNull String plugin, @NotNull String description) {
return CompatibilityRule.builder()
.labelToApply(new PluginInfo.Label("Warning", "#fcba03", description))
.resourceName(plugin).build();
}

@NotNull
private String getMessagesFile() {
return "messages-%s.yml".formatted(getPlugin().getSettings().getLanguage());
}

@NotNull
HuskHomes getPlugin();

}
Loading

0 comments on commit 115dd1d

Please sign in to comment.