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

重新设计

This commit is contained in:
XiaoMoMi
2025-09-26 21:58:21 +08:00
parent f9448bfbff
commit e12273e600
101 changed files with 5278 additions and 6137 deletions

View File

@@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.block;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig;
import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigs;
@@ -16,54 +16,81 @@ import net.momirealms.craftengine.core.pack.ResourceLocation;
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;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.*;
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
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 net.momirealms.craftengine.core.plugin.locale.TranslationManager;
import net.momirealms.craftengine.core.util.*;
import org.incendo.cloud.suggestion.Suggestion;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager {
protected final BlockParser blockParser;
// CraftEngine objects
protected final BlockStateMappingParser blockStateMappingParser;
// 根据id获取自定义方块
protected final Map<Key, CustomBlock> byId = new HashMap<>();
// Cached command suggestions
// 缓存的指令建议
protected final List<Suggestion> cachedSuggestions = new ArrayList<>();
// Cached Namespace
// 缓存的使用中的命名空间
protected final Set<String> namespacesInUse = new HashSet<>();
// for mod, real block id -> state models
protected final Map<Key, JsonElement> modBlockStates = new HashMap<>();
// A temporary map that stores the model path of a certain vanilla block state
// 用于检测单个外观方块状态是否被绑定了不同模型
protected final Map<Integer, JsonElement> tempVanillaBlockStateModels = new Int2ObjectOpenHashMap<>();
// A temporary map used to detect whether the same block state corresponds to multiple models.
protected final Map<Integer, Key> tempRegistryIdConflictMap = new Int2ObjectOpenHashMap<>();
// A temporary map that converts the custom block registered on the server to the vanilla block ID.
protected final Map<Integer, Integer> tempBlockAppearanceConvertor = new Int2IntOpenHashMap();
// Used to store override information of json files
// Map<方块类型, Map<方块状态NBT,模型>>用于生成block state json
protected final Map<Key, Map<String, JsonElement>> blockStateOverrides = new HashMap<>();
// a reverted mapper
// 用于生成mod使用的block state json
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<>();
// 全方块状态映射文件,用于网络包映射
protected final int[] blockStateMappings;
// 原版方块状态数量
protected final int vanillaBlockStateCount;
// 注册的大宝贝
protected final DelegatingBlock[] customBlocks;
protected final DelegatingBlockState[] customBlockStates;
protected final Object[] customBlockHolders;
// 自定义状态列表,会随着重载变化
protected final ImmutableBlockState[] immutableBlockStates;
// 原版方块的属性缓存
protected final BlockSettings[] vanillaBlockSettings;
// client side block tags
protected Map<Integer, List<String>> clientBoundTags = Map.of();
protected Map<Integer, List<String>> previousClientBoundTags = Map.of();
// Used to automatically arrange block states for strings such as minecraft:note_block:0
protected Map<Key, List<Integer>> blockAppearanceArranger;
protected Map<Key, List<Integer>> realBlockArranger;
protected Map<Key, Integer> internalId2StateId;
protected Map<Key, DelegatingBlock> registeredBlocks;
protected AbstractBlockManager(CraftEngine plugin) {
protected AbstractBlockManager(CraftEngine plugin, int vanillaBlockStateCount, int customBlockCount) {
super(plugin);
this.vanillaBlockStateCount = vanillaBlockStateCount;
this.blockParser = new BlockParser();
this.blockStateMappingParser = new BlockStateMappingParser();
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];
Arrays.fill(this.blockStateMappings, -1);
}
@NotNull
@Override
public ImmutableBlockState getImmutableBlockStateUnsafe(int stateId) {
return this.immutableBlockStates[stateId - this.vanillaBlockStateCount];
}
@Nullable
@Override
public ImmutableBlockState getImmutableBlockState(int stateId) {
if (!isVanillaBlockState(stateId)) {
return this.immutableBlockStates[stateId - this.vanillaBlockStateCount];
}
return null;
}
@Override
@@ -71,12 +98,15 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
super.clearModelsToGenerate();
this.clearCache();
this.cachedSuggestions.clear();
this.namespacesInUse.clear();
this.blockStateOverrides.clear();
this.modBlockStates.clear();
this.modBlockStateOverrides.clear();
this.byId.clear();
this.previousClientBoundTags = this.clientBoundTags;
this.clientBoundTags = new HashMap<>();
this.soundReplacements.clear();
this.blockStateArranger.clear();
this.appearanceToRealState.clear();
Arrays.fill(this.blockStateMappings, -1);
Arrays.fill(this.immutableBlockStates, EmptyBlock.STATE);
}
@Override
@@ -97,23 +127,39 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
}
protected void addBlockInternal(Key id, CustomBlock customBlock) {
this.byId.put(id, customBlock);
// generate mod assets
if (Config.generateModAssets()) {
for (ImmutableBlockState state : customBlock.variantProvider().states()) {
this.modBlockStates.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(state.vanillaBlockState().registryId()));
ExceptionCollector<LocalizedResourceConfigException> exceptionCollector = new ExceptionCollector<>();
// 绑定外观状态等
for (ImmutableBlockState state : customBlock.variantProvider().states()) {
int internalId = state.customBlockState().registryId();
int appearanceId = state.vanillaBlockState().registryId();
int index = internalId - this.vanillaBlockStateCount;
ImmutableBlockState previous = this.immutableBlockStates[index];
// todo 应当提前判断位置
if (previous != null && !previous.isEmpty()) {
exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.bind_failed",
state.toString(), previous.toString(), getBlockOwnerId(previous.customBlockState()).toString()));
continue;
}
this.immutableBlockStates[index] = state;
this.blockStateMappings[internalId] = appearanceId;
this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId);
// generate mod assets
if (Config.generateModAssets()) {
this.modBlockStateOverrides.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(appearanceId));
}
}
this.byId.put(id, customBlock);
exceptionCollector.throwIfPresent();
}
@Override
public ConfigParser parser() {
return this.blockParser;
public ConfigParser[] parsers() {
return new ConfigParser[]{this.blockParser, this.blockStateMappingParser};
}
@Override
public Map<Key, JsonElement> modBlockStates() {
return Collections.unmodifiableMap(this.modBlockStates);
return Collections.unmodifiableMap(this.modBlockStateOverrides);
}
@Override
@@ -126,13 +172,21 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
return Collections.unmodifiableCollection(this.cachedSuggestions);
}
@Nullable
public Key replaceSoundIfExist(Key id) {
return this.soundReplacements.get(id);
}
@Override
public Map<Key, Key> soundReplacements() {
return Collections.unmodifiableMap(this.soundReplacements);
}
public Set<String> namespacesInUse() {
return Collections.unmodifiableSet(this.namespacesInUse);
}
protected void clearCache() {
this.tempRegistryIdConflictMap.clear();
this.tempBlockAppearanceConvertor.clear();
this.tempVanillaBlockStateModels.clear();
}
@@ -161,15 +215,55 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
protected abstract boolean isVanillaBlock(Key id);
protected abstract int getBlockRegistryId(Key id);
protected abstract String stateRegistryIdToStateSNBT(int id);
protected abstract Key getBlockOwnerId(int id);
protected abstract CustomBlock.Builder platformBuilder(Key id);
public class BlockParser implements ConfigParser {
protected abstract void setVanillaBlockTags(Key id, List<String> tags);
public abstract int vanillaBlockStateCount();
public class BlockStateMappingParser implements SectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[]{"block-state-mappings", "block-state-mapping"};
@Override
public String[] sectionId() {
return CONFIG_SECTION_NAME;
}
@Override
public int loadingSequence() {
return LoadingSequence.BLOCK_STATE_MAPPING;
}
@Override
public void parseSection(Pack pack, Path path, Map<String, Object> section) throws LocalizedException {
for (Map.Entry<String, Object> entry : section.entrySet()) {
String before = entry.getKey();
String after = entry.getValue().toString();
// 先解析为唯一的wrapper
BlockStateWrapper beforeState = createVanillaBlockState(before);
BlockStateWrapper afterState = createVanillaBlockState(before);
if (beforeState == null) {
TranslationManager.instance().log("warning.config.block_state_mapping.invalid_state", path.toString(), before);
return;
}
if (afterState == null) {
TranslationManager.instance().log("warning.config.block_state_mapping.invalid_state", path.toString(), after);
return;
}
int previous = AbstractBlockManager.this.blockStateMappings[beforeState.registryId()];
if (previous != -1 && previous != afterState.registryId()) {
TranslationManager.instance().log("warning.config.block_state_mapping.conflict", path.toString(), beforeState.toString(), afterState.toString(), BlockRegistryMirror.byId(previous).toString());
return;
}
AbstractBlockManager.this.blockStateMappings[beforeState.registryId()] = afterState.registryId();
AbstractBlockManager.this.blockStateArranger.computeIfAbsent(getBlockOwnerId(beforeState), k -> new ArrayList<>()).add(afterState);
}
}
}
public class BlockParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"};
@Override
@@ -201,7 +295,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
Object clientBoundTags = settings.get("client-bound-tags");
if (clientBoundTags instanceof List<?> list) {
List<String> clientSideTags = MiscUtils.getAsStringList(list).stream().filter(ResourceLocation::isValid).toList();
AbstractBlockManager.this.clientBoundTags.put(getBlockRegistryId(id), clientSideTags);
AbstractBlockManager.this.setVanillaBlockTags(id, clientSideTags);
}
}
}
@@ -219,19 +313,16 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
boolean singleState = !stateSection.containsKey("properties");
// 单方块状态
if (singleState) {
int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(
stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id");
int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id");
// 获取原版外观的注册表id
int appearanceId = pluginFormattedBlockStateToRegistryId(ResourceConfigUtils.requireNonEmptyStringOrThrow(
stateSection.get("state"), "warning.config.block.state.missing_state"));
BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(stateSection.get("state"), "warning.config.block.state.missing_state"));
Optional<BlockEntityElementConfig<? extends BlockEntityElement>[]> blockEntityRenderer = parseBlockEntityRender(stateSection.get("entity-renderer"));
// 为原版外观赋予外观模型并检查模型冲突
this.arrangeModelForStateAndVerify(appearanceId, ResourceConfigUtils.get(stateSection, "model", "models"));
this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(stateSection, "model", "models"));
// 设置参数
properties = Map.of();
appearances = Map.of("", new BlockStateAppearance(appearanceId, blockEntityRenderer));
variants = Map.of("", new BlockStateVariant("", settings, getInternalBlockId(internalId, appearanceId)));
appearances = Map.of("", new BlockStateAppearance(appearanceState, blockEntityRenderer));
variants = Map.of("", new BlockStateVariant("", settings, getInternalBlockState(internalId)));
}
// 多方块状态
else {
@@ -239,10 +330,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
appearances = parseBlockAppearances(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances"));
variants = parseBlockVariants(
ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), "variants"),
it -> {
BlockStateAppearance blockStateAppearance = appearances.get(it);
return blockStateAppearance == null ? -1 : blockStateAppearance.stateRegistryId();
}, settings
appearances::containsKey, settings
);
}
@@ -258,39 +346,35 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
}
private Map<String, BlockStateVariant> parseBlockVariants(Map<String, Object> variantsSection,
Function<String, Integer> appearanceValidator,
Predicate<String> appearanceValidator,
BlockSettings parentSettings) {
Map<String, BlockStateVariant> variants = new HashMap<>();
for (Map.Entry<String, Object> entry : variantsSection.entrySet()) {
Map<String, Object> variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey());
String variantNBT = entry.getKey();
String appearance = ResourceConfigUtils.requireNonEmptyStringOrThrow(variantSection.get("appearance"), "warning.config.block.state.variant.missing_appearance");
int appearanceId = appearanceValidator.apply(appearance);
if (appearanceId == -1) {
if (!appearanceValidator.test(appearance)) {
throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearance);
}
int internalId = getInternalBlockId(ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id"), appearanceId);
BlockStateWrapper internalBlockState = getInternalBlockState(ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id"));
Map<String, Object> anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings");
variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? parentSettings : BlockSettings.ofFullCopy(parentSettings, anotherSetting), internalId));
variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? parentSettings : BlockSettings.ofFullCopy(parentSettings, anotherSetting), internalBlockState));
}
return variants;
}
private int getInternalBlockId(int internalId, int appearanceId) {
Key baseBlock = getBlockOwnerId(appearanceId);
Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, baseBlock.value() + "_" + internalId);
int internalBlockRegistryId = Optional.ofNullable(AbstractBlockManager.this.internalId2StateId.get(internalBlockId)).orElse(-1);
if (internalBlockRegistryId == -1) {
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(baseBlock) - 1));
private BlockStateWrapper getInternalBlockState(int internalId) {
if (internalId >= Config.serverSideBlocks()) {
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", BlockManager.createCustomBlockKey(internalId).asString(), String.valueOf(Config.serverSideBlocks() - 1));
}
return internalBlockRegistryId;
return BlockRegistryMirror.byId(internalId + vanillaBlockStateCount());
}
private Map<String, BlockStateAppearance> parseBlockAppearances(Map<String, Object> appearancesSection) {
Map<String, BlockStateAppearance> appearances = new HashMap<>();
for (Map.Entry<String, Object> entry : appearancesSection.entrySet()) {
Map<String, Object> appearanceSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey());
int appearanceId = pluginFormattedBlockStateToRegistryId(ResourceConfigUtils.requireNonEmptyStringOrThrow(
BlockStateWrapper appearanceId = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(
appearanceSection.get("state"), "warning.config.block.state.missing_state"));
this.arrangeModelForStateAndVerify(appearanceId, ResourceConfigUtils.get(appearanceSection, "model", "models"));
appearances.put(entry.getKey(), new BlockStateAppearance(appearanceId, parseBlockEntityRender(appearanceSection.get("entity-renderer"))));
@@ -316,7 +400,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
return properties;
}
private void arrangeModelForStateAndVerify(int registryId, Object modelOrModels) {
private void arrangeModelForStateAndVerify(BlockStateWrapper blockStateWrapper, Object modelOrModels) {
// 如果没有配置models
if (modelOrModels == null) {
return;
@@ -334,13 +418,13 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
}
}
// 拆分方块id与属性
String blockState = stateRegistryIdToStateSNBT(registryId);
String blockState = blockStateWrapper.toString();
Key blockId = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}')));
String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']'));
// 结合variants
JsonElement combinedVariant = GsonHelper.combine(variants);
Map<String, JsonElement> overrideMap = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>());
AbstractBlockManager.this.tempVanillaBlockStateModels.put(registryId, combinedVariant);
AbstractBlockManager.this.tempVanillaBlockStateModels.put(blockStateWrapper.registryId(), combinedVariant);
JsonElement previous = overrideMap.get(propertyNBT);
if (previous != null && !previous.equals(combinedVariant)) {
throw new LocalizedResourceConfigException("warning.config.block.state.model.conflict", GsonHelper.get().toJson(combinedVariant), blockState, GsonHelper.get().toJson(previous));
@@ -370,7 +454,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
}
// 从方块外观的state里获取其原版方块的state id
private int pluginFormattedBlockStateToRegistryId(String blockState) {
private BlockStateWrapper parsePluginFormattedBlockState(String blockState) {
// 五种合理情况
// minecraft:note_block:10
// note_block:10
@@ -381,7 +465,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
if (split.length >= 4) {
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState);
}
int registryId;
BlockStateWrapper wrapper;
String stateOrId = split[split.length - 1];
boolean isId = false;
int arrangerIndex = 0;
@@ -401,14 +485,14 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
// 获取原版方块的id
Key block = split.length == 2 ? Key.of(split[0]) : Key.of(split[0], split[1]);
try {
List<Integer> arranger = blockAppearanceArranger.get(block);
List<BlockStateWrapper> arranger =blockStateArranger.get(block);
if (arranger == null) {
throw new LocalizedResourceConfigException("warning.config.block.state.unavailable_vanilla", blockState);
}
if (arrangerIndex >= arranger.size()) {
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla_id", blockState, String.valueOf(arranger.size() - 1));
}
registryId = arranger.get(arrangerIndex);
wrapper = arranger.get(arrangerIndex);
} catch (NumberFormatException e) {
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", e, blockState);
}
@@ -418,9 +502,21 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
if (packedBlockState == null) {
throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState);
}
registryId = packedBlockState.registryId();
wrapper = packedBlockState;
}
return registryId;
return wrapper;
}
}
public boolean isVanillaBlockState(int id) {
return id < this.vanillaBlockStateCount && id >= 0;
}
public BlockParser blockParser() {
return blockParser;
}
public BlockStateMappingParser blockStateMappingParser() {
return blockStateMappingParser;
}
}

