9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2025-12-27 19:09:18 +00:00

Added debug command

This commit is contained in:
XiaoMoMi
2024-07-10 19:40:47 +08:00
parent c2b8392f58
commit d5eea4cdb7
16 changed files with 219 additions and 7 deletions

View File

@@ -54,7 +54,8 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
new AddStatisticsCommand(this),
new SetStatisticsCommand(this),
new ResetStatisticsCommand(this),
new QueryStatisticsCommand(this)
new QueryStatisticsCommand(this),
new DebugLootCommand(this)
);
private final Index<String, CommandFeature<CommandSender>> INDEX = Index.create(CommandFeature::getFeatureID, FEATURES);

View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) <2022> <XiaoMoMi>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.momirealms.customfishing.bukkit.command.feature;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.momirealms.customfishing.api.BukkitCustomFishingPlugin;
import net.momirealms.customfishing.api.mechanic.context.Context;
import net.momirealms.customfishing.api.mechanic.context.ContextKeys;
import net.momirealms.customfishing.api.mechanic.effect.Effect;
import net.momirealms.customfishing.api.mechanic.effect.EffectModifier;
import net.momirealms.customfishing.api.mechanic.effect.EffectProperties;
import net.momirealms.customfishing.api.mechanic.fishing.FishingGears;
import net.momirealms.customfishing.bukkit.command.BukkitCommandFeature;
import net.momirealms.customfishing.common.command.CustomFishingCommandManager;
import net.momirealms.customfishing.common.locale.MessageConstants;
import net.momirealms.customfishing.common.util.TriConsumer;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.Command;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.context.CommandInput;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.parser.standard.UUIDParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
public class DebugLootCommand extends BukkitCommandFeature<CommandSender> {
public DebugLootCommand(CustomFishingCommandManager<CommandSender> commandManager) {
super(commandManager);
}
@Override
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
return builder
.senderType(Player.class)
.required("surrounding", StringParser.stringComponent().suggestionProvider(new SuggestionProvider<>() {
@Override
public @NonNull CompletableFuture<? extends @NonNull Iterable<? extends @NonNull Suggestion>> suggestionsFuture(@NonNull CommandContext<Object> context, @NonNull CommandInput input) {
return CompletableFuture.completedFuture(Stream.of("lava", "water", "void").map(Suggestion::suggestion).toList());
}
}))
.handler(context -> {
String surrounding = context.get("surrounding");
if (context.sender().getInventory().getItemInMainHand().getType() != Material.FISHING_ROD) {
handleFeedback(context, MessageConstants.COMMAND_DEBUG_LOOT_FAILURE_ROD);
return;
}
final Player player = context.sender();
Context<Player> playerContext = Context.player(player);
FishingGears gears = new FishingGears(playerContext);
Effect effect = Effect.newInstance();
// The effects impact mechanism at this stage
for (EffectModifier modifier : gears.effectModifiers()) {
for (TriConsumer<Effect, Context<Player>, Integer> consumer : modifier.modifiers()) {
consumer.accept(effect, playerContext, 0);
}
}
playerContext.arg(ContextKeys.SURROUNDING, surrounding);
Effect tempEffect = effect.copy();
for (EffectModifier modifier : gears.effectModifiers()) {
for (TriConsumer<Effect, Context<Player>, Integer> consumer : modifier.modifiers()) {
consumer.accept(tempEffect, playerContext, 1);
}
}
playerContext.arg(ContextKeys.OTHER_LOCATION, player.getLocation());
playerContext.arg(ContextKeys.OTHER_X, player.getLocation().getBlockX());
playerContext.arg(ContextKeys.OTHER_Y, player.getLocation().getBlockY());
playerContext.arg(ContextKeys.OTHER_Z, player.getLocation().getBlockZ());
Map<String, Double> weightMap = BukkitCustomFishingPlugin.getInstance().getLootManager().getWeightedLoots(tempEffect, playerContext);
if (weightMap.isEmpty()) {
handleFeedback(context, MessageConstants.COMMAND_DEBUG_LOOT_FAILURE_NO_LOOT);
return;
}
List<LootWithWeight> loots = new ArrayList<>();
double sum = 0;
for (Map.Entry<String, Double> entry : weightMap.entrySet()) {
double weight = entry.getValue();
String loot = entry.getKey();
if (weight <= 0) continue;
loots.add(new LootWithWeight(loot, weight));
sum += weight;
}
LootWithWeight[] lootArray = loots.toArray(new LootWithWeight[0]);
quickSort(lootArray, 0,lootArray.length - 1);
Component component = Component.text().build();
for (LootWithWeight loot : lootArray) {
component = component.append(Component.newline())
.append(Component.text(loot.key + ": ").color(NamedTextColor.WHITE))
.append(Component.text(String.format("%.4f", loot.weight * 100 / sum) + "% ").color(NamedTextColor.GOLD))
.append(Component.text("(" + loot.weight + ")").color(NamedTextColor.GRAY));
}
handleFeedback(context, MessageConstants.COMMAND_DEBUG_LOOT_SUCCESS, component);
});
}
@Override
public String getFeatureID() {
return "debug_loot";
}
public record LootWithWeight(String key, double weight) {
}
private static void quickSort(LootWithWeight[] loot, int low, int high) {
if (low < high) {
int pi = partition(loot, low, high);
quickSort(loot, low, pi - 1);
quickSort(loot, pi + 1, high);
}
}
private static int partition(LootWithWeight[] loot, int low, int high) {
double pivot = loot[high].weight();
int i = low - 1;
for (int j = low; j <= high - 1; j++) {
if (loot[j].weight() > pivot) {
i++;
swap(loot, i, j);
}
}
swap(loot, i + 1, high);
return i + 1;
}
private static void swap(LootWithWeight[] loot, int i, int j) {
LootWithWeight temp = loot[i];
loot[i] = loot[j];
loot[j] = temp;
}
}

