mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 09:59:20 +00:00
Merge branch 'Xiao-MoMi:dev' into dev
This commit is contained in:
@@ -82,10 +82,19 @@ warning.config.item.custom_model_data_conflict: "<yellow>Issue found in file <ar
|
||||
warning.config.item.lack_model_id: "<yellow>Issue found in file <arg:0> - The item '<arg:1>' is missing the required 'custom-model-data' or 'item-model' argument.</yellow>"
|
||||
warning.config.block.duplicated: "<yellow>Issue found in file <arg:0> - Duplicated block '<arg:1>'.</yellow>"
|
||||
warning.config.block.lack_state: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'state' argument.</yellow>"
|
||||
warning.config.block.lack_real_id: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'id' argument for 'state'.</yellow>"
|
||||
warning.config.block.state.lack_real_id: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'id' argument for 'state'.</yellow>"
|
||||
warning.config.block.state.lack_state: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'state' argument for 'state'.</yellow>"
|
||||
warning.config.block.state.lack_properties: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'properties' section for 'states'.</yellow>"
|
||||
warning.config.block.state.lack_appearances: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'appearances' section for 'states'.</yellow>"
|
||||
warning.config.block.state.lack_variants: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'variants' section for 'states'.</yellow>"
|
||||
warning.config.block.state.variant.lack_appearance: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'appearance' argument for variant '<arg:2>'.</yellow>"
|
||||
warning.config.block.state.variant.invalid_appearance: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' has an error that the variant '<arg:2>' is using a non-existing appearance '<arg:3>'.</yellow>"
|
||||
warning.config.block.state.variant.invalid_appearance: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' has an error that the variant '<arg:2>' is using a non-existing appearance '<arg:3>'.</yellow>"
|
||||
warning.config.block.state.invalid_state: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is using an invalid vanilla block state '<arg:2>'."
|
||||
warning.config.block.state.unavailable_state: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is using an unavailable vanilla block state '<arg:2>'."
|
||||
warning.config.block.state.invalid_vanilla_state_id: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is using a vanilla block state '<arg:2>' that exceeds the available slot range '0~<arg:3>'."
|
||||
warning.config.block.state.conflict: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is using a vanilla block state '<arg:2>' that has been occupied by '<arg:3>'."
|
||||
warning.config.block.bind_real_state: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' failed to bind real block state for '<arg:2>' as the state has been occupied by '<arg:3>'.</yellow>"
|
||||
warning.config.block.state.invalid_property_structure: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' has an invalid property structure '<arg:2>'."
|
||||
warning.config.block.state.invalid_property: "<yellow>Issue found in file <arg:0> - Failed to create property '<arg:2>' for block '<arg:1>': <arg:3>."
|
||||
warning.config.block.state.no_model_set: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'model' or 'models' argument.</yellow>"
|
||||
warning.config.block.state.invalid_real_state_id: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is using a real block state '<arg:2>' that exceeds the available slot range '0~<arg:3>'. Consider adding more real states in 'additional-real-blocks.yml' if the slots are used up.</yellow>"
|
||||
@@ -82,7 +82,7 @@ warning.config.item.custom_model_data_conflict: "<yellow>在文件 <arg:0> 中
|
||||
warning.config.item.lack_model_id: "<yellow>在文件 <arg:0> 中发现问题 - 物品 '<arg:1>' 缺少必要的 'custom-model-data' 或 'item-model' 模型标识参数</yellow>"
|
||||
warning.config.block.duplicated: "<yellow>在文件 <arg:0> 中发现问题 - 方块 '<arg:1>' 重复定义</yellow>"
|
||||
warning.config.block.lack_state: "<yellow>在文件 <arg:0> 中发现问题 - 方块 '<arg:1>' 缺少必要的 'state' 状态参数</yellow>"
|
||||
warning.config.block.lack_real_id: "<yellow>在文件 <arg:0> 中发现问题 - 方块 '<arg:1>' 的 'state' 配置缺少必要的 'id' 标识参数</yellow>"
|
||||
warning.config.block.state.lack_real_id: "<yellow>在文件 <arg:0> 中发现问题 - 方块 '<arg:1>' 的 'state' 配置缺少必要的 'id' 标识参数</yellow>"
|
||||
warning.config.block.state.lack_state: "<yellow>在文件 <arg:0> 中发现问题 - 方块 '<arg:1>' 的 'state' 配置缺少必要的 'state' 状态参数</yellow>"
|
||||
warning.config.block.state.lack_properties: "<yellow>在文件 <arg:0> 中发现问题 - 方块 '<arg:1>' 的 'states' 配置缺少必要的 'properties' 属性配置</yellow>"
|
||||
warning.config.block.state.lack_appearances: "<yellow>在文件 <arg:0> 中发现问题 - 方块 '<arg:1>' 的 'states' 配置缺少必要的 'appearances' 外观配置</yellow>"
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class CraftEngineBlocks {
|
||||
*/
|
||||
@Nullable
|
||||
public static CustomBlock byId(@NotNull Key id) {
|
||||
return BukkitBlockManager.instance().getBlock(id).orElse(null);
|
||||
return BukkitBlockManager.instance().blockById(id).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,6 @@ import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.incendo.cloud.suggestion.Suggestion;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -59,11 +58,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
// The total amount of blocks registered
|
||||
private int customBlockCount;
|
||||
|
||||
// CraftEngine objects
|
||||
private final Map<Key, CustomBlock> byId = new HashMap<>();
|
||||
private final ImmutableBlockState[] stateId2ImmutableBlockStates;
|
||||
|
||||
protected final ImmutableBlockState[] stateId2ImmutableBlockStates;
|
||||
// Minecraft objects
|
||||
// Cached new blocks $ holders
|
||||
private ImmutableMap<Key, Integer> internalId2StateId;
|
||||
@@ -87,14 +82,9 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
private final Map<Key, Map<String, JsonElement>> blockStateOverrides = new HashMap<>();
|
||||
// for mod, real block id -> state models
|
||||
private final Map<Key, JsonElement> modBlockStates = new HashMap<>();
|
||||
// Cached command suggestions
|
||||
private final List<Suggestion> cachedSuggestions = new ArrayList<>();
|
||||
// Cached Namespace
|
||||
private final Set<String> namespacesInUse = new HashSet<>();
|
||||
// Event listeners
|
||||
private final BlockEventListener blockEventListener;
|
||||
private final FallingBlockRemoveListener fallingBlockRemoveListener;
|
||||
|
||||
private WorldEditCommandHelper weCommandHelper;
|
||||
|
||||
public BukkitBlockManager(BukkitCraftEngine plugin) {
|
||||
@@ -106,7 +96,7 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
if (plugin.hasMod() && plugin.requiresRestart()) {
|
||||
blockEventListener = null;
|
||||
fallingBlockRemoveListener = null;
|
||||
stateId2ImmutableBlockStates = null;
|
||||
stateId2ImmutableBlockStates = new ImmutableBlockState[]{};
|
||||
return;
|
||||
}
|
||||
this.registerBlocks();
|
||||
@@ -152,11 +142,9 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
super.clearModelsToGenerate();
|
||||
super.unload();
|
||||
this.clearCache();
|
||||
this.appearanceToRealState.clear();
|
||||
this.byId.clear();
|
||||
this.cachedSuggestions.clear();
|
||||
this.blockStateOverrides.clear();
|
||||
this.modBlockStates.clear();
|
||||
if (EmptyBlock.INSTANCE != null)
|
||||
@@ -236,41 +224,6 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
return Collections.unmodifiableMap(this.blockStateOverrides);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, CustomBlock> blocks() {
|
||||
return Collections.unmodifiableMap(this.byId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CustomBlock> getBlock(Key key) {
|
||||
return Optional.ofNullable(this.byId.get(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Suggestion> cachedSuggestions() {
|
||||
return Collections.unmodifiableCollection(this.cachedSuggestions);
|
||||
}
|
||||
|
||||
private void initSuggestions() {
|
||||
this.cachedSuggestions.clear();
|
||||
this.namespacesInUse.clear();
|
||||
Set<String> states = new HashSet<>();
|
||||
for (CustomBlock block : this.byId.values()) {
|
||||
states.add(block.id().toString());
|
||||
this.namespacesInUse.add(block.id().namespace());
|
||||
for (ImmutableBlockState state : block.variantProvider().states()) {
|
||||
states.add(state.toString());
|
||||
}
|
||||
}
|
||||
for (String state : states) {
|
||||
this.cachedSuggestions.add(Suggestion.suggestion(state));
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> namespacesInUse() {
|
||||
return Collections.unmodifiableSet(this.namespacesInUse);
|
||||
}
|
||||
|
||||
public ImmutableMap<Key, List<Integer>> blockAppearanceArranger() {
|
||||
return blockAppearanceArranger;
|
||||
}
|
||||
@@ -392,11 +345,11 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
@Override
|
||||
public void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) {
|
||||
// check duplicated config
|
||||
if (byId.containsKey(id)) {
|
||||
TranslationManager.instance().log("warning.config.block.duplicated", path.toString(), id.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
// read block settings
|
||||
BlockSettings settings = BlockSettings.fromMap(MiscUtils.castToMap(section.getOrDefault("settings", Map.of()), false));
|
||||
// read loot table
|
||||
@@ -410,38 +363,46 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
properties = Map.of();
|
||||
int internalId = MiscUtils.getAsInt(stateSection.getOrDefault("id", -1));
|
||||
if (internalId < 0) {
|
||||
TranslationManager.instance().log("warning.config.block.lack_real_id", path.toString(), id.toString());
|
||||
TranslationManager.instance().log("warning.config.block.state.lack_real_id", path.toString(), id.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
Pair<Key, Integer> pair = parseAppearanceSection(path, id, stateSection);
|
||||
if (pair == null) return;
|
||||
|
||||
appearances = Map.of("default", pair.right());
|
||||
Key internalBlockId = Key.of(CraftEngine.NAMESPACE, pair.left().value() + "_" + internalId);
|
||||
int internalBlockRegistryId = MiscUtils.getAsInt(internalId2StateId.getOrDefault(internalBlockId, -1));
|
||||
if (internalBlockRegistryId == -1) {
|
||||
plugin.logger().warn(path, "Failed to register " + id + " because id " + internalId + " is not a value between 0~" + (MiscUtils.getAsInt(registeredRealBlockSlots.get(pair.left()))-1) +
|
||||
". Consider editing additional-real-blocks.yml if the number of real block IDs is insufficient while there are still available appearances");
|
||||
TranslationManager.instance().log("warning.config.block.state.invalid_real_state_id",
|
||||
path.toString(),
|
||||
id.toString(),
|
||||
pair.left().value() + "_" + internalId,
|
||||
String.valueOf(MiscUtils.getAsInt(registeredRealBlockSlots.get(pair.left()))-1)
|
||||
);
|
||||
return;
|
||||
}
|
||||
variants = Map.of("", new VariantState("default", settings, internalBlockRegistryId));
|
||||
} else {
|
||||
// states
|
||||
Map<String, Object> statesSection = MiscUtils.castToMap(section.get("states"), true);
|
||||
if (statesSection == null) {
|
||||
TranslationManager.instance().log("warning.config.block.lack_state", path.toString(), id.toString());
|
||||
return;
|
||||
}
|
||||
// properties
|
||||
Map<String, Object> propertySection = MiscUtils.castToMap(statesSection.get("properties"), true);
|
||||
if (propertySection == null) {
|
||||
TranslationManager.instance().log("warning.config.block.state.lack_properties", path.toString(), id.toString());
|
||||
return;
|
||||
}
|
||||
properties = parseProperties(path, propertySection);
|
||||
properties = parseProperties(path, id, propertySection);
|
||||
// appearance
|
||||
Map<String, Object> appearancesSection = MiscUtils.castToMap(statesSection.get("appearances"), true);
|
||||
if (appearancesSection == null) {
|
||||
TranslationManager.instance().log("warning.config.block.state.lack_appearances", path.toString(), id.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
appearances = new HashMap<>();
|
||||
Map<String, Key> tempTypeMap = new HashMap<>();
|
||||
for (Map.Entry<String, Object> appearanceEntry : appearancesSection.entrySet()) {
|
||||
@@ -452,13 +413,12 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
tempTypeMap.put(appearanceEntry.getKey(), pair.left());
|
||||
}
|
||||
}
|
||||
|
||||
// variants
|
||||
Map<String, Object> variantsSection = MiscUtils.castToMap(statesSection.get("variants"), true);
|
||||
if (variantsSection == null) {
|
||||
TranslationManager.instance().log("warning.config.block.state.lack_variants", path.toString(), id.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
variants = new HashMap<>();
|
||||
for (Map.Entry<String, Object> variantEntry : variantsSection.entrySet()) {
|
||||
if (variantEntry.getValue() instanceof Map<?, ?> variantSection0) {
|
||||
@@ -478,8 +438,12 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
Key internalBlockId = Key.of(CraftEngine.NAMESPACE, baseBlock.value() + "_" + internalId);
|
||||
int internalBlockRegistryId = MiscUtils.getAsInt(internalId2StateId.getOrDefault(internalBlockId, -1));
|
||||
if (internalBlockRegistryId == -1) {
|
||||
plugin.logger().warn(path, "Failed to register " + id + " because id " + internalId + " is not a value between 0~" + (MiscUtils.getAsInt(registeredRealBlockSlots.getOrDefault(baseBlock, 1))-1) +
|
||||
". Consider editing additional-real-blocks.yml if the number of real block IDs is insufficient while there are still available appearances");
|
||||
TranslationManager.instance().log("warning.config.block.state.invalid_real_state_id",
|
||||
path.toString(),
|
||||
id.toString(),
|
||||
internalBlockId.toString(),
|
||||
String.valueOf(MiscUtils.getAsInt(registeredRealBlockSlots.getOrDefault(baseBlock, 1)) - 1)
|
||||
);
|
||||
return;
|
||||
}
|
||||
Map<String, Object> anotherSetting = MiscUtils.castToMap(variantSection.get("settings"), true);
|
||||
@@ -487,18 +451,27 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create or get block holder
|
||||
Holder.Reference<CustomBlock> holder = BuiltInRegistries.BLOCK.get(id).orElseGet(() ->
|
||||
((WritableRegistry<CustomBlock>) BuiltInRegistries.BLOCK).registerForHolder(new ResourceKey<>(BuiltInRegistries.BLOCK.key().location(), id)));
|
||||
// create block
|
||||
Map<String, Object> behaviorSection = MiscUtils.castToMap(section.getOrDefault("behavior", Map.of()), false);
|
||||
|
||||
BukkitCustomBlock block = new BukkitCustomBlock(id, holder, properties, appearances, variants, settings, behaviorSection, lootTable);
|
||||
|
||||
// bind appearance
|
||||
bindAppearance(block);
|
||||
byId.put(id, block);
|
||||
// bind appearance and real state
|
||||
for (ImmutableBlockState state : block.variantProvider().states()) {
|
||||
ImmutableBlockState previous = stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()];
|
||||
if (previous != null && !previous.isEmpty()) {
|
||||
TranslationManager.instance().log("warning.config.block.bind_real_state", path.toString(), id.toString(), state.toString(), previous.toString());
|
||||
continue;
|
||||
}
|
||||
stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state;
|
||||
tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId());
|
||||
appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new ArrayList<>()).add(state.customBlockState().registryId());
|
||||
}
|
||||
|
||||
byId.put(id, block);
|
||||
// generate mod assets
|
||||
if (Config.generateModAssets()) {
|
||||
for (ImmutableBlockState state : block.variantProvider().states()) {
|
||||
@@ -509,27 +482,18 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void bindAppearance(CustomBlock block) {
|
||||
for (ImmutableBlockState state : block.variantProvider().states()) {
|
||||
ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()];
|
||||
if (previous != null && !previous.isEmpty()) {
|
||||
this.plugin.logger().severe("[Fatal] Failed to bind real block state for " + state + ": the state is already occupied by " + previous);
|
||||
continue;
|
||||
}
|
||||
this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state;
|
||||
this.tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId());
|
||||
this.appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new ArrayList<>()).add(state.customBlockState().registryId());
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Property<?>> parseProperties(Path path, Map<String, Object> propertiesSection) {
|
||||
private Map<String, Property<?>> parseProperties(Path path, Key id, Map<String, Object> propertiesSection) {
|
||||
Map<String, Property<?>> properties = new HashMap<>();
|
||||
for (Map.Entry<String, Object> entry : propertiesSection.entrySet()) {
|
||||
if (entry.getValue() instanceof Map<?, ?> params) {
|
||||
Property<?> property = Properties.fromMap(entry.getKey(), MiscUtils.castToMap(params, false));
|
||||
properties.put(entry.getKey(), property);
|
||||
try {
|
||||
Property<?> property = Properties.fromMap(entry.getKey(), MiscUtils.castToMap(params, false));
|
||||
properties.put(entry.getKey(), property);
|
||||
} catch (Exception e) {
|
||||
TranslationManager.instance().log("warning.config.block.state.invalid_property", path.toString(), id.toString(), entry.getKey(), e.getMessage());
|
||||
}
|
||||
} else {
|
||||
this.plugin.logger().warn(path, "Invalid property format: " + entry.getKey());
|
||||
TranslationManager.instance().log("warning.config.block.state.invalid_property_structure", path.toString(), id.toString(), entry.getKey());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
@@ -537,25 +501,41 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
|
||||
@Nullable
|
||||
private Pair<Key, Integer> parseAppearanceSection(Path path, Key id, Map<String, Object> section) {
|
||||
// require state non null
|
||||
String vanillaStateString = (String) section.get("state");
|
||||
if (vanillaStateString == null) {
|
||||
TranslationManager.instance().log("warning.config.block.state.lack_state", path.toString(), id.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
// get its registry id
|
||||
int vanillaStateRegistryId;
|
||||
try {
|
||||
vanillaStateRegistryId = parseVanillaStateRegistryId(vanillaStateString);
|
||||
} catch (BlockStateArrangeException e) {
|
||||
this.plugin.logger().warn(path, "Failed to load " + id + " - " + e.getMessage(), e);
|
||||
VanillaStateParseResult parseResult = parseVanillaStateRegistryId(vanillaStateString);
|
||||
if (parseResult.success()) {
|
||||
vanillaStateRegistryId = parseResult.result;
|
||||
} else {
|
||||
String[] args = new String[parseResult.args.length + 2];
|
||||
args[0] = path.toString();
|
||||
args[1] = id.toString();
|
||||
System.arraycopy(parseResult.args, 0, args, 2, parseResult.args.length);
|
||||
TranslationManager.instance().log(parseResult.reason(), args);
|
||||
return null;
|
||||
}
|
||||
|
||||
// check conflict
|
||||
Key ifAny = this.tempRegistryIdConflictMap.get(vanillaStateRegistryId);
|
||||
if (ifAny != null && !ifAny.equals(id)) {
|
||||
this.plugin.logger().warn(path, "Can't use " + BlockStateUtils.idToBlockState(vanillaStateRegistryId) + " as the base block for " + id + " because the state has already been used by " + ifAny);
|
||||
TranslationManager.instance().log("warning.config.block.state.conflict", path.toString(), id.toString(), BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(vanillaStateRegistryId)).getAsString(), ifAny.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
// require models not to be null
|
||||
Object models = section.getOrDefault("models", section.get("model"));
|
||||
if (models == null) {
|
||||
TranslationManager.instance().log("warning.config.block.state.no_model_set", path.toString(), id.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
List<JsonObject> variants = new ArrayList<>();
|
||||
if (models instanceof Map<?, ?> singleModelSection) {
|
||||
loadVariantModel(variants, MiscUtils.castToMap(singleModelSection, false));
|
||||
@@ -565,11 +545,9 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
loadVariantModel(variants, MiscUtils.castToMap(singleModelMap, false));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.plugin.logger().warn(path, "No model set for " + id);
|
||||
return null;
|
||||
}
|
||||
if (variants.isEmpty()) return null;
|
||||
|
||||
this.tempRegistryIdConflictMap.put(vanillaStateRegistryId, id);
|
||||
String blockState = BlockStateUtils.idToBlockState(vanillaStateRegistryId).toString();
|
||||
Key block = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}')));
|
||||
@@ -604,46 +582,50 @@ public class BukkitBlockManager extends AbstractBlockManager {
|
||||
variants.add(json);
|
||||
}
|
||||
|
||||
private int parseVanillaStateRegistryId(String blockState) throws BlockStateArrangeException {
|
||||
private VanillaStateParseResult parseVanillaStateRegistryId(String blockState) {
|
||||
String[] split = blockState.split(":", 3);
|
||||
PreConditions.runIfTrue(split.length >= 4, () -> {
|
||||
throw new BlockStateArrangeException("Invalid vanilla block state: " + blockState);
|
||||
});
|
||||
if (split.length >= 4) {
|
||||
return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState});
|
||||
}
|
||||
int registryId;
|
||||
// minecraft:xxx:0
|
||||
// xxx:0
|
||||
String stateOrId = split[split.length - 1];
|
||||
boolean isId = !stateOrId.contains("[") && !stateOrId.contains("]");
|
||||
if (isId) {
|
||||
if (split.length == 1) {
|
||||
throw new BlockStateArrangeException("Invalid vanilla block state: " + blockState);
|
||||
}
|
||||
if (split.length == 1) return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState});
|
||||
Key block = split.length == 2 ? Key.of(split[0]) : Key.of(split[0], split[1]);
|
||||
try {
|
||||
int id = split.length == 2 ? Integer.parseInt(split[1]) : Integer.parseInt(split[2]);
|
||||
PreConditions.runIfTrue(id < 0, () -> {
|
||||
throw new BlockStateArrangeException("Invalid block state: " + blockState);
|
||||
});
|
||||
if (id < 0) return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState});
|
||||
List<Integer> arranger = this.blockAppearanceArranger.get(block);
|
||||
if (arranger == null) {
|
||||
throw new BlockStateArrangeException("No freed block state is available for block " + block);
|
||||
}
|
||||
if (id >= arranger.size()) {
|
||||
throw new BlockStateArrangeException(blockState + " is not a valid block state because " + id + " is outside of the range (0~" + (arranger.size() - 1) + ")");
|
||||
}
|
||||
if (arranger == null) return VanillaStateParseResult.failure("warning.config.block.state.unavailable_state", new String[]{blockState});
|
||||
if (id >= arranger.size()) return VanillaStateParseResult.failure("warning.config.block.state.invalid_vanilla_state_id", new String[]{blockState, String.valueOf(arranger.size() - 1)});
|
||||
registryId = arranger.get(id);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new BlockStateArrangeException("Invalid block state: " + blockState);
|
||||
return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState});
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
BlockData blockData = Bukkit.createBlockData(blockState);
|
||||
registryId = BlockStateUtils.blockDataToId(blockData);
|
||||
if (!this.blockAppearanceMapper.containsKey(registryId)) {
|
||||
return VanillaStateParseResult.failure("warning.config.block.state.unavailable_state", new String[]{blockState});
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new BlockStateArrangeException("Invalid block state: " + blockState);
|
||||
return VanillaStateParseResult.failure("warning.config.block.state.invalid_state", new String[]{blockState});
|
||||
}
|
||||
}
|
||||
return registryId;
|
||||
return VanillaStateParseResult.success(registryId);
|
||||
}
|
||||
|
||||
public record VanillaStateParseResult(boolean success, int result, String reason, String[] args) {
|
||||
|
||||
public static VanillaStateParseResult success(int result) {
|
||||
return new VanillaStateParseResult(true, result, null, null);
|
||||
}
|
||||
|
||||
public static VanillaStateParseResult failure(String reason, String[] args) {
|
||||
return new VanillaStateParseResult(false, -1, reason, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMappingsAndAdditionalBlocks() {
|
||||
|
||||
@@ -48,7 +48,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior {
|
||||
if (this.defaultBlockState != null) {
|
||||
return this.defaultBlockState;
|
||||
}
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().getBlock(this.targetBlock);
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().blockById(this.targetBlock);
|
||||
if (optionalCustomBlock.isPresent()) {
|
||||
CustomBlock customBlock = optionalCustomBlock.get();
|
||||
this.defaultBlockState = customBlock.defaultState().customBlockState().handle();
|
||||
|
||||
@@ -60,7 +60,7 @@ public class AxeItemBehavior extends ItemBehavior {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
Optional<CustomBlock> optionalNewCustomBlock = BukkitBlockManager.instance().getBlock(blockBehavior.stripped());
|
||||
Optional<CustomBlock> optionalNewCustomBlock = BukkitBlockManager.instance().blockById(blockBehavior.stripped());
|
||||
if (optionalNewCustomBlock.isEmpty()) {
|
||||
CraftEngine.instance().logger().warn("stripped block " + blockBehavior.stripped() + " does not exist");
|
||||
return InteractionResult.FAIL;
|
||||
|
||||
@@ -61,7 +61,7 @@ public class BlockItemBehavior extends ItemBehavior {
|
||||
if (!context.canPlace()) {
|
||||
return InteractionResult.FAIL;
|
||||
}
|
||||
Optional<CustomBlock> optionalBlock = BukkitBlockManager.instance().getBlock(this.blockId);
|
||||
Optional<CustomBlock> optionalBlock = BukkitBlockManager.instance().blockById(this.blockId);
|
||||
if (optionalBlock.isEmpty()) {
|
||||
CraftEngine.instance().logger().warn("Failed to place unknown block " + this.blockId);
|
||||
return InteractionResult.FAIL;
|
||||
|
||||
@@ -39,7 +39,7 @@ public class BlockStateUtils {
|
||||
} else {
|
||||
String blockTypeString = blockState.substring(0, index);
|
||||
Key block = Key.of(blockTypeString);
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().getBlock(block);
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().blockById(block);
|
||||
if (optionalCustomBlock.isPresent()) {
|
||||
ImmutableBlockState state = BlockStateParser.deserialize(blockState);
|
||||
if (state == null) {
|
||||
@@ -55,7 +55,7 @@ public class BlockStateUtils {
|
||||
}
|
||||
|
||||
public static List<Object> getAllBlockStates(Key block) {
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().getBlock(block);
|
||||
Optional<CustomBlock> optionalCustomBlock = BukkitBlockManager.instance().blockById(block);
|
||||
return optionalCustomBlock.map(customBlock -> customBlock.variantProvider().states().stream().map(it -> it.customBlockState().handle()).toList())
|
||||
.orElseGet(() -> getAllVanillaBlockStates(block));
|
||||
}
|
||||
@@ -80,7 +80,7 @@ public class BlockStateUtils {
|
||||
}
|
||||
|
||||
public static BlockData fromBlockData(Object blockState) {
|
||||
return (BlockData) FastNMS.INSTANCE.method$CraftBlockData$fromData(blockState);
|
||||
return FastNMS.INSTANCE.method$CraftBlockData$fromData(blockState);
|
||||
}
|
||||
|
||||
public static int blockDataToId(BlockData blockData) {
|
||||
|
||||
@@ -2,10 +2,62 @@ package net.momirealms.craftengine.core.block;
|
||||
|
||||
import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import org.incendo.cloud.suggestion.Suggestion;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager {
|
||||
// CraftEngine objects
|
||||
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<>();
|
||||
|
||||
public AbstractBlockManager(CraftEngine plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key, CustomBlock> blocks() {
|
||||
return Collections.unmodifiableMap(this.byId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CustomBlock> blockById(Key id) {
|
||||
return Optional.ofNullable(this.byId.get(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
super.clearModelsToGenerate();
|
||||
this.cachedSuggestions.clear();
|
||||
this.byId.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Suggestion> cachedSuggestions() {
|
||||
return Collections.unmodifiableCollection(this.cachedSuggestions);
|
||||
}
|
||||
|
||||
public Set<String> namespacesInUse() {
|
||||
return Collections.unmodifiableSet(this.namespacesInUse);
|
||||
}
|
||||
|
||||
protected void initSuggestions() {
|
||||
this.cachedSuggestions.clear();
|
||||
this.namespacesInUse.clear();
|
||||
Set<String> states = new HashSet<>();
|
||||
for (CustomBlock block : this.byId.values()) {
|
||||
states.add(block.id().toString());
|
||||
this.namespacesInUse.add(block.id().namespace());
|
||||
for (ImmutableBlockState state : block.variantProvider().states()) {
|
||||
states.add(state.toString());
|
||||
}
|
||||
}
|
||||
for (String state : states) {
|
||||
this.cachedSuggestions.add(Suggestion.suggestion(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public interface BlockManager extends Manageable, ModelGenerator {
|
||||
|
||||
Map<Key, CustomBlock> blocks();
|
||||
|
||||
Optional<CustomBlock> getBlock(Key key);
|
||||
Optional<CustomBlock> blockById(Key key);
|
||||
|
||||
Collection<Suggestion> cachedSuggestions();
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ public class Properties {
|
||||
public static Property<?> fromMap(String name, Map<String, Object> map) {
|
||||
String type = (String) map.getOrDefault("type", "empty");
|
||||
if (type == null) {
|
||||
throw new NullPointerException("behavior type cannot be null");
|
||||
throw new NullPointerException("Property type cannot be null");
|
||||
}
|
||||
Key key = Key.withDefaultNamespace(type, "craftengine");
|
||||
PropertyFactory factory = BuiltInRegistries.PROPERTY_FACTORY.getValue(key);
|
||||
|
||||
@@ -444,10 +444,8 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
int hashIndex = key.indexOf('#');
|
||||
String configType = hashIndex != -1 ? key.substring(0, hashIndex) : key;
|
||||
Optional.ofNullable(this.sectionParsers.get(configType))
|
||||
.ifPresent(parser -> {
|
||||
this.cachedConfigs.computeIfAbsent(parser, k -> new ArrayList<>())
|
||||
.add(new CachedConfig(castToMap(typeSections0, false), path, pack));
|
||||
});
|
||||
.ifPresent(parser -> this.cachedConfigs.computeIfAbsent(parser, k -> new ArrayList<>())
|
||||
.add(new CachedConfig(castToMap(typeSections0, false), path, pack)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ public class ResourceLocation {
|
||||
return character == '_' || character == '-' || character >= 'a' && character <= 'z' || character >= '0' && character <= '9' || character == '.';
|
||||
}
|
||||
|
||||
private static boolean isValidNamespace(String namespace) {
|
||||
public static boolean isValidNamespace(String namespace) {
|
||||
for(int i = 0; i < namespace.length(); ++i) {
|
||||
if (!validNamespaceChar(namespace.charAt(i))) {
|
||||
return false;
|
||||
@@ -28,7 +28,7 @@ public class ResourceLocation {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isValidPath(String path) {
|
||||
public static boolean isValidPath(String path) {
|
||||
for(int i = 0; i < path.length(); ++i) {
|
||||
if (!validPathChar(path.charAt(i))) {
|
||||
return false;
|
||||
|
||||
@@ -22,7 +22,7 @@ public class I18NData {
|
||||
return List.of("block." + stateToRealBlockId(parsed));
|
||||
} else {
|
||||
Key blockId = Key.of(id);
|
||||
Optional<CustomBlock> blockOptional = CraftEngine.instance().blockManager().getBlock(blockId);
|
||||
Optional<CustomBlock> blockOptional = CraftEngine.instance().blockManager().blockById(blockId);
|
||||
if (blockOptional.isPresent()) {
|
||||
List<ImmutableBlockState> states = blockOptional.get().variantProvider().states();
|
||||
if (states.size() == 1) {
|
||||
|
||||
Reference in New Issue
Block a user