View File

@@ -61,6 +61,7 @@ public abstract class AbstractCustomBlock implements CustomBlock {
this.placementFunction = composite(placements);
EntityBlockBehavior entityBlockBehavior = this.behavior.getEntityBehavior();
boolean isEntityBlock = entityBlockBehavior != null;
for (Map.Entry<String, BlockStateVariant> entry : variantMapper.entrySet()) {
String nbtString = entry.getKey();
CompoundTag tag = BlockNbtParser.deserialize(this, nbtString);
@@ -72,20 +73,12 @@ public abstract class AbstractCustomBlock implements CustomBlock {
throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString);
}
BlockStateVariant blockStateVariant = entry.getValue();
BlockStateAppearance blockStateAppearance = appearances.getOrDefault(blockStateVariant.appearance(), BlockStateAppearance.INVALID);
int stateId;
// This should never happen
if (blockStateAppearance.isInvalid()) {
stateId = appearances.values().iterator().next().stateRegistryId();
} else {
stateId = blockStateAppearance.stateRegistryId();
}
BlockStateAppearance blockStateAppearance = appearances.get(blockStateVariant.appearance());
// Late init states
ImmutableBlockState state = possibleStates.getFirst();
state.setSettings(blockStateVariant.settings());
state.setVanillaBlockState(BlockRegistryMirror.stateByRegistryId(stateId));
state.setCustomBlockState(BlockRegistryMirror.stateByRegistryId(blockStateVariant.internalRegistryId()));
state.setVanillaBlockState(blockStateAppearance.blockState());
state.setCustomBlockState(blockStateVariant.blockState());
blockStateAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers);
}
@@ -99,7 +92,6 @@ public abstract class AbstractCustomBlock implements CustomBlock {
state.setBlockEntityType(entityBlockBehavior.blockEntityType());
}
}
this.applyPlatformSettings();
}
protected BlockBehavior setupBehavior(List<Map<String, Object>> behaviorConfig) {
@@ -124,8 +116,6 @@ public abstract class AbstractCustomBlock implements CustomBlock {
};
}
protected abstract void applyPlatformSettings();
@Override
public @Nullable LootTable<?> lootTable() {
return this.lootTable;

View File

@@ -16,7 +16,7 @@ import java.util.Optional;
public interface BlockManager extends Manageable, ModelGenerator {
ConfigParser parser();
ConfigParser[] parsers();
Collection<ModelGeneration> modelsToGenerate();
@@ -35,9 +35,7 @@ public interface BlockManager extends Manageable, ModelGenerator {
Collection<Suggestion> cachedSuggestions();
Map<Key, Key> soundMapper();
int availableAppearances(Key blockType);
Map<Key, Key> soundReplacements();
Key getBlockOwnerId(BlockStateWrapper state);
@@ -49,4 +47,11 @@ public interface BlockManager extends Manageable, ModelGenerator {
@Nullable
BlockStateWrapper createBlockState(String blockState);
@Nullable
BlockStateWrapper createVanillaBlockState(String blockState);
static Key createCustomBlockKey(int id) {
return Key.of("craftengine", "custom_" + id);
}
}

View File

@@ -5,14 +5,14 @@ public final class BlockRegistryMirror {
private static BlockStateWrapper stoneState;
public static void init(BlockStateWrapper[] states, BlockStateWrapper state) {
if (blockStates != null) throw new IllegalStateException("block states are already set");
if (blockStates != null) throw new IllegalStateException("block states have already been set");
blockStates = states;
stoneState = state;
}
public static BlockStateWrapper stateByRegistryId(int vanillaId) {
if (vanillaId < 0) return stoneState;
return blockStates[vanillaId];
public static BlockStateWrapper byId(int stateId) {
if (stateId < 0) return stoneState;
return blockStates[stateId];
}
public static int size() {

View File

@@ -15,25 +15,20 @@ public final class BlockSounds {
Land 0.3 1
Destroy 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);
public static final BlockSounds EMPTY = new BlockSounds(SoundData.EMPTY, SoundData.EMPTY, SoundData.EMPTY, SoundData.EMPTY, SoundData.EMPTY);
private final SoundData breakSound;
private final SoundData stepSound;
private final SoundData placeSound;
private final SoundData hitSound;
private final SoundData fallSound;
private final SoundData landSound;
private final SoundData destroySound;
public BlockSounds(SoundData breakSound, SoundData stepSound, SoundData placeSound, SoundData hitSound, SoundData fallSound, SoundData landSound, SoundData destroySound) {
public BlockSounds(SoundData breakSound, SoundData stepSound, SoundData placeSound, SoundData hitSound, SoundData fallSound) {
this.breakSound = breakSound;
this.stepSound = stepSound;
this.placeSound = placeSound;
this.hitSound = hitSound;
this.fallSound = fallSound;
this.landSound = landSound;
this.destroySound = destroySound;
}
public static BlockSounds fromMap(Map<String, Object> map) {
@@ -43,16 +38,10 @@ public final class BlockSounds {
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)
SoundData.create(map.getOrDefault("fall", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.FIXED_0_75)
);
}
public SoundData destroySound() {
return destroySound;
}
public SoundData breakSound() {
return breakSound;
}
@@ -69,10 +58,6 @@ public final class BlockSounds {
return hitSound;
}
public SoundData landSound() {
return landSound;
}
public SoundData fallSound() {
return fallSound;
}

View File

@@ -5,10 +5,5 @@ import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityEl
import java.util.Optional;
public record BlockStateAppearance(int stateRegistryId, Optional<BlockEntityElementConfig<? extends BlockEntityElement>[]> blockEntityRenderer) {
public static final BlockStateAppearance INVALID = new BlockStateAppearance(-1, Optional.empty());
public boolean isInvalid() {
return this.stateRegistryId < 0;
}
public record BlockStateAppearance(BlockStateWrapper blockState, Optional<BlockEntityElementConfig<? extends BlockEntityElement>[]> blockEntityRenderer) {
}

View File

@@ -3,12 +3,12 @@ package net.momirealms.craftengine.core.block;
public class BlockStateVariant {
private final String appearance;
private final BlockSettings settings;
private final int internalId;
private final BlockStateWrapper blockState;
public BlockStateVariant(String appearance, BlockSettings settings, int internalId) {
public BlockStateVariant(String appearance, BlockSettings settings, BlockStateWrapper blockState) {
this.appearance = appearance;
this.settings = settings;
this.internalId = internalId;
this.blockState = blockState;
}
public String appearance() {
@@ -19,7 +19,7 @@ public class BlockStateVariant {
return settings;
}
public int internalRegistryId() {
return internalId;
public BlockStateWrapper blockState() {
return blockState;
}
}

View File

@@ -1,8 +1,12 @@
package net.momirealms.craftengine.core.block;
import net.momirealms.craftengine.core.util.Key;
public interface BlockStateWrapper {
Object literalObject();
int registryId();
Key ownerId();
}

View File

@@ -32,9 +32,11 @@ public interface DelegatingBlock {
*/
ObjectHolder<BlockBehavior> behaviorDelegate();
// 其实是错误的做法
@Deprecated
boolean isNoteBlock();
// 其实是错误的做法
@Deprecated
boolean isTripwire();
}

View File

@@ -15,8 +15,4 @@ public final class EmptyBlock extends AbstractCustomBlock {
INSTANCE = this;
STATE = defaultState();
}
@Override
protected void applyPlatformSettings() {
}
}

View File

@@ -16,10 +16,6 @@ public final class InactiveCustomBlock extends AbstractCustomBlock {
super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), List.of(), null);
}
@Override
protected void applyPlatformSettings() {
}
@Override
public ImmutableBlockState getBlockState(CompoundTag nbt) {
return this.cachedData.computeIfAbsent(nbt, k -> {

View File

@@ -5,5 +5,7 @@ public enum PushReaction {
DESTROY,
BLOCK,
IGNORE,
PUSH_ONLY
PUSH_ONLY;
public static final PushReaction[] VALUES = values();
}

View File

@@ -1,6 +1,5 @@
package net.momirealms.craftengine.core.block.properties;
import com.google.common.base.MoreObjects;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
import net.momirealms.craftengine.core.util.Direction;

View File

@@ -6,7 +6,7 @@ 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.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key;
@@ -31,7 +31,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
}
@Override
public ConfigParser parser() {
public IdSectionConfigParser parser() {
return this.furnitureParser;
}
@@ -74,7 +74,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager {
protected abstract CustomFurniture.Builder furnitureBuilder();
public class FurnitureParser implements ConfigParser {
public class FurnitureParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" };
@Override

View File

@@ -7,6 +7,7 @@ import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.pack.ResourceLocation;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
@@ -371,7 +372,7 @@ public abstract class AbstractFontManager implements FontManager {
return this.fonts.computeIfAbsent(key, Font::new);
}
public class EmojiParser implements ConfigParser {
public class EmojiParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"emoji", "emojis"};
@Override
@@ -438,7 +439,7 @@ public abstract class AbstractFontManager implements FontManager {
}
}
public class ImageParser implements ConfigParser {
public class ImageParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"images", "image"};
@Override

View File

@@ -22,6 +22,7 @@ import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectPrope
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.context.event.EventFunctions;
import net.momirealms.craftengine.core.plugin.context.event.EventTrigger;
@@ -267,7 +268,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
protected abstract void registerArmorTrimPattern(Collection<Key> equipments);
public class EquipmentParser implements ConfigParser {
public class EquipmentParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"equipments", "equipment"};
@Override
@@ -310,7 +311,7 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
}
}
public class ItemParser implements ConfigParser {
public class ItemParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"};
private boolean isModernFormatRequired() {

View File

@@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.Config;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.UniqueKey;
@@ -120,7 +121,7 @@ public abstract class AbstractRecipeManager<T> implements RecipeManager<T> {
return true;
}
public class RecipeParser implements ConfigParser {
public class RecipeParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"};
@Override

View File

@@ -27,9 +27,7 @@ import net.momirealms.craftengine.core.pack.obfuscation.ObfA;
import net.momirealms.craftengine.core.pack.revision.Revision;
import net.momirealms.craftengine.core.pack.revision.Revisions;
import net.momirealms.craftengine.core.plugin.CraftEngine;
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.config.*;
import net.momirealms.craftengine.core.plugin.locale.I18NData;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
@@ -374,6 +372,7 @@ public abstract class AbstractPackManager implements PackManager {
plugin.saveResource("resources/internal/configuration/fix_client_visual.yml");
plugin.saveResource("resources/internal/configuration/offset_chars.yml");
plugin.saveResource("resources/internal/configuration/gui.yml");
plugin.saveResource("resources/internal/configuration/mappings.yml");
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/offset/space_split.png");
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/item_browser.png");
plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/category.png");
@@ -609,6 +608,7 @@ public abstract class AbstractPackManager implements PackManager {
return cachedConfigs;
}
// todo 本地化日志
private void loadResourceConfigs(Predicate<ConfigParser> predicate) {
long o1 = System.nanoTime();
TreeMap<ConfigParser, List<CachedConfigSection>> cachedConfigs = this.updateCachedConfigFiles();
@@ -619,34 +619,62 @@ public abstract class AbstractPackManager implements PackManager {
if (!predicate.test(parser)) continue;
long t1 = System.nanoTime();
parser.preProcess();
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());
try {
if (parser.supportsParsingObject()) {
// do not apply templates
parser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue());
} else {
if (configEntry.getValue() instanceof Map<?, ?> configSection0) {
Map<String, Object> config = castToMap(configSection0, 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)) {
parser.parseSection(cached.pack(), cached.filePath(), id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false));
}
} else {
TranslationManager.instance().log("warning.config.structure.not_section", cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName());
}
switch (parser) {
case SectionConfigParser configParser -> {
for (CachedConfigSection cached : entry.getValue()) {
try {
configParser.parseSection(cached.pack(), cached.filePath(), cached.config());
} catch (LocalizedException e) {
printWarningRecursively(e, cached.filePath(), cached.prefix());
} catch (Exception e) {
this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "'. Please find the cause according to the stacktrace or seek developer help. Additional info: " + GsonHelper.get().toJson(cached.config()), e);
}
} catch (LocalizedException e) {
printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key);
} catch (Exception e) {
this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "." + key + "'. Please find the cause according to the stacktrace or seek developer help. Additional info: " + GsonHelper.get().toJson(configEntry.getValue()), e);
}
}
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());
try {
configParser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue());
} catch (LocalizedException e) {
printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key);
} catch (Exception e) {
this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "." + key + "'. Please find the cause according to the stacktrace or seek developer help. Additional info: " + GsonHelper.get().toJson(configEntry.getValue()), e);
}
}
}
}
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());
try {
if (configEntry.getValue() instanceof Map<?, ?> configSection0) {
Map<String, Object> config = castToMap(configSection0, 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)) {
configParser.parseSection(cached.pack(), cached.filePath(), id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false));
}
} else {
TranslationManager.instance().log("warning.config.structure.not_section", cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName());
}
} catch (LocalizedException e) {
printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key);
} catch (Exception e) {
this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "." + key + "'. Please find the cause according to the stacktrace or seek developer help. Additional info: " + GsonHelper.get().toJson(configEntry.getValue()), e);
}
}
}
}
default -> {
}
}
parser.postProcess();
long t2 = System.nanoTime();
this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms");
@@ -1722,7 +1750,7 @@ public abstract class AbstractPackManager implements PackManager {
soundJson = new JsonObject();
}
for (Map.Entry<Key, Key> mapper : plugin.blockManager().soundMapper().entrySet()) {
for (Map.Entry<Key, Key> mapper : plugin.blockManager().soundReplacements().entrySet()) {
Key originalKey = mapper.getKey();
JsonObject empty = new JsonObject();
empty.add("sounds", new JsonArray());

View File

@@ -4,6 +4,7 @@ public final class LoadingSequence {
private LoadingSequence() {}
public static final int TEMPLATE = 0;
public static final int BLOCK_STATE_MAPPING = 5;
public static final int GLOBAL_VAR = 10;
public static final int LANG = 20;
public static final int TRANSLATION = 30;

View File

@@ -92,6 +92,8 @@ public abstract class CraftEngine implements Plugin {
protected CraftEngine(Consumer<CraftEngine> reloadEventDispatcher) {
instance = this;
this.reloadEventDispatcher = reloadEventDispatcher;
((Logger) LogManager.getRootLogger()).addFilter(new LogFilter());
((Logger) LogManager.getRootLogger()).addFilter(new DisconnectLogFilter());
}
public static CraftEngine instance() {
@@ -105,9 +107,6 @@ public abstract class CraftEngine implements Plugin {
RecipeDisplayTypes.init();
SlotDisplayTypes.init();
LegacyRecipeTypes.init();
((Logger) LogManager.getRootLogger()).addFilter(new LogFilter());
((Logger) LogManager.getRootLogger()).addFilter(new DisconnectLogFilter());
this.config.load();
}
public record ReloadResult(boolean success, long asyncTime, long syncTime) {
@@ -281,7 +280,7 @@ public abstract class CraftEngine implements Plugin {
// register furniture parser
this.packManager.registerConfigSectionParser(this.furnitureManager.parser());
// register block parser
this.packManager.registerConfigSectionParser(this.blockManager.parser());
this.packManager.registerConfigSectionParsers(this.blockManager.parsers());
// register recipe parser
this.packManager.registerConfigSectionParser(this.recipeManager.parser());
// register category parser

View File

@@ -44,6 +44,7 @@ public class Config {
protected boolean checkUpdate;
protected boolean metrics;
protected boolean filterConfigurationPhaseDisconnect;
protected Locale forcedLocale;
protected boolean debug$common;
protected boolean debug$packet;
@@ -123,7 +124,7 @@ public class Config {
protected int block$predict_breaking_interval;
protected double block$extended_interaction_range;
protected boolean block$chunk_relighter;
protected int block$serverside_blocks;
protected int block$serverside_blocks = -1;
protected boolean recipe$enable;
protected boolean recipe$disable_vanilla_recipes$all;
@@ -177,7 +178,7 @@ public class Config {
instance = this;
}
public void load() {
public boolean updateConfigCache() {
// 文件不存在,则保存
if (!Files.exists(this.configFilePath)) {
this.plugin.saveResource("config.yml");
@@ -195,13 +196,20 @@ public class Config {
this.updateConfigVersion(configFileBytes);
}
}
// 加载配置文件
this.loadSettings();
this.lastModified = lastModified;
this.size = size;
return true;
}
} catch (IOException e) {
this.plugin.logger().severe("Failed to load config.yml", e);
this.plugin.logger().severe("Failed to update config.yml", e);
}
return false;
}
public void load() {
boolean isUpdated = updateConfigCache();
if (isUpdated) {
loadFullSettings();
}
}
@@ -240,9 +248,14 @@ public class Config {
}
}
private void loadSettings() {
public void loadForcedLocale() {
YamlDocument config = settings();
plugin.translationManager().forcedLocale(TranslationManager.parseLocale(config.getString("forced-locale", "")));
forcedLocale = TranslationManager.parseLocale(config.getString("forced-locale", ""));
}
public void loadFullSettings() {
YamlDocument config = settings();
forcedLocale = TranslationManager.parseLocale(config.getString("forced-locale", ""));
// basics
metrics = config.getBoolean("metrics", false);
@@ -379,7 +392,7 @@ public class Config {
equipment$sacrificed_vanilla_armor$humanoid_leggings = Key.of(config.getString("equipment.sacrificed-vanilla-armor.humanoid-leggings", "minecraft:trims/entity/humanoid_leggings/chainmail"));
// item
item$client_bound_model = config.getBoolean("item.client-bound-model", false);
item$client_bound_model = config.getBoolean("item.client-bound-model", true) && VersionHelper.PREMIUM;
item$non_italic_tag = config.getBoolean("item.non-italic-tag", false);
item$update_triggers$attack = config.getBoolean("item.update-triggers.attack", false);
item$update_triggers$click_in_inventory = config.getBoolean("item.update-triggers.click-in-inventory", false);
@@ -394,7 +407,10 @@ public class Config {
block$predict_breaking_interval = Math.max(config.getInt("block.predict-breaking.interval", 10), 1);
block$extended_interaction_range = Math.max(config.getDouble("block.predict-breaking.extended-interaction-range", 0.5), 0.0);
block$chunk_relighter = config.getBoolean("block.chunk-relighter", true);
block$serverside_blocks = config.getInt("block.serverside-blocks", 2000);
if (firstTime) {
block$serverside_blocks = config.getInt("block.serverside-blocks", 2000);
if (block$serverside_blocks < 0) block$serverside_blocks = 0;
}
// recipe
recipe$enable = config.getBoolean("recipe.enable", true);
@@ -445,6 +461,10 @@ public class Config {
return MinecraftVersion.parse(version);
}
public static Locale forcedLocale() {
return instance.forcedLocale;
}
public static String configVersion() {
return instance.configVersion;
}
@@ -465,6 +485,10 @@ public class Config {
return false;
}
public static boolean debugBlock() {
return false;
}
public static boolean debugFurniture() {
return instance.debug$furniture;
}

View File

@@ -1,30 +1,13 @@
package net.momirealms.craftengine.core.plugin.config;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.util.Key;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
import java.util.Map;
public interface ConfigParser extends Comparable<ConfigParser> {
String[] sectionId();
default void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) throws LocalizedException {
this.parseObject(pack, path, id, section);
}
default void parseObject(Pack pack, Path path, Key id, Object object) throws LocalizedException {
}
int loadingSequence();
default boolean supportsParsingObject() {
return false;
}
@Override
default int compareTo(@NotNull ConfigParser another) {
return Integer.compare(loadingSequence(), another.loadingSequence());

View File

@@ -0,0 +1,13 @@
package net.momirealms.craftengine.core.plugin.config;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.util.Key;
import java.nio.file.Path;
public interface IdObjectConfigParser extends ConfigParser {
default void parseObject(Pack pack, Path path, Key id, Object object) throws LocalizedException {
}
}

View File

@@ -0,0 +1,14 @@
package net.momirealms.craftengine.core.plugin.config;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import net.momirealms.craftengine.core.util.Key;
import java.nio.file.Path;
import java.util.Map;
public interface IdSectionConfigParser extends ConfigParser {
default void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) throws LocalizedException {
}
}

View File

@@ -0,0 +1,13 @@
package net.momirealms.craftengine.core.plugin.config;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import java.nio.file.Path;
import java.util.Map;
public interface SectionConfigParser extends ConfigParser {
default void parseSection(Pack pack, Path path, Map<String, Object> section) throws LocalizedException {
}
}

View File

@@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.plugin.config.template;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdObjectConfigParser;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.MiscUtils;
@@ -36,7 +37,7 @@ public class TemplateManagerImpl implements TemplateManager {
return this.templateParser;
}
public class TemplateParser implements ConfigParser {
public class TemplateParser implements IdObjectConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"};
@Override
@@ -49,11 +50,6 @@ public class TemplateManagerImpl implements TemplateManager {
return LoadingSequence.TEMPLATE;
}
@Override
public boolean supportsParsingObject() {
return true;
}
@Override
public void parseObject(Pack pack, Path path, Key id, Object obj) {
if (templates.containsKey(id)) {

View File

@@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.Manageable;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdObjectConfigParser;
import net.momirealms.craftengine.core.plugin.locale.LocalizedException;
import org.jetbrains.annotations.Nullable;
@@ -34,7 +35,7 @@ public class GlobalVariableManager implements Manageable {
return this.parser;
}
public class GlobalVariableParser implements ConfigParser {
public class GlobalVariableParser implements IdObjectConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"global-variables", "global-variable"};
@Override
@@ -47,11 +48,6 @@ public class GlobalVariableManager implements Manageable {
return CONFIG_SECTION_NAME;
}
@Override
public boolean supportsParsingObject() {
return true;
}
@Override
public void parseObject(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Object object) throws LocalizedException {
if (object != null) {

View File

@@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.context.ContextHolder;
import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext;
import net.momirealms.craftengine.core.plugin.gui.*;
@@ -95,7 +96,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager {
return Optional.ofNullable(this.byId.get(key));
}
public class CategoryParser implements ConfigParser {
public class CategoryParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"categories", "category"};
@Override

View File

@@ -50,8 +50,6 @@ public interface TranslationManager extends Manageable {
return miniMessageTranslation(key, null);
}
void forcedLocale(Locale locale);
String miniMessageTranslation(String key, @Nullable Locale locale);
default Component render(Component component) {

View File

@@ -7,9 +7,7 @@ import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.Plugin;
import net.momirealms.craftengine.core.plugin.PluginProperties;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor;
import net.momirealms.craftengine.core.plugin.config.TranslationConfigConstructor;
import net.momirealms.craftengine.core.plugin.config.*;
import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag;
import net.momirealms.craftengine.core.util.AdventureHelper;
import org.jetbrains.annotations.NotNull;
@@ -38,7 +36,6 @@ public class TranslationManagerImpl implements TranslationManager {
private final String langVersion;
private final String[] supportedLanguages;
private final Map<String, String> translationFallback = new LinkedHashMap<>();
private Locale forcedLocale = null;
private Locale selectedLocale = DEFAULT_LOCALE;
private MiniMessageTranslationRegistry registry;
private final Map<String, I18NData> clientLangData = new HashMap<>();
@@ -67,11 +64,6 @@ public class TranslationManagerImpl implements TranslationManager {
return new ConfigParser[] {this.langParser, this.i18nParser};
}
@Override
public void forcedLocale(Locale locale) {
this.forcedLocale = locale;
}
@Override
public void delayedLoad() {
this.clientLangData.values().forEach(I18NData::processTranslations);
@@ -98,8 +90,8 @@ public class TranslationManagerImpl implements TranslationManager {
}
private void setSelectedLocale() {
if (this.forcedLocale != null) {
this.selectedLocale = forcedLocale;
if (Config.forcedLocale() != null) {
this.selectedLocale = Config.forcedLocale();
return;
}
@@ -251,7 +243,7 @@ public class TranslationManagerImpl implements TranslationManager {
}
}
public class I18NParser implements ConfigParser {
public class I18NParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"};
@Override
@@ -282,7 +274,7 @@ public class TranslationManagerImpl implements TranslationManager {
}
}
public class LangParser implements ConfigParser {
public class LangParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"};
@Override

View File

@@ -11,6 +11,7 @@ public enum Debugger {
FURNITURE(Config::debugFurniture),
RESOURCE_PACK(Config::debugResourcePack),
ITEM(Config::debugItem),
BLOCK(Config::debugBlock),
BLOCK_ENTITY(Config::debugBlockEntity);
private final Supplier<Boolean> condition;

View File

@@ -97,6 +97,7 @@ public interface NetWorkUser {
void removeTrackedChunk(long chunkPos);
@Nullable
IntIdentityList clientBlockList();
void setClientBlockList(IntIdentityList integers);

View File

@@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.config.ConfigParser;
import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.*;
@@ -65,7 +66,7 @@ public abstract class AbstractSoundManager implements SoundManager {
protected abstract void registerSounds(Collection<Key> sounds);
public class SongParser implements ConfigParser {
public class SongParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "jukebox_song", "jukebox-songs", "jukebox-song"};
@Override
@@ -92,7 +93,7 @@ public abstract class AbstractSoundManager implements SoundManager {
}
}
public class SoundParser implements ConfigParser {
public class SoundParser implements IdSectionConfigParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"};
@Override

View File

@@ -10,6 +10,7 @@ import java.util.Optional;
import java.util.function.Supplier;
public record SoundData(Key id, SoundValue volume, SoundValue pitch) {
public static final SoundData EMPTY = new SoundData(Key.of("minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1);
public static SoundData create(Object obj, SoundValue volume, SoundValue pitch) {
if (obj instanceof String key) {

View File

@@ -34,4 +34,6 @@ public enum Instrument {
public String id() {
return id;
}
public static final Instrument[] VALUES = Instrument.values();
}