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

重构声音part 1

This commit is contained in:
XiaoMoMi
2025-09-28 18:59:14 +08:00
parent 7300f0e278
commit 2aa75f7178
6 changed files with 152 additions and 122 deletions

View File

@@ -73,18 +73,14 @@ public final class BlockEventListener implements Listener {
// send sound if the placed block's sounds are removed
if (Config.enableSoundSystem()) {
Block block = event.getBlock();
Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData());
if (blockState != MBlocks.AIR$defaultState) {
Object ownerBlock = BlockStateUtils.getBlockOwner(blockState);
if (this.manager.isBlockSoundRemoved(ownerBlock)) {
Object blockState = BlockStateUtils.getBlockState(block);
if (blockState != MBlocks.AIR$defaultState && BlockStateUtils.isVanillaBlock(blockState)) {
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object soundEvent = FastNMS.INSTANCE.field$SoundType$placeSound(soundType);
Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);
if (this.manager.isPlaceSoundMissing(soundId)) {
if (player.getInventory().getItemInMainHand().getType() != Material.DEBUG_STICK) {
try {
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock);
Object placeSound = CoreReflections.field$SoundType$placeSound.get(soundType);
player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(placeSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get sound type", e);
}
player.playSound(block.getLocation().add(0.5, 0.5, 0.5), soundId.toString(), SoundCategory.BLOCKS, 1f, 0.8f);
}
return;
}
@@ -92,23 +88,19 @@ public final class BlockEventListener implements Listener {
}
// resend sound if the clicked block is interactable on client side
if (serverPlayer.shouldResendSound()) {
try {
Block block = event.getBlock();
Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData());
Object ownerBlock = BlockStateUtils.getBlockOwner(blockState);
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock);
Object placeSound = CoreReflections.field$SoundType$placeSound.get(soundType);
player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(placeSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get sound type", e);
}
Block block = event.getBlock();
Object blockState = BlockStateUtils.getBlockState(block);
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object soundEvent = FastNMS.INSTANCE.field$SoundType$placeSound(soundType);
Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);
player.playSound(block.getLocation().add(0.5, 0.5, 0.5), soundId.toString(), SoundCategory.BLOCKS, 1f, 0.8f);
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onPlayerBreak(BlockBreakEvent event) {
org.bukkit.block.Block block = event.getBlock();
Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData());
Object blockState = BlockStateUtils.getBlockState(block);
int stateId = BlockStateUtils.blockStateToId(blockState);
Player player = event.getPlayer();
Location location = block.getLocation();
@@ -194,15 +186,11 @@ public final class BlockEventListener implements Listener {
}
// sound system
if (Config.enableSoundSystem()) {
Object ownerBlock = BlockStateUtils.getBlockOwner(blockState);
if (this.manager.isBlockSoundRemoved(ownerBlock)) {
try {
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock);
Object breakSound = CoreReflections.field$SoundType$breakSound.get(soundType);
player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get sound type", e);
}
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object soundEvent = FastNMS.INSTANCE.field$SoundType$breakSound(soundType);
Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);
if (this.manager.isBreakSoundMissing(soundId)) {
player.playSound(block.getLocation().add(0.5, 0.5, 0.5), soundId.toString(), SoundCategory.BLOCKS, 1f, 0.8f);
}
}
}
@@ -259,15 +247,11 @@ public final class BlockEventListener implements Listener {
}
player.playSound(location, state.settings().sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.settings().sounds().stepSound().volume().get(), state.settings().sounds().stepSound().pitch().get());
} else if (Config.enableSoundSystem()) {
Object ownerBlock = BlockStateUtils.getBlockOwner(blockState);
if (this.manager.isBlockSoundRemoved(ownerBlock)) {
try {
Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock);
Object stepSound = CoreReflections.field$SoundType$stepSound.get(soundType);
player.playSound(player.getLocation(), FastNMS.INSTANCE.field$SoundEvent$location(stepSound).toString(), SoundCategory.BLOCKS, 0.15f, 1f);
} catch (ReflectiveOperationException e) {
this.plugin.logger().warn("Failed to get sound type", e);
}
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object soundEvent = FastNMS.INSTANCE.field$SoundType$stepSound(soundType);
Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);
if (this.manager.isStepSoundMissing(soundId)) {
player.playSound(player.getLocation(), soundId.toString(), SoundCategory.BLOCKS, 0.15f, 1f);
}
}
}

View File

