From 3f98c117fcc4a64e635e8b9d48415177670576d6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <70987828+Xiao-MoMi@users.noreply.github.com> Date: Mon, 2 Sep 2024 00:31:29 +0800 Subject: [PATCH] force tick --- .../customcrops/api/core/MappedRegistry.java | 11 ++ .../customcrops/api/core/Registry.java | 4 + .../customcrops/api/core/block/CropBlock.java | 9 +- .../api/core/block/CrowAttack.java | 38 ++--- .../api/core/block/CustomCropsBlock.java | 2 + .../api/core/block/GreenhouseBlock.java | 13 +- .../customcrops/api/core/block/PotBlock.java | 13 +- .../api/core/block/ScarecrowBlock.java | 13 +- .../api/core/block/SprinklerBlock.java | 9 +- .../customcrops/api/core/item/SeedItem.java | 4 +- .../api/core/item/SprinklerItem.java | 4 +- .../api/core/world/CustomCropsChunk.java | 2 +- .../api/core/world/CustomCropsChunkImpl.java | 4 +- .../api/core/world/CustomCropsWorld.java | 2 + .../api/core/world/CustomCropsWorldImpl.java | 5 + .../common/locale/MessageConstants.java | 3 + .../customcrops/common/util/QuadConsumer.java | 22 +++ gradle.properties | 2 +- .../bukkit/command/BukkitCommandManager.java | 3 +- .../command/feature/ForceTickCommand.java | 132 ++++++++++++++++++ .../bukkit/item/BukkitItemManager.java | 19 ++- plugin/src/main/resources/commands.yml | 7 + plugin/src/main/resources/translations/en.yml | 3 + .../src/main/resources/translations/zh_cn.yml | 3 + 24 files changed, 278 insertions(+), 49 deletions(-) create mode 100644 common/src/main/java/net/momirealms/customcrops/common/util/QuadConsumer.java create mode 100644 plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/ForceTickCommand.java diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/MappedRegistry.java b/api/src/main/java/net/momirealms/customcrops/api/core/MappedRegistry.java index 53994b4..153986d 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/MappedRegistry.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/MappedRegistry.java @@ -38,6 +38,7 @@ public class MappedRegistry implements WriteableRegistry { public void register(K key, T value) { byKey.put(key, value); byValue.put(value, key); + byID.add(value); } @Override @@ -67,6 +68,16 @@ public class MappedRegistry implements WriteableRegistry { return byKey.get(key); } + @Override + public boolean containsKey(@Nullable K key) { + return byKey.containsKey(key); + } + + @Override + public boolean containsValue(@Nullable T value) { + return byValue.containsKey(value); + } + @NotNull @Override public Iterator iterator() { diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/Registry.java b/api/src/main/java/net/momirealms/customcrops/api/core/Registry.java index f4ee23f..5f7cfa4 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/Registry.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/Registry.java @@ -30,4 +30,8 @@ public interface Registry extends IdMap { @Nullable T get(@Nullable K key); + + boolean containsKey(@Nullable K key); + + boolean containsValue(@Nullable T value); } 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 34447a8..474e2a1 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 @@ -153,6 +153,11 @@ public class CropBlock extends AbstractCustomCropsBlock { fixOrGetState(world, pos3, event.placedID()); } + @Override + public boolean isBlockInstance(String id) { + return Registries.STAGE_TO_CROP_UNSAFE.containsKey(id); + } + @Override public void onInteract(WrappedInteractEvent event) { final Player player = event.player(); @@ -287,8 +292,8 @@ public class CropBlock extends AbstractCustomCropsBlock { id(state, cropConfig.id()); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); return state; diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/block/CrowAttack.java b/api/src/main/java/net/momirealms/customcrops/api/core/block/CrowAttack.java index bb95d4f..181391d 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/block/CrowAttack.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/block/CrowAttack.java @@ -52,7 +52,7 @@ public class CrowAttack { } } this.viewers = viewers.toArray(new Player[0]); - this.cropLocation = location.clone().add(RandomUtils.generateRandomDouble(-0.25, 0.25), 0, RandomUtils.generateRandomDouble(-0.25, 0.25)); + this.cropLocation = LocationUtils.toBlockCenterLocation(location).add(RandomUtils.generateRandomDouble(-0.25, 0.25), 0, RandomUtils.generateRandomDouble(-0.25, 0.25)); float yaw = RandomUtils.generateRandomInt(-180, 180); this.cropLocation.setYaw(yaw); this.flyModel = flyModel; @@ -66,47 +66,39 @@ public class CrowAttack { public void start() { if (this.viewers.length == 0) return; - FakeArmorStand fake1 = SparrowHeart.getInstance().createFakeArmorStand(dynamicLocation); - fake1.invisible(true); - fake1.small(true); - fake1.equipment(EquipmentSlot.HEAD, flyModel); - FakeArmorStand fake2 = SparrowHeart.getInstance().createFakeArmorStand(cropLocation); - fake1.invisible(true); - fake1.small(true); - fake1.equipment(EquipmentSlot.HEAD, standModel); + FakeArmorStand fake = SparrowHeart.getInstance().createFakeArmorStand(dynamicLocation); + fake.invisible(true); + fake.small(true); + fake.equipment(EquipmentSlot.HEAD, flyModel); for (Player player : this.viewers) { - fake1.spawn(player); + fake.spawn(player); } this.task = BukkitCustomCropsPlugin.getInstance().getScheduler().asyncRepeating(() -> { timer++; if (timer < 100) { dynamicLocation.add(vectorDown); for (Player player : this.viewers) { - SparrowHeart.getInstance().sendClientSideTeleportEntity(player, dynamicLocation, false, fake1.entityID()); + SparrowHeart.getInstance().sendClientSideTeleportEntity(player, dynamicLocation, false, fake.entityID()); } - } else if (timer == 100){ + } else if (timer == 100) { + fake.equipment(EquipmentSlot.HEAD, standModel); for (Player player : this.viewers) { - fake1.destroy(player); - } - for (Player player : this.viewers) { - fake2.spawn(player); + fake.updateEquipment(player); } } else if (timer == 150) { + fake.equipment(EquipmentSlot.HEAD, flyModel); for (Player player : this.viewers) { - fake2.destroy(player); - } - for (Player player : this.viewers) { - fake1.spawn(player); + fake.updateEquipment(player); } } else if (timer > 150) { dynamicLocation.add(vectorUp); for (Player player : this.viewers) { - SparrowHeart.getInstance().sendClientSideTeleportEntity(player, dynamicLocation, false, fake1.entityID()); + SparrowHeart.getInstance().sendClientSideTeleportEntity(player, dynamicLocation, false, fake.entityID()); } } - if (timer > 300) { + if (timer > 250) { for (Player player : this.viewers) { - fake1.destroy(player); + fake.destroy(player); } task.cancel(); } 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 d0a4166..efcf9fb 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 @@ -43,4 +43,6 @@ public interface CustomCropsBlock { void onBreak(WrappedBreakEvent event); void onPlace(WrappedPlaceEvent event); + + boolean isBlockInstance(String id); } 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 d742276..4728083 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 @@ -90,12 +90,17 @@ public class GreenhouseBlock extends AbstractCustomCropsBlock { CustomCropsWorld world = event.world(); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); } + @Override + public boolean isBlockInstance(String id) { + return ConfigManager.greenhouse().contains(id); + } + public CustomCropsBlockState getOrFixState(CustomCropsWorld world, Pos3 pos3) { Optional optional = world.getBlockState(pos3); if (optional.isPresent() && optional.get().type() instanceof GreenhouseBlock) { @@ -104,8 +109,8 @@ public class GreenhouseBlock extends AbstractCustomCropsBlock { CustomCropsBlockState state = createBlockState(); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at pos3[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at pos3[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); return state; 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 e29d8eb..0312001 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 @@ -199,13 +199,18 @@ public class PotBlock extends AbstractCustomCropsBlock { world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); ActionManager.trigger(context, config.placeActions()); } + @Override + public boolean isBlockInstance(String id) { + return Registries.ITEM_TO_POT.containsKey(id); + } + @Override public void onInteract(WrappedInteractEvent event) { PotConfig potConfig = Registries.ITEM_TO_POT.get(event.relatedID()); @@ -291,8 +296,8 @@ public class PotBlock extends AbstractCustomCropsBlock { water(state, potConfig.isWet(blockID) ? 1 : 0); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); return state; 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 d5cb140..1aad9b2 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 @@ -90,12 +90,17 @@ public class ScarecrowBlock extends AbstractCustomCropsBlock { CustomCropsWorld world = event.world(); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); } + @Override + public boolean isBlockInstance(String id) { + return ConfigManager.scarecrow().contains(id); + } + public CustomCropsBlockState getOrFixState(CustomCropsWorld world, Pos3 pos3) { Optional optional = world.getBlockState(pos3); if (optional.isPresent() && optional.get().type() instanceof ScarecrowBlock) { @@ -104,8 +109,8 @@ public class ScarecrowBlock extends AbstractCustomCropsBlock { CustomCropsBlockState state = createBlockState(); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at pos3[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at pos3[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); return state; 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 c340fd1..dd6baac 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 @@ -137,6 +137,11 @@ public class SprinklerBlock extends AbstractCustomCropsBlock { ActionManager.trigger(context, config.placeActions()); } + @Override + public boolean isBlockInstance(String id) { + return Registries.ITEM_TO_SPRINKLER.containsKey(id); + } + @Override public void onInteract(WrappedInteractEvent event) { SprinklerConfig config = Registries.ITEM_TO_SPRINKLER.get(event.relatedID()); @@ -225,8 +230,8 @@ public class SprinklerBlock extends AbstractCustomCropsBlock { water(state, blockID.equals(sprinklerConfig.threeDItemWithWater()) ? 1 : 0); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); return state; diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/item/SeedItem.java b/api/src/main/java/net/momirealms/customcrops/api/core/item/SeedItem.java index 6aa8366..ba13002 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/item/SeedItem.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/item/SeedItem.java @@ -118,8 +118,8 @@ public class SeedItem extends AbstractCustomCropsItem { cropBlock.point(state, point); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/item/SprinklerItem.java b/api/src/main/java/net/momirealms/customcrops/api/core/item/SprinklerItem.java index be56483..e0cc68a 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/item/SprinklerItem.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/item/SprinklerItem.java @@ -111,8 +111,8 @@ public class SprinklerItem extends AbstractCustomCropsItem { BukkitCustomCropsPlugin.getInstance().getItemManager().place(LocationUtils.toSurfaceCenterLocation(targetLocation), config.existenceForm(), config.threeDItem(), FurnitureRotation.NONE); world.addBlockState(pos3, state).ifPresent(previous -> { BukkitCustomCropsPlugin.getInstance().debug( - "Overwrite old data with " + state.compoundMap().toString() + - " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous.compoundMap().toString() + "Overwrite old data with " + state + + " at location[" + world.worldName() + "," + pos3 + "] which used to be " + previous ); }); ActionManager.trigger(context, config.placeActions()); diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsChunk.java b/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsChunk.java index 16f66cc..0ae1cb8 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsChunk.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsChunk.java @@ -179,7 +179,7 @@ public interface CustomCropsChunk { CustomCropsSection getSection(int sectionID); - Collection sections(); + CustomCropsSection[] sections(); Optional removeSection(int sectionID); diff --git a/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsChunkImpl.java b/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsChunkImpl.java index ba3269a..c0d79ae 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsChunkImpl.java +++ b/api/src/main/java/net/momirealms/customcrops/api/core/world/CustomCropsChunkImpl.java @@ -257,8 +257,8 @@ public class CustomCropsChunkImpl implements CustomCropsChunk { } @Override - public Collection sections() { - return loadedSections.values(); + public CustomCropsSection[] sections() { + return loadedSections.values().toArray(new CustomCropsSection[0]); } @Override 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 33e5cc4..ebb5793 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 @@ -80,6 +80,8 @@ public interface CustomCropsWorld { int getChunkBlockAmount(Pos3 pos3, Class clazz); + CustomCropsChunk[] loadedChunks(); + /** * Get the state of the block at a certain 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 831144c..94c3a31 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 @@ -131,6 +131,11 @@ public class CustomCropsWorldImpl implements CustomCropsWorld { } } + @Override + public CustomCropsChunk[] loadedChunks() { + return loadedChunks.values().toArray(new CustomCropsChunk[0]); + } + @NotNull @Override public Optional getBlockState(Pos3 location) { diff --git a/common/src/main/java/net/momirealms/customcrops/common/locale/MessageConstants.java b/common/src/main/java/net/momirealms/customcrops/common/locale/MessageConstants.java index 4fec42c..2d6548c 100644 --- a/common/src/main/java/net/momirealms/customcrops/common/locale/MessageConstants.java +++ b/common/src/main/java/net/momirealms/customcrops/common/locale/MessageConstants.java @@ -43,4 +43,7 @@ public interface MessageConstants { TranslatableComponent.Builder COMMAND_SET_DATE_FAILURE_REFERENCE = Component.translatable().key("command.date.set.failure.reference"); TranslatableComponent.Builder COMMAND_SET_DATE_FAILURE_OTHER = Component.translatable().key("command.date.set.failure.other"); TranslatableComponent.Builder COMMAND_SET_DATE_FAILURE_INVALID = Component.translatable().key("command.date.set.failure.invalid"); + 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"); } diff --git a/common/src/main/java/net/momirealms/customcrops/common/util/QuadConsumer.java b/common/src/main/java/net/momirealms/customcrops/common/util/QuadConsumer.java new file mode 100644 index 0000000..0c129be --- /dev/null +++ b/common/src/main/java/net/momirealms/customcrops/common/util/QuadConsumer.java @@ -0,0 +1,22 @@ +/* + * 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.common.util; + +public interface QuadConsumer { + void accept(K k, V v, S s, O o); +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 63f69e9..b2e4607 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ asm_commons_version=9.7 jar_relocator_version=1.7 adventure_bundle_version=4.17.0 adventure_platform_version=4.3.4 -sparrow_heart_version=0.39 +sparrow_heart_version=0.40 cloud_core_version=2.0.0-rc.2 cloud_services_version=2.0.0-rc.2 cloud_brigadier_version=2.0.0-beta.9 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 c7ee24e..7b7cd7d 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 @@ -40,7 +40,8 @@ public class BukkitCommandManager extends AbstractCommandManager new GetSeasonCommand(this), new SetSeasonCommand(this), new GetDateCommand(this), - new SetDateCommand(this) + new SetDateCommand(this), + new ForceTickCommand(this) ); private final Index> INDEX = Index.create(CommandFeature::getFeatureID, FEATURES); diff --git a/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/ForceTickCommand.java b/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/ForceTickCommand.java new file mode 100644 index 0000000..92ea411 --- /dev/null +++ b/plugin/src/main/java/net/momirealms/customcrops/bukkit/command/feature/ForceTickCommand.java @@ -0,0 +1,132 @@ +/* + * 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.kyori.adventure.text.Component; +import net.momirealms.customcrops.api.BukkitCustomCropsPlugin; +import net.momirealms.customcrops.api.core.Registries; +import net.momirealms.customcrops.api.core.block.CustomCropsBlock; +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 net.momirealms.customcrops.common.util.Key; +import net.momirealms.customcrops.common.util.QuadConsumer; +import net.momirealms.customcrops.common.util.TriConsumer; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.Command; +import org.incendo.cloud.CommandManager; +import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; +import org.incendo.cloud.bukkit.parser.WorldParser; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.EnumParser; +import org.incendo.cloud.parser.standard.StringParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public class ForceTickCommand extends BukkitCommandFeature { + + public ForceTickCommand(CustomCropsCommandManager commandManager) { + super(commandManager); + } + + @Override + public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { + return builder + .required("world", WorldParser.worldParser()) + .required("type", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + int all = Registries.BLOCK.size(); + ArrayList blocks = new ArrayList<>(); + for (int i = 0; i < all; i++) { + blocks.add(Registries.BLOCK.byId(i)); + } + return CompletableFuture.completedFuture( + blocks.stream().map(block -> Suggestion.suggestion(block.type().asString())).toList() + ); + } + })) + .required("mode", EnumParser.enumParser(Mode.class)) + .flag(manager.flagBuilder("silent").build()) + .handler(context -> { + World world = context.get("world"); + NamespacedKey type = context.get("type"); + Mode mode = context.get("mode"); + Key key = Key.key(type.asString()); + CustomCropsBlock customCropsBlock = Registries.BLOCK.get(key); + if (customCropsBlock == null) { + handleFeedback(context.sender(), MessageConstants.COMMAND_FORCE_TICK_FAILURE_TYPE, Component.text(key.asString())); + return; + } + Optional> optionalWorld = BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(world); + if (optionalWorld.isEmpty()) { + handleFeedback(context.sender(), MessageConstants.COMMAND_FORCE_TICK_FAILURE_DISABLE, Component.text(world.getName())); + return; + } + CustomCropsWorld customCropsWorld = optionalWorld.get(); + BukkitCustomCropsPlugin.getInstance().getScheduler().async().execute(() -> { + int amount = 0; + long time1 = System.currentTimeMillis(); + for (CustomCropsChunk customCropsChunk : customCropsWorld.loadedChunks()) { + for (CustomCropsSection customCropsSection : customCropsChunk.sections()) { + for (Map.Entry entry : customCropsSection.blockMap().entrySet()) { + CustomCropsBlockState state = entry.getValue(); + if (state.type() == customCropsBlock) { + Pos3 pos3 = entry.getKey().toPos3(customCropsChunk.chunkPos()); + mode.consumer.accept(customCropsBlock, state, customCropsWorld, pos3); + amount++; + } + } + } + } + handleFeedback(context.sender(), MessageConstants.COMMAND_FORCE_TICK_SUCCESS, Component.text(System.currentTimeMillis() - time1), Component.text(amount)); + }); + }); + } + + private enum Mode { + + RANDOM_TICK(CustomCropsBlock::randomTick), + SCHEDULED_TICK(CustomCropsBlock::scheduledTick), + ALL((b, s, w, p) -> { + b.randomTick(s, w, p); + b.scheduledTick(s, w, p); + }); + + private final QuadConsumer, Pos3> consumer; + + Mode(QuadConsumer, Pos3> consumer) { + this.consumer = consumer; + } + } + + @Override + public String getFeatureID() { + return "force_tick"; + } +} diff --git a/plugin/src/main/java/net/momirealms/customcrops/bukkit/item/BukkitItemManager.java b/plugin/src/main/java/net/momirealms/customcrops/bukkit/item/BukkitItemManager.java index 2c4f866..83e7a39 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/bukkit/item/BukkitItemManager.java +++ b/plugin/src/main/java/net/momirealms/customcrops/bukkit/item/BukkitItemManager.java @@ -24,7 +24,9 @@ import net.momirealms.customcrops.api.core.*; import net.momirealms.customcrops.api.core.block.BreakReason; import net.momirealms.customcrops.api.core.block.CustomCropsBlock; import net.momirealms.customcrops.api.core.item.CustomCropsItem; +import net.momirealms.customcrops.api.core.world.CustomCropsBlockState; import net.momirealms.customcrops.api.core.world.CustomCropsWorld; +import net.momirealms.customcrops.api.core.world.Pos3; import net.momirealms.customcrops.api.core.wrapper.WrappedBreakEvent; import net.momirealms.customcrops.api.core.wrapper.WrappedInteractAirEvent; import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent; @@ -454,8 +456,23 @@ public class BukkitItemManager extends AbstractItemManager { return; } - String itemID = id(itemInHand); CustomCropsWorld world = optionalWorld.get(); + Pos3 pos3 = Pos3.from(location); + Optional optionalState = world.getBlockState(pos3); + if (optionalState.isPresent()) { + CustomCropsBlockState customCropsBlockState = optionalState.get(); + String anyID = anyID(location); + System.out.println(anyID); + if (!customCropsBlockState.type().isBlockInstance(anyID)) { + world.removeBlockState(pos3); + plugin.debug("[" + location.getWorld().getName() + "] Removed inconsistent block data at " + pos3 + " which used to be " + customCropsBlockState); + } else { + event.setCancelled(true); + return; + } + } + + String itemID = id(itemInHand); WrappedPlaceEvent wrapped = new WrappedPlaceEvent(player, world, location, placedID, hand, itemInHand, itemID, event); CustomCropsBlock customCropsBlock = Registries.BLOCKS.get(placedID); if (customCropsBlock != null) { diff --git a/plugin/src/main/resources/commands.yml b/plugin/src/main/resources/commands.yml index c5d32aa..fe9c732 100644 --- a/plugin/src/main/resources/commands.yml +++ b/plugin/src/main/resources/commands.yml @@ -50,3 +50,10 @@ debug_data: usage: - /customcrops debug data - /ccrops debug data + +force_tick: + enable: true + permission: customcrops.command.force_tick + usage: + - /customcrops force-tick + - /ccrops force-tick \ No newline at end of file diff --git a/plugin/src/main/resources/translations/en.yml b/plugin/src/main/resources/translations/en.yml index 96d3173..58ab14b 100644 --- a/plugin/src/main/resources/translations/en.yml +++ b/plugin/src/main/resources/translations/en.yml @@ -54,6 +54,9 @@ command.date.set.failure.disable: "Date is disabled in world []World [] is not the reference world" command.date.set.failure.other: "Can't set date for world [] because plugin [] takes over the calendar" command.date.set.failure.invalid: "Invalid date []" +command.force_tick.success: "Took ms ticking blocks" +command.force_tick.failure.disable: "CustomCrops is not enabled in world []" +command.force_tick.failure.type: "Unknown type []" season.spring: "Spring" season.summer: "Summer" season.autumn: "Autumn" diff --git a/plugin/src/main/resources/translations/zh_cn.yml b/plugin/src/main/resources/translations/zh_cn.yml index 96e4aa0..702ccf8 100644 --- a/plugin/src/main/resources/translations/zh_cn.yml +++ b/plugin/src/main/resources/translations/zh_cn.yml @@ -53,6 +53,9 @@ command.date.set.success: "成功设置世界 [] 的日期为 [世界 [] 不是同步季节设置的参考世界" command.date.set.failure.other: "无法设置世界 [] 的日期,原因是插件 [] 接管了日历" command.date.set.failure.invalid: "无效的日期 []" +command.force_tick.success: "花费 ms 更新了 个方块" +command.force_tick.failure.disable: "CustomCrops没有在世界 [] 启用" +command.force_tick.failure.type: "未知的类型 []" season.spring: "春" season.summer: "夏" season.autumn: "秋"