9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

初步打火石音效补全

This commit is contained in:
XiaoMoMi
2025-06-12 02:09:06 +08:00
parent 2187362984
commit a56d94a803
10 changed files with 167 additions and 4 deletions

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item;
import com.saicone.rtag.item.ItemTagStream;
import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.FlintAndSteelItemBehavior;
import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior;
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
import net.momirealms.craftengine.bukkit.item.listener.ArmorEventListener;
@@ -43,6 +44,7 @@ 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);
}
private static BukkitItemManager instance;

View File

@@ -10,6 +10,7 @@ public class BukkitItemBehaviors extends ItemBehaviors {
public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item");
public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item");
public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item");
public static final Key FLINT_AND_STEEL_ITEM = Key.from("craftengine:flint_and_steel_item");
public static void init() {
register(EMPTY, EmptyItemBehavior.FACTORY);
@@ -18,5 +19,6 @@ public class BukkitItemBehaviors extends ItemBehaviors {
register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY);
register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY);
register(BUCKET_ITEM, BucketItemBehavior.FACTORY);
register(FLINT_AND_STEEL_ITEM, FlintAndSteelItemBehavior.FACTORY);
}
}

View File

@@ -0,0 +1,120 @@
package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
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.BukkitBlockInWorld;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.entity.player.InteractionResult;
import net.momirealms.craftengine.core.item.Item;
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.sound.SoundSource;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.RandomUtils;
import net.momirealms.craftengine.core.world.BlockPos;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.nio.file.Path;
import java.util.Map;
public class FlintAndSteelItemBehavior extends ItemBehavior {
public static final FlintAndSteelItemBehavior INSTANCE = new FlintAndSteelItemBehavior();
public static final Factory FACTORY = new Factory();
private static final Key FLINT_SOUND = Key.of("item.flintandsteel.use");
@SuppressWarnings("unchecked")
@Override
public InteractionResult useOnBlock(UseOnContext context) {
BlockPos clickedPos = context.getClickedPos();
BukkitBlockInWorld clicked = (BukkitBlockInWorld) context.getLevel().getBlockAt(clickedPos);
Block block = clicked.block();
BlockPos firePos = clickedPos.relative(context.getClickedFace());
Direction direction = context.getHorizontalDirection();
// 最基础的判断能不能着火,不能着火都是扯蛋
try {
if (!(boolean) CoreReflections.method$BaseFireBlock$canBePlacedAt.invoke(null, context.getLevel().serverWorld(), LocationUtils.toBlockPos(firePos), DirectionUtils.toNMSDirection(direction))) {
return InteractionResult.PASS;
}
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to run BaseFireBlock$canBePlacedAt", e);
return InteractionResult.PASS;
}
net.momirealms.craftengine.core.entity.player.Player player = context.getPlayer();
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData()));
if (state == null || state.isEmpty()) {
return InteractionResult.PASS;
} else {
// 玩家交互目标是自定义方块
if (context.getClickedFace() == Direction.UP) {
// 客户端层面必须可交互
if (!InteractUtils.isInteractable((Player) player.platformPlayer(), BlockStateUtils.fromBlockData(state.vanillaBlockState().handle()), context.getHitResult(), (Item<ItemStack>) context.getItem())) {
return InteractionResult.PASS;
}
// 且没有shift
if (!player.isSecondaryUseActive()) {
player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
}
} else {
BlockData vanillaBlockState = BlockStateUtils.fromBlockData(state.vanillaBlockState().handle());
// 原版状态可燃烧,则跳过
if (BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(vanillaBlockState))) {
return InteractionResult.PASS;
}
// 客户端一定觉得这个东西不可燃烧
BlockPos belowFirePos = firePos.relative(Direction.DOWN);
BukkitBlockInWorld belowFireBlock = (BukkitBlockInWorld) context.getLevel().getBlockAt(belowFirePos);
boolean belowCanBurn;
try {
Block belowBlock = belowFireBlock.block();
belowCanBurn = BlockStateUtils.isBurnable(BlockStateUtils.blockDataToBlockState(belowBlock.getBlockData())) ||
(boolean) CoreReflections.method$BlockStateBase$isFaceSturdy.invoke(
BlockStateUtils.blockDataToBlockState(belowFireBlock.block().getBlockData()), context.getLevel().serverWorld(), LocationUtils.toBlockPos(belowFirePos), CoreReflections.instance$Direction$UP, CoreReflections.instance$SupportType$FULL);
} catch (ReflectiveOperationException e) {
CraftEngine.instance().logger().warn("Failed to call method$BlockStateBase$isFaceSturdy", e);
return InteractionResult.PASS;
}
// 客户端觉得这玩意可交互,就会忽略声音
if (InteractUtils.isInteractable((Player) player.platformPlayer(), vanillaBlockState, context.getHitResult(), (Item<ItemStack>) context.getItem())) {
// 如果按住了shift则不会挥手补发
if (player.isSecondaryUseActive()) {
// 如果底部不能燃烧,则燃烧点位为侧面,需要补发
if (!belowCanBurn) {
player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
player.swingHand(context.getHand());
}
} else {
player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
}
} else {
if (!belowCanBurn) {
player.playSound(FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f));
player.swingHand(context.getHand());
}
}
}
}
return InteractionResult.PASS;
}
public static class Factory implements ItemBehaviorFactory {
@Override
public ItemBehavior create(Pack pack, Path path, Key id, Map<String, Object> arguments) {
return INSTANCE;
}
}
}