@@ -1,6 +1,8 @@
package net.momirealms.craftengine.bukkit.block;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBehavior;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
@@ -31,6 +33,7 @@ import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.*;
public final class BukkitBlockManager extends AbstractBlockManager {
@@ -40,7 +43,11 @@ public final class BukkitBlockManager extends AbstractBlockManager {
private static BukkitBlockManager instance;
private final BukkitCraftEngine plugin;
// 事件监听器
private BlockEventListener blockEventListener;
private final BlockEventListener blockEventListener;
// 用于缓存string形式的方块状态到原版方块状态
private final Map<String, Object> blockStateCache = new HashMap<>(1024);
// 用于临时存储可燃烧自定义方块的列表
private final List<DelegatingBlock> burnableBlocks = new ArrayList<>();
// 可燃烧的方块
private Map<Object, Integer> igniteOdds;
private Map<Object, Integer> burnOdds;
@@ -50,15 +57,15 @@ public final class BukkitBlockManager extends AbstractBlockManager {
// 缓存的原版方块tag包
private Object cachedUpdateTagsPacket;
// 被移除声音的原版方块
private final Set<Object> replacedBlockSounds = new HashSet<>();
// 用于缓存string形式的方块状态到原版方块状态
private final Map<String, Object> blockStateCache = new HashMap<>(1024);
// 用于临时存储可燃烧自定义方块的列表
private final List<DelegatingBlock> burnableBlocks = new ArrayList<>();
private Set<Object> missingPlaceSounds = Set.of();
private Set<Object> missingBreakSounds = Set.of();
private Set<Object> missingHitSounds = Set.of();
private Set<Object> missingStepSounds = Set.of();
public BukkitBlockManager(BukkitCraftEngine plugin) {
super(plugin, RegistryUtils.currentBlockRegistrySize(), Config.serverSideBlocks());
this.plugin = plugin;
this.blockEventListener = new BlockEventListener(plugin, this);
this.registerServerSideCustomBlocks(Config.serverSideBlocks());
EmptyBlock.initialize();
instance = this;
@@ -71,7 +78,6 @@ public final class BukkitBlockManager extends AbstractBlockManager {
this.initVanillaBlockSettings();
this.deceiveBukkitRegistry();
this.markVanillaNoteBlocks();
this.blockEventListener = new BlockEventListener(plugin, this);
Arrays.fill(this.immutableBlockStates, EmptyBlock.INSTANCE.defaultState());
this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings); // 一定要预先初始化一次预防id超出上限
}
@@ -411,8 +417,20 @@ public final class BukkitBlockManager extends AbstractBlockManager {
this.clientBoundTags.put(FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, block).orElseThrow(() -> new IllegalStateException("Block " + id + " not found")), tags);
}
public boolean isBlockSoundRemoved(Object block) {
return this.replacedBlockSounds.contains(block);
public boolean isPlaceSoundMissing(Object sound) {
return this.missingPlaceSounds.contains(sound);
}
public boolean isBreakSoundMissing(Object sound) {
return this.missingBreakSounds.contains(sound);
}
public boolean isHitSoundMissing(Object sound) {
return this.missingHitSounds.contains(sound);
}
public boolean isStepSoundMissing(Object sound) {
return this.missingStepSounds.contains(sound);
}
private void unfreezeRegistry() {
@@ -463,6 +481,51 @@ public final class BukkitBlockManager extends AbstractBlockManager {
return this.vanillaBlockStateCount;
}
@SuppressWarnings("DuplicatedCode")
@Override
protected void processSounds() {
Set<Object> affectedBlockSoundTypes = new HashSet<>();
for (BlockStateWrapper vanillaBlockState : super.tempVisualBlocksInUse) {
affectedBlockSoundTypes.add(FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(vanillaBlockState.literalObject()));
}
Set<Object> placeSounds = new HashSet<>();
Set<Object> breakSounds = new HashSet<>();
Set<Object> stepSounds = new HashSet<>();
Set<Object> hitSounds = new HashSet<>();
for (Object soundType : affectedBlockSoundTypes) {
placeSounds.add(FastNMS.INSTANCE.field$SoundEvent$location(FastNMS.INSTANCE.field$SoundType$placeSound(soundType)));
breakSounds.add(FastNMS.INSTANCE.field$SoundEvent$location(FastNMS.INSTANCE.field$SoundType$breakSound(soundType)));
stepSounds.add(FastNMS.INSTANCE.field$SoundEvent$location(FastNMS.INSTANCE.field$SoundType$stepSound(soundType)));
hitSounds.add(FastNMS.INSTANCE.field$SoundEvent$location(FastNMS.INSTANCE.field$SoundType$hitSound(soundType)));
}
ImmutableMap.Builder<Key, Key> soundReplacementBuilder = ImmutableMap.builder();
for (Object soundId : placeSounds) {
Key previousId = KeyUtils.resourceLocationToKey(soundId);
soundReplacementBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value()));
}
for (Object soundId : breakSounds) {
Key previousId = KeyUtils.resourceLocationToKey(soundId);
soundReplacementBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value()));
}
for (Object soundId : stepSounds) {
Key previousId = KeyUtils.resourceLocationToKey(soundId);
soundReplacementBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value()));
}
for (Object soundId : hitSounds) {
Key previousId = KeyUtils.resourceLocationToKey(soundId);
soundReplacementBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value()));
}
this.missingPlaceSounds = placeSounds;
this.missingBreakSounds = breakSounds;
this.missingHitSounds = hitSounds;
this.missingStepSounds = stepSounds;
this.soundReplacements = soundReplacementBuilder.buildKeepingLast();
}
@Override
protected CustomBlock createCustomBlock(@NotNull Holder.Reference<CustomBlock> holder,
@NotNull BlockStateVariantProvider variantProvider,

View File

@@ -1037,8 +1037,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
// not a custom block
if (BlockStateUtils.isVanillaBlock(stateId)) {
if (Config.enableSoundSystem()) {
Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState);
if (BukkitBlockManager.instance().isBlockSoundRemoved(blockOwner)) {
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object soundEvent = FastNMS.INSTANCE.field$SoundType$hitSound(soundType);
Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);
if (BukkitBlockManager.instance().isHitSoundMissing(soundId)) {
player.startMiningBlock(pos, blockState, null);
return;
}
@@ -2293,47 +2295,31 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes
int state = buf.readInt();
boolean global = buf.readBoolean();
int newState = user.clientModEnabled() ? modBlockStateMapper[state] : blockStateMapper[state];
Object blockState = BlockStateUtils.idToBlockState(state);
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object soundEvent = FastNMS.INSTANCE.field$SoundType$breakSound(soundType);
Object rawSoundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent);
if (BlockStateUtils.isVanillaBlock(state)) {
Object blockState = BlockStateUtils.idToBlockState(state);
Object block = BlockStateUtils.getBlockOwner(blockState);
if (BukkitBlockManager.instance().isBlockSoundRemoved(block)) {
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType);
Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString());
Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId);
if (BukkitBlockManager.instance().isBreakSoundMissing(rawSoundId)) {
Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(KeyUtils.resourceLocationToKey(rawSoundId));
if (mappedSoundId != null) {
Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty());
Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound);
Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket(
mappedBreakSoundHolder,
FastNMS.INSTANCE.method$Holder$direct(FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty())),
CoreReflections.instance$SoundSource$BLOCKS,
blockPos.x() + 0.5,
blockPos.y() + 0.5,
blockPos.z() + 0.5,
1f,
0.8F,
blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5, 1f, 0.8F,
RandomUtils.generateRandomLong()
);
user.sendPacket(packet, true);
}
}
} else {
Object blockState = BlockStateUtils.idToBlockState(state);
Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState);
Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType);
Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString());
Key soundId = KeyUtils.resourceLocationToKey(rawSoundId);
Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId);
Object finalSoundId = KeyUtils.toResourceLocation(mappedSoundId == null ? soundId : mappedSoundId);
Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(finalSoundId, Optional.empty());
Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound);
Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket(
mappedBreakSoundHolder,
FastNMS.INSTANCE.method$Holder$direct(FastNMS.INSTANCE.constructor$SoundEvent(finalSoundId, Optional.empty())),
CoreReflections.instance$SoundSource$BLOCKS,
blockPos.x() + 0.5,
blockPos.y() + 0.5,
blockPos.z() + 0.5,
1f,
0.8F,
blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5, 1f, 0.8F,
RandomUtils.generateRandomLong()
);
user.sendPacket(packet, true);