View File

@@ -439,6 +439,8 @@ public class BukkitConfigManager extends ConfigManager {
float size = (float) RandomUtils.generateRandomDouble(minSize, maxSize);
item.setTag(size, "CustomFishing", "size");
context.arg(ContextKeys.SIZE, size);
context.arg(ContextKeys.MIN_SIZE, minSize);
context.arg(ContextKeys.MAX_SIZE, maxSize);
context.arg(ContextKeys.SIZE_FORMATTED, String.format("%.2f", size));
};
}, 1_000, "size");

View File

@@ -155,6 +155,7 @@ public class Migration {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(outPut), StandardCharsets.UTF_8))) {
writer.write(sb.toString()
.replace("{sold-item-amount}", "{sold_item_amount}")
.replace("{size}", "{size_formatted}")
.replace("{record}", "{record_formatted}")
.replace("{loot}", "{id}")

View File

@@ -46,6 +46,8 @@ import org.bukkit.event.player.PlayerQuitEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashSet;
@@ -77,6 +79,11 @@ public class BukkitStorageManager implements StorageManager, Listener {
@Override
public void reload() {
YamlDocument config = plugin.getConfigManager().loadConfig("database.yml");
try {
config.save(new File(plugin.getDataFolder(), "database.yml"));
} catch (IOException e) {
throw new RuntimeException(e);
}
this.serverID = config.getString("unique-server-id", "default");
// Check if storage type has changed and reinitialize if necessary
@@ -291,7 +298,7 @@ public class BukkitStorageManager implements StorageManager, Listener {
if (player == null || !player.isOnline())
return;
if (times > 3) {
plugin.getPluginLogger().warn("Tried 3 times when getting data for " + uuid + ". Giving up.");
plugin.getPluginLogger().warn("Tried 3 times getting data for " + uuid + ". Giving up.");
return;
}
this.dataSource.getPlayerData(uuid, ConfigManager.lockData()).thenAccept(optionalData -> {

View File

@@ -183,4 +183,13 @@ statistics_add:
permission: customfishing.command.statistics
usage:
- /customfishing statistics add
- /cfishing statistics add
- /cfishing statistics add
# A command to debug the loot table
# Usage: [COMMAND] [surrounding]
debug_loot:
enable: true
permission: customfishing.command.debug
usage:
- /customfishing debug loot
- /cfishing debug loot

View File

@@ -417,6 +417,7 @@ other-settings:
'{date}': '%server_time_yyyy-MM-dd-HH:mm:ss%'
# Requires player expansion
'{yaw}': '%player_yaw%'
'{random}': '%customfishing_random%'
# CustomFishing supports using items/blocks from other plugins
# If items share the same id, they would inherit the effects
# Check the wiki for examples

View File

@@ -117,7 +117,7 @@ rubbish:
display:
name: <#00BFFF>Radioactive Fish</#00BFFF>
lore:
- <gray>Protect the environment...
- <gray>Time to protect the environment
custom-model-data: 50000
show-in-fishfinder: false
disable-stat: true

View File

@@ -76,6 +76,9 @@ command.statistics.modify.success: "<white>Successfully modified the fishing sta
command.statistics.reset.success: "<white>Successfully reset the fishing statistics for <arg:0></white>"
command.statistics.query.size: "<white>Max sizes: <arg:0></white>"
command.statistics.query.amount: "<white>Amount of fish caught: <arg:0></white>"
command.debug.loot.failure.rod: "<red>Please hold a fishing rod before using this command</red>"
command.debug.loot.failure.no_loot: "<red>No loot available</red>"
command.debug.loot.success: "<yellow><b>Available loots:</b></yellow> <arg:0>"
competition.no_score: "No Score"
competition.no_player: "No Player"
competition.no_rank: "No Rank"

View File

@@ -76,6 +76,8 @@ command.statistics.modify.success: "<white>成功修改 <arg:0> 的钓鱼统计
command.statistics.reset.success: "<white>成功重置 <arg:0> 的钓鱼统计数据</white>"
command.statistics.query.size: "<white>最长的鱼的长度: <arg:0></white>"
command.statistics.query.amount: "<white>钓到鱼的数量: <arg:0></white>"
command.debug.loot.failure.rod: "<red>请手持鱼竿后再执行此命令</red>"
command.debug.loot.success: "<yellow><b>战利品概率表:</b></yellow> <arg:0>"
competition.no_score: "暂无得分"
competition.no_player: "暂无玩家"
competition.no_rank: "暂无排名"