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

范围音量

This commit is contained in:
XiaoMoMi
2025-06-20 01:25:07 +08:00
parent d632c4cd10
commit 2332f23f25
11 changed files with 93 additions and 30 deletions

View File

@@ -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;

View File

@@ -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)) {

View File

@@ -329,8 +329,8 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
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.FIXED_1)).orElse(null);
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1)).orElse(null);
}
return new DoorBlockBehavior(block, half, facing, hinge, powered, open, canOpenWithHand, canOpenByWindCharge, openSound, closeSound);
}

View File

@@ -18,6 +18,7 @@ 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;
@@ -74,8 +75,8 @@ public class StackableBlockBehavior extends BukkitBlockBehavior {
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);
}
FastNMS.INSTANCE.method$ItemStack$consume(item.getLiteralObject(), 1, player.serverPlayer());
player.swingHand(hand);
@@ -90,7 +91,7 @@ public class StackableBlockBehavior extends BukkitBlockBehavior {
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();

View File

@@ -247,8 +247,8 @@ public class TrapDoorBlockBehavior extends BukkitBlockBehavior {
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.FIXED_1)).orElse(null);
closeSound = Optional.ofNullable(sounds.get("close")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1)).orElse(null);
}
return new TrapDoorBlockBehavior(block, half, facing, powered, open, canOpenWithHand, canOpenByWindCharge, openSound, closeSound);
}

View File

@@ -84,7 +84,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());
}

View File

