diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/block/AbstractCustomCropsBlock.java b/api/src/main/java/net/momirealms/customcrops/api/core/block/AbstractCustomCropsBlock.java index cef84aa..2e2420b 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/block/AbstractCustomCropsBlock.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/block/AbstractCustomCropsBlock.java @@ -21,6 +21,7 @@ import com.flowpowered.nbt.CompoundMap; import com.flowpowered.nbt.IntTag; import com.flowpowered.nbt.StringTag; import com.flowpowered.nbt.Tag; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.customcrops.api.core.world.CustomCropsBlockState; import net.momirealms.customcrops.api.core.world.CustomCropsWorld; import net.momirealms.customcrops.api.core.world.Pos3; @@ -96,4 +97,9 @@ public abstract class AbstractCustomCropsBlock implements CustomCropsBlock { @Override public void onPlace(WrappedPlaceEvent event) { } + + @Override + public NamedTextColor insightColor() { + return NamedTextColor.WHITE; + } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/block/CropBlock.java b/api/src/main/java/net/momirealms/customcrops/api/core/block/CropBlock.java index af62f4c..200e8c5 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/block/CropBlock.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/block/CropBlock.java @@ -18,6 +18,7 @@ package net.momirealms.customcrops.api.core.block; import com.flowpowered.nbt.IntTag; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.customcrops.api.BukkitCustomCropsPlugin; import net.momirealms.customcrops.api.action.ActionManager; import net.momirealms.customcrops.api.context.Context; @@ -386,4 +387,9 @@ public class CropBlock extends AbstractCustomCropsBlock { public CropConfig config(CustomCropsBlockState state) { return Registries.CROP.get(id(state)); } + + @Override + public NamedTextColor insightColor() { + return NamedTextColor.GREEN; + } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/block/CustomCropsBlock.java b/api/src/main/java/net/momirealms/customcrops/api/core/block/CustomCropsBlock.java index a7a9c25..92e91cd 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/block/CustomCropsBlock.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/block/CustomCropsBlock.java @@ -18,6 +18,7 @@ package net.momirealms.customcrops.api.core.block; import com.flowpowered.nbt.CompoundMap; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.customcrops.api.core.world.CustomCropsBlockState; import net.momirealms.customcrops.api.core.world.CustomCropsWorld; import net.momirealms.customcrops.api.core.world.Pos3; @@ -45,4 +46,6 @@ public interface CustomCropsBlock { void onPlace(WrappedPlaceEvent event); boolean isBlockInstance(String id); + + NamedTextColor insightColor(); } diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/block/GreenhouseBlock.java b/api/src/main/java/net/momirealms/customcrops/api/core/block/GreenhouseBlock.java index 3bb3d8b..0b5c96a 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/block/GreenhouseBlock.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/block/GreenhouseBlock.java @@ -17,6 +17,7 @@ package net.momirealms.customcrops.api.core.block; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.customcrops.api.BukkitCustomCropsPlugin; import net.momirealms.customcrops.api.core.BuiltInBlockMechanics; import net.momirealms.customcrops.api.core.ConfigManager; @@ -115,4 +116,9 @@ public class GreenhouseBlock extends AbstractCustomCropsBlock { }); return state; } + + @Override + public NamedTextColor insightColor() { + return NamedTextColor.GRAY; + } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/block/PotBlock.java b/api/src/main/java/net/momirealms/customcrops/api/core/block/PotBlock.java index 0e6652d..c813221 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/block/PotBlock.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/block/PotBlock.java @@ -18,6 +18,7 @@ package net.momirealms.customcrops.api.core.block; import com.flowpowered.nbt.*; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.customcrops.api.BukkitCustomCropsPlugin; import net.momirealms.customcrops.api.action.ActionManager; import net.momirealms.customcrops.api.context.Context; @@ -638,4 +639,9 @@ public class PotBlock extends AbstractCustomCropsBlock { tag.put(new StringTag("id", fertilizer.id())); return tag; } + + @Override + public NamedTextColor insightColor() { + return NamedTextColor.LIGHT_PURPLE; + } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/block/ScarecrowBlock.java b/api/src/main/java/net/momirealms/customcrops/api/core/block/ScarecrowBlock.java index 80aea7a..0562698 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/block/ScarecrowBlock.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/block/ScarecrowBlock.java @@ -17,6 +17,7 @@ package net.momirealms.customcrops.api.core.block; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.customcrops.api.BukkitCustomCropsPlugin; import net.momirealms.customcrops.api.core.BuiltInBlockMechanics; import net.momirealms.customcrops.api.core.ConfigManager; @@ -115,4 +116,9 @@ public class ScarecrowBlock extends AbstractCustomCropsBlock { }); return state; } + + @Override + public NamedTextColor insightColor() { + return NamedTextColor.YELLOW; + } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/block/SprinklerBlock.java b/api/src/main/java/net/momirealms/customcrops/api/core/block/SprinklerBlock.java index 86c3989..b9b580b 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/block/SprinklerBlock.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/block/SprinklerBlock.java @@ -19,6 +19,7 @@ package net.momirealms.customcrops.api.core.block; import com.flowpowered.nbt.IntTag; import com.flowpowered.nbt.Tag; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.customcrops.api.BukkitCustomCropsPlugin; import net.momirealms.customcrops.api.action.ActionManager; import net.momirealms.customcrops.api.context.Context; @@ -359,4 +360,9 @@ public class SprinklerBlock extends AbstractCustomCropsBlock { FurnitureRotation rotation = BukkitCustomCropsPlugin.getInstance().getItemManager().remove(location, ExistenceForm.ANY); BukkitCustomCropsPlugin.getInstance().getItemManager().place(location, config.existenceForm(), hasWater ? config.threeDItemWithWater() : config.threeDItem(), rotation); } + + @Override + public NamedTextColor insightColor() { + return NamedTextColor.AQUA; + } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsWorld.java b/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsWorld.java index 18bd980..43fbc3c 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsWorld.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsWorld.java @@ -149,6 +149,13 @@ public interface CustomCropsWorld { */ CustomCropsChunk[] loadedChunks(); + /** + * Gets all the lazy chunks in this world. + * + * @return An array of {@link CustomCropsChunk} representing the lazy chunks. + */ + CustomCropsChunk[] lazyChunks(); + /** * Gets the block state at a specific location. * diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsWorldImpl.java b/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsWorldImpl.java index 16d7859..344ff4f 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsWorldImpl.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsWorldImpl.java @@ -137,6 +137,11 @@ public class CustomCropsWorldImpl implements CustomCropsWorld { return loadedChunks.values().toArray(new CustomCropsChunk[0]); } + @Override + public CustomCropsChunk[] lazyChunks() { + return lazyChunks.values().toArray(new CustomCropsChunk[0]); + } + @NotNull @Override public Optional getBlockState(Pos3 location) { diff --git a/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/BukkitCommandManager.java b/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/BukkitCommandManager.java index 7b7cd7d..0dd0c38 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/BukkitCommandManager.java +++ b/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/BukkitCommandManager.java @@ -41,7 +41,9 @@ public class BukkitCommandManager extends AbstractCommandManager new SetSeasonCommand(this), new GetDateCommand(this), new SetDateCommand(this), - new ForceTickCommand(this) + new ForceTickCommand(this), + new DebugWorldsCommand(this), + new DebugInsightCommand(this) ); private final Index> INDEX = Index.create(CommandFeature::getFeatureID, FEATURES); diff --git a/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/DebugInsightCommand.java b/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/DebugInsightCommand.java new file mode 100644 index 0000000..a95ad49 --- /dev/null +++ b/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/DebugInsightCommand.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) <2024> + * + * 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 . + */ + +package net.momirealms.customcrops.bukkit.command.feature; + +import net.momirealms.customcrops.api.BukkitCustomCropsPlugin; +import net.momirealms.customcrops.api.core.world.*; +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.plugin.scheduler.SchedulerTask; +import net.momirealms.sparrow.heart.SparrowHeart; +import net.momirealms.sparrow.heart.feature.color.NamedTextColor; +import net.momirealms.sparrow.heart.feature.highlight.HighlightBlocks; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +public class DebugInsightCommand extends BukkitCommandFeature { + + public DebugInsightCommand(CustomCropsCommandManager commandManager) { + super(commandManager); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .senderType(Player.class) + .handler(context -> { + BukkitCustomCropsPlugin plugin = BukkitCustomCropsPlugin.getInstance(); + Player player = context.sender(); + if (player.hasMetadata("customcrops:insight")) { + player.removeMetadata("customcrops:insight", plugin.getBoostrap()); + plugin.getSenderFactory().wrap(player).sendMessage(AdventureHelper.miniMessage("Insight mode: OFF")); + return; + } + + player.setMetadata("customcrops:insight", new FixedMetadataValue(plugin.getBoostrap(), 1)); + new InsightPlayer(player.getUniqueId()); + plugin.getSenderFactory().wrap(player).sendMessage(AdventureHelper.miniMessage("Insight mode: ON")); + plugin.getSenderFactory().wrap(player).sendMessage(AdventureHelper.miniMessage("Note: ")); + }); + } + + @Override + public String getFeatureID() { + return "debug_insight"; + } + + public static class InsightPlayer implements Runnable { + + private final SchedulerTask task; + private final UUID uuid; + private final HashMap highlightCache = new HashMap<>(); + private ChunkPos currentPos = null; + private String currentWorld = null; + + public InsightPlayer(UUID uuid) { + this.uuid = uuid; + this.task = BukkitCustomCropsPlugin.getInstance().getScheduler().asyncRepeating(this, 50, 50, TimeUnit.MILLISECONDS); + } + + @Override + public void run() { + Player player = Bukkit.getPlayer(uuid); + if (player == null || !player.isOnline() || !player.hasMetadata("customcrops:insight")) { + for (HighlightBlocks[] blocks : highlightCache.values()) { + for (HighlightBlocks block : blocks) { + block.destroy(player); + } + } + highlightCache.clear(); + task.cancel(); + return; + } + World world = player.getWorld(); + String worldName = player.getWorld().getName(); + if (!worldName.equals(currentWorld)) { + currentWorld = worldName; + for (HighlightBlocks[] blocks : highlightCache.values()) { + for (HighlightBlocks block : blocks) { + block.destroy(player); + } + } + highlightCache.clear(); + currentPos = null; + } + + Optional> optionWorld = BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(world); + if (optionWorld.isEmpty()) { + return; + } + CustomCropsWorld customCropsWorld = optionWorld.get(); + + Chunk chunk = player.getLocation().getChunk(); + ChunkPos chunkPos = ChunkPos.fromBukkitChunk(chunk); + if (!chunkPos.equals(currentPos)) { + currentPos = chunkPos; + HashSet nearbyChunks = new HashSet<>(); + for (int i = -2; i < 3; i++) { + for (int j = -2; j < 3; j++) { + nearbyChunks.add(ChunkPos.of(currentPos.x() + i, currentPos.z() + j)); + } + } + ArrayList chunksToRemove = new ArrayList<>(); + for (Map.Entry entry : highlightCache.entrySet()) { + if (!nearbyChunks.contains(entry.getKey())) { + chunksToRemove.add(entry.getKey()); + } + } + for (ChunkPos pos : chunksToRemove) { + HighlightBlocks[] blocks = highlightCache.remove(pos); + for (HighlightBlocks block : blocks) { + block.destroy(player); + } + } + for (ChunkPos pos : nearbyChunks) { + if (!highlightCache.containsKey(pos)) { + customCropsWorld.getChunk(pos).ifPresentOrElse(cropsChunk -> { + ArrayList highlightBlockList = new ArrayList<>(); + HashMap> blockMap = new HashMap<>(); + for (CustomCropsSection section : cropsChunk.sections()) { + for (Map.Entry entry : section.blockMap().entrySet()) { + net.kyori.adventure.text.format.NamedTextColor namedTextColor = entry.getValue().type().insightColor(); + Location location = LocationUtils.toSurfaceCenterLocation(entry.getKey().toPos3(pos).toLocation(world)); + List locations = blockMap.computeIfAbsent(namedTextColor, k -> new ArrayList<>()); + locations.add(location); + } + } + for (Map.Entry> entry : blockMap.entrySet()) { + highlightBlockList.add(SparrowHeart.getInstance().highlightBlocks( + player, NamedTextColor.namedColor(entry.getKey().value()), entry.getValue().toArray(new Location[0]) + )); + } + highlightCache.put(pos, highlightBlockList.toArray(new HighlightBlocks[0])); + }, () -> { + highlightCache.put(pos, new HighlightBlocks[0]); + }); + } + } + } + } + } +} diff --git a/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/DebugWorldsCommand.java b/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/DebugWorldsCommand.java new file mode 100644 index 0000000..8ea00fc --- /dev/null +++ b/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/DebugWorldsCommand.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) <2024> + * + * 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 . + */ + +package net.momirealms.customcrops.bukkit.command.feature; + +import net.momirealms.customcrops.api.BukkitCustomCropsPlugin; +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 org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; + +public class DebugWorldsCommand extends BukkitCommandFeature { + + public DebugWorldsCommand(CustomCropsCommandManager commandManager) { + super(commandManager); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .handler(context -> { + Sender sender = BukkitCustomCropsPlugin.getInstance().getSenderFactory().wrap(context.sender()); + for (World world : Bukkit.getWorlds()) { + BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(world).ifPresent(w -> { + sender.sendMessage(AdventureHelper.miniMessage("World: " + world.getName() + "")); + sender.sendMessage(AdventureHelper.miniMessage(" - Loaded chunks: " + w.loadedChunks().length)); + sender.sendMessage(AdventureHelper.miniMessage(" - Lazy chunks: " + w.lazyChunks().length)); + }); + } + }); + } + + @Override + public String getFeatureID() { + return "debug_worlds"; + } +} diff --git a/plugin/src/main/java/net/momirealms/customcrops/bukkit/config/BukkitConfigManager.java b/plugin/src/main/java/net/momirealms/customcrops/bukkit/config/BukkitConfigManager.java index 461eadc..be37f37 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/bukkit/config/BukkitConfigManager.java +++ b/plugin/src/main/java/net/momirealms/customcrops/bukkit/config/BukkitConfigManager.java @@ -143,6 +143,13 @@ public class BukkitConfigManager extends ConfigManager { } } } + + for (String id : scarecrow) { + Registries.BLOCKS.register(id, BuiltInBlockMechanics.SCARECROW.mechanic()); + } + for (String id : greenhouse) { + Registries.BLOCKS.register(id, BuiltInBlockMechanics.GREENHOUSE.mechanic()); + } } @Override diff --git a/plugin/src/main/resources/commands.yml b/plugin/src/main/resources/commands.yml index fe9c732..a6f2bc3 100644 --- a/plugin/src/main/resources/commands.yml +++ b/plugin/src/main/resources/commands.yml @@ -51,6 +51,20 @@ debug_data: - /customcrops debug data - /ccrops debug data +debug_worlds: + enable: true + permission: customcrops.command.debug + usage: + - /customcrops debug worlds + - /ccrops debug worlds + +debug_insight: + enable: true + permission: customcrops.command.debug + usage: + - /customcrops debug insight + - /ccrops debug insight + force_tick: enable: true permission: customcrops.command.force_tick