View File

@@ -33,6 +33,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;

View File

@@ -5,6 +5,7 @@ import com.google.gson.JsonElement;
import com.mojang.serialization.DynamicOps;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
import net.momirealms.craftengine.bukkit.util.BukkitReflectionUtils;
import net.momirealms.craftengine.core.util.ReflectionUtils;
@@ -3296,4 +3297,19 @@ public final class CoreReflections {
throw new ReflectionInitException("Failed to initialize reflection", e);
}
}
public static final Class<?> clazz$BaseFireBlock = requireNonNull(
BukkitReflectionUtils.findReobfOrMojmapClass(
"world.level.block.BlockFireAbstract",
"world.level.block.BaseFireBlock"
)
);
public static final Method method$BaseFireBlock$canBePlacedAt = requireNonNull(
ReflectionUtils.getStaticMethod(clazz$BaseFireBlock, boolean.class, clazz$Level, clazz$BlockPos, clazz$Direction)
);
public static final Field field$FireBlock$igniteOdds = requireNonNull(
ReflectionUtils.getDeclaredField(clazz$FireBlock, Object2IntMap.class, 0)
);
}

View File

@@ -30,6 +30,7 @@ import net.momirealms.craftengine.core.plugin.context.CooldownData;
import net.momirealms.craftengine.core.plugin.network.ConnectionState;
import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler;
import net.momirealms.craftengine.core.plugin.network.ProtocolVersion;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.Direction;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.VersionHelper;
@@ -283,8 +284,8 @@ public class BukkitServerPlayer extends Player {
}
@Override
public void playSound(Key sound, float volume, float pitch) {
platformPlayer().playSound(platformPlayer(), sound.toString(), SoundCategory.MASTER, volume, pitch);
public void playSound(Key sound, SoundSource source, float volume, float pitch) {
platformPlayer().playSound(platformPlayer(), sound.toString(), SoundUtils.toBukkit(source), volume, pitch);
}
@Override

View File

@@ -2,8 +2,10 @@ package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException;
import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections;
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.MBuiltInRegistries;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections;
import net.momirealms.craftengine.core.block.*;
@@ -22,18 +24,26 @@ import org.jetbrains.annotations.Nullable;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class BlockStateUtils {
public static final IdentityHashMap<Object, Object> CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>();
private static int vanillaStateSize;
private static boolean hasInit;
public static Map<Object, Integer> IGNITE_ODDS;
@SuppressWarnings("unchecked")
public static void init(int size) {
if (hasInit) {
throw new IllegalStateException("BlockStateUtils has already been initialized");
}
vanillaStateSize = size;
try {
IGNITE_ODDS = (Map<Object, Integer>) CoreReflections.field$FireBlock$igniteOdds.get(MBlocks.FIRE);
} catch (ReflectiveOperationException e) {
throw new ReflectionInitException("Failed to initialize instance$FireBlock$igniteOdds", e);
}
hasInit = true;
}
@@ -248,4 +258,9 @@ public class BlockStateUtils {
public static int vanillaStateSize() {
return vanillaStateSize;
}
public static boolean isBurnable(Object state) {
Object blockOwner = getBlockOwner(state);
return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0;
}
}

View File

@@ -167,7 +167,7 @@ items#misc:
template: "default:loot_table/self"
settings:
template:
- default:sound/sand
- default:sound/stone
- default:pickaxe_power/level_1
- default:settings/solid_1x1x1
overrides:

View File

@@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.entity.AbstractEntity;
import net.momirealms.craftengine.core.item.Item;
import net.momirealms.craftengine.core.plugin.context.CooldownData;
import net.momirealms.craftengine.core.plugin.network.NetWorkUser;
import net.momirealms.craftengine.core.sound.SoundSource;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.world.BlockPos;
import org.jetbrains.annotations.Nullable;
@@ -81,7 +82,11 @@ public abstract class Player extends AbstractEntity implements NetWorkUser {
playSound(sound, 1f, 1f);
}
public abstract void playSound(Key sound, float volume, float pitch);
public void playSound(Key sound, float volume, float pitch) {
playSound(sound, SoundSource.MASTER, volume, pitch);
}
public abstract void playSound(Key sound, SoundSource source, float volume, float pitch);
public abstract void giveItem(Item<?> item);

View File

@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.util.Key;
public class ItemKeys {
public static final Key AIR = Key.of("minecraft:air");
public static final Key FLINT_AND_STEEL = Key.of("minecraft:flint_and_steel");
public static final Key STONE = Key.of("minecraft:stone");
public static final Key TRIDENT = Key.of("minecraft:trident");
public static final Key SHIELD = Key.of("minecraft:shield");