mirror of
https://github.com/Xiao-MoMi/Custom-Crops.git
synced 2025-12-27 19:09:09 +00:00
Added unsafe commands
This commit is contained in:
@@ -92,29 +92,6 @@ public interface ActionManager<T> extends Reloadable {
|
||||
*/
|
||||
Action<T> parseAction(@NotNull String type, @NotNull Object args);
|
||||
|
||||
/**
|
||||
* Generates a map of actions triggered by specific events from a configuration section.
|
||||
*
|
||||
* @param section The configuration section containing event-action mappings.
|
||||
* @return A map where the keys are action triggers and the values are arrays of actions associated with those triggers.
|
||||
*/
|
||||
default Map<ActionTrigger, Action<T>[]> parseEventActions(Section section) {
|
||||
HashMap<ActionTrigger, Action<T>[]> actionMap = new HashMap<>();
|
||||
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof Section innerSection) {
|
||||
try {
|
||||
actionMap.put(
|
||||
ActionTrigger.valueOf(entry.getKey().toUpperCase(Locale.ENGLISH)),
|
||||
parseActions(innerSection)
|
||||
);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return actionMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a configuration section to generate a map of timed actions.
|
||||
*
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.api.action;
|
||||
|
||||
public enum ActionTrigger {
|
||||
PLACE,
|
||||
BREAK,
|
||||
WORK, INTERACT
|
||||
}
|
||||
@@ -117,6 +117,10 @@ public class SynchronizedCompoundMap {
|
||||
return compoundMapToString("BlockData", compoundMap);
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
return compoundMapToString("", compoundMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively converts a CompoundMap to a string representation.
|
||||
*
|
||||
@@ -126,12 +130,15 @@ public class SynchronizedCompoundMap {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private String compoundMapToString(String key, CompoundMap compoundMap) {
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
StringJoiner joiner = new StringJoiner(",");
|
||||
for (Map.Entry<String, Tag<?>> entry : compoundMap.entrySet()) {
|
||||
Tag<?> tag = entry.getValue();
|
||||
String tagValue;
|
||||
switch (tag.getType()) {
|
||||
case TAG_STRING, TAG_BYTE, TAG_DOUBLE, TAG_FLOAT, TAG_INT, TAG_INT_ARRAY,
|
||||
case TAG_STRING -> {
|
||||
tagValue = "\"" + tag.getValue().toString() + "\"";
|
||||
}
|
||||
case TAG_BYTE, TAG_DOUBLE, TAG_FLOAT, TAG_INT, TAG_INT_ARRAY,
|
||||
TAG_LONG, TAG_SHORT, TAG_SHORT_ARRAY, TAG_LONG_ARRAY, TAG_BYTE_ARRAY ->
|
||||
tagValue = tag.getValue().toString();
|
||||
case TAG_LIST -> {
|
||||
@@ -151,8 +158,12 @@ public class SynchronizedCompoundMap {
|
||||
continue; // skip unsupported tag types
|
||||
}
|
||||
}
|
||||
joiner.add("\"" + entry.getKey() + "\":\"" + tagValue + "\"");
|
||||
joiner.add(entry.getKey() + "=" + tagValue);
|
||||
}
|
||||
if (key.isEmpty()) {
|
||||
return joiner.toString();
|
||||
} else {
|
||||
return key + "=[" + joiner + "]";
|
||||
}
|
||||
return key + "{" + joiner + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,10 +168,21 @@ public class CropBlock extends AbstractCustomCropsBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockInstance(String id) {
|
||||
public boolean isInstance(String id) {
|
||||
return Registries.STAGE_TO_CROP_UNSAFE.containsKey(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(Location location, CustomCropsBlockState state) {
|
||||
CropConfig config = config(state);
|
||||
if (config == null) return;
|
||||
int point = point(state);
|
||||
CropStageConfig stageConfig = config.stageWithModelByPoint(point);
|
||||
if (stageConfig != null) {
|
||||
BukkitCustomCropsPlugin.getInstance().getItemManager().place(location, stageConfig.existenceForm(), Objects.requireNonNull(stageConfig.stageID()), config.rotation() ? FurnitureRotation.random() : FurnitureRotation.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(WrappedInteractEvent event) {
|
||||
final Player player = event.player();
|
||||
|
||||
@@ -26,26 +26,76 @@ import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
|
||||
import net.momirealms.customcrops.api.core.wrapper.WrappedPlaceEvent;
|
||||
import net.momirealms.customcrops.api.misc.NamedTextColor;
|
||||
import net.momirealms.customcrops.common.util.Key;
|
||||
import org.bukkit.Location;
|
||||
|
||||
public interface CustomCropsBlock {
|
||||
|
||||
/**
|
||||
* Get the key
|
||||
*
|
||||
* @return key
|
||||
*/
|
||||
Key type();
|
||||
|
||||
/**
|
||||
* Create a CustomCropsBlockState based on this type
|
||||
*
|
||||
* @return CustomCropsBlockState
|
||||
*/
|
||||
CustomCropsBlockState createBlockState();
|
||||
|
||||
/**
|
||||
* Create a CustomCropsBlockState based on this type and provided data
|
||||
*
|
||||
* @return CustomCropsBlockState
|
||||
*/
|
||||
CustomCropsBlockState createBlockState(CompoundMap data);
|
||||
|
||||
/**
|
||||
* Runs scheduled tick tasks
|
||||
*/
|
||||
void scheduledTick(CustomCropsBlockState state, CustomCropsWorld<?> world, Pos3 location, boolean offlineTick);
|
||||
|
||||
/**
|
||||
* Runs random tick tasks
|
||||
*/
|
||||
void randomTick(CustomCropsBlockState state, CustomCropsWorld<?> world, Pos3 location, boolean offlineTick);
|
||||
|
||||
/**
|
||||
* Handles interactions
|
||||
*/
|
||||
void onInteract(WrappedInteractEvent event);
|
||||
|
||||
/**
|
||||
* Handles breaks
|
||||
*/
|
||||
void onBreak(WrappedBreakEvent event);
|
||||
|
||||
/**
|
||||
* Handles placement
|
||||
*/
|
||||
void onPlace(WrappedPlaceEvent event);
|
||||
|
||||
boolean isBlockInstance(String id);
|
||||
/**
|
||||
* Checks if the id is an instance of this block type
|
||||
*
|
||||
* @param id id
|
||||
* @return is instance or not
|
||||
*/
|
||||
boolean isInstance(String id);
|
||||
|
||||
/**
|
||||
* Restores the bukkit block state or furniture based on the given block state
|
||||
*
|
||||
* @param location the location of the block
|
||||
* @param state the provided state
|
||||
*/
|
||||
void restore(Location location, CustomCropsBlockState state);
|
||||
|
||||
/**
|
||||
* Get the color on insight mode
|
||||
*
|
||||
* @return the color
|
||||
*/
|
||||
NamedTextColor insightColor();
|
||||
}
|
||||
|
||||
@@ -38,10 +38,15 @@ public class DeadCrop extends AbstractCustomCropsBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockInstance(String id) {
|
||||
public boolean isInstance(String id) {
|
||||
return Registries.ITEM_TO_DEAD_CROP.containsKey(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(Location location, CustomCropsBlockState state) {
|
||||
// do not restore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(WrappedInteractEvent event) {
|
||||
final Player player = event.player();
|
||||
|
||||
@@ -20,6 +20,7 @@ package net.momirealms.customcrops.api.core.block;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.BuiltInBlockMechanics;
|
||||
import net.momirealms.customcrops.api.core.ConfigManager;
|
||||
import net.momirealms.customcrops.api.core.FurnitureRotation;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.core.world.Pos3;
|
||||
@@ -102,10 +103,17 @@ public class GreenhouseBlock extends AbstractCustomCropsBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockInstance(String id) {
|
||||
public boolean isInstance(String id) {
|
||||
return ConfigManager.greenhouse().contains(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(Location location, CustomCropsBlockState state) {
|
||||
String id = ConfigManager.greenhouse().stream().findAny().orElse(null);
|
||||
if (id == null) return;
|
||||
BukkitCustomCropsPlugin.getInstance().getItemManager().place(location, ConfigManager.greenhouseExistenceForm(), id, FurnitureRotation.NONE);
|
||||
}
|
||||
|
||||
public CustomCropsBlockState getOrFixState(CustomCropsWorld<?> world, Pos3 pos3) {
|
||||
Optional<CustomCropsBlockState> optional = world.getBlockState(pos3);
|
||||
if (optional.isPresent() && optional.get().type() instanceof GreenhouseBlock) {
|
||||
|
||||
@@ -228,10 +228,15 @@ public class PotBlock extends AbstractCustomCropsBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockInstance(String id) {
|
||||
public boolean isInstance(String id) {
|
||||
return Registries.ITEM_TO_POT.containsKey(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(Location location, CustomCropsBlockState state) {
|
||||
updateBlockAppearance(location, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(WrappedInteractEvent event) {
|
||||
PotConfig potConfig = Registries.ITEM_TO_POT.get(event.relatedID());
|
||||
@@ -614,9 +619,13 @@ public class PotBlock extends AbstractCustomCropsBlock {
|
||||
}
|
||||
|
||||
public void updateBlockAppearance(Location location, PotConfig config, boolean hasWater, @Nullable Fertilizer fertilizer) {
|
||||
if (config.disablePluginMechanism()) return;
|
||||
String appearance = config.getPotAppearance(hasWater, fertilizer == null ? null : fertilizer.type());
|
||||
BukkitCustomCropsPlugin.getInstance().getItemManager().placeBlock(location, appearance);
|
||||
if (config.disablePluginMechanism()) {
|
||||
String appearance = config.blocks().stream().findAny().get();
|
||||
BukkitCustomCropsPlugin.getInstance().getItemManager().placeBlock(location, appearance);
|
||||
} else {
|
||||
String appearance = config.getPotAppearance(hasWater, fertilizer == null ? null : fertilizer.type());
|
||||
BukkitCustomCropsPlugin.getInstance().getItemManager().placeBlock(location, appearance);
|
||||
}
|
||||
}
|
||||
|
||||
private Fertilizer tagToFertilizer(CompoundMap tag) {
|
||||
|
||||
@@ -20,6 +20,7 @@ package net.momirealms.customcrops.api.core.block;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.BuiltInBlockMechanics;
|
||||
import net.momirealms.customcrops.api.core.ConfigManager;
|
||||
import net.momirealms.customcrops.api.core.FurnitureRotation;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.core.world.Pos3;
|
||||
@@ -102,10 +103,17 @@ public class ScarecrowBlock extends AbstractCustomCropsBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockInstance(String id) {
|
||||
public boolean isInstance(String id) {
|
||||
return ConfigManager.scarecrow().contains(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(Location location, CustomCropsBlockState state) {
|
||||
String id = ConfigManager.scarecrow().stream().findAny().orElse(null);
|
||||
if (id == null) return;
|
||||
BukkitCustomCropsPlugin.getInstance().getItemManager().place(location, ConfigManager.scarecrowExistenceForm(), id, FurnitureRotation.NONE);
|
||||
}
|
||||
|
||||
public CustomCropsBlockState getOrFixState(CustomCropsWorld<?> world, Pos3 pos3) {
|
||||
Optional<CustomCropsBlockState> optional = world.getBlockState(pos3);
|
||||
if (optional.isPresent() && optional.get().type() instanceof ScarecrowBlock) {
|
||||
|
||||
@@ -148,10 +148,17 @@ public class SprinklerBlock extends AbstractCustomCropsBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockInstance(String id) {
|
||||
public boolean isInstance(String id) {
|
||||
return Registries.ITEM_TO_SPRINKLER.containsKey(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restore(Location location, CustomCropsBlockState state) {
|
||||
SprinklerConfig config = config(state);
|
||||
if (config == null) return;
|
||||
updateBlockAppearance(location, config, water(state) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(WrappedInteractEvent event) {
|
||||
SprinklerConfig config = Registries.ITEM_TO_SPRINKLER.get(event.relatedID());
|
||||
|
||||
@@ -55,4 +55,6 @@ public interface CustomCropsBlockState extends DataBlock {
|
||||
|
||||
@ApiStatus.Internal
|
||||
byte[] getNBTDataAsBytes();
|
||||
|
||||
String asString();
|
||||
}
|
||||
|
||||
@@ -46,6 +46,13 @@ public class CustomCropsBlockStateImpl implements CustomCropsBlockState {
|
||||
return TagUtils.toBytes(new CompoundTag("data", compoundMap.originalMap()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asString() {
|
||||
return owner.type().asString() +
|
||||
"[" + compoundMap.asString() +
|
||||
']';
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag<?> set(String key, Tag<?> tag) {
|
||||
return compoundMap.put(key, tag);
|
||||
@@ -68,10 +75,9 @@ public class CustomCropsBlockStateImpl implements CustomCropsBlockState {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CustomCropsBlock{" +
|
||||
"Type{" + owner.type().asString() +
|
||||
"}, " + compoundMap +
|
||||
'}';
|
||||
return owner.type().asString() +
|
||||
"[" + compoundMap +
|
||||
']';
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -333,6 +333,12 @@ public class CustomCropsWorldImpl<W> implements CustomCropsWorld<W> {
|
||||
return this.lazyChunks.remove(chunkPos);
|
||||
}
|
||||
|
||||
public void deleteChunk(ChunkPos chunkPos) {
|
||||
this.lazyChunks.remove(chunkPos);
|
||||
this.loadedChunks.remove(chunkPos);
|
||||
getRegion(RegionPos.getByChunkPos(chunkPos)).ifPresent(region -> region.removeCachedChunk(chunkPos));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CustomCropsChunk getLazyChunk(ChunkPos chunkPos) {
|
||||
return this.lazyChunks.get(chunkPos);
|
||||
|
||||
@@ -46,4 +46,16 @@ public interface MessageConstants {
|
||||
TranslatableComponent.Builder COMMAND_FORCE_TICK_SUCCESS = Component.translatable().key("command.force_tick.success");
|
||||
TranslatableComponent.Builder COMMAND_FORCE_TICK_FAILURE_TYPE = Component.translatable().key("command.force_tick.failure.type");
|
||||
TranslatableComponent.Builder COMMAND_FORCE_TICK_FAILURE_DISABLE = Component.translatable().key("command.force_tick.failure.disable");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_DATA_FAILURE = Component.translatable().key("command.debug.data.failure");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_DATA_SUCCESS_VANILLA = Component.translatable().key("command.debug.data.success.vanilla");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_DATA_SUCCESS_CUSTOM = Component.translatable().key("command.debug.data.success.custom");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_WORLDS_FAILURE = Component.translatable().key("command.debug.worlds.failure");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_WORLDS_SUCCESS = Component.translatable().key("command.debug.worlds.success");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_INSIGHT_OFF = Component.translatable().key("command.debug.insight.off");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_INSIGHT_ON = Component.translatable().key("command.debug.insight.on");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_DELETE_FAILURE_WORLD = Component.translatable().key("command.unsafe.delete.failure.world");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_DELETE_SUCCESS = Component.translatable().key("command.unsafe.delete.success");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_RESTORE_FAILURE_WORLD = Component.translatable().key("command.unsafe.restore.failure.world");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_RESTORE_FAILURE_CHUNK = Component.translatable().key("command.unsafe.restore.failure.chunk");
|
||||
TranslatableComponent.Builder COMMAND_DEBUG_RESTORE_SUCCESS = Component.translatable().key("command.unsafe.restore.success");
|
||||
}
|
||||
|
||||
@@ -168,9 +168,9 @@ public class TranslationManager {
|
||||
}
|
||||
|
||||
Map<String, String> bundle = new HashMap<>();
|
||||
YamlDocument document = plugin.getConfigManager().loadConfig("translations" + "\\" + translationFile.getFileName(), '@');
|
||||
YamlDocument document = plugin.getConfigManager().loadConfig("translations" + File.separator + translationFile.getFileName(), '@');
|
||||
try {
|
||||
document.save(new File(plugin.getDataDirectory().toFile(), "translations" + "\\" + translationFile.getFileName()));
|
||||
document.save(new File(plugin.getDataDirectory().toFile(), "translations" + File.separator + translationFile.getFileName()));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Could not update translation file: " + translationFile.getFileName(), e);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Project settings
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=3.6.10
|
||||
config_version=40
|
||||
config_version=41
|
||||
project_group=net.momirealms
|
||||
|
||||
# Dependency settings
|
||||
|
||||
@@ -98,7 +98,7 @@ public class BukkitCustomCropsPluginImpl extends BukkitCustomCropsPlugin {
|
||||
|
||||
@Override
|
||||
public InputStream getResourceStream(String filePath) {
|
||||
return getBootstrap().getResource(filePath);
|
||||
return getBootstrap().getResource(filePath.replace("\\", "/"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,7 +43,9 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
|
||||
new SetDateCommand(this),
|
||||
new ForceTickCommand(this),
|
||||
new DebugWorldsCommand(this),
|
||||
new DebugInsightCommand(this)
|
||||
new DebugInsightCommand(this),
|
||||
new UnsafeRestoreCommand(this),
|
||||
new UnsafeDeleteCommand(this)
|
||||
);
|
||||
|
||||
private final Index<String, CommandFeature<CommandSender>> INDEX = Index.create(CommandFeature::getFeatureID, FEATURES);
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
|
||||
package net.momirealms.customcrops.bukkit.command.feature;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.core.world.Pos3;
|
||||
import net.momirealms.customcrops.bukkit.command.BukkitCommandFeature;
|
||||
import net.momirealms.customcrops.common.command.CustomCropsCommandManager;
|
||||
import net.momirealms.customcrops.common.helper.AdventureHelper;
|
||||
import net.momirealms.customcrops.common.locale.MessageConstants;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -52,22 +54,21 @@ public class DebugDataCommand extends BukkitCommandFeature<CommandSender> {
|
||||
block = location.getBlock();
|
||||
} else {
|
||||
block = player.getTargetBlockExact(10);
|
||||
if (block == null) return;
|
||||
if (block == null) {
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_DATA_FAILURE);
|
||||
return;
|
||||
}
|
||||
location = block.getLocation();
|
||||
}
|
||||
BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(location.getWorld()).ifPresent(world -> {
|
||||
Optional<CustomCropsBlockState> state = world.getBlockState(Pos3.from(location));
|
||||
if (state.isPresent()) {
|
||||
BukkitCustomCropsPlugin.getInstance().getSenderFactory().wrap(player)
|
||||
.sendMessage(AdventureHelper.miniMessage("<gold>" + state.get()));
|
||||
} else {
|
||||
BukkitCustomCropsPlugin.getInstance().getSenderFactory().wrap(player)
|
||||
.sendMessage(AdventureHelper.miniMessage("<red>CustomCrops Data not found"));
|
||||
}
|
||||
state.ifPresent(customCropsBlockState ->
|
||||
handleFeedback(context,
|
||||
MessageConstants.COMMAND_DEBUG_DATA_SUCCESS_CUSTOM,
|
||||
Component.text(customCropsBlockState.asString())));
|
||||
});
|
||||
String bData = block.getBlockData().getAsString();
|
||||
BukkitCustomCropsPlugin.getInstance().getSenderFactory().wrap(player)
|
||||
.sendMessage(AdventureHelper.miniMessage("<green>Vanilla crop data: <hover:show_text:'<yellow>Copy'><click:copy_to_clipboard:'"+bData+"'>" + bData + "</click>"));
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_DATA_SUCCESS_VANILLA, Component.text(bData));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import net.momirealms.customcrops.api.util.LocationUtils;
|
||||
import net.momirealms.customcrops.bukkit.command.BukkitCommandFeature;
|
||||
import net.momirealms.customcrops.common.command.CustomCropsCommandManager;
|
||||
import net.momirealms.customcrops.common.helper.AdventureHelper;
|
||||
import net.momirealms.customcrops.common.locale.MessageConstants;
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.SchedulerTask;
|
||||
import net.momirealms.sparrow.heart.SparrowHeart;
|
||||
import net.momirealms.sparrow.heart.feature.color.NamedTextColor;
|
||||
@@ -59,14 +60,13 @@ public class DebugInsightCommand extends BukkitCommandFeature<CommandSender> imp
|
||||
Player player = context.sender();
|
||||
if (player.hasMetadata("customcrops:insight")) {
|
||||
player.removeMetadata("customcrops:insight", plugin.getBootstrap());
|
||||
plugin.getSenderFactory().wrap(player).sendMessage(AdventureHelper.miniMessage("<red>Insight mode: OFF"));
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_INSIGHT_OFF);
|
||||
return;
|
||||
}
|
||||
|
||||
player.setMetadata("customcrops:insight", new FixedMetadataValue(plugin.getBootstrap(), 1));
|
||||
new InsightPlayer(player.getUniqueId());
|
||||
plugin.getSenderFactory().wrap(player).sendMessage(AdventureHelper.miniMessage("<green>Insight mode: ON"));
|
||||
plugin.getSenderFactory().wrap(player).sendMessage(AdventureHelper.miniMessage("<white>Note that this only shows a snapshot of the data."));
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_INSIGHT_ON);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,17 +17,20 @@
|
||||
|
||||
package net.momirealms.customcrops.bukkit.command.feature;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.bukkit.command.BukkitCommandFeature;
|
||||
import net.momirealms.customcrops.common.command.CustomCropsCommandManager;
|
||||
import net.momirealms.customcrops.common.helper.AdventureHelper;
|
||||
import net.momirealms.customcrops.common.sender.Sender;
|
||||
import net.momirealms.customcrops.common.locale.MessageConstants;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class DebugWorldsCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public DebugWorldsCommand(CustomCropsCommandManager<CommandSender> commandManager) {
|
||||
@@ -38,14 +41,19 @@ public class DebugWorldsCommand extends BukkitCommandFeature<CommandSender> {
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.handler(context -> {
|
||||
Sender sender = BukkitCustomCropsPlugin.getInstance().getSenderFactory().wrap(context.sender());
|
||||
int worldCount = 0;
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(world).ifPresent(w -> {
|
||||
sender.sendMessage(AdventureHelper.miniMessage("<gold>World: " + world.getName() + "</gold>"));
|
||||
sender.sendMessage(AdventureHelper.miniMessage(" - Loaded regions: " + w.loadedRegions().length));
|
||||
sender.sendMessage(AdventureHelper.miniMessage(" - Loaded chunks: " + w.loadedChunks().length));
|
||||
sender.sendMessage(AdventureHelper.miniMessage(" - Lazy chunks: " + w.lazyChunks().length));
|
||||
});
|
||||
Optional<CustomCropsWorld<?>> optional = BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(world);
|
||||
if (optional.isPresent()) {
|
||||
worldCount++;
|
||||
CustomCropsWorld<?> w = optional.get();
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_WORLDS_SUCCESS,
|
||||
Component.text(world.getName()), Component.text(w.loadedRegions().length), Component.text(w.loadedChunks().length), Component.text(w.lazyChunks().length)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (worldCount == 0) {
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_WORLDS_FAILURE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.bukkit.command.feature;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.world.ChunkPos;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorldImpl;
|
||||
import net.momirealms.customcrops.bukkit.command.BukkitCommandFeature;
|
||||
import net.momirealms.customcrops.common.command.CustomCropsCommandManager;
|
||||
import net.momirealms.customcrops.common.locale.MessageConstants;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class UnsafeDeleteCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public UnsafeDeleteCommand(CustomCropsCommandManager<CommandSender> commandManager) {
|
||||
super(commandManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.senderType(Player.class)
|
||||
.flag(manager.flagBuilder("silent").build())
|
||||
.handler(context -> {
|
||||
Player player = context.sender();
|
||||
Optional<CustomCropsWorld<?>> optional = BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(player.getWorld());
|
||||
if (optional.isEmpty()) {
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_DELETE_FAILURE_WORLD, Component.text(player.getWorld().getName()));
|
||||
return;
|
||||
}
|
||||
CustomCropsWorld<?> world = optional.get();
|
||||
CustomCropsWorldImpl<?> customCropsWorld = (CustomCropsWorldImpl<?>) world;
|
||||
ChunkPos chunkPos = ChunkPos.fromBukkitChunk(player.getLocation().getChunk());
|
||||
customCropsWorld.deleteChunk(chunkPos);
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_DELETE_SUCCESS);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "unsafe_delete";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.bukkit.command.feature;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.AbstractItemManager;
|
||||
import net.momirealms.customcrops.api.core.world.*;
|
||||
import net.momirealms.customcrops.bukkit.command.BukkitCommandFeature;
|
||||
import net.momirealms.customcrops.common.command.CustomCropsCommandManager;
|
||||
import net.momirealms.customcrops.common.locale.MessageConstants;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class UnsafeRestoreCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public UnsafeRestoreCommand(CustomCropsCommandManager<CommandSender> commandManager) {
|
||||
super(commandManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.senderType(Player.class)
|
||||
.flag(manager.flagBuilder("silent").build())
|
||||
.handler(context -> {
|
||||
Player player = context.sender();
|
||||
World bukkitWorld = player.getWorld();
|
||||
Optional<CustomCropsWorld<?>> optional = BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(bukkitWorld);
|
||||
if (optional.isEmpty()) {
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_RESTORE_FAILURE_WORLD, Component.text(bukkitWorld.getName()));
|
||||
return;
|
||||
}
|
||||
ChunkPos chunkPos = ChunkPos.fromBukkitChunk(player.getLocation().getChunk());
|
||||
CustomCropsWorld<?> world = optional.get();
|
||||
Optional<CustomCropsChunk> chunk = world.getLoadedChunk(chunkPos);
|
||||
if (chunk.isEmpty()) {
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_RESTORE_FAILURE_CHUNK);
|
||||
return;
|
||||
}
|
||||
CustomCropsChunk customCropsChunk = chunk.get();
|
||||
AbstractItemManager itemManager = BukkitCustomCropsPlugin.getInstance().getItemManager();
|
||||
int totalBlocks = 0;
|
||||
int restoredBlocks = 0;
|
||||
for (CustomCropsSection section : customCropsChunk.sections()) {
|
||||
for (Map.Entry<BlockPos, CustomCropsBlockState> entry : section.blockMap().entrySet()) {
|
||||
totalBlocks++;
|
||||
Pos3 pos3 = entry.getKey().toPos3(chunkPos);
|
||||
Location location = pos3.toLocation(bukkitWorld);
|
||||
String realID = itemManager.anyID(location);
|
||||
if (!entry.getValue().type().isInstance(realID)) {
|
||||
restoredBlocks++;
|
||||
entry.getValue().type().restore(location, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
handleFeedback(context, MessageConstants.COMMAND_DEBUG_RESTORE_SUCCESS, Component.text(restoredBlocks), Component.text(totalBlocks));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "unsafe_restore";
|
||||
}
|
||||
}
|
||||
@@ -574,7 +574,7 @@ public class BukkitItemManager extends AbstractItemManager {
|
||||
CustomCropsBlockState customCropsBlockState = optionalState.get();
|
||||
String anyFurnitureID = furnitureID(location);
|
||||
if (anyFurnitureID != null) {
|
||||
if (!customCropsBlockState.type().isBlockInstance(anyFurnitureID)) {
|
||||
if (!customCropsBlockState.type().isInstance(anyFurnitureID)) {
|
||||
world.removeBlockState(pos3);
|
||||
plugin.debug(() -> "[" + location.getWorld().getName() + "] Removed inconsistent block data at " + pos3 + " which used to be " + customCropsBlockState);
|
||||
} else {
|
||||
@@ -583,7 +583,7 @@ public class BukkitItemManager extends AbstractItemManager {
|
||||
}
|
||||
}
|
||||
String anyBlockID = blockID(location);
|
||||
if (!customCropsBlockState.type().isBlockInstance(anyBlockID)) {
|
||||
if (!customCropsBlockState.type().isInstance(anyBlockID)) {
|
||||
world.removeBlockState(pos3);
|
||||
plugin.debug(() -> "[" + location.getWorld().getName() + "] Removed inconsistent block data at " + pos3 + " which used to be " + customCropsBlockState);
|
||||
} else {
|
||||
|
||||
@@ -86,4 +86,22 @@ force_tick:
|
||||
permission: customcrops.command.force_tick
|
||||
usage:
|
||||
- /customcrops force-tick
|
||||
- /ccrops force-tick
|
||||
- /ccrops force-tick
|
||||
|
||||
# A command to restore the blocks by CustomCrops data in one chunk
|
||||
# Usage: [COMMAND]
|
||||
unsafe_restore:
|
||||
enable: true
|
||||
permission: customcrops.command.unsafe.restore
|
||||
usage:
|
||||
- /customcrops unsafe restore
|
||||
- /ccrops unsafe restore
|
||||
|
||||
# A command to delete the CustomCrops data in one chunk
|
||||
# Usage: [COMMAND]
|
||||
unsafe_delete:
|
||||
enable: true
|
||||
permission: customcrops.command.unsafe.delete
|
||||
usage:
|
||||
- /customcrops unsafe delete
|
||||
- /ccrops unsafe delete
|
||||
@@ -1,6 +1,11 @@
|
||||
# Don"t change this
|
||||
config-version: "38"
|
||||
config-version: "41"
|
||||
|
||||
season.spring: "Spring"
|
||||
season.summer: "Summer"
|
||||
season.autumn: "Autumn"
|
||||
season.winter: "Winter"
|
||||
season.disable: "Disable"
|
||||
exception.invalid_syntax: "<red>Invalid syntax. Correct syntax: <white><arg:0></white></red>"
|
||||
exception.invalid_argument: "<red>Invalid argument. Reason: <white><arg:0></white></red>"
|
||||
exception.invalid_sender: "<red><arg:0> is not allowed to execute that command. Must be of type <arg:1></red>"
|
||||
@@ -57,8 +62,21 @@ command.date.set.failure.invalid: "<red>Invalid date [<arg:1>]</red>"
|
||||
command.force_tick.success: "<white>Took <arg:0>ms ticking <arg:1> blocks</white>"
|
||||
command.force_tick.failure.disable: "<red>CustomCrops is not enabled in world [<arg:0>]</red>"
|
||||
command.force_tick.failure.type: "<red>Unknown type [<arg:0>]</red>"
|
||||
season.spring: "Spring"
|
||||
season.summer: "Summer"
|
||||
season.autumn: "Autumn"
|
||||
season.winter: "Winter"
|
||||
season.disable: "Disable"
|
||||
command.unsafe.delete.failure.world: "<red>CustomCrops is not enabled in world [<arg:0>]</red>"
|
||||
command.unsafe.delete.success: "<white>Deleted block data in this chunk"
|
||||
command.unsafe.restore.failure.world: "<red>CustomCrops is not enabled in world [<arg:0>]</red>"
|
||||
command.unsafe.restore.failure.chunk: "<red>This chunk doesn't contain any data</red>"
|
||||
command.unsafe.restore.success: "<white>Restored (<arg:0>/<arg:1>) blocks</white>"
|
||||
command.debug.data.failure: "<red>No block selected</red>"
|
||||
command.debug.data.success.vanilla: "<green>Vanilla block data: <hover:show_text:'<yellow>Copy'><click:copy_to_clipboard:'<arg:0>'><arg:0></click>"
|
||||
command.debug.data.success.custom: "<gold>Custom block data: <hover:show_text:'<yellow>Copy'><click:copy_to_clipboard:'<arg:0>'><arg:0></click>"
|
||||
command.debug.worlds.failure: "<red>There's no world loaded</red>"
|
||||
command.debug.worlds.success:
|
||||
- "<gold>World: <arg:0></gold>"
|
||||
- " - Loaded regions: <arg:1>"
|
||||
- " - Loaded chunks: <arg:2>"
|
||||
- " - Lazy chunks: <arg:3>"
|
||||
command.debug.insight.off: "<red>Insight mode: OFF</red>"
|
||||
command.debug.insight.on:
|
||||
- "<green>Insight mode: ON</green>"
|
||||
- "<white>Note that this only shows a snapshot of the data."
|
||||
@@ -1,6 +1,11 @@
|
||||
# 别动这个
|
||||
config-version: "38"
|
||||
config-version: "41"
|
||||
|
||||
season.spring: "春"
|
||||
season.summer: "夏"
|
||||
season.autumn: "秋"
|
||||
season.winter: "冬"
|
||||
season.disable: "未启用"
|
||||
exception.invalid_syntax: "<red>无效语法. 正确语法:<white><arg:0></white></red>"
|
||||
exception.invalid_argument: "<red>无效参数. 原因:<white><arg:0></white></red>"
|
||||
exception.invalid_sender: "<red><arg:0> 不允许执行该命令. 执行者必须是 <arg:1></red>"
|
||||
@@ -56,8 +61,21 @@ command.date.set.failure.invalid: "<red>无效的日期 [<arg:1>]</red>"
|
||||
command.force_tick.success: "<white>花费 <arg:0>ms 更新了 <arg:1> 个方块</white>"
|
||||
command.force_tick.failure.disable: "<red>CustomCrops没有在世界 [<arg:0>] 启用</red>"
|
||||
command.force_tick.failure.type: "<red>未知的类型 [<arg:0>]</red>"
|
||||
season.spring: "春"
|
||||
season.summer: "夏"
|
||||
season.autumn: "秋"
|
||||
season.winter: "冬"
|
||||
season.disable: "未启用"
|
||||
command.unsafe.delete.failure.world: "<red>CustomCrops没有在世界 [<arg:0>] 启用</red>"
|
||||
command.unsafe.delete.success: "<white>删除了这个区块的数据"
|
||||
command.unsafe.restore.failure.world: "<red>CustomCrops没有在世界 [<arg:0>] 启用</red>"
|
||||
command.unsafe.restore.failure.chunk: "<red>这个区块没有任何数据</red>"
|
||||
command.unsafe.restore.success: "<white>恢复了 (<arg:0>/<arg:1>) 方块</white>"
|
||||
command.debug.data.failure: "<red>未选中任何方块</red>"
|
||||
command.debug.data.success.vanilla: "<green>原版方块数据: <hover:show_text:'<yellow>Copy'><click:copy_to_clipboard:'<arg:0>'><arg:0></click>"
|
||||
command.debug.data.success.custom: "<gold>自定义方块数据: <hover:show_text:'<yellow>Copy'><click:copy_to_clipboard:'<arg:0>'><arg:0></click>"
|
||||
command.debug.worlds.failure: "<red>没有农作物世界被加载</red>"
|
||||
command.debug.worlds.success:
|
||||
- "<gold>世界: <arg:0></gold>"
|
||||
- " - 加载中的区域: <arg:1>"
|
||||
- " - 加载中的区块: <arg:2>"
|
||||
- " - 不活跃的区块: <arg:3>"
|
||||
command.debug.insight.off: "<red>洞察模式: OFF</red>"
|
||||
command.debug.insight.on:
|
||||
- "<green>洞察模式: ON</green>"
|
||||
- "<white>注意在这个模式下你只能看到数据的快照"
|
||||
|
||||
Reference in New Issue
Block a user