mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-30 04:19:27 +00:00
Merge remote-tracking branch 'refs/remotes/origin/dev' into dev
# Conflicts: # bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java # bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java
This commit is contained in:
@@ -118,7 +118,7 @@ public final class CraftEngineBlocks {
|
||||
FastNMS.INSTANCE.method$BlockStateBase$onPlace(blockState, worldServer, blockPos, oldBlockState, false);
|
||||
if (playSound) {
|
||||
SoundData data = block.sounds().placeSound();
|
||||
location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume(), data.pitch());
|
||||
location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume().get(), data.pitch().get());
|
||||
}
|
||||
}
|
||||
return success;
|
||||
|
||||
@@ -311,7 +311,7 @@ public class BlockEventListener implements Listener {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
player.playSound(location, state.sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.sounds().stepSound().volume(), state.sounds().stepSound().pitch());
|
||||
player.playSound(location, state.sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.sounds().stepSound().volume().get(), state.sounds().stepSound().pitch().get());
|
||||
} else if (Config.enableSoundSystem()) {
|
||||
Object ownerBlock = BlockStateUtils.getBlockOwner(blockState);
|
||||
if (manager.isBlockSoundRemoved(ownerBlock)) {
|
||||
|
||||
@@ -34,11 +34,14 @@ import net.momirealms.craftengine.core.pack.ResourceLocation;
|
||||
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
|
||||
import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.registry.BuiltInRegistries;
|
||||
import net.momirealms.craftengine.core.registry.Holder;
|
||||
import net.momirealms.craftengine.core.registry.WritableRegistry;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.sound.Sounds;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
@@ -48,11 +51,19 @@ import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class BukkitBlockManager extends AbstractBlockManager {
|
||||
private static BukkitBlockManager instance;
|
||||
@@ -74,6 +85,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
private Map<Key, Integer> registeredRealBlockSlots;
|
||||
// A set of blocks that sounds have been removed
|
||||
private Set<Object> affectedSoundBlocks;
|
||||
private Map<Object, Pair<SoundData, SoundData>> affectedOpenableBlockSounds;
|
||||
private Map<Key, Key> soundMapper;
|
||||
// A list to record the order of registration
|
||||
private List<Key> blockRegisterOrder = new ObjectArrayList<>();
|
||||
@@ -285,7 +297,8 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
ImmutableMap.Builder<Key, Integer> builder1 = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<Integer, Object> builder2 = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<Key, List<Integer>> builder3 = ImmutableMap.builder();
|
||||
Set<Object> affectedSounds = new HashSet<>();
|
||||
Set<Object> affectedBlockSounds = new HashSet<>();
|
||||
Map<Object, Pair<SoundData, SoundData>> affectedDoors = new IdentityHashMap<>();
|
||||
Set<Object> affectedBlocks = new HashSet<>();
|
||||
List<Key> order = new ArrayList<>();
|
||||
|
||||
@@ -293,7 +306,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
int counter = 0;
|
||||
for (Map.Entry<Key, Integer> baseBlockAndItsCount : this.registeredRealBlockSlots.entrySet()) {
|
||||
counter = registerBlockVariants(baseBlockAndItsCount, counter, builder1, builder2, builder3, affectedSounds, order);
|
||||
counter = registerBlockVariants(baseBlockAndItsCount, counter, builder1, builder2, builder3, affectedBlockSounds, order);
|
||||
}
|
||||
|
||||
freezeRegistry();
|
||||
@@ -306,7 +319,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
for (Object block : (Iterable<Object>) MBuiltInRegistries.BLOCK) {
|
||||
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(block);
|
||||
if (affectedSounds.contains(soundType)) {
|
||||
if (affectedBlockSounds.contains(soundType)) {
|
||||
Object state = getOnlyBlockState(block);
|
||||
if (BlockStateUtils.isVanillaBlock(state)) {
|
||||
affectedBlocks.add(block);
|
||||
@@ -320,7 +333,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
this.affectedSoundBlocks = ImmutableSet.copyOf(affectedBlocks);
|
||||
|
||||
ImmutableMap.Builder<Key, Key> soundMapperBuilder = ImmutableMap.builder();
|
||||
for (Object soundType : affectedSounds) {
|
||||
for (Object soundType : affectedBlockSounds) {
|
||||
for (Field field : List.of(CoreReflections.field$SoundType$placeSound, CoreReflections.field$SoundType$fallSound, CoreReflections.field$SoundType$hitSound, CoreReflections.field$SoundType$stepSound, CoreReflections.field$SoundType$breakSound)) {
|
||||
Object soundEvent = field.get(soundType);
|
||||
Key previousId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(soundEvent).toString());
|
||||
@@ -328,12 +341,53 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
Predicate<Key> predicate = it -> this.realBlockArranger.containsKey(it);
|
||||
Consumer<Key> soundCallback = s -> soundMapperBuilder.put(s, Key.of("replaced." + s.value()));
|
||||
BiConsumer<Object, Pair<SoundData, SoundData>> affectedBlockCallback = affectedDoors::put;
|
||||
Function<Key, SoundData> soundMapper = (k) -> SoundData.of(k, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f));
|
||||
collectDoorSounds(predicate, Sounds.WOODEN_TRAPDOOR_OPEN, Sounds.WOODEN_TRAPDOOR_CLOSE, Sounds.WOODEN_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.NETHER_WOOD_TRAPDOOR_OPEN, Sounds.NETHER_WOOD_TRAPDOOR_CLOSE, Sounds.NETHER_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_TRAPDOOR_OPEN, Sounds.BAMBOO_WOOD_TRAPDOOR_CLOSE, Sounds.BAMBOO_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.CHERRY_WOOD_TRAPDOOR_OPEN, Sounds.CHERRY_WOOD_TRAPDOOR_CLOSE, Sounds.CHERRY_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.COPPER_TRAPDOOR_OPEN, Sounds.COPPER_TRAPDOOR_CLOSE, Sounds.COPPER_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.WOODEN_DOOR_OPEN, Sounds.WOODEN_DOOR_CLOSE, Sounds.WOODEN_DOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.NETHER_WOOD_DOOR_OPEN, Sounds.NETHER_WOOD_DOOR_CLOSE, Sounds.NETHER_DOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_DOOR_OPEN, Sounds.BAMBOO_WOOD_DOOR_CLOSE, Sounds.BAMBOO_DOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.CHERRY_WOOD_DOOR_OPEN, Sounds.CHERRY_WOOD_DOOR_CLOSE, Sounds.CHERRY_DOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.COPPER_DOOR_OPEN, Sounds.COPPER_DOOR_CLOSE, Sounds.COPPER_DOORS, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.WOODEN_FENCE_GATE_OPEN, Sounds.WOODEN_FENCE_GATE_CLOSE, Sounds.WOODEN_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.NETHER_WOOD_FENCE_GATE_OPEN, Sounds.NETHER_WOOD_FENCE_GATE_CLOSE, Sounds.NETHER_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_FENCE_GATE_OPEN, Sounds.BAMBOO_WOOD_FENCE_GATE_CLOSE, Sounds.BAMBOO_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback);
|
||||
collectDoorSounds(predicate, Sounds.CHERRY_WOOD_FENCE_GATE_OPEN, Sounds.CHERRY_WOOD_FENCE_GATE_CLOSE, Sounds.CHERRY_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback);
|
||||
this.affectedOpenableBlockSounds = ImmutableMap.copyOf(affectedDoors);
|
||||
this.soundMapper = soundMapperBuilder.buildKeepingLast();
|
||||
} catch (Throwable e) {
|
||||
plugin.logger().warn("Failed to inject blocks.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void collectDoorSounds(Predicate<Key> isUsedForCustomBlock,
|
||||
Key openSound,
|
||||
Key closeSound,
|
||||
List<Key> doors,
|
||||
Function<Key, SoundData> soundMapper,
|
||||
Consumer<Key> soundCallback,
|
||||
BiConsumer<Object, Pair<SoundData, SoundData>> affectedBlockCallback) {
|
||||
for (Key d : doors) {
|
||||
if (isUsedForCustomBlock.test(d)) {
|
||||
soundCallback.accept(openSound);
|
||||
soundCallback.accept(closeSound);
|
||||
for (Key door : doors) {
|
||||
Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(door));
|
||||
if (block != null) {
|
||||
affectedBlockCallback.accept(block, Pair.of(soundMapper.apply(Key.of("replaced." + openSound.value())), soundMapper.apply(Key.of("replaced." + closeSound.value()))));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BlockParser implements ConfigParser {
|
||||
public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"};
|
||||
|
||||
@@ -501,7 +555,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
json.addProperty("x", ResourceConfigUtils.getAsInt(singleModelMap.get("x"), "x"));
|
||||
if (singleModelMap.containsKey("y"))
|
||||
json.addProperty("y", ResourceConfigUtils.getAsInt(singleModelMap.get("y"), "y"));
|
||||
if (singleModelMap.containsKey("uvlock")) json.addProperty("uvlock", (boolean) singleModelMap.get("uvlock"));
|
||||
if (singleModelMap.containsKey("uvlock")) json.addProperty("uvlock", ResourceConfigUtils.getAsBoolean(singleModelMap.get("uvlock"), "uvlock"));
|
||||
if (singleModelMap.containsKey("weight"))
|
||||
json.addProperty("weight", ResourceConfigUtils.getAsInt(singleModelMap.get("weight"), "weight"));
|
||||
Map<String, Object> generationMap = MiscUtils.castToMap(singleModelMap.get("generation"), true);
|
||||
@@ -556,22 +610,29 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
private void loadMappingsAndAdditionalBlocks() {
|
||||
this.plugin.logger().info("Loading mappings.yml.");
|
||||
File mappingFile = new File(plugin.dataFolderFile(), "mappings.yml");
|
||||
YamlDocument mappings = Config.instance().loadOrCreateYamlData("mappings.yml");
|
||||
Map<String, String> blockStateMappings = loadBlockStateMappings(mappings);
|
||||
this.validateBlockStateMappings(mappingFile, blockStateMappings);
|
||||
Map<Integer, String> stateMap = new Int2ObjectOpenHashMap<>();
|
||||
Map<Key, Integer> blockTypeCounter = new LinkedHashMap<>();
|
||||
Map<Integer, Integer> appearanceMapper = new Int2IntOpenHashMap();
|
||||
Map<Key, List<Integer>> appearanceArranger = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : blockStateMappings.entrySet()) {
|
||||
this.processBlockStateMapping(mappingFile, entry, stateMap, blockTypeCounter, appearanceMapper, appearanceArranger);
|
||||
Path mappingsFile = this.plugin.dataFolderPath().resolve("mappings.yml");
|
||||
if (!Files.exists(mappingsFile)) {
|
||||
this.plugin.saveResource("mappings.yml");
|
||||
}
|
||||
Yaml yaml = new Yaml(new StringKeyConstructor(mappingsFile, new LoaderOptions()));
|
||||
try (InputStream inputStream = Files.newInputStream(mappingsFile)) {
|
||||
Map<String, String> blockStateMappings = loadBlockStateMappings(yaml.load(inputStream));
|
||||
this.validateBlockStateMappings(mappingsFile, blockStateMappings);
|
||||
Map<Integer, String> stateMap = new Int2ObjectOpenHashMap<>();
|
||||
Map<Key, Integer> blockTypeCounter = new LinkedHashMap<>();
|
||||
Map<Integer, Integer> appearanceMapper = new Int2IntOpenHashMap();
|
||||
Map<Key, List<Integer>> appearanceArranger = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : blockStateMappings.entrySet()) {
|
||||
this.processBlockStateMapping(mappingsFile, entry, stateMap, blockTypeCounter, appearanceMapper, appearanceArranger);
|
||||
}
|
||||
this.blockAppearanceMapper = ImmutableMap.copyOf(appearanceMapper);
|
||||
this.blockAppearanceArranger = ImmutableMap.copyOf(appearanceArranger);
|
||||
this.plugin.logger().info("Freed " + this.blockAppearanceMapper.size() + " block state appearances.");
|
||||
YamlDocument additionalYaml = Config.instance().loadOrCreateYamlData("additional-real-blocks.yml");
|
||||
this.registeredRealBlockSlots = this.buildRegisteredRealBlockSlots(blockTypeCounter, additionalYaml);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to init mappings.yml", e);
|
||||
}
|
||||
this.blockAppearanceMapper = ImmutableMap.copyOf(appearanceMapper);
|
||||
this.blockAppearanceArranger = ImmutableMap.copyOf(appearanceArranger);
|
||||
this.plugin.logger().info("Freed " + this.blockAppearanceMapper.size() + " block state appearances.");
|
||||
YamlDocument additionalYaml = Config.instance().loadOrCreateYamlData("additional-real-blocks.yml");
|
||||
this.registeredRealBlockSlots = this.buildRegisteredRealBlockSlots(blockTypeCounter, additionalYaml);
|
||||
}
|
||||
|
||||
private void recordVanillaNoteBlocks() {
|
||||
@@ -598,9 +659,17 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
return this.affectedSoundBlocks.contains(block);
|
||||
}
|
||||
|
||||
private Map<String, String> loadBlockStateMappings(YamlDocument mappings) {
|
||||
public boolean isOpenableBlockSoundRemoved(Object block) {
|
||||
return this.affectedOpenableBlockSounds.containsKey(block);
|
||||
}
|
||||
|
||||
public SoundData getRemovedOpenableBlockSound(Object block, boolean open) {
|
||||
return open ? this.affectedOpenableBlockSounds.get(block).left() : this.affectedOpenableBlockSounds.get(block).right();
|
||||
}
|
||||
|
||||
private Map<String, String> loadBlockStateMappings(Map<String, Object> mappings) {
|
||||
Map<String, String> blockStateMappings = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Object> entry : mappings.getStringRouteMappedValues(false).entrySet()) {
|
||||
for (Map.Entry<String, Object> entry : mappings.entrySet()) {
|
||||
if (entry.getValue() instanceof String afterValue) {
|
||||
blockStateMappings.put(entry.getKey(), afterValue);
|
||||
}
|
||||
@@ -608,7 +677,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
return blockStateMappings;
|
||||
}
|
||||
|
||||
private void validateBlockStateMappings(File mappingFile, Map<String, String> blockStateMappings) {
|
||||
private void validateBlockStateMappings(Path mappingFile, Map<String, String> blockStateMappings) {
|
||||
Map<String, String> temp = new HashMap<>(blockStateMappings);
|
||||
for (Map.Entry<String, String> entry : temp.entrySet()) {
|
||||
String state = entry.getValue();
|
||||
@@ -619,7 +688,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void processBlockStateMapping(File mappingFile,
|
||||
private void processBlockStateMapping(Path mappingFile,
|
||||
Map.Entry<String, String> entry,
|
||||
Map<Integer, String> stateMap,
|
||||
Map<Key, Integer> counter,
|
||||
@@ -654,7 +723,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
private Object createBlockState(File mappingFile, String state) {
|
||||
private Object createBlockState(Path mappingFile, String state) {
|
||||
try {
|
||||
Object registryOrLookUp = MBuiltInRegistries.BLOCK;
|
||||
if (CoreReflections.method$Registry$asLookup != null) {
|
||||
|
||||
@@ -92,12 +92,27 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
BlockStateUtils.setHardness(mcBlockState, settings.hardness());
|
||||
BlockStateUtils.setPushReaction(mcBlockState, settings.pushReaction());
|
||||
BlockStateUtils.setReplaceable(mcBlockState, settings.replaceable());
|
||||
boolean canOcclude;
|
||||
if (settings.canOcclude() == Tristate.TRUE) {
|
||||
BlockStateUtils.setCanOcclude(mcBlockState, true);
|
||||
canOcclude = true;
|
||||
} else if (settings.canOcclude() == Tristate.FALSE) {
|
||||
BlockStateUtils.setCanOcclude(mcBlockState, false);
|
||||
canOcclude = false;
|
||||
} else {
|
||||
BlockStateUtils.setCanOcclude(mcBlockState, BlockStateUtils.isOcclude(state.vanillaBlockState().handle()));
|
||||
canOcclude = BlockStateUtils.isOcclude(state.vanillaBlockState().handle());
|
||||
BlockStateUtils.setCanOcclude(mcBlockState, canOcclude);
|
||||
}
|
||||
boolean useShapeForLightOcclusion;
|
||||
if (settings.useShapeForLightOcclusion() == Tristate.TRUE) {
|
||||
BlockStateUtils.setUseShapeForLightOcclusion(mcBlockState, true);
|
||||
useShapeForLightOcclusion = true;
|
||||
} else if (settings.useShapeForLightOcclusion() == Tristate.FALSE) {
|
||||
BlockStateUtils.setUseShapeForLightOcclusion(mcBlockState, false);
|
||||
useShapeForLightOcclusion = false;
|
||||
} else {
|
||||
useShapeForLightOcclusion = CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.getBoolean(state.vanillaBlockState().handle());
|
||||
BlockStateUtils.setUseShapeForLightOcclusion(mcBlockState, useShapeForLightOcclusion);
|
||||
}
|
||||
if (settings.isRedstoneConductor() == Tristate.TRUE) {
|
||||
BlockStateUtils.setIsRedstoneConductor(mcBlockState, ALWAYS_TRUE);
|
||||
@@ -144,15 +159,39 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
// set block side properties
|
||||
CoreReflections.field$BlockBehaviour$explosionResistance.set(mcBlock, settings.resistance());
|
||||
CoreReflections.field$BlockBehaviour$soundType.set(mcBlock, SoundUtils.toSoundType(settings.sounds()));
|
||||
// 1.21.2以前要在init cache之前设定 isConditionallyFullOpaque
|
||||
if (!VersionHelper.isOrAbove1_21_2()) {
|
||||
boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion;
|
||||
CoreReflections.field$BlockStateBase$isConditionallyFullOpaque.set(mcBlockState, isConditionallyFullOpaque);
|
||||
}
|
||||
// init cache
|
||||
CoreReflections.method$BlockStateBase$initCache.invoke(mcBlockState);
|
||||
// set block light
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(state.vanillaBlockState().handle());
|
||||
// modify cache
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(state.vanillaBlockState().handle());
|
||||
// set block light
|
||||
CoreReflections.field$BlockStateBase$lightBlock.set(mcBlockState, blockLight);
|
||||
// set propagates skylight
|
||||
if (settings.propagatesSkylightDown() == Tristate.TRUE) {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(mcBlockState, true);
|
||||
} else if (settings.propagatesSkylightDown() == Tristate.FALSE) {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(mcBlockState, false);
|
||||
} else {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(mcBlockState, CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(state.vanillaBlockState().handle()));
|
||||
}
|
||||
} else {
|
||||
Object cache = CoreReflections.field$BlockStateBase$cache.get(mcBlockState);
|
||||
int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(CoreReflections.field$BlockStateBase$cache.get(state.vanillaBlockState().handle()));
|
||||
// set block light
|
||||
CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, blockLight);
|
||||
// set propagates skylight
|
||||
if (settings.propagatesSkylightDown() == Tristate.TRUE) {
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, true);
|
||||
} else if (settings.propagatesSkylightDown() == Tristate.FALSE) {
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, false);
|
||||
} else {
|
||||
CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(state.vanillaBlockState().handle())));
|
||||
}
|
||||
}
|
||||
// set fluid later
|
||||
if (settings.fluidState()) {
|
||||
@@ -162,8 +201,6 @@ public class BukkitCustomBlock extends AbstractCustomBlock {
|
||||
}
|
||||
// set random tick later
|
||||
BlockStateUtils.setIsRandomlyTicking(mcBlockState, settings.isRandomlyTicking());
|
||||
// set propagates skylight
|
||||
BlockStateUtils.setPropagatesSkylightDown(mcBlockState, settings.propagatesSkylightDown());
|
||||
// bind tags
|
||||
Object holder = BukkitCraftEngine.instance().blockManager().getMinecraftBlockHolder(state.customBlockState().registryId());
|
||||
Set<Object> tags = new HashSet<>();
|
||||
|
||||
@@ -13,7 +13,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
public static final Key SAPLING_BLOCK = Key.from("craftengine:sapling_block");
|
||||
public static final Key ON_LIQUID_BLOCK = Key.from("craftengine:on_liquid_block");
|
||||
public static final Key NEAR_LIQUID_BLOCK = Key.from("craftengine:near_liquid_block");
|
||||
public static final Key WATERLOGGED_BLOCK = Key.from("craftengine:waterlogged_block");
|
||||
public static final Key CONCRETE_POWDER_BLOCK = Key.from("craftengine:concrete_powder_block");
|
||||
public static final Key VERTICAL_CROP_BLOCK = Key.from("craftengine:vertical_crop_block");
|
||||
public static final Key CROP_BLOCK = Key.from("craftengine:crop_block");
|
||||
@@ -23,6 +22,10 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
public static final Key DOOR_BLOCK = Key.from("craftengine:door_block");
|
||||
public static final Key STACKABLE_BLOCK = Key.from("craftengine:stackable_block");
|
||||
public static final Key STURDY_BASE_BLOCK = Key.from("craftengine:sturdy_base_block");
|
||||
public static final Key FENCE_GATE_BLOCK = Key.from("craftengine:fence_gate_block");
|
||||
public static final Key SLAB_BLOCK = Key.from("craftengine:slab_block");
|
||||
public static final Key STAIRS_BLOCK = Key.from("craftengine:stairs_block");
|
||||
public static final Key PRESSURE_PLATE_BLOCK = Key.from("craftengine:pressure_plate_block");
|
||||
|
||||
public static void init() {
|
||||
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
|
||||
@@ -43,5 +46,9 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
|
||||
register(DOOR_BLOCK, DoorBlockBehavior.FACTORY);
|
||||
register(STACKABLE_BLOCK, StackableBlockBehavior.FACTORY);
|
||||
register(STURDY_BASE_BLOCK, SturdyBaseBlockBehavior.FACTORY);
|
||||
register(FENCE_GATE_BLOCK, FenceGateBlockBehavior.FACTORY);
|
||||
register(SLAB_BLOCK, SlabBlockBehavior.FACTORY);
|
||||
register(STAIRS_BLOCK, StairsBlockBehavior.FACTORY);
|
||||
register(PRESSURE_PLATE_BLOCK, PressurePlateBlockBehavior.FACTORY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,9 +42,9 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments, false);
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
boolean blacklistMode = (boolean) arguments.getOrDefault("blacklist", false);
|
||||
boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist");
|
||||
return new BushBlockBehavior(block, delay, blacklistMode, stackable, tuple.left(), tuple.mid(), tuple.right());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior {
|
||||
Property<Integer> ageProperty = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.crop.missing_age");
|
||||
int minGrowLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("light-requirement", 9), "light-requirement");
|
||||
float growSpeed = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.125f), "grow-speed");
|
||||
boolean isBoneMealTarget = (boolean) arguments.getOrDefault("is-bone-meal-target", true);
|
||||
boolean isBoneMealTarget = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("is-bone-meal-target", true), "is-bone-meal-target");
|
||||
NumberProvider boneMealAgeBonus = NumberProviders.fromObject(arguments.getOrDefault("bone-meal-age-bonus", 1));
|
||||
return new CropBlockBehavior(block, ageProperty, growSpeed, minGrowLight, isBoneMealTarget, boneMealAgeBonus);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
@@ -51,6 +52,8 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
private final Property<Boolean> openProperty;
|
||||
private final boolean canOpenWithHand;
|
||||
private final boolean canOpenByWindCharge;
|
||||
private final SoundData openSound;
|
||||
private final SoundData closeSound;
|
||||
|
||||
public DoorBlockBehavior(CustomBlock block,
|
||||
Property<DoubleBlockHalf> halfProperty,
|
||||
@@ -59,7 +62,9 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
Property<Boolean> poweredProperty,
|
||||
Property<Boolean> openProperty,
|
||||
boolean canOpenWithHand,
|
||||
boolean canOpenByWindCharge) {
|
||||
boolean canOpenByWindCharge,
|
||||
SoundData openSound,
|
||||
SoundData closeSound) {
|
||||
super(block, 0);
|
||||
this.halfProperty = halfProperty;
|
||||
this.facingProperty = facingProperty;
|
||||
@@ -68,6 +73,8 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
this.openProperty = openProperty;
|
||||
this.canOpenWithHand = canOpenWithHand;
|
||||
this.canOpenByWindCharge = canOpenByWindCharge;
|
||||
this.openSound = openSound;
|
||||
this.closeSound = closeSound;
|
||||
}
|
||||
|
||||
public boolean isOpen(ImmutableBlockState state) {
|
||||
@@ -90,7 +97,7 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return blockState;
|
||||
DoubleBlockHalf half = immutableBlockState.get(this.halfProperty);
|
||||
Object direction = VersionHelper.isOrAbove1_21_2() ? args[4] : args[0];
|
||||
Object direction = VersionHelper.isOrAbove1_21_2() ? args[4] : args[1];
|
||||
if (DirectionUtils.isYAxis(direction) && half == DoubleBlockHalf.LOWER == (direction == CoreReflections.instance$Direction$UP)) {
|
||||
ImmutableBlockState neighborState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(VersionHelper.isOrAbove1_21_2() ? args[6] : args[2]));
|
||||
if (neighborState == null || neighborState.isEmpty()) {
|
||||
@@ -138,7 +145,7 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@Override
|
||||
public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
BlockPos pos = context.getClickedPos();
|
||||
context.getLevel().setBlockAt(pos.x(), pos.y() + 1, pos.z(), state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState(), 3);
|
||||
context.getLevel().setBlockAt(pos.x(), pos.y() + 1, pos.z(), state.with(this.halfProperty, DoubleBlockHalf.UPPER).customBlockState(), UpdateOption.UPDATE_ALL.flags());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -213,15 +220,22 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
|
||||
public void setOpen(@Nullable Player player, Object serverLevel, ImmutableBlockState state, BlockPos pos, boolean isOpen) {
|
||||
if (isOpen(state) != isOpen) {
|
||||
org.bukkit.World world = FastNMS.INSTANCE.method$Level$getCraftWorld(serverLevel);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(serverLevel, LocationUtils.toBlockPos(pos), state.with(this.openProperty, isOpen).customBlockState().handle(), UpdateOption.builder().updateImmediate().updateClients().build().flags());
|
||||
FastNMS.INSTANCE.method$Level$getCraftWorld(serverLevel).sendGameEvent(player == null ? null : (org.bukkit.entity.Player) player.platformPlayer(), isOpen ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, new Vector(pos.x(), pos.y(), pos.z()));
|
||||
// todo 播放声音
|
||||
world.sendGameEvent(player == null ? null : (org.bukkit.entity.Player) player.platformPlayer(), isOpen ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, new Vector(pos.x(), pos.y(), pos.z()));
|
||||
SoundData soundData = isOpen ? this.openSound : this.closeSound;
|
||||
if (soundData != null) {
|
||||
new BukkitWorld(world).playBlockSound(
|
||||
new Vec3d(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5),
|
||||
soundData
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
if (!this.canOpenWithHand || context.getPlayer().isSecondaryUseActive()) {
|
||||
if (!this.canOpenWithHand) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
setOpen(context.getPlayer(), context.getLevel().serverWorld(), state, context.getClickedPos(), !state.get(this.openProperty));
|
||||
@@ -258,8 +272,15 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
boolean flag = event.getNewCurrent() > 0;
|
||||
if (flag != immutableBlockState.get(this.openProperty)) {
|
||||
FastNMS.INSTANCE.method$Level$getCraftWorld(level).sendGameEvent(null, flag ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, new Vector(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()));
|
||||
// todo 播放声音
|
||||
org.bukkit.World world = FastNMS.INSTANCE.method$Level$getCraftWorld(level);
|
||||
world.sendGameEvent(null, flag ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, new Vector(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()));
|
||||
SoundData soundData = flag ? this.openSound : this.closeSound;
|
||||
if (soundData != null) {
|
||||
new BukkitWorld(world).playBlockSound(
|
||||
new Vec3d(FastNMS.INSTANCE.field$Vec3i$x(blockPos) + 0.5, FastNMS.INSTANCE.field$Vec3i$y(blockPos) + 0.5, FastNMS.INSTANCE.field$Vec3i$z(blockPos) + 0.5),
|
||||
soundData
|
||||
);
|
||||
}
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, immutableBlockState.with(this.poweredProperty, flag).with(this.openProperty, flag).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
}
|
||||
@@ -267,18 +288,23 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws Exception {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return false;
|
||||
if (immutableBlockState.get(this.halfProperty) == DoubleBlockHalf.UPPER) return true;
|
||||
ImmutableBlockState customBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (customBlockState == null || customBlockState.isEmpty()) return false;
|
||||
int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos);
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos) - 1;
|
||||
int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos);
|
||||
Object targetPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, targetPos);
|
||||
return (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
|
||||
blockState, world, targetPos, CoreReflections.instance$Direction$UP,
|
||||
CoreReflections.instance$SupportType$FULL
|
||||
);
|
||||
Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
|
||||
Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos);
|
||||
if (customBlockState.get(this.halfProperty) == DoubleBlockHalf.UPPER) {
|
||||
ImmutableBlockState belowCustomState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(belowState));
|
||||
if (belowCustomState == null || belowCustomState.isEmpty()) return false;
|
||||
return belowCustomState.owner().value() == super.customBlock;
|
||||
} else {
|
||||
return (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
|
||||
belowState, world, belowPos, CoreReflections.instance$Direction$UP,
|
||||
CoreReflections.instance$SupportType$FULL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -290,9 +316,16 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
Property<DoorHinge> hinge = (Property<DoorHinge>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("hinge"), "warning.config.block.behavior.door.missing_hinge");
|
||||
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.door.missing_open");
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.door.missing_powered");
|
||||
boolean canOpenWithHand = (boolean) arguments.getOrDefault("can-open-with-hand", true);
|
||||
boolean canOpenByWindCharge = (boolean) arguments.getOrDefault("can-open-by-wind-charge", true);
|
||||
return new DoorBlockBehavior(block, half, facing, hinge, powered, open, canOpenWithHand, canOpenByWindCharge);
|
||||
boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-with-hand", true), "can-open-with-hand");
|
||||
boolean canOpenByWindCharge = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-by-wind-charge", true), "can-open-by-wind-charge");
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
SoundData openSound = null;
|
||||
SoundData closeSound = null;
|
||||
if (sounds != null) {
|
||||
openSound = Optional.ofNullable(sounds.get("open")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
}
|
||||
return new DoorBlockBehavior(block, half, facing, hinge, powered, open, canOpenWithHand, canOpenByWindCharge, openSound, closeSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MTagKeys;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.InteractUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class FenceGateBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<HorizontalDirection> facingProperty;
|
||||
private final Property<Boolean> inWallProperty;
|
||||
private final Property<Boolean> openProperty;
|
||||
private final Property<Boolean> poweredProperty;
|
||||
private final boolean canOpenWithHand;
|
||||
private final boolean canOpenByWindCharge;
|
||||
private final SoundData openSound;
|
||||
private final SoundData closeSound;
|
||||
|
||||
public FenceGateBlockBehavior(
|
||||
CustomBlock customBlock,
|
||||
Property<HorizontalDirection> facing,
|
||||
Property<Boolean> inWall,
|
||||
Property<Boolean> open,
|
||||
Property<Boolean> powered,
|
||||
boolean canOpenWithHand,
|
||||
boolean canOpenByWindCharge,
|
||||
SoundData openSound,
|
||||
SoundData closeSound
|
||||
) {
|
||||
super(customBlock);
|
||||
this.facingProperty = facing;
|
||||
this.inWallProperty = inWall;
|
||||
this.openProperty = open;
|
||||
this.poweredProperty = powered;
|
||||
this.canOpenWithHand = canOpenWithHand;
|
||||
this.canOpenByWindCharge = canOpenByWindCharge;
|
||||
this.openSound = openSound;
|
||||
this.closeSound = closeSound;
|
||||
}
|
||||
|
||||
public boolean isOpen(ImmutableBlockState state) {
|
||||
if (state == null || state.isEmpty() || !state.contains(this.openProperty)) return false;
|
||||
return state.get(this.openProperty);
|
||||
}
|
||||
|
||||
public boolean isWall(Object state) {
|
||||
if (state == null) return false;
|
||||
return FastNMS.INSTANCE.method$BlockStateBase$isTagKeyBlock(state, MTagKeys.Block$WALLS);
|
||||
}
|
||||
|
||||
private Object getBlockState(Object level, BlockPos blockPos) {
|
||||
return FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(blockPos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object blockState = args[0];
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return blockState;
|
||||
if (state.get(this.facingProperty).toDirection().clockWise().axis() != direction.axis()) {
|
||||
return superMethod.call();
|
||||
}
|
||||
Object neighborState = VersionHelper.isOrAbove1_21_2() ? args[6] : args[2];
|
||||
Object level = VersionHelper.isOrAbove1_21_2() ? args[1] : args[3];
|
||||
BlockPos blockPos = LocationUtils.fromBlockPos(VersionHelper.isOrAbove1_21_2() ? args[3] : args[4]);
|
||||
Object relativeState = getBlockState(level, blockPos.relative(direction.opposite()));
|
||||
boolean neighborStateIsWall = this.isWall(neighborState);
|
||||
boolean relativeStateIsWall = this.isWall(relativeState);
|
||||
boolean flag = neighborStateIsWall || relativeStateIsWall;
|
||||
if (neighborStateIsWall) {
|
||||
// TODO: 连接原版方块
|
||||
}
|
||||
if (relativeStateIsWall) {
|
||||
// TODO: 连接原版方块
|
||||
}
|
||||
return state.with(this.inWallProperty, flag).customBlockState().handle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
Object level = context.getLevel().serverWorld();
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
boolean hasNeighborSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, LocationUtils.toBlockPos(clickedPos));
|
||||
Direction horizontalDirection = context.getHorizontalDirection();
|
||||
Direction.Axis axis = horizontalDirection.axis();
|
||||
boolean flag = axis == Direction.Axis.Z && (this.isWall(getBlockState(level, clickedPos.relative(Direction.WEST))))
|
||||
|| this.isWall(getBlockState(level, clickedPos.relative(Direction.EAST)))
|
||||
|| axis == Direction.Axis.X && (this.isWall(getBlockState(level, clickedPos.relative(Direction.NORTH)))
|
||||
|| this.isWall(getBlockState(level, clickedPos.relative(Direction.SOUTH))));
|
||||
// TODO: 连接原版方块
|
||||
return state.owner().value().defaultState()
|
||||
.with(this.facingProperty, horizontalDirection.toHorizontalDirection())
|
||||
.with(this.openProperty, hasNeighborSignal)
|
||||
.with(this.poweredProperty, hasNeighborSignal)
|
||||
.with(this.inWallProperty, flag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
if (!this.canOpenWithHand) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
if (context.getItem() == null) {
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS;
|
||||
} else if (!context.getPlayer().isSecondaryUseActive()) {
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
} else {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void playerToggle(UseOnContext context, ImmutableBlockState state) {
|
||||
Player player = context.getPlayer();
|
||||
this.toggle(state, context.getLevel(), context.getClickedPos(), player);
|
||||
if (!InteractUtils.isInteractable((org.bukkit.entity.Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object type = VersionHelper.isOrAbove1_20_5() ? args[1] : args[3];
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return false;
|
||||
if (type == CoreReflections.instance$PathComputationType$LAND || type == CoreReflections.instance$PathComputationType$AIR) {
|
||||
return isOpen(state);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) {
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0]));
|
||||
if (state == null || state.isEmpty()) return;
|
||||
this.toggle(state, new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(args[1])), LocationUtils.fromBlockPos(args[2]), null);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@Override
|
||||
public void neighborChanged(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return;
|
||||
Object level = args[1];
|
||||
Object blockPos = args[2];
|
||||
boolean hasSignal = FastNMS.INSTANCE.method$SignalGetter$hasNeighborSignal(level, blockPos);
|
||||
if (hasSignal == immutableBlockState.get(this.poweredProperty)) return;
|
||||
|
||||
Block bblock = FastNMS.INSTANCE.method$CraftBlock$at(level, blockPos);
|
||||
int power = bblock.getBlockPower();
|
||||
int oldPower = isOpen(immutableBlockState) ? 15 : 0;
|
||||
Object neighborBlock = args[3];
|
||||
|
||||
if (oldPower == 0 ^ power == 0 || FastNMS.INSTANCE.method$BlockStateBase$isSignalSource(FastNMS.INSTANCE.method$Block$defaultState(neighborBlock))) {
|
||||
BlockRedstoneEvent event = new BlockRedstoneEvent(bblock, oldPower, power);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
hasSignal = event.getNewCurrent() > 0;
|
||||
}
|
||||
|
||||
World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
boolean changed = isOpen(immutableBlockState) != hasSignal;
|
||||
if (hasSignal && changed) {
|
||||
Object abovePos = LocationUtils.above(blockPos);
|
||||
Object aboveBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, abovePos);
|
||||
if (CoreReflections.clazz$RedStoneWireBlock.isInstance(FastNMS.INSTANCE.method$BlockState$getBlock(aboveBlockState))) {
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, abovePos, MBlocks.AIR$defaultState, UpdateOption.UPDATE_ALL.flags());
|
||||
world.dropItemNaturally(
|
||||
new Vec3d(FastNMS.INSTANCE.field$Vec3i$x(abovePos) + 0.5, FastNMS.INSTANCE.field$Vec3i$y(abovePos) + 0.5, FastNMS.INSTANCE.field$Vec3i$z(abovePos) + 0.5),
|
||||
BukkitItemManager.instance().createWrappedItem(ItemKeys.REDSTONE, null)
|
||||
);
|
||||
if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos) != blockPos) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
immutableBlockState = immutableBlockState.with(this.openProperty, hasSignal);
|
||||
FastNMS.INSTANCE.method$Level$getCraftWorld(level).sendGameEvent(null,
|
||||
hasSignal ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE,
|
||||
new Vector(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos), FastNMS.INSTANCE.field$Vec3i$z(blockPos))
|
||||
);
|
||||
this.playSound(LocationUtils.fromBlockPos(blockPos), world, hasSignal);
|
||||
}
|
||||
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, immutableBlockState.with(this.poweredProperty, hasSignal).customBlockState().handle(), UpdateOption.Flags.UPDATE_CLIENTS);
|
||||
}
|
||||
private void toggle(ImmutableBlockState state, World world, BlockPos pos, @Nullable Player player) {
|
||||
ImmutableBlockState newState;
|
||||
if (state.get(this.openProperty)) {
|
||||
newState = state.with(this.openProperty, false);
|
||||
} else {
|
||||
ImmutableBlockState blockState = state;
|
||||
if (player != null) {
|
||||
Direction direction = player.getDirection();
|
||||
if (state.get(this.facingProperty).toDirection() == direction.opposite()) {
|
||||
blockState = blockState.with(this.facingProperty, direction.toHorizontalDirection());
|
||||
}
|
||||
}
|
||||
newState = blockState.with(this.openProperty, true);
|
||||
}
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags());
|
||||
boolean open = isOpen(newState);
|
||||
((org.bukkit.World) world.platformWorld()).sendGameEvent(
|
||||
player != null ? (org.bukkit.entity.Player) player.platformPlayer() : null,
|
||||
open ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE,
|
||||
new Vector(pos.x(), pos.y(), pos.z())
|
||||
);
|
||||
this.playSound(pos, world, open);
|
||||
}
|
||||
|
||||
private void playSound(BlockPos pos, World world, boolean open) {
|
||||
if (open) {
|
||||
if (this.openSound != null) {
|
||||
world.playBlockSound(new Vec3d(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5), this.openSound);
|
||||
}
|
||||
} else {
|
||||
if (this.closeSound != null) {
|
||||
world.playBlockSound(new Vec3d(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5), this.closeSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.fence_gate.missing_facing");
|
||||
Property<Boolean> inWall = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("in_wall"), "warning.config.block.behavior.fence_gate.missing_in_wall");
|
||||
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.fence_gate.missing_open");
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.fence_gate.missing_powered");
|
||||
boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-with-hand", true), "can-open-with-hand");
|
||||
boolean canOpenByWindCharge = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-by-wind-charge", true), "can-open-by-wind-charge");
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
SoundData openSound = null;
|
||||
SoundData closeSound = null;
|
||||
if (sounds != null) {
|
||||
openSound = Optional.ofNullable(sounds.get("open")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
}
|
||||
return new FenceGateBlockBehavior(block, facing, inWall, open, powered, canOpenWithHand, canOpenByWindCharge, openSound, closeSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,9 +33,9 @@ public class HangingBlockBehavior extends BushBlockBehavior {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Tuple<List<Object>, Set<Object>, Set<String>> tuple = readTagsAndState(arguments, true);
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
boolean blacklistMode = (boolean) arguments.getOrDefault("blacklist", false);
|
||||
boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist");
|
||||
return new HangingBlockBehavior(block, delay, blacklistMode, stackable, tuple.left(), tuple.mid(), tuple.right());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class NearLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water")));
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
List<String> positionsToCheck = MiscUtils.getAsStringList(arguments.getOrDefault("positions", List.of()));
|
||||
if (positionsToCheck.isEmpty()) {
|
||||
|
||||
@@ -41,7 +41,7 @@ public class OnLiquidBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
List<String> liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water")));
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
return new OnLiquidBlockBehavior(block, delay, stackable, liquidTypes.contains("water"), liquidTypes.contains("lava"));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import io.papermc.paper.event.entity.EntityInsideBlockEvent;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.EventUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorld;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorldManager;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.PressurePlateSensitivity;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.*;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<Boolean> poweredProperty;
|
||||
private final SoundData onSound;
|
||||
private final SoundData offSound;
|
||||
private final PressurePlateSensitivity pressurePlateSensitivity;
|
||||
private final int pressedTime;
|
||||
|
||||
public PressurePlateBlockBehavior(
|
||||
CustomBlock block,
|
||||
Property<Boolean> poweredProperty,
|
||||
SoundData onSound,
|
||||
SoundData offSound,
|
||||
PressurePlateSensitivity pressurePlateSensitivity,
|
||||
int pressedTime
|
||||
) {
|
||||
super(block);
|
||||
this.poweredProperty = poweredProperty;
|
||||
this.onSound = onSound;
|
||||
this.offSound = offSound;
|
||||
this.pressurePlateSensitivity = pressurePlateSensitivity;
|
||||
this.pressedTime = pressedTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object state = args[0];
|
||||
Object level;
|
||||
Object blockPos;
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
level = args[1];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
level = args[3];
|
||||
blockPos = args[4];
|
||||
}
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
|
||||
if (direction == Direction.DOWN && !FastNMS.INSTANCE.method$BlockStateBase$canSurvive(state, level, blockPos)) {
|
||||
BlockPos pos = LocationUtils.fromBlockPos(blockPos);
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
|
||||
ContextHolder.Builder builder = ContextHolder.builder()
|
||||
.withParameter(DirectContextParameters.POSITION, position);
|
||||
int stateId = BlockStateUtils.blockStateToId(state);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return MBlocks.AIR$defaultState;
|
||||
for (Item<Object> item : immutableBlockState.getDrops(builder, world, null)) {
|
||||
world.dropItemNaturally(position, item);
|
||||
}
|
||||
world.playBlockSound(position, immutableBlockState.sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, stateId);
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object blockPos = LocationUtils.below(args[2]);
|
||||
Object level = args[1];
|
||||
return FastNMS.INSTANCE.method$Block$canSupportRigidBlock(level, blockPos)
|
||||
|| FastNMS.INSTANCE.method$Block$canSupportCenter(level, blockPos, CoreReflections.instance$Direction$UP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object state = args[0];
|
||||
int signalForState = this.getSignalForState(state);
|
||||
if (signalForState > 0) {
|
||||
this.checkPressed(null, args[1], args[2], state, signalForState, thisBlock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public void entityInside(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
EntityInsideBlockEvent event = new EntityInsideBlockEvent(FastNMS.INSTANCE.method$Entity$getBukkitEntity(args[3]), FastNMS.INSTANCE.method$CraftBlock$at(args[1], args[2]));
|
||||
if (EventUtils.fireAndCheckCancel(event)) {
|
||||
return;
|
||||
}
|
||||
Object state = args[0];
|
||||
int signalForState = this.getSignalForState(state);
|
||||
if (signalForState == 0) {
|
||||
this.checkPressed(args[3], args[1], args[2], state, signalForState, thisBlock);
|
||||
} else {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime);
|
||||
}
|
||||
}
|
||||
|
||||
protected int getSignalStrength(Object level, Object pos) {
|
||||
Class<?> clazz = switch (this.pressurePlateSensitivity) {
|
||||
case EVERYTHING -> CoreReflections.clazz$Entity;
|
||||
case MOBS -> CoreReflections.clazz$LivingEntity;
|
||||
};
|
||||
Object box = FastNMS.INSTANCE.method$AABB$move(CoreReflections.instance$BasePressurePlateBlock$TOUCH_AABB, pos);
|
||||
return FastNMS.INSTANCE.method$BasePressurePlateBlock$getEntityCount(level, box, clazz) > 0 ? 15 : 0;
|
||||
}
|
||||
|
||||
private Object setSignalForState(Object state, int strength) {
|
||||
ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (blockState == null || blockState.isEmpty()) return state;
|
||||
return blockState.with(this.poweredProperty, strength > 0).customBlockState().handle();
|
||||
}
|
||||
|
||||
private void checkPressed(@Nullable Object entity, Object level, Object pos, Object state, int currentSignal, Object thisBlock) {
|
||||
int signalStrength = this.getSignalStrength(level, pos);
|
||||
boolean wasActive = currentSignal > 0;
|
||||
boolean isActive = signalStrength > 0;
|
||||
|
||||
if (currentSignal != signalStrength) {
|
||||
Object blockState = this.setSignalForState(state, signalStrength);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState, 2);
|
||||
this.updateNeighbours(level, pos, thisBlock);
|
||||
FastNMS.INSTANCE.method$Level$setBlocksDirty(level, pos, state, blockState);
|
||||
}
|
||||
|
||||
org.bukkit.World craftWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level);
|
||||
int x = FastNMS.INSTANCE.field$Vec3i$x(pos);
|
||||
int y = FastNMS.INSTANCE.field$Vec3i$y(pos);
|
||||
int z = FastNMS.INSTANCE.field$Vec3i$z(pos);
|
||||
Vector positionVector = new Vector(x, y, z);
|
||||
|
||||
if (!isActive && wasActive) {
|
||||
handleDeactivation(entity, craftWorld, pos, positionVector);
|
||||
} else if (isActive && !wasActive) {
|
||||
handleActivation(entity, craftWorld, pos, positionVector);
|
||||
}
|
||||
|
||||
if (isActive) {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleBlockTick(level, pos, thisBlock, this.pressedTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDeactivation(Object entity, org.bukkit.World craftWorld, Object pos, Vector positionVector) {
|
||||
World world = BukkitWorldManager.instance().getWorld(craftWorld).world();
|
||||
world.playBlockSound(LocationUtils.toVec3d(LocationUtils.fromBlockPos(pos)), this.offSound);
|
||||
craftWorld.sendGameEvent(
|
||||
entity != null ? FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity) : null,
|
||||
GameEvent.BLOCK_DEACTIVATE,
|
||||
positionVector
|
||||
);
|
||||
}
|
||||
|
||||
private void handleActivation(Object entity, org.bukkit.World craftWorld, Object pos, Vector positionVector) {
|
||||
World world = BukkitWorldManager.instance().getWorld(craftWorld).world();
|
||||
world.playBlockSound(LocationUtils.toVec3d(LocationUtils.fromBlockPos(pos)), this.onSound);
|
||||
craftWorld.sendGameEvent(
|
||||
entity != null ? FastNMS.INSTANCE.method$Entity$getBukkitEntity(entity) : null,
|
||||
GameEvent.BLOCK_ACTIVATE,
|
||||
positionVector
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectNeighborsAfterRemoval(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
boolean movedByPiston = (boolean) args[3];
|
||||
if (!movedByPiston && this.getSignalForState(args[0]) > 0) {
|
||||
this.updateNeighbours(args[1], args[2], thisBlock);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateNeighbours(Object level, Object pos, Object thisBlock) {
|
||||
FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, pos, thisBlock);
|
||||
FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, LocationUtils.below(pos), thisBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSignal(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
return this.getSignalForState(args[0]);
|
||||
}
|
||||
|
||||
private int getSignalForState(Object state) {
|
||||
ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (blockState == null || blockState.isEmpty()) return 0;
|
||||
return blockState.get(this.poweredProperty) ? 15 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDirectSignal(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Direction direction = DirectionUtils.fromNMSDirection(args[3]);
|
||||
return direction == Direction.UP ? this.getSignalForState(args[0]) : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSignalSource(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.pressure_plate.missing_powered");
|
||||
PressurePlateSensitivity pressurePlateSensitivity = PressurePlateSensitivity.byName(arguments.getOrDefault("sensitivity", "everything").toString());
|
||||
int pressedTime = ResourceConfigUtils.getAsInt(arguments.getOrDefault("pressed-time", 20), "pressed-time");
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
SoundData onSound = null;
|
||||
SoundData offSound = null;
|
||||
if (sounds != null) {
|
||||
onSound = Optional.ofNullable(sounds.get("on")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
offSound = Optional.ofNullable(sounds.get("off")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
}
|
||||
return new PressurePlateBlockBehavior(block, powered, onSound, offSound, pressurePlateSensitivity, pressedTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.block.state.properties.SlabType;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.behavior.BlockBoundItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class SlabBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<SlabType> typeProperty;
|
||||
|
||||
public SlabBlockBehavior(CustomBlock block, Property<SlabType> typeProperty) {
|
||||
super(block);
|
||||
this.typeProperty = typeProperty;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
SlabType type = state.get(this.typeProperty);
|
||||
Item<ItemStack> item = (Item<ItemStack>) context.getItem();
|
||||
if (type == SlabType.DOUBLE || item == null) return false;
|
||||
Optional<CustomItem<ItemStack>> itemInHand = item.getCustomItem();
|
||||
if (itemInHand.isEmpty()) return false;
|
||||
CustomItem<ItemStack> customItem = itemInHand.get();
|
||||
Key blockId = null;
|
||||
for (ItemBehavior itemBehavior : customItem.behaviors()) {
|
||||
if (itemBehavior instanceof BlockBoundItemBehavior behavior) {
|
||||
blockId = behavior.block();
|
||||
}
|
||||
}
|
||||
if (blockId == null || !blockId.equals(super.customBlock.id())) return false;
|
||||
if (!context.replacingClickedOnBlock()) return true;
|
||||
boolean upper = context.getClickLocation().y - (double) context.getClickedPos().y() > (double) 0.5F;
|
||||
Direction clickedFace = context.getClickedFace();
|
||||
return type == SlabType.BOTTOM ?
|
||||
clickedFace == Direction.UP || (upper && clickedFace.axis().isHorizontal()) :
|
||||
clickedFace == Direction.DOWN || (!upper && clickedFace.axis().isHorizontal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
ImmutableBlockState blockState = context.getLevel().getBlockAt(clickedPos).customBlockState();
|
||||
if (blockState != null && blockState.owner().value() == super.customBlock) {
|
||||
if (super.waterloggedProperty != null)
|
||||
blockState = blockState.with(super.waterloggedProperty, false);
|
||||
return blockState.with(this.typeProperty, SlabType.DOUBLE);
|
||||
} else {
|
||||
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos));
|
||||
if (super.waterloggedProperty != null)
|
||||
state = state.with(super.waterloggedProperty, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER);
|
||||
Direction clickedFace = context.getClickedFace();
|
||||
return clickedFace == Direction.DOWN || clickedFace != Direction.UP && context.getClickLocation().y - (double) clickedPos.y() > (double) 0.5F ? state.with(this.typeProperty, SlabType.TOP) : state.with(this.typeProperty, SlabType.BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = args[2];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return false;
|
||||
return immutableBlockState.get(this.typeProperty) != SlabType.DOUBLE && super.placeLiquid(thisBlock, args, superMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceLiquid(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object blockState = VersionHelper.isOrAbove1_20_2() ? args[3] : args[2];
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return false;
|
||||
return immutableBlockState.get(this.typeProperty) != SlabType.DOUBLE && super.canPlaceLiquid(thisBlock, args, superMethod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object blockState = args[0];
|
||||
if (super.waterloggedProperty == null) return blockState;
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return blockState;
|
||||
if (immutableBlockState.get(super.waterloggedProperty)) {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(VersionHelper.isOrAbove1_21_2() ? args[2] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[4], MFluids.WATER, 5);
|
||||
}
|
||||
return blockState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPathFindable(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
Object type = VersionHelper.isOrAbove1_20_5() ? args[1] : args[3];
|
||||
Object blockState = args[0];
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (state == null || state.isEmpty()) return false;
|
||||
if (type == CoreReflections.instance$PathComputationType$WATER) {
|
||||
return super.waterloggedProperty != null && state.get(this.typeProperty) != SlabType.DOUBLE && state.get(super.waterloggedProperty);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<SlabType> type = (Property<SlabType>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("type"), "warning.config.block.behavior.slab.missing_type");
|
||||
return new SlabBlockBehavior(block, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,14 +13,15 @@ import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.SoundCategory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
@@ -56,28 +57,23 @@ public class StackableBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
BlockPos pos = context.getClickedPos();
|
||||
World world = context.getLevel();
|
||||
if (state.get(this.amountProperty) < this.amountProperty.max) {
|
||||
updateStackableBlock(state, pos, world, item, player, context.getHand());
|
||||
if (state.get(this.amountProperty) >= this.amountProperty.max) {
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
}
|
||||
BlockPos actualPos = pos.relative(context.getClickedFace());
|
||||
ImmutableBlockState actualState = world.getBlockAt(actualPos).customBlockState();
|
||||
boolean isValid = actualState != null && !actualState.isEmpty() && actualState.contains(this.amountProperty);
|
||||
if (isValid && actualState.get(this.amountProperty) < this.amountProperty.max) {
|
||||
updateStackableBlock(actualState, actualPos, world, item, player, context.getHand());
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
}
|
||||
return InteractionResult.PASS;
|
||||
updateStackableBlock(state, pos, world, item, player, context.getHand());
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
}
|
||||
|
||||
private void updateStackableBlock(ImmutableBlockState state, BlockPos pos, World world, Item<ItemStack> item, Player player, InteractionHand hand) {
|
||||
ImmutableBlockState nextStage = state.cycle(this.amountProperty);
|
||||
Location location = new Location((org.bukkit.World) world.platformWorld(), pos.x(), pos.y(), pos.z());
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(world.serverWorld(), LocationUtils.toBlockPos(pos), nextStage.customBlockState().handle(), UpdateOption.UPDATE_NONE.flags());
|
||||
if (stackSound != null) {
|
||||
location.getWorld().playSound(location, stackSound.id().toString(), SoundCategory.BLOCKS, stackSound.volume(), stackSound.pitch());
|
||||
if (this.stackSound != null) {
|
||||
world.playBlockSound(new Vec3d(location.getX(), location.getY(), location.getZ()), this.stackSound);
|
||||
}
|
||||
if (!player.isCreativeMode()) {
|
||||
item.count(item.count() - 1);
|
||||
}
|
||||
FastNMS.INSTANCE.method$ItemStack$consume(item.getLiteralObject(), 1, player.serverPlayer());
|
||||
player.swingHand(hand);
|
||||
}
|
||||
|
||||
@@ -86,11 +82,14 @@ public class StackableBlockBehavior extends BukkitBlockBehavior {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
IntegerProperty amount = (IntegerProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("amount"), "warning.config.block.behavior.stackable.missing_amount");
|
||||
String propertyName = String.valueOf(arguments.getOrDefault("property", "amount"));
|
||||
IntegerProperty amount = (IntegerProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty(propertyName), () -> {
|
||||
throw new LocalizedResourceConfigException("warning.config.block.behavior.stackable.missing_property", propertyName);
|
||||
});
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
SoundData stackSound = null;
|
||||
if (sounds != null) {
|
||||
stackSound = Optional.ofNullable(sounds.get("stack")).map(obj -> SoundData.create(obj, 1, 1)).orElse(null);
|
||||
stackSound = Optional.ofNullable(sounds.get("stack")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1)).orElse(null);
|
||||
}
|
||||
Object itemsObj = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("items"), "warning.config.block.behavior.stackable.missing_items");
|
||||
List<Key> items = MiscUtils.getAsStringList(itemsObj).stream().map(Key::of).toList();
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.block.state.properties.SingleBlockHalf;
|
||||
import net.momirealms.craftengine.core.block.state.properties.StairsShape;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class StairsBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Property<HorizontalDirection> facingProperty;
|
||||
private final Property<SingleBlockHalf> halfProperty;
|
||||
private final Property<StairsShape> shapeProperty;
|
||||
|
||||
public StairsBlockBehavior(CustomBlock block, Property<HorizontalDirection> facing, Property<SingleBlockHalf> half, Property<StairsShape> shape) {
|
||||
super(block);
|
||||
this.facingProperty = facing;
|
||||
this.halfProperty = half;
|
||||
this.shapeProperty = shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
Direction clickedFace = context.getClickedFace();
|
||||
BlockPos clickedPos = context.getClickedPos();
|
||||
ImmutableBlockState blockState = state.owner().value().defaultState()
|
||||
.with(this.facingProperty, context.getHorizontalDirection().toHorizontalDirection())
|
||||
.with(this.halfProperty, clickedFace != Direction.DOWN && (clickedFace == Direction.UP || !(context.getClickLocation().y - clickedPos.y() > 0.5)) ? SingleBlockHalf.BOTTOM : SingleBlockHalf.TOP);
|
||||
if (super.waterloggedProperty != null) {
|
||||
Object fluidState = FastNMS.INSTANCE.method$Level$getFluidState(context.getLevel().serverWorld(), LocationUtils.toBlockPos(clickedPos));
|
||||
blockState = blockState.with(this.waterloggedProperty, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER);
|
||||
}
|
||||
return blockState.with(this.shapeProperty, getStairsShape(blockState, context.getLevel().serverWorld(), clickedPos));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object updateShape(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object level;
|
||||
Object blockPos;
|
||||
Object blockState = args[0];
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
level = args[1];
|
||||
blockPos = args[3];
|
||||
} else {
|
||||
level = args[3];
|
||||
blockPos = args[4];
|
||||
}
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) return blockState;
|
||||
if (super.waterloggedProperty != null && immutableBlockState.get(this.waterloggedProperty)) {
|
||||
FastNMS.INSTANCE.method$LevelAccessor$scheduleFluidTick(VersionHelper.isOrAbove1_21_2() ? args[2] : args[3], VersionHelper.isOrAbove1_21_2() ? args[3] : args[4], MFluids.WATER, 5);
|
||||
}
|
||||
Direction direction = DirectionUtils.fromNMSDirection(VersionHelper.isOrAbove1_21_2() ? args[4] : args[1]);
|
||||
StairsShape stairsShape = getStairsShape(immutableBlockState, level, LocationUtils.fromBlockPos(blockPos));
|
||||
return direction.axis().isHorizontal()
|
||||
? immutableBlockState.with(this.shapeProperty, stairsShape).customBlockState().handle()
|
||||
: superMethod.call();
|
||||
}
|
||||
|
||||
private StairsShape getStairsShape(ImmutableBlockState state, Object level, BlockPos pos) {
|
||||
Direction direction = state.get(this.facingProperty).toDirection();
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(direction)));
|
||||
int stateId = BlockStateUtils.blockStateToId(blockState);
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState != null && !immutableBlockState.isEmpty()) {
|
||||
if (isStairs(blockState) && state.get(this.halfProperty) == immutableBlockState.get(this.halfProperty)) {
|
||||
Direction direction1 = immutableBlockState.get(this.facingProperty).toDirection();
|
||||
if (direction1.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction1.opposite())) {
|
||||
if (direction1 == direction.counterClockWise()) {
|
||||
return StairsShape.OUTER_LEFT;
|
||||
}
|
||||
return StairsShape.OUTER_RIGHT;
|
||||
}
|
||||
}
|
||||
} else if (isStairs(blockState)) {
|
||||
// 处理可能是原版楼梯
|
||||
// try {
|
||||
// Object nmsHalf = CoreReflections.method$StateHolder$getValue.invoke(blockState, CoreReflections.instance$StairBlock$HALF);
|
||||
// SingleBlockHalf half = SingleBlockHalf.valueOf(nmsHalf.toString().toUpperCase(Locale.ROOT));
|
||||
// if (state.get(this.halfProperty).equals(half)) {
|
||||
// Object nmsFacing = CoreReflections.method$StateHolder$getValue.invoke(blockState, CoreReflections.instance$StairBlock$FACING);
|
||||
// Direction direction1 = DirectionUtils.fromNMSDirection(nmsFacing);
|
||||
// if (direction1.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction1.opposite())) {
|
||||
// if (direction1 == direction.counterClockWise()) {
|
||||
// return StairsShape.OUTER_LEFT;
|
||||
// }
|
||||
// return StairsShape.OUTER_RIGHT;
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// CraftEngine.instance().logger().warn("Failed to get facing from blockState", e);
|
||||
// }
|
||||
}
|
||||
|
||||
Object blockState1 = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(direction.opposite())));
|
||||
int stateId1 = BlockStateUtils.blockStateToId(blockState1);
|
||||
ImmutableBlockState immutableBlockState1 = BukkitBlockManager.instance().getImmutableBlockState(stateId1);
|
||||
if (immutableBlockState1 != null && !immutableBlockState1.isEmpty()) {
|
||||
if (isStairs(blockState1) && state.get(this.halfProperty) == immutableBlockState1.get(this.halfProperty)) {
|
||||
Direction direction2 = immutableBlockState1.get(this.facingProperty).toDirection();
|
||||
if (direction2.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction2)) {
|
||||
if (direction2 == direction.counterClockWise()) {
|
||||
return StairsShape.INNER_LEFT;
|
||||
}
|
||||
return StairsShape.INNER_RIGHT;
|
||||
}
|
||||
}
|
||||
} else if (isStairs(blockState1)) {
|
||||
// 处理可能是原版楼梯
|
||||
// try {
|
||||
// Object nmsHalf = CoreReflections.method$StateHolder$getValue.invoke(blockState1, CoreReflections.instance$StairBlock$HALF);
|
||||
// SingleBlockHalf half = SingleBlockHalf.valueOf(nmsHalf.toString().toUpperCase(Locale.ROOT));
|
||||
// if (state.get(this.halfProperty).equals(half)) {
|
||||
// Object nmsFacing = CoreReflections.method$StateHolder$getValue.invoke(blockState1, CoreReflections.instance$StairBlock$FACING);
|
||||
// Direction direction1 = DirectionUtils.fromNMSDirection(nmsFacing);
|
||||
// if (direction1.axis() != state.get(this.facingProperty).toDirection().axis() && canTakeShape(state, level, pos, direction1)) {
|
||||
// if (direction1 == direction.counterClockWise()) {
|
||||
// return StairsShape.INNER_LEFT;
|
||||
// }
|
||||
// return StairsShape.INNER_RIGHT;
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// CraftEngine.instance().logger().warn("Failed to get facing from blockState", e);
|
||||
// }
|
||||
}
|
||||
|
||||
return StairsShape.STRAIGHT;
|
||||
}
|
||||
|
||||
private boolean isStairs(Object state) {
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
|
||||
return FastNMS.INSTANCE.method$BlockState$getBlock(state).equals(CoreReflections.clazz$StairBlock);
|
||||
}
|
||||
Optional<StairsBlockBehavior> optionalBehavior = immutableBlockState.behavior().getAs(StairsBlockBehavior.class);
|
||||
return optionalBehavior.isPresent();
|
||||
}
|
||||
|
||||
private boolean canTakeShape(ImmutableBlockState state, Object level, BlockPos pos, Direction face) {
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.toBlockPos(pos.relative(face)));
|
||||
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
|
||||
// 处理可能是原版楼梯
|
||||
// try {
|
||||
// Object nmsFacing = CoreReflections.method$StateHolder$getValue.invoke(blockState, CoreReflections.instance$StairBlock$FACING);
|
||||
// Direction direction = DirectionUtils.fromNMSDirection(nmsFacing);
|
||||
// if (direction != state.get(this.facingProperty).toDirection()) return true;
|
||||
// Object nmsHalf = CoreReflections.method$StateHolder$getValue.invoke(blockState, CoreReflections.instance$StairBlock$HALF);
|
||||
// SingleBlockHalf half = SingleBlockHalf.valueOf(nmsHalf.toString().toUpperCase(Locale.ROOT));
|
||||
// if (half != state.get(this.halfProperty)) return true;
|
||||
// } catch (Exception e) {
|
||||
// CraftEngine.instance().logger().warn("Failed to handle canTakeShape", e);
|
||||
// }
|
||||
return !isStairs(blockState);
|
||||
}
|
||||
return !isStairs(blockState) || immutableBlockState.get(this.facingProperty) != state.get(this.facingProperty) || immutableBlockState.get(this.halfProperty) != state.get(this.halfProperty);
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.stairs.missing_facing");
|
||||
Property<SingleBlockHalf> half = (Property<SingleBlockHalf>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("half"), "warning.config.block.behavior.stairs.missing_half");
|
||||
Property<StairsShape> shape = (Property<StairsShape>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("shape"), "warning.config.block.behavior.stairs.missing_shape");
|
||||
return new StairsBlockBehavior(block, facing, half, shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,15 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.core.block.BlockBehavior;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class StrippableBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private static final Key AXE_STRIP_SOUND = Key.of("minecraft:item.axe.strip");
|
||||
private final Key stripped;
|
||||
|
||||
public StrippableBlockBehavior(CustomBlock block, Key stripped) {
|
||||
@@ -49,84 +21,6 @@ public class StrippableBlockBehavior extends BukkitBlockBehavior {
|
||||
return this.stripped;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
Item<ItemStack> item = (Item<ItemStack>) context.getItem();
|
||||
if (item == null) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = item.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) {
|
||||
if (!item.is(ItemTags.AXES))
|
||||
return InteractionResult.PASS;
|
||||
} else {
|
||||
CustomItem<ItemStack> customItem = optionalCustomItem.get();
|
||||
if (!customItem.settings().tags().contains(ItemTags.AXES) && !item.is(ItemTags.AXES))
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
Player player = context.getPlayer();
|
||||
// no adventure mode
|
||||
if (player.isAdventureMode()) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
Item<?> offHandItem = player.getItemInHand(InteractionHand.OFF_HAND);
|
||||
// is using a shield
|
||||
if (context.getHand() == InteractionHand.MAIN_HAND && offHandItem != null && offHandItem.vanillaId().equals(ItemKeys.SHIELD) && !player.isSecondaryUseActive()) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
Optional<CustomBlock> optionalNewCustomBlock = BukkitBlockManager.instance().blockById(stripped());
|
||||
if (optionalNewCustomBlock.isEmpty()) {
|
||||
CraftEngine.instance().logger().warn("stripped block " + stripped() + " does not exist");
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
CustomBlock newCustomBlock = optionalNewCustomBlock.get();
|
||||
CompoundTag compoundTag = state.propertiesNbt();
|
||||
ImmutableBlockState newState = newCustomBlock.getBlockState(compoundTag);
|
||||
|
||||
org.bukkit.entity.Player bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer());
|
||||
|
||||
BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
Block block = clicked.block();
|
||||
// Call bukkit event
|
||||
EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, block, BlockStateUtils.fromBlockData(newState.customBlockState().handle()));
|
||||
if (EventUtils.fireAndCheckCancel(event)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
BlockPos pos = context.getClickedPos();
|
||||
context.getLevel().playBlockSound(Vec3d.atCenterOf(pos), AXE_STRIP_SOUND, 1, 1);
|
||||
CraftEngineBlocks.place(block.getLocation(), newState, UpdateOption.UPDATE_ALL_IMMEDIATE, false);
|
||||
block.getWorld().sendGameEvent(bukkitPlayer, GameEvent.BLOCK_CHANGE, new Vector(pos.x(), pos.y(), pos.z()));
|
||||
Material material = MaterialUtils.getMaterial(item.vanillaId());
|
||||
bukkitPlayer.setStatistic(Statistic.USE_ITEM, material, bukkitPlayer.getStatistic(Statistic.USE_ITEM, material) + 1);
|
||||
|
||||
// resend swing if it's not interactable on client side
|
||||
if (!InteractUtils.isInteractable(
|
||||
bukkitPlayer, BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()),
|
||||
context.getHitResult(), item
|
||||
) || player.isSecondaryUseActive()) {
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
// shrink item amount
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
Object itemStack = item.getLiteralObject();
|
||||
Object serverPlayer = player.serverPlayer();
|
||||
Object equipmentSlot = context.getHand() == InteractionHand.MAIN_HAND ? CoreReflections.instance$EquipmentSlot$MAINHAND : CoreReflections.instance$EquipmentSlot$OFFHAND;
|
||||
try {
|
||||
CoreReflections.method$ItemStack$hurtAndBreak.invoke(itemStack, 1, serverPlayer, equipmentSlot);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to hurt itemStack", e);
|
||||
}
|
||||
} else {
|
||||
ItemStack itemStack = item.getItem();
|
||||
itemStack.damage(1, bukkitPlayer);
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,20 +10,30 @@ import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.MiscUtils;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class SturdyBaseBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Direction direction;
|
||||
private final boolean stackable;
|
||||
private final boolean checkFull;
|
||||
private final boolean checkRigid;
|
||||
private final boolean checkCenter;
|
||||
|
||||
public SturdyBaseBlockBehavior(CustomBlock block, int delay, Direction direction, boolean stackable) {
|
||||
public SturdyBaseBlockBehavior(CustomBlock block, int delay, Direction direction, boolean stackable, boolean checkFull, boolean checkRigid, boolean checkCenter) {
|
||||
super(block, delay);
|
||||
this.direction = direction;
|
||||
this.stackable = stackable;
|
||||
this.checkFull = checkFull;
|
||||
this.checkRigid = checkRigid;
|
||||
this.checkCenter = checkCenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,12 +43,18 @@ public class SturdyBaseBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos) + this.direction.stepZ();
|
||||
Object targetPos = FastNMS.INSTANCE.constructor$BlockPos(x, y, z);
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, targetPos);
|
||||
if ((boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
|
||||
if (this.checkFull && (boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
|
||||
blockState, world, targetPos, DirectionUtils.toNMSDirection(this.direction.opposite()),
|
||||
CoreReflections.instance$SupportType$FULL
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
if (this.checkRigid && FastNMS.INSTANCE.method$Block$canSupportRigidBlock(world, targetPos)) {
|
||||
return true;
|
||||
}
|
||||
if (this.checkCenter && FastNMS.INSTANCE.method$Block$canSupportCenter(world, targetPos, DirectionUtils.toNMSDirection(this.direction.opposite()))) {
|
||||
return true;
|
||||
}
|
||||
if (!this.stackable) {
|
||||
return false;
|
||||
}
|
||||
@@ -53,8 +69,9 @@ public class SturdyBaseBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay");
|
||||
Direction direction = Direction.valueOf(arguments.getOrDefault("direction", "down").toString().toUpperCase(Locale.ENGLISH));
|
||||
boolean stackable = (boolean) arguments.getOrDefault("stackable", false);
|
||||
return new SturdyBaseBlockBehavior(block, delay, direction, stackable);
|
||||
boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable");
|
||||
List<String> supportTypes = MiscUtils.getAsStringList(arguments.getOrDefault("support-types", List.of("full")));
|
||||
return new SturdyBaseBlockBehavior(block, delay, direction, stackable, supportTypes.contains("full"), supportTypes.contains("rigid"), supportTypes.contains("center"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,7 @@ import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.util.Direction;
|
||||
import net.momirealms.craftengine.core.util.HorizontalDirection;
|
||||
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
@@ -108,19 +105,12 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
|
||||
if (!this.canOpenWithHand) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
if (context.getItem() == null) {
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS;
|
||||
} else if (!context.getPlayer().isSecondaryUseActive()) {
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
} else {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
playerToggle(context, state);
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -241,14 +231,14 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
|
||||
Property<HorizontalDirection> facing = (Property<HorizontalDirection>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.trapdoor.missing_facing");
|
||||
Property<Boolean> open = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("open"), "warning.config.block.behavior.trapdoor.missing_open");
|
||||
Property<Boolean> powered = (Property<Boolean>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.trapdoor.missing_powered");
|
||||
boolean canOpenWithHand = (boolean) arguments.getOrDefault("can-open-with-hand", true);
|
||||
boolean canOpenByWindCharge = (boolean) arguments.getOrDefault("can-open-by-wind-charge", true);
|
||||
Map<String, Object> sounds = (Map<String, Object>) arguments.get("sounds");
|
||||
boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-with-hand", true), "can-open-with-hand");
|
||||
boolean canOpenByWindCharge = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-by-wind-charge", true), "can-open-by-wind-charge");
|
||||
Map<String, Object> sounds = MiscUtils.castToMap(arguments.get("sounds"), true);
|
||||
SoundData openSound = null;
|
||||
SoundData closeSound = null;
|
||||
if (sounds != null) {
|
||||
openSound = Optional.ofNullable(sounds.get("open")).map(obj -> SoundData.create(obj, 1, 1)).orElse(null);
|
||||
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, 1, 1)).orElse(null);
|
||||
openSound = Optional.ofNullable(sounds.get("open")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null);
|
||||
}
|
||||
return new TrapDoorBlockBehavior(block, half, facing, powered, open, canOpenWithHand, canOpenByWindCharge, openSound, closeSound);
|
||||
}
|
||||
|
||||
@@ -35,13 +35,24 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
public InteractionResult useOnBlock(UseOnContext context, ImmutableBlockState state) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
InteractionResult result = behavior.useOnBlock(context, state);
|
||||
if (result != InteractionResult.PASS) {
|
||||
if (result != InteractionResult.PASS && result != InteractionResult.TRY_EMPTY_HAND) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return super.useOnBlock(context, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
InteractionResult result = behavior.useWithoutItem(context, state);
|
||||
if (result != InteractionResult.PASS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return super.useWithoutItem(context, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
@@ -182,4 +193,67 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
behavior.onExplosionHit(thisBlock, args, superMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
behavior.setPlacedBy(context, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canBeReplaced(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
if (!behavior.canBeReplaced(context, state)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.canBeReplaced(context, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void entityInside(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
behavior.entityInside(thisBlock, args, superMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void affectNeighborsAfterRemoval(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
behavior.affectNeighborsAfterRemoval(thisBlock, args, superMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSignal(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
int signal = behavior.getSignal(thisBlock, args, superMethod);
|
||||
if (signal != 0) {
|
||||
return signal;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDirectSignal(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
int signal = behavior.getDirectSignal(thisBlock, args, superMethod);
|
||||
if (signal != 0) {
|
||||
return signal;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSignalSource(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
if (behavior.isSignalSource(thisBlock, args, superMethod)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
public static final NamespacedKey FURNITURE_KEY = KeyUtils.toNamespacedKey(FurnitureManager.FURNITURE_KEY);
|
||||
@@ -82,7 +83,7 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
});
|
||||
if (playSound) {
|
||||
SoundData data = furniture.settings().sounds().placeSound();
|
||||
location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume(), data.pitch());
|
||||
location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume().get(), data.pitch().get());
|
||||
}
|
||||
return loadedFurnitureByRealEntityId(furnitureEntity.getEntityId());
|
||||
}
|
||||
@@ -94,15 +95,31 @@ public class BukkitFurnitureManager extends AbstractFurnitureManager {
|
||||
COLLISION_ENTITY_TYPE = Config.colliderType();
|
||||
Bukkit.getPluginManager().registerEvents(this.dismountListener, this.plugin.javaPlugin());
|
||||
Bukkit.getPluginManager().registerEvents(this.furnitureEventListener, this.plugin.javaPlugin());
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
List<Entity> entities = world.getEntities();
|
||||
for (Entity entity : entities) {
|
||||
if (entity instanceof ItemDisplay display) {
|
||||
handleBaseEntityLoadEarly(display);
|
||||
} else if (entity instanceof Interaction interaction) {
|
||||
handleCollisionEntityLoadOnEntitiesLoad(interaction);
|
||||
} else if (entity instanceof Boat boat) {
|
||||
handleCollisionEntityLoadOnEntitiesLoad(boat);
|
||||
if (VersionHelper.isFolia()) {
|
||||
BiConsumer<Entity, Runnable> taskExecutor = (entity, runnable) -> entity.getScheduler().run(this.plugin.javaPlugin(), (t) -> runnable.run(), () -> {});
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
List<Entity> entities = world.getEntities();
|
||||
for (Entity entity : entities) {
|
||||
if (entity instanceof ItemDisplay display) {
|
||||
taskExecutor.accept(entity, () -> handleBaseEntityLoadEarly(display));
|
||||
} else if (entity instanceof Interaction interaction) {
|
||||
taskExecutor.accept(entity, () -> handleCollisionEntityLoadOnEntitiesLoad(interaction));
|
||||
} else if (entity instanceof Boat boat) {
|
||||
taskExecutor.accept(entity, () -> handleCollisionEntityLoadOnEntitiesLoad(boat));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
List<Entity> entities = world.getEntities();
|
||||
for (Entity entity : entities) {
|
||||
if (entity instanceof ItemDisplay display) {
|
||||
handleBaseEntityLoadEarly(display);
|
||||
} else if (entity instanceof Interaction interaction) {
|
||||
handleCollisionEntityLoadOnEntitiesLoad(interaction);
|
||||
} else if (entity instanceof Boat boat) {
|
||||
handleCollisionEntityLoadOnEntitiesLoad(boat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ public class CustomHitBox extends AbstractHitBox {
|
||||
if (entityType == null) {
|
||||
throw new LocalizedResourceConfigException("warning.config.furniture.hitbox.custom.invalid_entity", new IllegalArgumentException("EntityType not found: " + type), type);
|
||||
}
|
||||
boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", false);
|
||||
boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", true);
|
||||
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile");
|
||||
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
|
||||
return new CustomHitBox(HitBoxFactory.getSeats(arguments), position, entityType, scale, blocksBuilding, canBeHitByProjectile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,10 +118,10 @@ public class HappyGhastHitBox extends AbstractHitBox {
|
||||
throw new UnsupportedOperationException("HappyGhastHitBox is only supported on 1.21.6+");
|
||||
}
|
||||
double scale = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("scale", 1), "scale");
|
||||
boolean hardCollision = (boolean) arguments.getOrDefault("hard-collision", true);
|
||||
boolean canUseOn = (boolean) arguments.getOrDefault("can-use-item-on", false);
|
||||
boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", false);
|
||||
boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", false);
|
||||
boolean hardCollision = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("hard-collision", true), "hard-collision");
|
||||
boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", false), "can-use-item-on");
|
||||
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile");
|
||||
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", false), "blocks-building");
|
||||
return new HappyGhastHitBox(
|
||||
HitBoxFactory.getSeats(arguments),
|
||||
MiscUtils.getAsVector3f(arguments.getOrDefault("position", "0"), "position"),
|
||||
|
||||
@@ -104,10 +104,10 @@ public class InteractionHitBox extends AbstractHitBox {
|
||||
width = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("width", "1"), "width");
|
||||
height = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("height", "1"), "height");
|
||||
}
|
||||
boolean canUseOn = (boolean) arguments.getOrDefault("can-use-item-on", false);
|
||||
boolean interactive = (boolean) arguments.getOrDefault("interactive", true);
|
||||
boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", false);
|
||||
boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", true);
|
||||
boolean canUseOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", false), "can-use-item-on");
|
||||
boolean interactive = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interactive", true), "interactive");
|
||||
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", false), "can-be-hit-by-projectile");
|
||||
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
|
||||
return new InteractionHitBox(
|
||||
HitBoxFactory.getSeats(arguments),
|
||||
position,
|
||||
|
||||
@@ -284,11 +284,11 @@ public class ShulkerHitBox extends AbstractHitBox {
|
||||
float scale = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("scale", "1"), "scale");
|
||||
byte peek = (byte) ResourceConfigUtils.getAsInt(arguments.getOrDefault("peek", 0), "peek");
|
||||
Direction directionEnum = Optional.ofNullable(arguments.get("direction")).map(it -> Direction.valueOf(it.toString().toUpperCase(Locale.ENGLISH))).orElse(Direction.UP);
|
||||
boolean interactive = (boolean) arguments.getOrDefault("interactive", true);
|
||||
boolean interactionEntity = (boolean) arguments.getOrDefault("interaction-entity", true);
|
||||
boolean canUseItemOn = (boolean) arguments.getOrDefault("can-use-item-on", true);
|
||||
boolean canBeHitByProjectile = (boolean) arguments.getOrDefault("can-be-hit-by-projectile", true);
|
||||
boolean blocksBuilding = (boolean) arguments.getOrDefault("blocks-building", true);
|
||||
boolean interactive = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interactive", true), "interactive");
|
||||
boolean interactionEntity = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("interaction-entity", true), "interaction-entity");
|
||||
boolean canUseItemOn = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-use-item-on", true), "can-use-item-on");
|
||||
boolean canBeHitByProjectile = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-hit-by-projectile", true), "can-be-hit-by-projectile");
|
||||
boolean blocksBuilding = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blocks-building", true), "blocks-building");
|
||||
return new ShulkerHitBox(
|
||||
HitBoxFactory.getSeats(arguments),
|
||||
position, directionEnum,
|
||||
|
||||
@@ -16,4 +16,10 @@ public class BukkitCustomProjectile extends AbstractCustomProjectile {
|
||||
public BukkitProjectile projectile() {
|
||||
return (BukkitProjectile) super.projectile();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Item<ItemStack> item() {
|
||||
return (Item<ItemStack>) item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,16 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.scheduler.impl.FoliaTask;
|
||||
import net.momirealms.craftengine.bukkit.util.ParticleUtils;
|
||||
import net.momirealms.craftengine.core.entity.projectile.CustomProjectile;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileManager;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileType;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -65,7 +66,7 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CustomProjectile> projectileByEntityId(int entityId) {
|
||||
public Optional<BukkitCustomProjectile> projectileByEntityId(int entityId) {
|
||||
return Optional.ofNullable(this.projectiles.get(entityId));
|
||||
}
|
||||
|
||||
@@ -116,16 +117,15 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
if (meta != null) {
|
||||
BukkitCustomProjectile customProjectile = new BukkitCustomProjectile(meta, projectile, wrapped);
|
||||
this.projectiles.put(projectile.getEntityId(), customProjectile);
|
||||
new ProjectileInjectTask(projectile);
|
||||
new ProjectileInjectTask(projectile, !projectileItem.getItemMeta().hasEnchant(Enchantment.LOYALTY));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerItemConsumeEvent event) {
|
||||
String type = getType(event.getItem());
|
||||
if (type == null) return;
|
||||
if (type.equals("bow") || type.equals("trident")) {
|
||||
public void onPlayerConsume(PlayerItemConsumeEvent event) {
|
||||
ProjectileType type = getCustomProjectileType(event.getItem());
|
||||
if (type == ProjectileType.TRIDENT) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
@@ -133,23 +133,21 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
@EventHandler
|
||||
public void onPlayerStopUsingItem(PlayerStopUsingItemEvent event) {
|
||||
ItemStack item = event.getItem();
|
||||
String type = getType(item);
|
||||
ProjectileType type = getCustomProjectileType(item);
|
||||
if (type == null) return;
|
||||
int ticksHeldFor = event.getTicksHeldFor();
|
||||
Player player = event.getPlayer();
|
||||
if (type.equals("trident")) {
|
||||
if (type == ProjectileType.TRIDENT) {
|
||||
if (ticksHeldFor < 10) return;
|
||||
Object nmsItemStack = FastNMS.INSTANCE.field$CraftItemStack$handle(item);
|
||||
Object nmsServerLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld());
|
||||
Object nmsEntity = FastNMS.INSTANCE.method$CraftEntity$getHandle(player);
|
||||
TridentRelease.releaseUsing(nmsItemStack, nmsServerLevel, nmsEntity);
|
||||
} else if (type.equals("bow")) {
|
||||
if (ticksHeldFor < 3) return;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String getType(ItemStack item) {
|
||||
private ProjectileType getCustomProjectileType(ItemStack item) {
|
||||
Item<ItemStack> wrapped = BukkitItemManager.instance().wrap(item);
|
||||
Optional<CustomItem<ItemStack>> optionalCustomItem = wrapped.getCustomItem();
|
||||
if (optionalCustomItem.isEmpty()) return null;
|
||||
@@ -162,11 +160,13 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
public class ProjectileInjectTask implements Runnable {
|
||||
private final Projectile projectile;
|
||||
private final SchedulerTask task;
|
||||
private final boolean checkInGround;
|
||||
private Object cachedServerEntity;
|
||||
private int lastInjectedInterval = 0;
|
||||
|
||||
public ProjectileInjectTask(Projectile projectile) {
|
||||
public ProjectileInjectTask(Projectile projectile, boolean checkInGround) {
|
||||
this.projectile = projectile;
|
||||
this.checkInGround = checkInGround;
|
||||
if (VersionHelper.isFolia()) {
|
||||
this.task = new FoliaTask(projectile.getScheduler().runAtFixedRate(plugin.javaPlugin(), (t) -> this.run(), () -> {}, 1, 1));
|
||||
} else {
|
||||
@@ -191,14 +191,18 @@ public class BukkitProjectileManager implements Listener, ProjectileManager {
|
||||
this.cachedServerEntity = serverEntity;
|
||||
}
|
||||
|
||||
boolean inGround = FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity);
|
||||
if (canSpawnParticle(nmsEntity, inGround)) {
|
||||
this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0);
|
||||
}
|
||||
if (inGround) {
|
||||
updateProjectileUpdateInterval(Integer.MAX_VALUE);
|
||||
} else {
|
||||
if (!CoreReflections.clazz$AbstractArrow.isInstance(nmsEntity) || !this.checkInGround) {
|
||||
updateProjectileUpdateInterval(1);
|
||||
} else {
|
||||
boolean inGround = FastNMS.INSTANCE.method$AbstractArrow$isInGround(nmsEntity);
|
||||
if (canSpawnParticle(nmsEntity, inGround)) {
|
||||
this.projectile.getWorld().spawnParticle(ParticleUtils.BUBBLE, this.projectile.getLocation(), 3, 0.1, 0.1, 0.1, 0);
|
||||
}
|
||||
if (inGround) {
|
||||
updateProjectileUpdateInterval(Integer.MAX_VALUE);
|
||||
} else {
|
||||
updateProjectileUpdateInterval(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
|
||||
import net.momirealms.craftengine.bukkit.item.listener.ArmorEventListener;
|
||||
@@ -38,9 +39,8 @@ import java.util.Set;
|
||||
|
||||
public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
static {
|
||||
// registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS);
|
||||
// registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET);
|
||||
registerVanillaItemExtraBehavior(FlintAndSteelItemBehavior.INSTANCE, ItemKeys.FLINT_AND_STEEL);
|
||||
registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.AXES);
|
||||
}
|
||||
|
||||
private static BukkitItemManager instance;
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package net.momirealms.craftengine.bukkit.item.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.block.behavior.StrippableBlockBehavior;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.UpdateOption;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.pack.Pack;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import org.bukkit.GameEvent;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.event.entity.EntityChangeBlockEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class AxeItemBehavior extends ItemBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
public static final AxeItemBehavior INSTANCE = new AxeItemBehavior();
|
||||
private static final Key AXE_STRIP_SOUND = Key.of("minecraft:item.axe.strip");
|
||||
|
||||
private boolean canBlockAttack(Item<ItemStack> item) {
|
||||
if (VersionHelper.isOrAbove1_21_5()) {
|
||||
return item.hasComponent("minecraft:blocks_attacks");
|
||||
} else {
|
||||
return item.vanillaId().equals(ItemKeys.SHIELD);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnstableApiUsage", "unchecked"})
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context) {
|
||||
Player player = context.getPlayer();
|
||||
// no adventure mode for the moment
|
||||
if (player.isAdventureMode()) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
BukkitBlockInWorld block = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
BlockData blockData = block.block().getBlockData();
|
||||
int stateId = BlockStateUtils.blockDataToId(blockData);
|
||||
if (BlockStateUtils.isVanillaBlock(stateId)) return InteractionResult.PASS;
|
||||
|
||||
ImmutableBlockState customBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (customBlockState == null || customBlockState.isEmpty()) return InteractionResult.PASS;
|
||||
|
||||
Optional<StrippableBlockBehavior> behaviorOptional = customBlockState.behavior().getAs(StrippableBlockBehavior.class);
|
||||
if (behaviorOptional.isEmpty()) return InteractionResult.PASS;
|
||||
Key stripped = behaviorOptional.get().stripped();
|
||||
Item<ItemStack> offHandItem = (Item<ItemStack>) player.getItemInHand(InteractionHand.OFF_HAND);
|
||||
// is using a shield
|
||||
if (context.getHand() == InteractionHand.MAIN_HAND && offHandItem != null && canBlockAttack(offHandItem) && !player.isSecondaryUseActive()) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
Optional<CustomBlock> optionalNewCustomBlock = BukkitBlockManager.instance().blockById(stripped);
|
||||
if (optionalNewCustomBlock.isEmpty()) {
|
||||
CraftEngine.instance().logger().warn("stripped block " + stripped + " does not exist");
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
CustomBlock newCustomBlock = optionalNewCustomBlock.get();
|
||||
CompoundTag compoundTag = customBlockState.propertiesNbt();
|
||||
ImmutableBlockState newState = newCustomBlock.getBlockState(compoundTag);
|
||||
|
||||
org.bukkit.entity.Player bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer());
|
||||
|
||||
BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
// Call bukkit event
|
||||
EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, clicked.block(), BlockStateUtils.fromBlockData(newState.customBlockState().handle()));
|
||||
if (EventUtils.fireAndCheckCancel(event)) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
|
||||
Item<ItemStack> item = (Item<ItemStack>) context.getItem();
|
||||
BlockPos pos = context.getClickedPos();
|
||||
context.getLevel().playBlockSound(Vec3d.atCenterOf(pos), AXE_STRIP_SOUND, 1, 1);
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(context.getLevel().serverWorld(), LocationUtils.toBlockPos(pos), newState.customBlockState().handle(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags());
|
||||
clicked.block().getWorld().sendGameEvent(bukkitPlayer, GameEvent.BLOCK_CHANGE, new Vector(pos.x(), pos.y(), pos.z()));
|
||||
Material material = MaterialUtils.getMaterial(item.vanillaId());
|
||||
bukkitPlayer.setStatistic(Statistic.USE_ITEM, material, bukkitPlayer.getStatistic(Statistic.USE_ITEM, material) + 1);
|
||||
|
||||
// resend swing if it's not interactable on client side
|
||||
if (!InteractUtils.isInteractable(
|
||||
bukkitPlayer, BlockStateUtils.fromBlockData(customBlockState.vanillaBlockState().handle()),
|
||||
context.getHitResult(), item
|
||||
) || player.isSecondaryUseActive()) {
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
// shrink item amount
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
Object itemStack = item.getLiteralObject();
|
||||
Object serverPlayer = player.serverPlayer();
|
||||
Object equipmentSlot = context.getHand() == InteractionHand.MAIN_HAND ? CoreReflections.instance$EquipmentSlot$MAINHAND : CoreReflections.instance$EquipmentSlot$OFFHAND;
|
||||
try {
|
||||
CoreReflections.method$ItemStack$hurtAndBreak.invoke(itemStack, 1, serverPlayer, equipmentSlot);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to hurt itemStack", e);
|
||||
}
|
||||
} else {
|
||||
ItemStack itemStack = item.getItem();
|
||||
itemStack.damage(1, bukkitPlayer);
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
public static class Factory implements ItemBehaviorFactory {
|
||||
@Override
|
||||
public ItemBehavior create(Pack pack, Path path, Key key, Map<String, Object> arguments) {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.behavior.BlockBoundItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
@@ -52,7 +53,7 @@ import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BlockItemBehavior extends ItemBehavior {
|
||||
public class BlockItemBehavior extends BlockBoundItemBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Key blockId;
|
||||
|
||||
@@ -196,7 +197,8 @@ public class BlockItemBehavior extends ItemBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
public Key blockId() {
|
||||
@Override
|
||||
public Key block() {
|
||||
return this.blockId;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ public class BukkitItemBehaviors extends ItemBehaviors {
|
||||
public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item");
|
||||
public static final Key FLINT_AND_STEEL_ITEM = Key.from("craftengine:flint_and_steel_item");
|
||||
public static final Key COMPOSTABLE_ITEM = Key.from("craftengine:compostable_item");
|
||||
public static final Key AXE_ITEM = Key.from("craftengine:axe_item");
|
||||
|
||||
public static void init() {
|
||||
register(EMPTY, EmptyItemBehavior.FACTORY);
|
||||
@@ -18,5 +19,6 @@ public class BukkitItemBehaviors extends ItemBehaviors {
|
||||
register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY);
|
||||
register(FLINT_AND_STEEL_ITEM, FlintAndSteelItemBehavior.FACTORY);
|
||||
register(COMPOSTABLE_ITEM, CompostableItemBehavior.FACTORY);
|
||||
register(AXE_ITEM, AxeItemBehavior.FACTORY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,18 +20,23 @@ import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.item.setting.FoodData;
|
||||
import net.momirealms.craftengine.core.plugin.config.Config;
|
||||
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
|
||||
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
|
||||
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
|
||||
import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
import net.momirealms.craftengine.core.sound.SoundSource;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import net.momirealms.craftengine.core.world.BlockHitResult;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import net.momirealms.craftengine.core.world.Vec3d;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.Openable;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
@@ -167,17 +172,45 @@ public class ItemEventListener implements Listener {
|
||||
|
||||
if (hitResult != null) {
|
||||
UseOnContext useOnContext = new UseOnContext(serverPlayer, hand, itemInHand, hitResult);
|
||||
if (immutableBlockState.behavior() instanceof AbstractBlockBehavior behavior) {
|
||||
InteractionResult result = behavior.useOnBlock(useOnContext, immutableBlockState);
|
||||
if (result.success()) {
|
||||
serverPlayer.updateLastSuccessfulInteractionTick(serverPlayer.gameTicks());
|
||||
boolean hasItem = player.getInventory().getItemInMainHand().getType() != Material.AIR || player.getInventory().getItemInOffHand().getType() != Material.AIR;
|
||||
boolean flag = player.isSneaking() && hasItem;
|
||||
if (!flag) {
|
||||
if (immutableBlockState.behavior() instanceof AbstractBlockBehavior behavior) {
|
||||
InteractionResult result = behavior.useOnBlock(useOnContext, immutableBlockState);
|
||||
if (result.success()) {
|
||||
serverPlayer.updateLastSuccessfulInteractionTick(serverPlayer.gameTicks());
|
||||
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (result == InteractionResult.TRY_EMPTY_HAND && hand == InteractionHand.MAIN_HAND) {
|
||||
result = behavior.useWithoutItem(useOnContext, immutableBlockState);
|
||||
if (result.success()) {
|
||||
serverPlayer.updateLastSuccessfulInteractionTick(serverPlayer.gameTicks());
|
||||
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (result == InteractionResult.FAIL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if (result != InteractionResult.PASS) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (Config.enableSoundSystem() && hitResult != null) {
|
||||
Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState);
|
||||
if (this.plugin.blockManager().isOpenableBlockSoundRemoved(blockOwner)) {
|
||||
boolean hasItem = player.getInventory().getItemInMainHand().getType() != Material.AIR || player.getInventory().getItemInOffHand().getType() != Material.AIR;
|
||||
boolean flag = player.isSneaking() && hasItem;
|
||||
if (!flag) {
|
||||
if (blockData instanceof Openable openable) {
|
||||
SoundData soundData = this.plugin.blockManager().getRemovedOpenableBlockSound(blockOwner, !openable.isOpen());
|
||||
serverPlayer.playSound(soundData.id(), SoundSource.BLOCK, soundData.volume().get(), soundData.pitch().get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,12 +303,14 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
public void unload() {
|
||||
if (!Config.enableRecipeSystem()) return;
|
||||
super.unload();
|
||||
try {
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager);
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
this.plugin.logger().warn("Failed to unregister recipes", e);
|
||||
if (VersionHelper.isOrAbove1_21_2()) {
|
||||
this.plugin.scheduler().executeSync(() -> {
|
||||
try {
|
||||
CoreReflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
this.plugin.logger().warn("Failed to unregister recipes", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +436,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager<ItemStack> {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.logger().warn("Failed to read data pack recipes", e);
|
||||
this.plugin.logger().warn("Failed to read data pack recipes", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new LocalizedResourceConfigException("warning.config.vanilla_loot.invalid_type", type, EnumUtils.toString(VanillaLoot.Type.values()));
|
||||
}
|
||||
boolean override = (boolean) section.getOrDefault("override", false);
|
||||
boolean override = ResourceConfigUtils.getAsBoolean(section.getOrDefault("override", false), "override");
|
||||
List<String> targets = MiscUtils.getAsStringList(section.getOrDefault("target", List.of()));
|
||||
LootTable<?> lootTable = LootTable.fromMap(MiscUtils.castToMap(section.get("loot"), false));
|
||||
switch (typeEnum) {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.Platform;
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
import net.momirealms.sparrow.nbt.CompoundTag;
|
||||
import net.momirealms.sparrow.nbt.Tag;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -19,14 +22,36 @@ public class BukkitPlatform implements Platform {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object nbt2Java(String nbt) {
|
||||
public Object snbtToJava(String nbt) {
|
||||
try {
|
||||
Object tag = FastNMS.INSTANCE.method$TagParser$parseCompoundFully("{\"root\":" + nbt + "}");
|
||||
Map<String, Object> map = (Map<String, Object>) MRegistryOps.NBT.convertTo(MRegistryOps.JAVA, tag);
|
||||
return map.get("root");
|
||||
} catch (CommandSyntaxException e) {
|
||||
CraftEngine.instance().debug(e::getMessage);
|
||||
throw new LocalizedResourceConfigException("warning.config.template.argument.default_value.invalid_syntax", e, nbt);
|
||||
throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e, nbt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag jsonToSparrowNBT(JsonElement json) {
|
||||
return MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag snbtToSparrowNBT(String nbt) {
|
||||
try {
|
||||
Object tag = FastNMS.INSTANCE.method$TagParser$parseCompoundFully("{\"root\":" + nbt + "}");
|
||||
CompoundTag map = (CompoundTag) MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, tag);
|
||||
return map.get("root");
|
||||
} catch (CommandSyntaxException e) {
|
||||
CraftEngine.instance().debug(e::getMessage);
|
||||
throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e, nbt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag javaToSparrowNBT(Object object) {
|
||||
return MRegistryOps.JAVA.convertTo(MRegistryOps.SPARROW_NBT, object);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public class BukkitCommandManager extends AbstractCommandManager<CommandSender>
|
||||
new DebugTargetBlockCommand(this, plugin),
|
||||
new DebugIsSectionInjectedCommand(this, plugin),
|
||||
new DebugMigrateTemplatesCommand(this, plugin),
|
||||
new DebugIsChunkPersistentLoadedCommand(this, plugin),
|
||||
new DebugEntityId2UUIDCommand(this, plugin),
|
||||
new TotemAnimationCommand(this, plugin),
|
||||
new EnableResourceCommand(this, plugin),
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.command.feature;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import net.momirealms.craftengine.core.plugin.command.sender.Sender;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.incendo.cloud.Command;
|
||||
|
||||
public class DebugIsChunkPersistentLoadedCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public DebugIsChunkPersistentLoadedCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
|
||||
super(commandManager, plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(org.incendo.cloud.CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.senderType(Player.class)
|
||||
.handler(context -> {
|
||||
Player player = context.sender();
|
||||
Chunk chunk = player.getChunk();
|
||||
Sender sender = plugin().senderFactory().wrap(player);
|
||||
sender.sendMessage(Component.text(chunk.isForceLoaded()));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "debug_is_chunk_persistent_loaded";
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager;
|
||||
import net.momirealms.craftengine.core.util.FileUtils;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.yaml.snakeyaml.DumperOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@@ -18,7 +16,7 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DebugMigrateTemplatesCommand extends BukkitCommandFeature<CommandSender> {
|
||||
private static final Pattern PATTERN = Pattern.compile("(?<!\\$)\\{([^}]+)}");
|
||||
private static final Pattern PATTERN = Pattern.compile("(?<!\\$)\\{([0-9a-zA-Z_]+)}");
|
||||
|
||||
public DebugMigrateTemplatesCommand(CraftEngineCommandManager<CommandSender> commandManager, CraftEngine plugin) {
|
||||
super(commandManager, plugin);
|
||||
@@ -31,13 +29,7 @@ public class DebugMigrateTemplatesCommand extends BukkitCommandFeature<CommandSe
|
||||
for (Pack pack : BukkitCraftEngine.instance().packManager().loadedPacks()) {
|
||||
for (Path file : FileUtils.getYmlConfigsDeeply(pack.configurationFolder())) {
|
||||
try {
|
||||
DumperOptions options = new DumperOptions();
|
||||
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||
options.setPrettyFlow(true);
|
||||
Yaml yaml = new Yaml(options);
|
||||
Object data = yaml.load(Files.newBufferedReader(file));
|
||||
String fileStr = yaml.dump(data);
|
||||
Files.writeString(file, fileStr);
|
||||
Files.writeString(file, replacePlaceholders(Files.readString(file)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -161,7 +161,24 @@ public final class BlockGenerator {
|
||||
.intercept(MethodDelegation.to(PlaceLiquidInterceptor.INSTANCE))
|
||||
// canPlaceLiquid
|
||||
.method(ElementMatchers.is(CoreReflections.method$SimpleWaterloggedBlock$canPlaceLiquid))
|
||||
.intercept(MethodDelegation.to(CanPlaceLiquidInterceptor.INSTANCE));
|
||||
.intercept(MethodDelegation.to(CanPlaceLiquidInterceptor.INSTANCE))
|
||||
// entityInside
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$entityInside))
|
||||
.intercept(MethodDelegation.to(EntityInsideInterceptor.INSTANCE))
|
||||
// getSignal
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$getSignal))
|
||||
.intercept(MethodDelegation.to(GetSignalInterceptor.INSTANCE))
|
||||
// getDirectSignal
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$getDirectSignal))
|
||||
.intercept(MethodDelegation.to(GetDirectSignalInterceptor.INSTANCE))
|
||||
// isSignalSource
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$isSignalSource))
|
||||
.intercept(MethodDelegation.to(IsSignalSourceInterceptor.INSTANCE));
|
||||
if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) {
|
||||
builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval))
|
||||
.intercept(MethodDelegation.to(AffectNeighborsAfterRemovalInterceptor.INSTANCE));
|
||||
}
|
||||
|
||||
Class<?> clazz$CraftEngineBlock = builder.make().load(BlockGenerator.class.getClassLoader()).getLoaded();
|
||||
constructor$CraftEngineBlock = MethodHandles.publicLookup().in(clazz$CraftEngineBlock)
|
||||
.findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$BlockBehaviour$Properties))
|
||||
@@ -197,6 +214,7 @@ public final class BlockGenerator {
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
ChainUpdateBlockIndicator indicator = (ChainUpdateBlockIndicator) thisObj;
|
||||
// todo chain updater
|
||||
if (indicator.isNoteBlock()) {
|
||||
if (CoreReflections.clazz$ServerLevel.isInstance(args[levelIndex])) {
|
||||
startNoteBlockChain(args);
|
||||
@@ -522,4 +540,77 @@ public final class BlockGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class GetDirectSignalInterceptor {
|
||||
public static final GetDirectSignalInterceptor INSTANCE = new GetDirectSignalInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public int intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
try {
|
||||
return holder.value().getDirectSignal(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().severe("Failed to run getDirectSignal", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class GetSignalInterceptor {
|
||||
public static final GetSignalInterceptor INSTANCE = new GetSignalInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public int intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
try {
|
||||
return holder.value().getSignal(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().severe("Failed to run getSignal", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class IsSignalSourceInterceptor {
|
||||
public static final IsSignalSourceInterceptor INSTANCE = new IsSignalSourceInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
try {
|
||||
return holder.value().isSignalSource(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().severe("Failed to run isSignalSource", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class AffectNeighborsAfterRemovalInterceptor {
|
||||
public static final AffectNeighborsAfterRemovalInterceptor INSTANCE = new AffectNeighborsAfterRemovalInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
try {
|
||||
holder.value().affectNeighborsAfterRemoval(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().severe("Failed to run affectNeighborsAfterRemoval", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class EntityInsideInterceptor {
|
||||
public static final EntityInsideInterceptor INSTANCE = new EntityInsideInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
|
||||
ObjectHolder<BlockBehavior> holder = ((BehaviorHolder) thisObj).getBehaviorHolder();
|
||||
try {
|
||||
holder.value().entityInside(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().severe("Failed to run entityInside", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import net.momirealms.craftengine.bukkit.util.*;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||
import net.momirealms.craftengine.core.entity.seat.SeatEntity;
|
||||
import net.momirealms.craftengine.core.font.FontManager;
|
||||
import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
@@ -129,16 +130,18 @@ public class PacketConsumers {
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EGG$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.POTION$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler();
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EGG$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.POTION$registryId] = createOptionalCustomProjectileEntityHandler(true);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(false);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false);
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.SPECTRAL_ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false);
|
||||
if (VersionHelper.isOrAbove1_20_5()) {
|
||||
ADD_ENTITY_HANDLERS[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE);
|
||||
}
|
||||
@@ -199,7 +202,7 @@ public class PacketConsumers {
|
||||
};
|
||||
}
|
||||
|
||||
private static BukkitNetworkManager.Handlers createOptionalCustomProjectileEntityHandler() {
|
||||
private static BukkitNetworkManager.Handlers createOptionalCustomProjectileEntityHandler(boolean fallback) {
|
||||
return (user, event) -> {
|
||||
FriendlyByteBuf buf = event.getBuffer();
|
||||
int id = buf.readVarInt();
|
||||
@@ -208,7 +211,9 @@ public class PacketConsumers {
|
||||
handler.convertAddCustomProjectilePacket(buf, event);
|
||||
user.entityPacketHandlers().put(id, handler);
|
||||
}, () -> {
|
||||
user.entityPacketHandlers().put(id, CommonItemPacketHandler.INSTANCE);
|
||||
if (fallback) {
|
||||
user.entityPacketHandlers().put(id, CommonItemPacketHandler.INSTANCE);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1654,14 +1659,15 @@ public class PacketConsumers {
|
||||
LocationUtils.toBlockPos(hitResult.blockPos())
|
||||
);
|
||||
} else {
|
||||
furniture.findFirstAvailableSeat(entityId).ifPresent(seat -> {
|
||||
if (furniture.tryOccupySeat(seat)) {
|
||||
SeatEntity currentSeat = serverPlayer.seat();
|
||||
if (currentSeat != null) currentSeat.dismount(serverPlayer);
|
||||
|
||||
furniture.spawnSeatEntityForPlayer(serverPlayer, seat);
|
||||
}
|
||||
});
|
||||
if (!serverPlayer.isSecondaryUseActive()) {
|
||||
furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> {
|
||||
if (furniture.tryOccupySeat(seatPos)) {
|
||||
SeatEntity currentSeat = serverPlayer.seat();
|
||||
if (currentSeat != null) currentSeat.dismount(serverPlayer);
|
||||
furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
} else if (actionType == 0) {
|
||||
@@ -2429,6 +2435,7 @@ public class PacketConsumers {
|
||||
CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e);
|
||||
}
|
||||
};
|
||||
|
||||
public static final TriConsumer<NetWorkUser, NMSPacketEvent, Object> SET_EQUIPMENT_NMS = (user, event, packet) -> {
|
||||
try {
|
||||
int entityId = (int) NetworkReflections.method$ClientboundSetEquipmentPacket$getEntity.invoke(packet);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.network.handler;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.entity.data.ItemDisplayEntityData;
|
||||
import net.momirealms.craftengine.bukkit.entity.projectile.BukkitCustomProjectile;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes;
|
||||
import net.momirealms.craftengine.core.entity.projectile.CustomProjectile;
|
||||
import net.momirealms.craftengine.core.entity.projectile.ProjectileMeta;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
@@ -26,11 +26,11 @@ import java.util.UUID;
|
||||
|
||||
public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
private final int entityId;
|
||||
private final CustomProjectile projectile;
|
||||
private final BukkitCustomProjectile projectile;
|
||||
private final Object cachedPacket;
|
||||
private final List<Object> cachedData;
|
||||
|
||||
public ProjectilePacketHandler(CustomProjectile projectile, int entityId) {
|
||||
public ProjectilePacketHandler(BukkitCustomProjectile projectile, int entityId) {
|
||||
this.projectile = projectile;
|
||||
this.entityId = entityId;
|
||||
this.cachedData = createCustomProjectileEntityDataValues();
|
||||
@@ -111,7 +111,7 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
Optional<CustomItem<ItemStack>> customItem = BukkitItemManager.instance().getCustomItem(this.projectile.metadata().item());
|
||||
if (customItem.isEmpty()) return itemDisplayValues;
|
||||
ProjectileMeta meta = this.projectile.metadata();
|
||||
Item<?> displayedItem = customItem.get().buildItem(ItemBuildContext.EMPTY);
|
||||
Item<ItemStack> displayedItem = customItem.get().buildItem(ItemBuildContext.EMPTY);
|
||||
// 我们应当使用新的展示物品的组件覆盖原物品的组件,以完成附魔,附魔光效等组件的继承
|
||||
displayedItem = this.projectile.item().mergeCopy(displayedItem);
|
||||
ItemDisplayEntityData.InterpolationDelay.addEntityDataIfNotDefaultValue(-1, itemDisplayValues);
|
||||
@@ -124,8 +124,13 @@ public class ProjectilePacketHandler implements EntityPacketHandler {
|
||||
} else {
|
||||
ItemDisplayEntityData.InterpolationDuration.addEntityDataIfNotDefaultValue(1, itemDisplayValues);
|
||||
}
|
||||
ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(displayedItem.getLiteralObject(), itemDisplayValues);
|
||||
|
||||
Object literalItem = displayedItem.getLiteralObject();
|
||||
BukkitItemManager.instance().s2c(displayedItem.getItem(), null).ifPresentOrElse(
|
||||
it -> ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(FastNMS.INSTANCE.field$CraftItemStack$handle(it), itemDisplayValues),
|
||||
() -> ItemDisplayEntityData.DisplayedItem.addEntityDataIfNotDefaultValue(literalItem, itemDisplayValues));
|
||||
ItemDisplayEntityData.DisplayType.addEntityDataIfNotDefaultValue(meta.displayType().id(), itemDisplayValues);
|
||||
ItemDisplayEntityData.BillboardConstraints.addEntityDataIfNotDefaultValue(meta.billboard().id(), itemDisplayValues);
|
||||
return itemDisplayValues;
|
||||
}
|
||||
|
||||
|
||||
@@ -899,11 +899,11 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Field field$BLOCK_STATE_REGISTRY = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$Block, CoreReflections.clazz$IdMapper, 0)
|
||||
ReflectionUtils.getDeclaredField(clazz$Block, clazz$IdMapper, 0)
|
||||
);
|
||||
|
||||
public static final Method method$IdMapper$add = requireNonNull(
|
||||
ReflectionUtils.getMethod(CoreReflections.clazz$IdMapper, void.class, Object.class)
|
||||
ReflectionUtils.getMethod(clazz$IdMapper, void.class, Object.class)
|
||||
);
|
||||
|
||||
public static final Object instance$Block$BLOCK_STATE_REGISTRY;
|
||||
@@ -1253,6 +1253,10 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, float.class, 0)
|
||||
);
|
||||
|
||||
public static final Field field$BlockStateBase$useShapeForLightOcclusion = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, boolean.class, 0)
|
||||
);
|
||||
|
||||
public static final Field field$BlockStateBase$burnable = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, boolean.class, 2)
|
||||
);
|
||||
@@ -1261,10 +1265,20 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, boolean.class, 9)
|
||||
);
|
||||
|
||||
// 1.21.2以前用
|
||||
public static final Field field$BlockStateBase$isConditionallyFullOpaque = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, boolean.class, VersionHelper.isOrAbove1_21() ? 10 : 11)
|
||||
);
|
||||
|
||||
// 1.21.2+,其他版本在cache里
|
||||
public static final Field field$BlockStateBase$propagatesSkylightDown = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, boolean.class, 11)
|
||||
);
|
||||
|
||||
public static final Field field$BlockStateBase$Cache$propagatesSkylightDown = ReflectionUtils.getDeclaredField(
|
||||
clazz$BlockStateBase$Cache, boolean.class, 2
|
||||
);
|
||||
|
||||
public static final Field field$BlockStateBase$requiresCorrectToolForDrops = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockStateBase, boolean.class, 5)
|
||||
);
|
||||
@@ -1379,15 +1393,15 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$getShape = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getShape", "a"}, clazz$BlockState, clazz$BlockGetter, CoreReflections.clazz$BlockPos, clazz$CollisionContext)
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getShape", "a"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$CollisionContext)
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$getCollisionShape = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getCollisionShape", VersionHelper.isOrAbove1_20_3() ? "b" : "c"}, clazz$BlockState, clazz$BlockGetter, CoreReflections.clazz$BlockPos, clazz$CollisionContext)
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getCollisionShape", VersionHelper.isOrAbove1_20_3() ? "b" : "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$CollisionContext)
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$getBlockSupportShape = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getBlockSupportShape", "b_"}, clazz$BlockState, clazz$BlockGetter, CoreReflections.clazz$BlockPos)
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$VoxelShape, new String[]{"getBlockSupportShape", "b_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Field field$BlockBehaviour$properties = requireNonNull(
|
||||
@@ -1564,7 +1578,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$Entity$getOnPos = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$Entity, CoreReflections.clazz$BlockPos, float.class)
|
||||
ReflectionUtils.getDeclaredMethod(clazz$Entity, clazz$BlockPos, float.class)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$ItemStack = requireNonNull(
|
||||
@@ -1594,8 +1608,8 @@ public final class CoreReflections {
|
||||
|
||||
public static final Method method$BlockBehaviour$updateShape = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_2() ?
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$BlockState, clazz$BlockState, clazz$LevelReader, clazz$ScheduledTickAccess, CoreReflections.clazz$BlockPos, CoreReflections.clazz$Direction, CoreReflections.clazz$BlockPos, clazz$BlockState, clazz$RandomSource) :
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$BlockState, clazz$BlockState, CoreReflections.clazz$Direction, clazz$BlockState, clazz$LevelAccessor, CoreReflections.clazz$BlockPos, CoreReflections.clazz$BlockPos)
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$BlockState, clazz$BlockState, clazz$LevelReader, clazz$ScheduledTickAccess, clazz$BlockPos, clazz$Direction, clazz$BlockPos, clazz$BlockState, clazz$RandomSource) :
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, clazz$BlockState, clazz$BlockState, clazz$Direction, clazz$BlockState, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$Fallable = requireNonNull(
|
||||
@@ -1621,7 +1635,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$FallingBlockEntity$fall = requireNonNull(
|
||||
ReflectionUtils.getStaticMethod(clazz$FallingBlockEntity, clazz$FallingBlockEntity, clazz$Level, CoreReflections.clazz$BlockPos, clazz$BlockState)
|
||||
ReflectionUtils.getStaticMethod(clazz$FallingBlockEntity, clazz$FallingBlockEntity, clazz$Level, clazz$BlockPos, clazz$BlockState)
|
||||
);
|
||||
|
||||
public static final Method method$FallingBlockEntity$setHurtsEntities = requireNonNull(
|
||||
@@ -1649,11 +1663,11 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateBase$hasTag = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, boolean.class, CoreReflections.clazz$TagKey)
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, boolean.class, clazz$TagKey)
|
||||
);
|
||||
|
||||
public static final Method method$Level$removeBlock = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$Level, boolean.class, CoreReflections.clazz$BlockPos, boolean.class)
|
||||
ReflectionUtils.getMethod(clazz$Level, boolean.class, clazz$BlockPos, boolean.class)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$LeavesBlock = requireNonNull(
|
||||
@@ -1691,18 +1705,18 @@ public final class CoreReflections {
|
||||
|
||||
|
||||
public static final Method method$Block$updateFromNeighbourShapes = requireNonNull(
|
||||
ReflectionUtils.getStaticMethod(clazz$Block, clazz$BlockState, clazz$BlockState, clazz$LevelAccessor, CoreReflections.clazz$BlockPos)
|
||||
ReflectionUtils.getStaticMethod(clazz$Block, clazz$BlockState, clazz$BlockState, clazz$LevelAccessor, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateBase$updateNeighbourShapes = requireNonNull(
|
||||
ReflectionUtils.getMethod(
|
||||
// flags // depth
|
||||
clazz$BlockStateBase, void.class, clazz$LevelAccessor, CoreReflections.clazz$BlockPos, int.class, int.class
|
||||
clazz$BlockStateBase, void.class, clazz$LevelAccessor, clazz$BlockPos, int.class, int.class
|
||||
)
|
||||
);
|
||||
|
||||
public static final Method method$BlockState$getShape = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, clazz$VoxelShape, new String[]{"getShape", "a"}, clazz$BlockGetter, CoreReflections.clazz$BlockPos, clazz$CollisionContext)
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, clazz$VoxelShape, new String[]{"getShape", "a"}, clazz$BlockGetter, clazz$BlockPos, clazz$CollisionContext)
|
||||
);
|
||||
|
||||
public static final Method method$VoxelShape$isEmpty = requireNonNull(
|
||||
@@ -1714,7 +1728,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$LevelWriter$setBlock = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$LevelWriter, boolean.class, CoreReflections.clazz$BlockPos, clazz$BlockState, int.class)
|
||||
ReflectionUtils.getMethod(clazz$LevelWriter, boolean.class, clazz$BlockPos, clazz$BlockState, int.class)
|
||||
);
|
||||
|
||||
public static final Method method$CollisionContext$of = requireNonNull(
|
||||
@@ -1726,15 +1740,15 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateBase$canSurvive = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, boolean.class, clazz$LevelReader, CoreReflections.clazz$BlockPos)
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, boolean.class, clazz$LevelReader, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Method method$BlockStateBase$onPlace = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, void.class, clazz$Level, CoreReflections.clazz$BlockPos, clazz$BlockState, boolean.class)
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, void.class, clazz$Level, clazz$BlockPos, clazz$BlockState, boolean.class)
|
||||
);
|
||||
|
||||
public static final Method method$ItemStack$isTag = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$ItemStack, boolean.class, CoreReflections.clazz$TagKey)
|
||||
ReflectionUtils.getMethod(clazz$ItemStack, boolean.class, clazz$TagKey)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$FireBlock = requireNonNull(
|
||||
@@ -1854,7 +1868,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Field field$Inventory$items = requireNonNull(
|
||||
ReflectionUtils.getInstanceDeclaredField(clazz$Inventory, CoreReflections.clazz$NonNullList, 0)
|
||||
ReflectionUtils.getInstanceDeclaredField(clazz$Inventory, clazz$NonNullList, 0)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$Ingredient = requireNonNull(
|
||||
@@ -1893,7 +1907,7 @@ public final class CoreReflections {
|
||||
|
||||
// 1.20.1-1.20.2
|
||||
public static final Field field$1_20_1$ShapedRecipe$recipeItems=
|
||||
ReflectionUtils.getDeclaredField(clazz$ShapedRecipe, CoreReflections.clazz$NonNullList, 0);
|
||||
ReflectionUtils.getDeclaredField(clazz$ShapedRecipe, clazz$NonNullList, 0);
|
||||
|
||||
// 1.20.3+
|
||||
public static final Field field$1_20_3$ShapedRecipe$pattern=
|
||||
@@ -1901,7 +1915,7 @@ public final class CoreReflections {
|
||||
|
||||
// 1.20.3-1.21.1
|
||||
public static final Field field$ShapedRecipePattern$ingredients1_20_3 = Optional.ofNullable(clazz$ShapedRecipePattern)
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, CoreReflections.clazz$NonNullList, 0))
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, clazz$NonNullList, 0))
|
||||
.orElse(null);
|
||||
|
||||
// 1.21.2+
|
||||
@@ -1954,7 +1968,7 @@ public final class CoreReflections {
|
||||
|
||||
public static final Field field$ShapelessRecipe$ingredients =
|
||||
Optional.ofNullable(ReflectionUtils.getDeclaredField(clazz$ShapelessRecipe, List.class, 0))
|
||||
.orElse(ReflectionUtils.getDeclaredField(clazz$ShapelessRecipe, CoreReflections.clazz$NonNullList, 0));
|
||||
.orElse(ReflectionUtils.getDeclaredField(clazz$ShapelessRecipe, clazz$NonNullList, 0));
|
||||
|
||||
// require ResourceLocation for 1.20.1-1.21.1
|
||||
// require ResourceKey for 1.21.2+
|
||||
@@ -2082,7 +2096,7 @@ public final class CoreReflections {
|
||||
.orElse(null);
|
||||
|
||||
public static final Field field$AbstractFurnaceBlockEntity$items = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$AbstractFurnaceBlockEntity, CoreReflections.clazz$NonNullList, 0)
|
||||
ReflectionUtils.getDeclaredField(clazz$AbstractFurnaceBlockEntity, clazz$NonNullList, 0)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$SimpleContainer = requireNonNull(
|
||||
@@ -2093,15 +2107,15 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Field field$SimpleContainer$items = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$SimpleContainer, CoreReflections.clazz$NonNullList, 0)
|
||||
ReflectionUtils.getDeclaredField(clazz$SimpleContainer, clazz$NonNullList, 0)
|
||||
);
|
||||
|
||||
public static final Method method$LevelReader$getMaxLocalRawBrightness = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$LevelReader, int.class, CoreReflections.clazz$BlockPos)
|
||||
ReflectionUtils.getMethod(clazz$LevelReader, int.class, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Method method$ConfiguredFeature$place = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$ConfiguredFeature, boolean.class, clazz$WorldGenLevel, clazz$ChunkGenerator, clazz$RandomSource, CoreReflections.clazz$BlockPos)
|
||||
ReflectionUtils.getMethod(clazz$ConfiguredFeature, boolean.class, clazz$WorldGenLevel, clazz$ChunkGenerator, clazz$RandomSource, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$BonemealableBlock = requireNonNull(
|
||||
@@ -2113,12 +2127,12 @@ public final class CoreReflections {
|
||||
|
||||
public static final Method method$BonemealableBlock$isValidBonemealTarget = requireNonNull(
|
||||
VersionHelper.isOrAbove1_20_2() ?
|
||||
ReflectionUtils.getInstanceMethod(clazz$BonemealableBlock, boolean.class, clazz$LevelReader, CoreReflections.clazz$BlockPos, clazz$BlockState) :
|
||||
ReflectionUtils.getInstanceMethod(clazz$BonemealableBlock, boolean.class, clazz$LevelReader, CoreReflections.clazz$BlockPos, clazz$BlockState, boolean.class)
|
||||
ReflectionUtils.getInstanceMethod(clazz$BonemealableBlock, boolean.class, clazz$LevelReader, clazz$BlockPos, clazz$BlockState) :
|
||||
ReflectionUtils.getInstanceMethod(clazz$BonemealableBlock, boolean.class, clazz$LevelReader, clazz$BlockPos, clazz$BlockState, boolean.class)
|
||||
);
|
||||
|
||||
public static final Method method$BonemealableBlock$isBonemealSuccess = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BonemealableBlock, boolean.class, clazz$Level, clazz$RandomSource, CoreReflections.clazz$BlockPos, clazz$BlockState)
|
||||
ReflectionUtils.getMethod(clazz$BonemealableBlock, boolean.class, clazz$Level, clazz$RandomSource, clazz$BlockPos, clazz$BlockState)
|
||||
);
|
||||
|
||||
public static final Method method$PalettedContainer$getAndSet = Objects.requireNonNull(
|
||||
@@ -2168,11 +2182,11 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Constructor<?> constructor$JukeboxSong = Optional.ofNullable(clazz$JukeboxSong)
|
||||
.map(it -> ReflectionUtils.getConstructor(it, CoreReflections.clazz$Holder, clazz$Component, float.class, int.class))
|
||||
.map(it -> ReflectionUtils.getConstructor(it, clazz$Holder, clazz$Component, float.class, int.class))
|
||||
.orElse(null);
|
||||
|
||||
public static final Field field$JukeboxSong$soundEvent = Optional.ofNullable(clazz$JukeboxSong)
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, CoreReflections.clazz$Holder, 0))
|
||||
.map(it -> ReflectionUtils.getDeclaredField(it, clazz$Holder, 0))
|
||||
.orElse(null);
|
||||
|
||||
public static final Field field$JukeboxSong$description = Optional.ofNullable(clazz$JukeboxSong)
|
||||
@@ -2285,15 +2299,15 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$BlockHitResult$withPosition = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockHitResult, clazz$BlockHitResult, CoreReflections.clazz$BlockPos)
|
||||
ReflectionUtils.getMethod(clazz$BlockHitResult, clazz$BlockHitResult, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Field field$BlockHitResul$blockPos = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockHitResult, CoreReflections.clazz$BlockPos, 0)
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockHitResult, clazz$BlockPos, 0)
|
||||
);
|
||||
|
||||
public static final Field field$BlockHitResul$direction = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockHitResult, CoreReflections.clazz$Direction, 0)
|
||||
ReflectionUtils.getDeclaredField(clazz$BlockHitResult, clazz$Direction, 0)
|
||||
);
|
||||
|
||||
public static final Field field$BlockHitResul$miss = requireNonNull(
|
||||
@@ -2324,22 +2338,22 @@ public final class CoreReflections {
|
||||
|
||||
public static final Method method$SimpleWaterloggedBlock$canPlaceLiquid = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_5()
|
||||
? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$LivingEntity, clazz$BlockGetter, CoreReflections.clazz$BlockPos, clazz$BlockState, clazz$Fluid)
|
||||
? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$LivingEntity, clazz$BlockGetter, clazz$BlockPos, clazz$BlockState, clazz$Fluid)
|
||||
: VersionHelper.isOrAbove1_20_2()
|
||||
? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$Player, clazz$BlockGetter, CoreReflections.clazz$BlockPos, clazz$BlockState, clazz$Fluid)
|
||||
: ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$BlockGetter, CoreReflections.clazz$BlockPos, clazz$BlockState, clazz$Fluid)
|
||||
? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$Player, clazz$BlockGetter, clazz$BlockPos, clazz$BlockState, clazz$Fluid)
|
||||
: ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$BlockGetter, clazz$BlockPos, clazz$BlockState, clazz$Fluid)
|
||||
);
|
||||
|
||||
public static final Method method$SimpleWaterloggedBlock$placeLiquid = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$LevelAccessor, CoreReflections.clazz$BlockPos, clazz$BlockState, clazz$FluidState)
|
||||
ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState, clazz$FluidState)
|
||||
);
|
||||
|
||||
public static final Method method$SimpleWaterloggedBlock$pickupBlock = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_5()
|
||||
? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$LivingEntity, clazz$LevelAccessor, CoreReflections.clazz$BlockPos, clazz$BlockState)
|
||||
? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$LivingEntity, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState)
|
||||
: VersionHelper.isOrAbove1_20_2()
|
||||
? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$Player, clazz$LevelAccessor, CoreReflections.clazz$BlockPos, clazz$BlockState)
|
||||
: ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$LevelAccessor, CoreReflections.clazz$BlockPos, clazz$BlockState)
|
||||
? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$Player, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState)
|
||||
: ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState)
|
||||
);
|
||||
|
||||
public static final Method method$Fluid$getTickDelay = requireNonNull(
|
||||
@@ -2435,7 +2449,7 @@ public final class CoreReflections {
|
||||
}
|
||||
|
||||
public static final Method method$BlockStateBase$isFaceSturdy = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, boolean.class, clazz$BlockGetter, CoreReflections.clazz$BlockPos, CoreReflections.clazz$Direction, clazz$SupportType)
|
||||
ReflectionUtils.getMethod(clazz$BlockStateBase, boolean.class, clazz$BlockGetter, clazz$BlockPos, clazz$Direction, clazz$SupportType)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$BlockInWorld = requireNonNull(
|
||||
@@ -2467,7 +2481,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$BlockAndTintGetter$getRawBrightness = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BlockAndTintGetter, int.class, CoreReflections.clazz$BlockPos, int.class)
|
||||
ReflectionUtils.getMethod(clazz$BlockAndTintGetter, int.class, clazz$BlockPos, int.class)
|
||||
);
|
||||
|
||||
public static final Field field$Entity$boundingBox = requireNonNull(
|
||||
@@ -2553,7 +2567,7 @@ public final class CoreReflections {
|
||||
|
||||
// 1.20.5+
|
||||
public static final Constructor<?> constructor$AttributeInstance =
|
||||
ReflectionUtils.getConstructor(clazz$AttributeInstance, CoreReflections.clazz$Holder, Consumer.class);
|
||||
ReflectionUtils.getConstructor(clazz$AttributeInstance, clazz$Holder, Consumer.class);
|
||||
|
||||
public static final Method method$AttributeInstance$setBaseValue = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$AttributeInstance, void.class, double.class)
|
||||
@@ -2717,9 +2731,9 @@ public final class CoreReflections {
|
||||
|
||||
public static final Method method$BlockBehaviour$neighborChanged = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_2() ?
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, CoreReflections.clazz$BlockPos, clazz$Block, clazz$Orientation, boolean.class) :
|
||||
Optional.ofNullable(ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, CoreReflections.clazz$BlockPos, clazz$Block, CoreReflections.clazz$BlockPos, boolean.class))
|
||||
.orElse(ReflectionUtils.getMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, CoreReflections.clazz$BlockPos, clazz$Block, CoreReflections.clazz$BlockPos, boolean.class))
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$Orientation, boolean.class) :
|
||||
Optional.ofNullable(ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class))
|
||||
.orElse(ReflectionUtils.getMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Block, clazz$BlockPos, boolean.class))
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$InventoryMenu = requireNonNull(
|
||||
@@ -2771,7 +2785,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$ServerLevel$getNoiseBiome = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$ServerLevel, CoreReflections.clazz$Holder, int.class, int.class, int.class)
|
||||
ReflectionUtils.getMethod(clazz$ServerLevel, clazz$Holder, int.class, int.class, int.class)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$MinecraftServer = requireNonNull(
|
||||
@@ -2783,7 +2797,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Field field$MinecraftServer$registries = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(clazz$MinecraftServer, CoreReflections.clazz$LayeredRegistryAccess, 0)
|
||||
ReflectionUtils.getDeclaredField(clazz$MinecraftServer, clazz$LayeredRegistryAccess, 0)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$ServerConnectionListener = requireNonNull(
|
||||
@@ -2917,13 +2931,13 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$ServerPlayerGameMode$destroyBlock = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$ServerPlayerGameMode, boolean.class, CoreReflections.clazz$BlockPos)
|
||||
ReflectionUtils.getMethod(clazz$ServerPlayerGameMode, boolean.class, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Method method$ServerPlayer$getEffect = requireNonNull(
|
||||
!VersionHelper.isOrAbove1_20_5() ?
|
||||
ReflectionUtils.getMethod(clazz$ServerPlayer, clazz$MobEffectInstance, clazz$MobEffect) :
|
||||
ReflectionUtils.getMethod(clazz$ServerPlayer, clazz$MobEffectInstance, CoreReflections.clazz$Holder)
|
||||
ReflectionUtils.getMethod(clazz$ServerPlayer, clazz$MobEffectInstance, clazz$Holder)
|
||||
);
|
||||
|
||||
public static final Field field$ServerLevel$uuid = requireNonNull(
|
||||
@@ -2931,7 +2945,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$ServerLevel$checkEntityCollision = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$ServerLevel, boolean.class, clazz$BlockState, clazz$Entity, clazz$CollisionContext, CoreReflections.clazz$BlockPos, boolean.class)
|
||||
ReflectionUtils.getMethod(clazz$ServerLevel, boolean.class, clazz$BlockState, clazz$Entity, clazz$CollisionContext, clazz$BlockPos, boolean.class)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$ResourceManager = requireNonNull(
|
||||
@@ -3048,19 +3062,19 @@ public final class CoreReflections {
|
||||
|
||||
public static final Method method$ServerLevel$sendBlockUpdated = requireNonNull(
|
||||
ReflectionUtils.getMethod(
|
||||
clazz$ServerLevel, void.class, CoreReflections.clazz$BlockPos, clazz$BlockState, clazz$BlockState, int.class
|
||||
clazz$ServerLevel, void.class, clazz$BlockPos, clazz$BlockState, clazz$BlockState, int.class
|
||||
)
|
||||
);
|
||||
|
||||
public static final Method method$ServerLevel$levelEvent = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_5()
|
||||
? ReflectionUtils.getMethod(clazz$ServerLevel, void.class, clazz$Entity, int.class, CoreReflections.clazz$BlockPos, int.class)
|
||||
: ReflectionUtils.getMethod(clazz$ServerLevel, void.class, clazz$Player, int.class, CoreReflections.clazz$BlockPos, int.class)
|
||||
? ReflectionUtils.getMethod(clazz$ServerLevel, void.class, clazz$Entity, int.class, clazz$BlockPos, int.class)
|
||||
: ReflectionUtils.getMethod(clazz$ServerLevel, void.class, clazz$Player, int.class, clazz$BlockPos, int.class)
|
||||
);
|
||||
|
||||
public static final Method method$ServerGamePacketListenerImpl$tryPickItem =
|
||||
VersionHelper.isOrAbove1_21_5() ?
|
||||
ReflectionUtils.getDeclaredMethod(clazz$ServerGamePacketListenerImpl, void.class, clazz$ItemStack, CoreReflections.clazz$BlockPos, clazz$Entity, boolean.class) :
|
||||
ReflectionUtils.getDeclaredMethod(clazz$ServerGamePacketListenerImpl, void.class, clazz$ItemStack, clazz$BlockPos, clazz$Entity, boolean.class) :
|
||||
ReflectionUtils.getDeclaredMethod(clazz$ServerGamePacketListenerImpl, void.class, clazz$ItemStack);
|
||||
|
||||
public static final Method method$ServerPlayer$nextContainerCounter = requireNonNull(
|
||||
@@ -3203,15 +3217,45 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$BonemealableBlock$performBonemeal = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$BonemealableBlock, void.class, clazz$ServerLevel, clazz$RandomSource, CoreReflections.clazz$BlockPos, clazz$BlockState)
|
||||
ReflectionUtils.getMethod(clazz$BonemealableBlock, void.class, clazz$ServerLevel, clazz$RandomSource, clazz$BlockPos, clazz$BlockState)
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$tick = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"tick", "a"}, clazz$BlockState, clazz$ServerLevel, CoreReflections.clazz$BlockPos, clazz$RandomSource)
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"tick", "a"}, clazz$BlockState, clazz$ServerLevel, clazz$BlockPos, clazz$RandomSource)
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$randomTick = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"randomTick", "b"}, clazz$BlockState, clazz$ServerLevel, CoreReflections.clazz$BlockPos, clazz$RandomSource)
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"randomTick", "b"}, clazz$BlockState, clazz$ServerLevel, clazz$BlockPos, clazz$RandomSource)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$InsideBlockEffectApplier = BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.entity.InsideBlockEffectApplier",
|
||||
"world.entity.InsideBlockEffectApplier"
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$entityInside = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_5() ?
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"entityInside", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Entity, clazz$InsideBlockEffectApplier) :
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"entityInside", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Entity)
|
||||
);
|
||||
|
||||
// 1.21.5+
|
||||
public static final Method method$BlockBehaviour$affectNeighborsAfterRemoval = ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"affectNeighborsAfterRemoval", "a"}, clazz$BlockState, clazz$ServerLevel, clazz$BlockPos, boolean.class);
|
||||
|
||||
public static final Method method$BlockBehaviour$getSignal = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, int.class, new String[]{"getSignal", "a"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$Direction)
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$getDirectSignal = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, int.class, new String[]{"getDirectSignal", "b"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos, clazz$Direction)
|
||||
);
|
||||
|
||||
public static final Method method$BlockBehaviour$isSignalSource = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{
|
||||
"isSignalSource",
|
||||
!VersionHelper.isOrAbove1_20_5() ? "f_" : // 1.20.1-1.20.4
|
||||
!VersionHelper.isOrAbove1_21_2() ? "e_" /* 1.20.5-1.21.1 */ : "f_" // 1.21.2+
|
||||
}, clazz$BlockState)
|
||||
);
|
||||
|
||||
public static final Method method$FileToIdConverter$listMatchingResources = requireNonNull(
|
||||
@@ -3219,7 +3263,7 @@ public final class CoreReflections {
|
||||
);
|
||||
|
||||
public static final Method method$RegistryOps$create = requireNonNull(
|
||||
ReflectionUtils.getStaticMethod(clazz$RegistryOps, clazz$RegistryOps, DynamicOps.class, CoreReflections.clazz$HolderLookup$Provider)
|
||||
ReflectionUtils.getStaticMethod(clazz$RegistryOps, clazz$RegistryOps, DynamicOps.class, clazz$HolderLookup$Provider)
|
||||
);
|
||||
|
||||
public static final Method method$DefaultedRegistry$get = requireNonNull(
|
||||
@@ -3349,6 +3393,118 @@ public final class CoreReflections {
|
||||
}
|
||||
}
|
||||
|
||||
public static final Class<?> clazz$StairBlock = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.BlockStairs",
|
||||
"world.level.block.StairBlock"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$StairsShape = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.state.properties.BlockPropertyStairsShape",
|
||||
"world.level.block.state.properties.StairsShape"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Method method$StairsShape$values = requireNonNull(
|
||||
ReflectionUtils.getStaticMethod(clazz$StairsShape, clazz$StairsShape.arrayType())
|
||||
);
|
||||
|
||||
public static final Method method$StairsShape$ordinal = requireNonNull(
|
||||
ReflectionUtils.getMethod(
|
||||
clazz$StairsShape, new String[]{"ordinal"}
|
||||
)
|
||||
);
|
||||
|
||||
public static final Object instance$StairsShape$STRAIGHT;
|
||||
public static final Object instance$StairsShape$INNER_LEFT;
|
||||
public static final Object instance$StairsShape$INNER_RIGHT;
|
||||
public static final Object instance$StairsShape$OUTER_LEFT;
|
||||
public static final Object instance$StairsShape$OUTER_RIGHT;
|
||||
|
||||
static {
|
||||
try {
|
||||
Object[] values = (Object[]) method$StairsShape$values.invoke(null);
|
||||
instance$StairsShape$STRAIGHT = values[0];
|
||||
instance$StairsShape$INNER_LEFT = values[1];
|
||||
instance$StairsShape$INNER_RIGHT = values[2];
|
||||
instance$StairsShape$OUTER_LEFT = values[3];
|
||||
instance$StairsShape$OUTER_RIGHT = values[4];
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Class<?> clazz$EnumProperty = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.state.properties.BlockStateEnum",
|
||||
"world.level.block.state.properties.EnumProperty"
|
||||
)
|
||||
);
|
||||
|
||||
// 1.20~1.21.1
|
||||
public static final Class<?> clazz$DirectionProperty =
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.state.properties.BlockStateDirection",
|
||||
"world.level.block.state.properties.DirectionProperty"
|
||||
);
|
||||
|
||||
public static final Field field$StairBlock$FACING = requireNonNull(
|
||||
VersionHelper.isOrAbove1_21_2()
|
||||
? ReflectionUtils.getDeclaredField(clazz$StairBlock, clazz$EnumProperty, 0)
|
||||
: ReflectionUtils.getDeclaredField(clazz$StairBlock, clazz$DirectionProperty, 0)
|
||||
);
|
||||
|
||||
public static final Field field$StairBlock$HALF = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(
|
||||
clazz$StairBlock, clazz$EnumProperty, VersionHelper.isOrAbove1_21_2() ? 1 : 0
|
||||
)
|
||||
);
|
||||
|
||||
public static final Field field$StairBlock$SHAPE = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(
|
||||
clazz$StairBlock, clazz$EnumProperty, VersionHelper.isOrAbove1_21_2() ? 2 : 1
|
||||
)
|
||||
);
|
||||
|
||||
public static final Object instance$StairBlock$FACING;
|
||||
public static final Object instance$StairBlock$HALF;
|
||||
public static final Object instance$StairBlock$SHAPE;
|
||||
|
||||
static {
|
||||
try {
|
||||
instance$StairBlock$FACING = requireNonNull(field$StairBlock$FACING.get(null));
|
||||
instance$StairBlock$HALF = requireNonNull(field$StairBlock$HALF.get(null));
|
||||
instance$StairBlock$SHAPE = requireNonNull(field$StairBlock$SHAPE.get(null));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Class<?> clazz$BasePressurePlateBlock = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.BlockPressurePlateAbstract",
|
||||
"world.level.block.BasePressurePlateBlock"
|
||||
)
|
||||
);
|
||||
|
||||
public static final Field field$BasePressurePlateBlock$TOUCH_AABB = requireNonNull(
|
||||
ReflectionUtils.getDeclaredField(
|
||||
clazz$BasePressurePlateBlock, clazz$AABB, 0
|
||||
)
|
||||
);
|
||||
|
||||
public static final Object instance$BasePressurePlateBlock$TOUCH_AABB;
|
||||
|
||||
static {
|
||||
try {
|
||||
instance$BasePressurePlateBlock$TOUCH_AABB = requireNonNull(field$BasePressurePlateBlock$TOUCH_AABB.get(null));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Method method$Entity$setInvisible = requireNonNull(
|
||||
ReflectionUtils.getMethod(
|
||||
clazz$Entity, new String[]{"j", "setInvisible"}, boolean.class
|
||||
|
||||
@@ -25,6 +25,10 @@ public final class MEntityTypes {
|
||||
public static final int OAK_BOAT$registryId;
|
||||
public static final Object TRIDENT;
|
||||
public static final int TRIDENT$registryId;
|
||||
public static final Object ARROW;
|
||||
public static final int ARROW$registryId;
|
||||
public static final Object SPECTRAL_ARROW;
|
||||
public static final int SPECTRAL_ARROW$registryId;
|
||||
public static final Object SNOWBALL;
|
||||
public static final int SNOWBALL$registryId;
|
||||
public static final Object FIREBALL;
|
||||
@@ -116,6 +120,10 @@ public final class MEntityTypes {
|
||||
HAPPY_GHAST$registryId = getRegistryId(HAPPY_GHAST);
|
||||
PLAYER = getById("player");
|
||||
PLAYER$registryId = getRegistryId(PLAYER);
|
||||
ARROW = getById("arrow");
|
||||
ARROW$registryId = getRegistryId(ARROW);
|
||||
SPECTRAL_ARROW = getById("spectral_arrow");
|
||||
SPECTRAL_ARROW$registryId = getRegistryId(SPECTRAL_ARROW);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ReflectionInitException("Failed to init EntityTypes", e);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import net.momirealms.sparrow.nbt.codec.NBTOps;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MRegistryOps {
|
||||
public final class MRegistryOps {
|
||||
public static final DynamicOps<Object> NBT;
|
||||
public static final DynamicOps<Tag> SPARROW_NBT;
|
||||
public static final DynamicOps<Object> JAVA;
|
||||
@@ -42,7 +42,7 @@ public class MRegistryOps {
|
||||
// 1.20.1-1.20.4
|
||||
JAVA = (DynamicOps<Object>) CoreReflections.method$RegistryOps$create.invoke(null, LegacyJavaOps.INSTANCE, FastNMS.INSTANCE.registryAccess());
|
||||
} else {
|
||||
JAVA = null;
|
||||
throw new ReflectionInitException("Could not find JavaOps");
|
||||
}
|
||||
NBT = (DynamicOps<Object>) CoreReflections.method$RegistryOps$create.invoke(null, ReflectionUtils.getDeclaredField(clazz$NbtOps, clazz$NbtOps, 0).get(null), FastNMS.INSTANCE.registryAccess());
|
||||
JSON = (DynamicOps<JsonElement>) CoreReflections.method$RegistryOps$create.invoke(null, JsonOps.INSTANCE, FastNMS.INSTANCE.registryAccess());
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class MTagKeys {
|
||||
private MTagKeys() {}
|
||||
|
||||
public static final Object Item$WOOL = create(MRegistries.ITEM, "wool");
|
||||
public static final Object Block$WALLS = create(MRegistries.BLOCK, "walls");
|
||||
|
||||
private static Object create(Object registry, String location) {
|
||||
Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location);
|
||||
Object tagKey = FastNMS.INSTANCE.method$TagKey$create(registry, resourceLocation);
|
||||
return Objects.requireNonNull(tagKey);
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,10 @@ public class BlockStateUtils {
|
||||
CoreReflections.field$BlockStateBase$burnable.set(state, burnable);
|
||||
}
|
||||
|
||||
public static void setUseShapeForLightOcclusion(Object state, boolean useShapeForLightOcclusion) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.set(state, useShapeForLightOcclusion);
|
||||
}
|
||||
|
||||
public static void setPushReaction(Object state, PushReaction reaction) throws ReflectiveOperationException {
|
||||
Object pushReaction = ((Object[]) CoreReflections.method$PushReaction$values.invoke(null))[reaction.ordinal()];
|
||||
CoreReflections.field$BlockStateBase$pushReaction.set(state, pushReaction);
|
||||
@@ -206,10 +210,6 @@ public class BlockStateUtils {
|
||||
CoreReflections.field$BlockStateBase$isRandomlyTicking.set(state, randomlyTicking);
|
||||
}
|
||||
|
||||
public static void setPropagatesSkylightDown(Object state, boolean propagatesSkylightDown) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(state, propagatesSkylightDown);
|
||||
}
|
||||
|
||||
public static void setReplaceable(Object state, boolean replaceable) throws ReflectiveOperationException {
|
||||
CoreReflections.field$BlockStateBase$replaceable.set(state, replaceable);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@ public class LocationUtils {
|
||||
);
|
||||
}
|
||||
|
||||
public static Vec3d toVec3d(BlockPos pos) {
|
||||
return new Vec3d(pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
public static double getDistance(Location location1, Location location2) {
|
||||
return Math.sqrt(Math.pow(location2.getX() - location1.getX(), 2) +
|
||||
Math.pow(location2.getY() - location1.getY(), 2) +
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.core.block.state.properties.StairsShape;
|
||||
|
||||
public class StairsShapeUtils {
|
||||
private StairsShapeUtils() {}
|
||||
|
||||
public static StairsShape fromNMSStairsShape(Object shape) {
|
||||
try {
|
||||
int index = (int) CoreReflections.method$StairsShape$ordinal.invoke(shape);
|
||||
return StairsShape.values()[index];
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Object toNMSStairsShape(StairsShape shape) {
|
||||
return switch (shape) {
|
||||
case STRAIGHT -> CoreReflections.instance$StairsShape$STRAIGHT;
|
||||
case INNER_LEFT -> CoreReflections.instance$StairsShape$INNER_LEFT;
|
||||
case INNER_RIGHT -> CoreReflections.instance$StairsShape$INNER_RIGHT;
|
||||
case OUTER_LEFT -> CoreReflections.instance$StairsShape$OUTER_LEFT;
|
||||
case OUTER_RIGHT -> CoreReflections.instance$StairsShape$OUTER_RIGHT;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,26 +2,17 @@ package net.momirealms.craftengine.bukkit.world;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.core.block.CustomBlock;
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.item.CustomItem;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.world.BlockInWorld;
|
||||
import net.momirealms.craftengine.core.world.World;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class BukkitBlockInWorld implements BlockInWorld {
|
||||
private final Block block;
|
||||
@@ -30,25 +21,11 @@ public class BukkitBlockInWorld implements BlockInWorld {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean canBeReplaced(BlockPlaceContext context) {
|
||||
ImmutableBlockState customState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(this.block.getBlockData()));
|
||||
if (customState != null && !customState.isEmpty()) {
|
||||
Key clickedBlockId = customState.owner().value().id();
|
||||
Item<ItemStack> item = (Item<ItemStack>) context.getPlayer().getItemInHand(context.getHand());
|
||||
Optional<CustomItem<ItemStack>> customItem = BukkitItemManager.instance().getCustomItem(item.id());
|
||||
if (customItem.isPresent()) {
|
||||
CustomItem<ItemStack> custom = customItem.get();
|
||||
for (ItemBehavior behavior : custom.behaviors()) {
|
||||
if (behavior instanceof BlockItemBehavior blockItemBehavior) {
|
||||
Key blockId = blockItemBehavior.blockId();
|
||||
if (blockId.equals(clickedBlockId)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return customState.behavior().canBeReplaced(context, customState);
|
||||
}
|
||||
return this.block.isReplaceable();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user