@@ -13,7 +13,7 @@ public class BlockSounds {
Hit 0.5 0.5
Break 1 0.8
*/
public static final SoundData EMPTY_SOUND = new SoundData(Key.of("minecraft:intentionally_empty"), 1, 1);
public static final SoundData EMPTY_SOUND = new SoundData(Key.of("minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1);
public static final BlockSounds EMPTY = new BlockSounds(EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND);
private final SoundData breakSound;
@@ -37,13 +37,13 @@ public class BlockSounds {
public static BlockSounds fromMap(Map<String, Object> map) {
if (map == null) return EMPTY;
return new BlockSounds(
SoundData.create(map.getOrDefault("break", "minecraft:intentionally_empty"), 1f, 0.8f),
SoundData.create(map.getOrDefault("step", "minecraft:intentionally_empty"), 0.15f, 1f),
SoundData.create(map.getOrDefault("place", "minecraft:intentionally_empty"), 1f, 0.8f),
SoundData.create(map.getOrDefault("hit", "minecraft:intentionally_empty"), 0.5f, 0.5f),
SoundData.create(map.getOrDefault("fall", "minecraft:intentionally_empty"), 0.5f, 0.75f),
SoundData.create(map.getOrDefault("land", "minecraft:intentionally_empty"), 0.3f, 1f),
SoundData.create(map.getOrDefault("destroy", "minecraft:intentionally_empty"), 1f, 1f)
SoundData.create(map.getOrDefault("break", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8),
SoundData.create(map.getOrDefault("step", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_15, SoundData.SoundValue.FIXED_1),
SoundData.create(map.getOrDefault("place", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8),
SoundData.create(map.getOrDefault("hit", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.FIXED_0_5),
SoundData.create(map.getOrDefault("fall", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.FIXED_0_75),
SoundData.create(map.getOrDefault("land", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_3, SoundData.SoundValue.FIXED_1),
SoundData.create(map.getOrDefault("destroy", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1)
);
}

View File

@@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.util.Key;
import java.util.Map;
public class FurnitureSounds {
public static final SoundData EMPTY_SOUND = new SoundData(Key.of("minecraft:intentionally_empty"), 1, 1);
public static final SoundData EMPTY_SOUND = new SoundData(Key.of("minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1);
public static final FurnitureSounds EMPTY = new FurnitureSounds(EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND);
private final SoundData breakSound;
@@ -22,9 +22,9 @@ public class FurnitureSounds {
public static FurnitureSounds fromMap(Map<String, Object> map) {
if (map == null) return EMPTY;
return new FurnitureSounds(
SoundData.create(map.getOrDefault("break", "minecraft:intentionally_empty"), 1f, 0.8f),
SoundData.create(map.getOrDefault("place", "minecraft:intentionally_empty"), 1f, 0.8f),
SoundData.create(map.getOrDefault("rotate", "minecraft:intentionally_empty"), 1f, 0.8f)
SoundData.create(map.getOrDefault("break", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8),
SoundData.create(map.getOrDefault("place", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8),
SoundData.create(map.getOrDefault("rotate", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8)
);
}

View File

@@ -332,7 +332,7 @@ public class ItemSettings {
}));
registerFactory("helmet", (value -> {
Map<String, Object> args = MiscUtils.castToMap(value, false);
return settings -> settings.helmet(new Helmet(SoundData.create(args.getOrDefault("equip-sound", "minecraft:intentionally_empty"), 1f, 1f)));
return settings -> settings.helmet(new Helmet(SoundData.create(args.getOrDefault("equip-sound", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1)));
}));
registerFactory("compost-probability", (value -> {
float chance = ResourceConfigUtils.getAsFloat(value, "compost-probability");

View File

@@ -2,24 +2,86 @@ package net.momirealms.craftengine.core.sound;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.RandomUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
public record SoundData(Key id, float volume, float pitch) {
public record SoundData(Key id, SoundValue volume, SoundValue pitch) {
// todo 支持范围音量音调
public static SoundData create(Object obj, float volume, float pitch) {
public static SoundData create(Object obj, SoundValue volume, SoundValue pitch) {
if (obj instanceof String key) {
return new SoundData(Key.of(key), volume, pitch);
} else if (obj instanceof Map<?,?> map) {
Map<String, Object> data = MiscUtils.castToMap(map, false);
Key id = Key.of((String) data.get("id"));
float volumeFloat = ResourceConfigUtils.getAsFloat(data.getOrDefault("volume", volume), "volume");
float pitchFloat = ResourceConfigUtils.getAsFloat(data.getOrDefault("pitch", pitch), "pitch");
return new SoundData(id, volumeFloat, pitchFloat);
SoundValue volumeValue = Optional.ofNullable(SoundValue.of(map.get("volume"))).orElse(volume);
SoundValue pitchValue = Optional.ofNullable(SoundValue.of(map.get("pitch"))).orElse(volume);
return new SoundData(id, volumeValue, pitchValue);
} else {
throw new IllegalArgumentException("Illegal object type for sound data: " + obj.getClass());
}
}
public interface SoundValue extends Supplier<Float> {
Map<Float, SoundValue> FIXED = new HashMap<>();
SoundValue FIXED_1 = new Fixed(1f);
SoundValue FIXED_0_8 = new Fixed(0.8f);
SoundValue FIXED_0_75 = new Fixed(0.75f);
SoundValue FIXED_0_15 = new Fixed(0.15f);
SoundValue FIXED_0_5 = new Fixed(0.5f);
SoundValue FIXED_0_3 = new Fixed(0.3f);
static SoundValue of(Object obj) {
if (obj instanceof Number number) {
return SoundValue.fixed(number.floatValue());
} else {
String volumeString = obj.toString();
if (volumeString.contains("~")) {
String[] split = volumeString.split("~");
return SoundValue.ranged(Float.parseFloat(split[0]), Float.parseFloat(split[1]));
}
}
return null;
}
static SoundValue fixed(float value) {
return FIXED.computeIfAbsent(value, v -> new Fixed(value));
}
static SoundValue ranged(float min, float max) {
return new Ranged(min, max);
}
class Fixed implements SoundValue {
private final float value;
public Fixed(float value) {
this.value = value;
}
@Override
public Float get() {
return this.value;
}
}
class Ranged implements SoundValue {
private final float min;
private final float max;
public Ranged(float min, float max) {
this.min = min;
this.max = max;
}
@Override
public Float get() {
return RandomUtils.generateRandomFloat(this.min, this.max);
}
}
}
}

View File

@@ -44,7 +44,7 @@ public interface World {
void playBlockSound(Position location, Key sound, float volume, float pitch);
default void playBlockSound(Position location, SoundData data) {
playBlockSound(location, data.id(), data.volume(), data.pitch());
playBlockSound(location, data.id(), data.volume().get(), data.pitch().get());
}
void levelEvent(int id, BlockPos pos, int data);