9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-27 10:59:07 +00:00

修复部分情况下配置未加载的问题

This commit is contained in:
XiaoMoMi
2025-09-29 19:49:27 +08:00
parent 66cd1c0962
commit 48bdf5f4e0
26 changed files with 212 additions and 168 deletions

View File

@@ -19,8 +19,8 @@ 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.allocator.BlockStateAllocator;
import net.momirealms.craftengine.core.pack.allocator.IdAllocator;
import net.momirealms.craftengine.core.pack.allocator.BlockStateCandidate;
import net.momirealms.craftengine.core.pack.allocator.IdAllocator;
import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator;
import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration;
import net.momirealms.craftengine.core.plugin.CraftEngine;
@@ -80,8 +80,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
protected final Object[] customBlockHolders;
// 自定义状态列表,会随着重载变化
protected final ImmutableBlockState[] immutableBlockStates;
// 原版方块的属性缓存
protected final BlockSettings[] vanillaBlockSettings;
// 倒推缓存
protected final BlockStateCandidate[] reversedBlockStateArranger;
// 临时存储哪些视觉方块被使用了
@@ -98,7 +96,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
this.customBlocks = new DelegatingBlock[customBlockCount];
this.customBlockHolders = new Object[customBlockCount];
this.customBlockStates = new DelegatingBlockState[customBlockCount];
this.vanillaBlockSettings = new BlockSettings[vanillaBlockStateCount];
this.immutableBlockStates = new ImmutableBlockState[customBlockCount];
this.blockStateMappings = new int[customBlockCount + vanillaBlockStateCount];
this.reversedBlockStateArranger = new BlockStateCandidate[vanillaBlockStateCount];
@@ -236,7 +233,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
@NotNull Map<EventTrigger, List<Function<PlayerOptionalContext>>> events,
@Nullable LootTable<?> lootTable);
public class BlockStateMappingParser implements SectionConfigParser {
public class BlockStateMappingParser extends SectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[]{"block-state-mappings", "block-state-mapping"};
@Override
@@ -285,7 +282,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
}
}
public class BlockParser implements IdSectionConfigParser {
public class BlockParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"};
private final IdAllocator internalIdAllocator;
private final List<PendingConfigSection> pendingConfigSections = new ArrayList<>();
@@ -618,9 +615,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
}
}
// 拆分方块id与属性
String blockState = blockStateWrapper.toString();
Key blockId = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}')));
String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']'));
String blockState = blockStateWrapper.getAsString();
int firstIndex = blockState.indexOf('[');
Key blockId = firstIndex == -1 ? Key.of(blockState) : Key.of(blockState.substring(0, firstIndex));
String propertyNBT = firstIndex == -1 ? "" : blockState.substring(firstIndex + 1, blockState.lastIndexOf(']'));
// 结合variants
JsonElement combinedVariant = GsonHelper.combine(variants);
Map<String, JsonElement> overrideMap = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>());

View File

@@ -18,4 +18,9 @@ public abstract class AbstractBlockStateWrapper implements BlockStateWrapper {
public int registryId() {
return this.registryId;
}
@Override
public String toString() {
return this.blockState.toString();
}
}

View File