View File

@@ -14,10 +14,7 @@ import net.momirealms.craftengine.core.block.parser.BlockNbtParser;
import net.momirealms.craftengine.core.block.properties.Properties;
import net.momirealms.craftengine.core.block.properties.Property;
import net.momirealms.craftengine.core.loot.LootTable;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.pack.PendingConfigSection;
import net.momirealms.craftengine.core.pack.ResourceLocation;
import net.momirealms.craftengine.core.pack.*;
import net.momirealms.craftengine.core.pack.cache.IdAllocator;
import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
@@ -65,8 +62,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
protected final Map<Key, JsonElement> modBlockStateOverrides = new HashMap<>();
// 根据外观查找真实状态用于debug指令
protected final Map<Integer, List<Integer>> appearanceToRealState = new Int2ObjectOpenHashMap<>();
// 声音映射表,和使用了哪些视觉方块有关
protected final Map<Key, Key> soundReplacements = new HashMap<>(512, 0.5f);
// 用于note_block:0这样格式的自动分配
protected final Map<Key, List<BlockStateWrapper>> blockStateArranger = new HashMap<>();
// 根据registry id找note_block:x中的x值
@@ -83,6 +78,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
protected final ImmutableBlockState[] immutableBlockStates;
// 原版方块的属性缓存
protected final BlockSettings[] vanillaBlockSettings;
// 临时存储哪些视觉方块被使用了
protected final Set<BlockStateWrapper> tempVisualBlocksInUse = new HashSet<>();
// 声音映射表,和使用了哪些视觉方块有关
protected Map<Key, Key> soundReplacements = Map.of();
protected AbstractBlockManager(CraftEngine plugin, int vanillaBlockStateCount, int customBlockCount) {
super(plugin);
@@ -122,7 +121,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
this.blockStateOverrides.clear();
this.modBlockStateOverrides.clear();
this.byId.clear();
this.soundReplacements.clear();
this.blockStateArranger.clear();
this.reversedBlockStateArranger.clear();
this.appearanceToRealState.clear();
@@ -133,8 +131,9 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
@Override
public void delayedLoad() {
this.initSuggestions();
this.clearCache();
this.resendTags();
this.processSounds();
this.clearCache();
}
@Override
@@ -147,24 +146,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
return Optional.ofNullable(this.byId.get(id));
}
protected void addCustomBlock(CustomBlock customBlock) {
// 绑定外观状态等
for (ImmutableBlockState state : customBlock.variantProvider().states()) {
int internalId = state.customBlockState().registryId();
int appearanceId = state.vanillaBlockState().registryId();
int index = internalId - this.vanillaBlockStateCount;
this.immutableBlockStates[index] = state;
this.blockStateMappings[internalId] = appearanceId;
this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId);
this.applyPlatformSettings(state);
// generate mod assets
if (Config.generateModAssets()) {
this.modBlockStateOverrides.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(appearanceId));
}
}
this.byId.put(customBlock.id(), customBlock);
}
protected abstract void applyPlatformSettings(ImmutableBlockState state);
@Override
@@ -203,6 +184,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
protected void clearCache() {
this.tempVanillaBlockStateModels.clear();
this.tempVisualBlocksInUse.clear();
}
protected void initSuggestions() {
@@ -238,6 +220,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
protected abstract int vanillaBlockStateCount();
protected abstract void processSounds();
protected abstract CustomBlock createCustomBlock(@NotNull Holder.Reference<CustomBlock> holder,
@NotNull BlockStateVariantProvider variantProvider,
@NotNull Map<EventTrigger, List<Function<PlayerOptionalContext>>> events,
@@ -538,15 +522,34 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
boolean isEntityBlock = entityBlockBehavior != null;
// 绑定行为
for (ImmutableBlockState blockState : states) {
blockState.setBehavior(blockBehavior);
for (ImmutableBlockState state : states) {
if (isEntityBlock) {
blockState.setBlockEntityType(entityBlockBehavior.blockEntityType());
state.setBlockEntityType(entityBlockBehavior.blockEntityType());
}
state.setBehavior(blockBehavior);
int internalId = state.customBlockState().registryId();
int appearanceId = state.vanillaBlockState().registryId();
int index = internalId - AbstractBlockManager.this.vanillaBlockStateCount;
AbstractBlockManager.this.immutableBlockStates[index] = state;
AbstractBlockManager.this.blockStateMappings[internalId] = appearanceId;
AbstractBlockManager.this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId);
AbstractBlockManager.this.tempVisualBlocksInUse.add(state.vanillaBlockState());
AbstractBlockManager.this.applyPlatformSettings(state);
// generate mod assets
if (Config.generateModAssets()) {
AbstractBlockManager.this.modBlockStateOverrides.put(BlockManager.createCustomBlockKey(index), Optional.ofNullable(AbstractBlockManager.this.tempVanillaBlockStateModels.get(appearanceId))
.orElseGet(() -> {
// 如果未指定模型,说明复用原版模型?但是部分模型是多部位模型,无法使用变体解决问题
// 未来需要靠mod重构彻底解决问题
JsonObject json = new JsonObject();
json.addProperty("model", "minecraft:block/air");
return json;
}));
}
}
// 添加方块
addCustomBlock(customBlock);
AbstractBlockManager.this.byId.put(customBlock.id(), customBlock);
}, () -> GsonHelper.get().toJson(section)));
}

View File

@@ -11,25 +11,19 @@ import java.nio.file.Path;
import java.util.List;
import java.util.Map;
public class GsonHelper {
private final Gson gson;
public final class GsonHelper {
private static final Gson GSON;
public GsonHelper() {
this.gson = new GsonBuilder()
private GsonHelper() {}
static {
GSON = new GsonBuilder()
.disableHtmlEscaping()
.create();
}
public Gson getGson() {
return gson;
}
public static Gson get() {
return SingletonHolder.INSTANCE.getGson();
}
private static class SingletonHolder {
private static final GsonHelper INSTANCE = new GsonHelper();
return GSON;
}
public static void writeJsonFile(JsonElement json, Path path) throws IOException {

View File

@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.5
anti_grief_version=0.20
nms_helper_version=1.0.96
nms_helper_version=1.0.97
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.33.1