9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-26 18:39:20 +00:00

重构配置读取,允许状态多绑一

This commit is contained in:
XiaoMoMi
2025-08-20 21:38:18 +08:00
parent c54ce3b660
commit 9b3c2e767d
10 changed files with 119 additions and 282 deletions

View File

@@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
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.ResourceLocation;
@@ -14,6 +15,7 @@ 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.context.event.EventFunctions;
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
import net.momirealms.craftengine.core.util.GsonHelper;
import net.momirealms.craftengine.core.util.Key;
@@ -24,8 +26,10 @@ import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager {
protected final BlockParser blockParser;
// CraftEngine objects
protected final Map<Key, CustomBlock> byId = new HashMap<>();
// Cached command suggestions
@@ -44,15 +48,19 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
protected final Map<Key, Map<String, JsonElement>> blockStateOverrides = new HashMap<>();
// a reverted mapper
protected final Map<Integer, List<Integer>> appearanceToRealState = new Int2ObjectOpenHashMap<>();
// 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) {
super(plugin);
this.blockParser = new BlockParser();
}
@Override
@@ -85,8 +93,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
return Optional.ofNullable(this.byId.get(id));
}
@Override
public void addBlock(Key id, CustomBlock customBlock) {
protected void addBlockInternal(Key id, CustomBlock customBlock) {
this.byId.put(id, customBlock);
// generate mod assets
if (Config.generateModAssets()) {
@@ -96,6 +103,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
}
}
@Override
public ConfigParser parser() {
return this.blockParser;
}
@Override
public Map<Key, JsonElement> modBlockStates() {
return Collections.unmodifiableMap(this.modBlockStates);
@@ -148,7 +160,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
protected abstract int getBlockRegistryId(Key id);
public abstract String stateRegistryIdToStateSNBT(int 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 {
public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"};
@@ -210,14 +226,56 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
// 设置参数
properties = Map.of();
appearances = Map.of("", appearanceId);
variants = Map.of("", new BlockStateVariant("", settings, internalId));
variants = Map.of("", new BlockStateVariant("", settings, getInternalBlockId(internalId, appearanceId)));
}
// 多方块状态
else {
properties = parseBlockProperties(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), "properties"));
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 -> appearances.getOrDefault(it, -1), settings
);
}
addBlockInternal(id, platformBuilder(id)
.appearances(appearances)
.variantMapper(variants)
.properties(properties)
.settings(settings)
.lootTable(LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot")))
.behavior(MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors")))
.events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")))
.build());
}
private Map<String, BlockStateVariant> parseBlockVariants(Map<String, Object> variantsSection,
Function<String, Integer> 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) {
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);
Map<String, Object> anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings");
variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? parentSettings : BlockSettings.ofFullCopy(parentSettings, anotherSetting), internalId));
}
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));
}
return internalBlockRegistryId;
}
private Map<String, Integer> parseBlockAppearances(Map<String, Object> appearancesSection) {
@@ -265,11 +323,12 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem
String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']'));
// 结合variants
JsonElement combinedVariant = GsonHelper.combine(variants);
JsonElement previous = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()).put(propertyNBT, combinedVariant);
Map<String, JsonElement> overrideMap = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>());
JsonElement previous = overrideMap.get(propertyNBT);
if (previous != null && !previous.equals(combinedVariant)) {
// todo 播报可能的冲突
plugin.logger().warn("warning 1");
throw new LocalizedResourceConfigException("warning.config.block.state.model.conflict", GsonHelper.get().toJson(combinedVariant), blockState, GsonHelper.get().toJson(previous));
}
overrideMap.put(propertyNBT, combinedVariant);
}
private JsonObject parseAppearanceModelSectionAsJson(Map<String, Object> section) {

View File

@@ -64,6 +64,10 @@ public abstract class AbstractCustomBlock implements CustomBlock {
if (tag == null) {
throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString);
}
List<ImmutableBlockState> possibleStates = this.getPossibleStates(tag);
if (possibleStates.size() != 1) {
throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString);
}
BlockStateVariant blockStateVariant = entry.getValue();
int vanillaStateRegistryId = appearances.getOrDefault(blockStateVariant.appearance(), -1);
// This should never happen
@@ -71,15 +75,14 @@ public abstract class AbstractCustomBlock implements CustomBlock {
vanillaStateRegistryId = appearances.values().iterator().next();
}
// Late init states
for (ImmutableBlockState state : this.getPossibleStates(tag)) {
state.setBehavior(this.behavior);
state.setSettings(blockStateVariant.settings());
state.setVanillaBlockState((BlockStateWrapper.VanillaBlockState) BlockRegistryMirror.stateByRegistryId(vanillaStateRegistryId));
state.setCustomBlockState((BlockStateWrapper.CustomBlockState) BlockRegistryMirror.stateByRegistryId(blockStateVariant.internalRegistryId()));
}
ImmutableBlockState state = possibleStates.getFirst();
state.setSettings(blockStateVariant.settings());
state.setVanillaBlockState((BlockStateWrapper.VanillaBlockState) BlockRegistryMirror.stateByRegistryId(vanillaStateRegistryId));
state.setCustomBlockState((BlockStateWrapper.CustomBlockState) BlockRegistryMirror.stateByRegistryId(blockStateVariant.internalRegistryId()));
}
// double check if there's any invalid state
for (ImmutableBlockState state : this.variantProvider().states()) {
state.setBehavior(this.behavior);
if (state.settings() == null) {
state.setSettings(settings);
}

View File

@@ -28,8 +28,6 @@ public interface BlockManager extends Manageable, ModelGenerator {
Optional<CustomBlock> blockById(Key key);
void addBlock(Key id, CustomBlock customBlock);
Collection<Suggestion> cachedSuggestions();
Map<Key, Key> soundMapper();

View File

@@ -6,13 +6,10 @@ import net.momirealms.craftengine.core.item.ItemBuildContext;
import net.momirealms.craftengine.core.item.ItemDataModifierFactory;
import net.momirealms.craftengine.core.plugin.CraftEngine;
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.util.VersionHelper;
import net.momirealms.sparrow.nbt.CompoundTag;
import net.momirealms.sparrow.nbt.Tag;
import java.util.List;
import java.util.Map;
import java.util.Optional;

View File

@@ -212,4 +212,15 @@ public final class ResourceConfigUtils {
}
throw new LocalizedResourceConfigException("warning.config.type.map", String.valueOf(obj), option);
}
@SuppressWarnings("unchecked")
public static Map<String, Object> getAsMapOrNull(Object obj, String option) {
if (obj == null) {
return null;
}
if (obj instanceof Map<?, ?> map) {
return (Map<String, Object>) map;
}
throw new LocalizedResourceConfigException("warning.config.type.map", String.valueOf(obj), option);
}
}

View File

@@ -16,7 +16,10 @@ import java.util.List;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.IntUnaryOperator;
import java.util.function.Predicate;
import java.util.stream.LongStream;
public class PalettedContainer<T> implements PaletteResizeListener<T>, ReadableContainer<T> {