@@ -19,6 +19,7 @@ import java.util.*;
import java.util.function.BiFunction;
public abstract class AbstractCustomBlock implements CustomBlock {
protected final Key id;
protected final Holder.Reference<CustomBlock> holder;
protected final BlockStateVariantProvider variantProvider;
protected final BiFunction<BlockPlaceContext, ImmutableBlockState, ImmutableBlockState> placementFunction;
@@ -34,6 +35,7 @@ public abstract class AbstractCustomBlock implements CustomBlock {
@NotNull Map<EventTrigger, List<Function<PlayerOptionalContext>>> events,
@Nullable LootTable<?> lootTable
) {
this.id = holder.key().location();
this.holder = holder;
this.lootTable = lootTable;
this.events = events;
@@ -85,7 +87,7 @@ public abstract class AbstractCustomBlock implements CustomBlock {
@NotNull
@Override
public final Key id() {
return this.holder.key().location();
return this.id;
}
public void setBehavior(@Nullable BlockBehavior behavior) {

View File

@@ -18,7 +18,7 @@ public class BlockStateHolder {
this.propertyMap = new Reference2ObjectArrayMap<>(propertyMap);
}
public Holder.Reference<CustomBlock> owner() {
public Holder<CustomBlock> owner() {
return this.owner;
}

View File

@@ -76,7 +76,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
protected abstract CustomFurniture.Builder furnitureBuilder();
public class FurnitureParser implements IdSectionConfigParser {
public class FurnitureParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" };
private final List<PendingConfigSection> pendingConfigSections = new ArrayList<>();
@@ -110,7 +110,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
@SuppressWarnings("unchecked")
@Override
public void parseSection(Pack pack, Path path, String node, Key id, Map<String, Object> section) {
if (byId.containsKey(id)) {
if (AbstractFurnitureManager.this.byId.containsKey(id)) {
throw new LocalizedResourceConfigException("warning.config.furniture.duplicate");
}
EnumMap<AnchorType, CustomFurniture.Placement> placements = new EnumMap<>(AnchorType.class);

View File

@@ -232,7 +232,7 @@ public abstract class AbstractFontManager implements FontManager {
emoji.content(),
PlayerOptionalContext.of(player, ContextHolder.builder()
.withOptionalParameter(EmojiParameters.EMOJI, emoji.emojiImage())
.withParameter(EmojiParameters.KEYWORD, emoji.keywords().get(0))
.withParameter(EmojiParameters.KEYWORD, emoji.keywords().getFirst())
).tagResolvers())
);
if (emojis.size() >= maxTimes) break;
@@ -390,7 +390,7 @@ public abstract class AbstractFontManager implements FontManager {
return this.fonts.computeIfAbsent(key, Font::new);
}
public class EmojiParser implements IdSectionConfigParser {
public class EmojiParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"emoji", "emojis"};
@Override
@@ -457,7 +457,7 @@ public abstract class AbstractFontManager implements FontManager {
}
}
public class ImageParser implements IdSectionConfigParser {
public class ImageParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"images", "image"};
private final Map<Key, IdAllocator> idAllocators = new HashMap<>();
@@ -577,7 +577,11 @@ public abstract class AbstractFontManager implements FontManager {
codepoints = CharacterUtils.charsToCodePoints(charString.toCharArray());
}
for (int j = 0; j < codepoints.length; j++) {
futureCodepoints.add(allocator.assignFixedId(id.asString() + ":" + i + ":" + j, codepoints[j]));
if (codepoints[j] == 0) {
futureCodepoints.add(CompletableFuture.completedFuture(0));
} else {
futureCodepoints.add(allocator.assignFixedId(id.asString() + ":" + i + ":" + j, codepoints[j]));
}
}
if (tempColumns == -1) {
tempColumns = codepoints.length;
@@ -607,7 +611,11 @@ public abstract class AbstractFontManager implements FontManager {
}
columns = codepoints.length;
for (int i = 0; i < codepoints.length; i++) {
futureCodepoints.add(allocator.assignFixedId(id.asString() + ":0:" + i, codepoints[i]));
if (codepoints[i] == 0) {
futureCodepoints.add(CompletableFuture.completedFuture(0));
} else {
futureCodepoints.add(allocator.assignFixedId(id.asString() + ":0:" + i, codepoints[i]));
}
}
}
}

View File

@@ -270,7 +270,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
protected abstract void registerArmorTrimPattern(Collection<Key> equipments);
public class EquipmentParser implements IdSectionConfigParser {
public class EquipmentParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"equipments", "equipment"};
@Override
@@ -313,7 +313,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
}
}
public class ItemParser implements IdSectionConfigParser {
public class ItemParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"};
private final Map<Key, IdAllocator> idAllocators = new HashMap<>();

View File

@@ -121,7 +121,7 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
return true;
}
public class RecipeParser implements IdSectionConfigParser {
public class RecipeParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"};
@Override

View File

@@ -86,6 +86,7 @@ public abstract class AbstractPackManager implements PackManager {
private final BiConsumer<Path, Path> generationEventDispatcher;
private final Map<String, Pack> loadedPacks = new HashMap<>();
private final Map<String, ConfigParser> sectionParsers = new HashMap<>();
private final TreeSet<ConfigParser> sortedParsers = new TreeSet<>();
private final JsonObject vanillaAtlas;
private Map<Path, CachedConfigFile> cachedConfigFiles = Collections.emptyMap();
private Map<Path, CachedAssetFile> cachedAssetFiles = Collections.emptyMap();
@@ -293,6 +294,7 @@ public abstract class AbstractPackManager implements PackManager {
for (String id : parser.sectionId()) {
this.sectionParsers.put(id, parser);
}
this.sortedParsers.add(parser);
return true;
}
@@ -548,10 +550,9 @@ public abstract class AbstractPackManager implements PackManager {
plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json");
}
private TreeMap<ConfigParser, List<CachedConfigSection>> updateCachedConfigFiles() {
TreeMap<ConfigParser, List<CachedConfigSection>> cachedConfigs = new TreeMap<>();
private void updateCachedConfigFiles() {
Map<Path, CachedConfigFile> previousFiles = this.cachedConfigFiles;
this.cachedConfigFiles = new Object2ObjectOpenHashMap<>(32);
this.cachedConfigFiles = new HashMap<>(64, 0.5f);
for (Pack pack : loadedPacks()) {
if (!pack.enabled()) continue;
Path configurationFolderPath = pack.configurationFolder();
@@ -596,9 +597,7 @@ public abstract class AbstractPackManager implements PackManager {
}
}
for (Map.Entry<String, Object> entry : cachedFile.config().entrySet()) {
processConfigEntry(entry, path, cachedFile.pack(), (p, c) ->
cachedConfigs.computeIfAbsent(p, k -> new ArrayList<>()).add(c)
);
processConfigEntry(entry, path, cachedFile.pack(), ConfigParser::addConfig);
}
}
return FileVisitResult.CONTINUE;
@@ -608,76 +607,20 @@ public abstract class AbstractPackManager implements PackManager {
this.plugin.logger().severe("Error while reading config file", e);
}
}
return cachedConfigs;
}
private void loadResourceConfigs(Predicate<ConfigParser> predicate) {
long o1 = System.nanoTime();
TreeMap<ConfigParser, List<CachedConfigSection>> cachedConfigs = this.updateCachedConfigFiles();
this.updateCachedConfigFiles();
long o2 = System.nanoTime();
this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms");
for (Map.Entry<ConfigParser, List<CachedConfigSection>> entry : cachedConfigs.entrySet()) {
ConfigParser parser = entry.getKey();
for (ConfigParser parser : this.sortedParsers) {
if (!predicate.test(parser)) continue;
long t1 = System.nanoTime();
parser.preProcess();
switch (parser) {
case SectionConfigParser configParser -> {
for (CachedConfigSection cached : entry.getValue()) {
ResourceConfigUtils.runCatching(
cached.filePath(),
cached.prefix(),
() -> configParser.parseSection(cached.pack(), cached.filePath(), cached.config()),
() -> GsonHelper.get().toJson(cached.config())
);
}
}
case IdObjectConfigParser configParser -> {
for (CachedConfigSection cached : entry.getValue()) {
for (Map.Entry<String, Object> configEntry : cached.config().entrySet()) {
String key = configEntry.getKey();
Key id = Key.withDefaultNamespace(key, cached.pack().namespace());
String node = cached.prefix() + "." + key;
ResourceConfigUtils.runCatching(
cached.filePath(),
node,
() -> configParser.parseObject(cached.pack(), cached.filePath(), node, id, configEntry.getValue()),
() -> GsonHelper.get().toJson(configEntry.getValue())
);
}
}
}
case IdSectionConfigParser configParser -> {
for (CachedConfigSection cached : entry.getValue()) {
for (Map.Entry<String, Object> configEntry : cached.config().entrySet()) {
String key = configEntry.getKey();
Key id = Key.withDefaultNamespace(key, cached.pack().namespace());
if (!(configEntry.getValue() instanceof Map<?, ?> section)) {
TranslationManager.instance().log("warning.config.structure.not_section",
cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName());
continue;
}
Map<String, Object> config = castToMap(section, false);
if ((boolean) config.getOrDefault("debug", false)) {
this.plugin.logger().info(GsonHelper.get().toJson(this.plugin.templateManager().applyTemplates(id, config)));
}
if (!(boolean) config.getOrDefault("enable", true)) {
continue;
}
String node = cached.prefix() + "." + key;
ResourceConfigUtils.runCatching(
cached.filePath(),
node,
() -> configParser.parseSection(cached.pack(), cached.filePath(), node, id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false)),
() -> GsonHelper.get().toJson(section)
);
}
}
}
default -> {
}
}
parser.loadAll();
parser.postProcess();
parser.clear();
long t2 = System.nanoTime();
this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms");
}
@@ -2252,9 +2195,9 @@ public abstract class AbstractPackManager implements PackManager {
}
private List<Pair<String, List<Path>>> updateCachedAssets(@NotNull PackCacheData cacheData, @Nullable FileSystem fs) throws IOException {
Map<String, List<Path>> conflictChecker = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size()));
Map<String, List<Path>> conflictChecker = new HashMap<>(Math.max(128, this.cachedAssetFiles.size()), 0.6f);
Map<Path, CachedAssetFile> previousFiles = this.cachedAssetFiles;
this.cachedAssetFiles = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size()));
this.cachedAssetFiles = new HashMap<>(Math.max(128, this.cachedAssetFiles.size()), 0.6f);
List<Path> folders = new ArrayList<>();
folders.addAll(loadedPacks().stream()

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.pack;
public final class LoadingSequence {
private LoadingSequence() {}
// 模板第一位
public static final int TEMPLATE = 0;
public static final int BLOCK_STATE_MAPPING = 10;
public static final int GLOBAL_VAR = 20;

View File

@@ -0,0 +1,32 @@
package net.momirealms.craftengine.core.plugin.config;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.momirealms.craftengine.core.pack.CachedConfigSection;
public abstract class AbstractConfigParser implements ConfigParser {
protected final ObjectArrayList<CachedConfigSection> configStorage;
public AbstractConfigParser() {
this.configStorage = new ObjectArrayList<>();
}
@Override
public void addConfig(CachedConfigSection section) {
this.configStorage.add(section);
}
@Override
public void loadAll() {
Object[] elements = this.configStorage.elements();
for (int i = 0, size = this.configStorage.size(); i < size; i++) {
parseSection((CachedConfigSection) elements[i]);
}
}
@Override
public void clear() {
this.configStorage.clear();
}
protected abstract void parseSection(CachedConfigSection section);
}

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.core.plugin.config;
import net.momirealms.craftengine.core.pack.CachedConfigSection;
import org.jetbrains.annotations.NotNull;
public interface ConfigParser extends Comparable<ConfigParser> {
@@ -18,4 +19,10 @@ public interface ConfigParser extends Comparable<ConfigParser> {
default void preProcess() {
}
void addConfig(CachedConfigSection section);
void loadAll();
void clear();
}

View File

@@ -1,13 +1,31 @@
package net.momirealms.craftengine.core.plugin.config;
import net.momirealms.craftengine.core.pack.CachedConfigSection;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.util.GsonHelper;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.nio.file.Path;
import java.util.Map;
public interface IdObjectConfigParser extends ConfigParser {
public abstract class IdObjectConfigParser extends AbstractConfigParser {
default void parseObject(Pack pack, Path path, String node, Key id, Object object) throws LocalizedException {
@Override
protected void parseSection(CachedConfigSection cached) {
for (Map.Entry<String, Object> configEntry : cached.config().entrySet()) {
String key = configEntry.getKey();
Key id = Key.withDefaultNamespace(key, cached.pack().namespace());
String node = cached.prefix() + "." + key;
ResourceConfigUtils.runCatching(
cached.filePath(),
node,
() -> parseObject(cached.pack(), cached.filePath(), node, id, configEntry.getValue()),
() -> GsonHelper.get().toJson(configEntry.getValue())
);
}
}
protected abstract void parseObject(Pack pack, Path path, String node, Key id, Object object) throws LocalizedException;
}

View File

@@ -1,14 +1,48 @@
package net.momirealms.craftengine.core.plugin.config;
import net.momirealms.craftengine.core.pack.CachedConfigSection;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.util.GsonHelper;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.nio.file.Path;
import java.util.Map;
public interface IdSectionConfigParser extends ConfigParser {
import static net.momirealms.craftengine.core.util.MiscUtils.castToMap;
default void parseSection(Pack pack, Path path, String node, Key id, Map<String, Object> section) throws LocalizedException {
public abstract class IdSectionConfigParser extends AbstractConfigParser {
@Override
protected void parseSection(CachedConfigSection cached) {
for (Map.Entry<String, Object> configEntry : cached.config().entrySet()) {
String key = configEntry.getKey();
Key id = Key.withDefaultNamespace(key, cached.pack().namespace());
if (!(configEntry.getValue() instanceof Map<?, ?> section)) {
TranslationManager.instance().log("warning.config.structure.not_section",
cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName());
continue;
}
Map<String, Object> config = castToMap(section, false);
if ((boolean) config.getOrDefault("debug", false)) {
CraftEngine.instance().logger().info(GsonHelper.get().toJson(CraftEngine.instance().templateManager().applyTemplates(id, config)));
}
if (!(boolean) config.getOrDefault("enable", true)) {
continue;
}
String node = cached.prefix() + "." + key;
ResourceConfigUtils.runCatching(
cached.filePath(),
node,
() -> parseSection(cached.pack(), cached.filePath(), node, id, MiscUtils.castToMap(CraftEngine.instance().templateManager().applyTemplates(id, config), false)),
() -> GsonHelper.get().toJson(section)
);
}
}
protected abstract void parseSection(Pack pack, Path path, String node, Key id, Map<String, Object> section) throws LocalizedException;
}

View File

@@ -1,13 +1,25 @@
package net.momirealms.craftengine.core.plugin.config;
import net.momirealms.craftengine.core.pack.CachedConfigSection;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.util.GsonHelper;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import java.nio.file.Path;
import java.util.Map;
public interface SectionConfigParser extends ConfigParser {
public abstract class SectionConfigParser extends AbstractConfigParser {
default void parseSection(Pack pack, Path path, Map<String, Object> section) throws LocalizedException {
@Override
protected void parseSection(CachedConfigSection cached) {
ResourceConfigUtils.runCatching(
cached.filePath(),
cached.prefix(),
() -> parseSection(cached.pack(), cached.filePath(), cached.config()),
() -> GsonHelper.get().toJson(cached.config())
);
}
protected abstract void parseSection(Pack pack, Path path, Map<String, Object> section) throws LocalizedException;
}

View File

@@ -37,7 +37,7 @@ public class TemplateManagerImpl implements TemplateManager {
return this.templateParser;
}
public class TemplateParser implements IdObjectConfigParser {
public class TemplateParser extends IdObjectConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"};
@Override

View File

@@ -36,7 +36,7 @@ public class GlobalVariableManager implements Manageable {
return this.parser;
}
public class GlobalVariableParser implements IdObjectConfigParser {
public class GlobalVariableParser extends IdObjectConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"global-variables", "global-variable"};
@Override

View File

@@ -96,7 +96,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
return Optional.ofNullable(this.byId.get(key));
}
public class CategoryParser implements IdSectionConfigParser {
public class CategoryParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"categories", "category"};
@Override

View File

@@ -246,7 +246,7 @@ public class TranslationManagerImpl implements TranslationManager {
}
}
public class I18NParser implements IdSectionConfigParser {
public class I18NParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"};
@Override
@@ -277,7 +277,7 @@ public class TranslationManagerImpl implements TranslationManager {
}
}
public class LangParser implements IdSectionConfigParser {
public class LangParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"};
private final Function<String, String> langProcessor = s -> {
Component deserialize = AdventureHelper.miniMessage().deserialize(AdventureHelper.legacyToMiniMessage(s), ShiftTag.INSTANCE, ImageTag.INSTANCE);

View File

@@ -66,8 +66,8 @@ public abstract class AbstractSoundManager implements SoundManager {
protected abstract void registerSounds(Collection<Key> sounds);
public class SongParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "jukebox_song", "jukebox-songs", "jukebox-song"};
public class SongParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox-songs", "jukebox-song", "jukebox_songs", "jukebox_song"};
@Override
public int loadingSequence() {
@@ -93,7 +93,7 @@ public abstract class AbstractSoundManager implements SoundManager {
}
}
public class SoundParser implements IdSectionConfigParser {
public class SoundParser extends IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"};
@Override