Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/generated/resources/assets/anvilcraft/lang/en_ud.json
Original file line number Diff line number Diff line change
Expand Up @@ -1326,7 +1326,8 @@
"key.categories.anvilcraft": "ʇɟɐɹƆꞁᴉʌuⱯ",
"message.anvilcraft.buffer_boots.charged": "dɯnɾ oʇ %1$s ssǝɹԀ",
"message.anvilcraft.building_rod.blocked": "pǝʇɔǝʇoɹd ɹo pǝʇɔnɹʇsqo sᴉ ɐǝɹɐ ʇuǝɯǝɔɐꞁԀ",
"message.anvilcraft.building_rod.component_mismatch": "ʇuǝɯǝɔɐꞁd ɯɹᴉɟuoɔ oʇ spuoɔǝs Ɛ uᴉɥʇᴉʍ uᴉɐᵷɐ ʞɔᴉꞁɔ-ʇɥᵷᴉɹ ⸵sʇuǝuodɯoɔ pǝɥɔʇɐɯsᴉɯ ǝʌɐɥ sʞɔoꞁq ǝɯoS",
"message.anvilcraft.building_rod.component_mismatch": "ɐʇɐp ɹᴉǝɥʇ puɐ sꞁɐᴉɹǝʇɐɯ ǝꞁqɐꞁᴉɐʌɐ ǝɥʇ ǝsn oʇ spuoɔǝs Ɛ uᴉɥʇᴉʍ uᴉɐᵷɐ ʞɔᴉꞁɔ-ʇɥᵷᴉɹ ⸵sʇuǝuodɯoɔ pǝɥɔʇɐɯsᴉɯ ǝʌɐɥ sʞɔoꞁq ǝɯoS",
"message.anvilcraft.building_rod.contents_missing": "ʎʇdɯǝ sɹǝuᴉɐʇuoɔ ǝsoɥʇ ǝɔɐꞁd oʇ spuoɔǝs Ɛ uᴉɥʇᴉʍ uᴉɐᵷɐ ʞɔᴉꞁɔ-ʇɥᵷᴉɹ ⸵sʇuǝʇuoɔ ɹǝuᴉɐʇuoɔ ᵷuᴉɥɔʇɐɯ ᵷuᴉssᴉW",
"message.anvilcraft.building_rod.invalid_structure": "9⥝×9⥝×9⥝ uɐɥʇ ɹǝᵷɹɐꞁ ɹo ʇuᴉɹdǝnꞁq pᴉꞁɐʌuI",
"message.anvilcraft.building_rod.missing_blocks": "pᴉnꞁɟ ɹo sꞁɐᴉɹǝʇɐɯ ɥᵷnouǝ ʇoN",
"message.anvilcraft.building_rod.missing_book": "ʇsᴉꞁ ꞁɐᴉɹǝʇɐɯ ɐ ǝʌᴉǝɔǝɹ oʇ ʞooq ɐ ʎɹɹɐɔ ⸵sꞁɐᴉɹǝʇɐɯ ᵷuᴉssᴉW",
Expand Down
3 changes: 2 additions & 1 deletion src/generated/resources/assets/anvilcraft/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -1326,7 +1326,8 @@
"key.categories.anvilcraft": "AnvilCraft",
"message.anvilcraft.buffer_boots.charged": "Press %1$s to jump",
"message.anvilcraft.building_rod.blocked": "Placement area is obstructed or protected",
"message.anvilcraft.building_rod.component_mismatch": "Some blocks have mismatched components; right-click again within 3 seconds to confirm placement",
"message.anvilcraft.building_rod.component_mismatch": "Some blocks have mismatched components; right-click again within 3 seconds to use the available materials and their data",
"message.anvilcraft.building_rod.contents_missing": "Missing matching container contents; right-click again within 3 seconds to place those containers empty",
"message.anvilcraft.building_rod.invalid_structure": "Invalid blueprint or larger than 16×16×16",
"message.anvilcraft.building_rod.missing_blocks": "Not enough materials or fluid",
"message.anvilcraft.building_rod.missing_book": "Missing materials; carry a book to receive a material list",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ public void addContainer(Level level, BlockPos pos) {
}

/**
* 登记刚加载的方块实体容器,并把网络重建延后一轮
* 登记刚加载的方块实体候选位置,并把容器检测与网络重建延后一轮
*
* <p>外部模组可能在方块实体首次 tick 时才完成多方块流体处理器初始化;
* 延后一轮可避免缓存到尚未刷新的处理器。</p>
* <p>能力查询可能通过多方块代理同步请求其他区块,因此加载回调中不能检测能力。
* 重建时会剔除非容器;延后一轮也可等待首次 tick 完成流体处理器初始化。</p>
*/
public void addContainerAfterLoad(Level level, BlockPos pos) {
if (level.isClientSide()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public boolean isItemValid(int slot, ItemStack stack) {
private String autoSaveStructureName = ""; // 自动保存的结构名称

/**
* 缓存的方块数据;nbt 为方块实体的完整原版结构语义数据(saveWithId),无方块实体时为 null
* 缓存的方块数据;nbt 为方块实体完整数据及扫描时的世界坐标,无方块实体时为 null
*/
public record CachedBlockData(
int x,
Expand Down Expand Up @@ -363,11 +363,11 @@ private void scanNextLayer() {
net.minecraft.world.level.block.state.BlockState blockState = this.level.getBlockState(worldPos);

if (!blockState.isAir() && BlueprintMultiblocks.shouldRecord(blockState)) {
// 与原版结构 fillFromWorld 一致,方块实体使用 saveWithId 保留完整数据
// 保留扫描时的世界坐标,用于粘贴时重定位蓝图内部的引用。
net.minecraft.world.level.block.entity.BlockEntity worldBlockEntity =
this.level.getBlockEntity(worldPos);
CompoundTag blockEntityNbt = worldBlockEntity != null
? worldBlockEntity.saveWithId(this.level.registryAccess())
? worldBlockEntity.saveWithFullMetadata(this.level.registryAccess())
: null;
this.scannedBlocks.add(
new CachedBlockData(x, this.currentScanLayer, z, blockState, blockEntityNbt)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package dev.dubhe.anvilcraft.building;

import dev.dubhe.anvilcraft.api.itemhandler.IItemHandlerHolder;
import dev.dubhe.anvilcraft.block.entity.storage.StorageBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.NonNullList;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ItemContainerContents;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.JukeboxBlockEntity;
import net.minecraft.world.level.block.entity.LecternBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.items.IItemHandler;
import net.neoforged.neoforge.items.IItemHandlerModifiable;

Expand Down Expand Up @@ -40,16 +50,49 @@ public static Extracted extract(BlockState state, @Nullable CompoundTag nbt, Hol
if (nbt == null || nbt.isEmpty()) {
return Extracted.empty();
}
return extract(BlockEntity.loadStatic(BlockPos.ZERO, state, nbt, registries), nbt, registries, null);
}

static Extracted extract(BlockEntity entity, HolderLookup.Provider registries, @Nullable Level level) {
return extract(entity, entity.saveWithFullMetadata(registries), registries, level);
}

private static Extracted extract(
@Nullable BlockEntity loaded, CompoundTag nbt, HolderLookup.Provider registries, @Nullable Level level
) {
if (nbt.contains("LootTable", Tag.TAG_STRING) && !nbt.getString("LootTable").isEmpty()) {
return new Extracted(stripResources(nbt), List.of(), true);
}
List<SlotStack> contents = new ArrayList<>();
BlockEntity loaded = BlockEntity.loadStatic(BlockPos.ZERO, state, nbt, registries);
if (loaded instanceof LecternBlockEntity lectern) {
ItemStack book = lectern.getBook();
if (!book.isEmpty() && !book.is(Items.WRITTEN_BOOK) && !book.is(Items.WRITABLE_BOOK)) {
throw new IllegalArgumentException("Blueprint lectern contains an invalid book");
}
if (!book.isEmpty()) contents.add(new SlotStack(0, book.copy()));
CompoundTag config = stripResources(nbt);
config.remove("Book");
config.remove("Page");
return new Extracted(config, List.copyOf(contents), false);
}
if (loaded instanceof JukeboxBlockEntity jukebox) {
ItemStack record = jukebox.getTheItem();
if (!record.isEmpty()) contents.add(new SlotStack(0, record.copy()));
CompoundTag config = stripResources(nbt);
config.remove("RecordItem");
config.remove("ticks_since_song_started");
return new Extracted(config, List.copyOf(contents), false);
}
if (loaded instanceof Container container) {
extractContainer(container, contents);
var components = loaded.collectComponents();
if (components.has(DataComponents.CONTAINER)) {
loaded.applyComponents(DataComponentMap.builder().addAll(components)
.set(DataComponents.CONTAINER, ItemContainerContents.EMPTY).build(), DataComponentPatch.EMPTY);
}
return new Extracted(configOf(loaded, registries), List.copyOf(contents), false);
}
IItemHandler handler = itemHandlerOf(loaded);
IItemHandler handler = itemHandlerOf(loaded, level);
if (handler != null) {
extractHandler(handler, contents);
CompoundTag config = configOf(loaded, registries);
Expand All @@ -68,6 +111,10 @@ public static void insert(
if (contents.isEmpty()) {
return;
}
if (blockEntity instanceof LecternBlockEntity lectern) {
lectern.setBook(contents.getFirst().stack().copy());
return;
}
if (blockEntity instanceof Container container) {
for (SlotStack content : contents) {
if (content.slot() >= 0 && content.slot() < container.getContainerSize()) {
Expand All @@ -77,7 +124,7 @@ public static void insert(
container.setChanged();
return;
}
IItemHandler handler = itemHandlerOf(blockEntity);
IItemHandler handler = itemHandlerOf(blockEntity, blockEntity.getLevel());
if (handler instanceof IItemHandlerModifiable modifiable) {
for (SlotStack content : contents) {
if (content.slot() >= 0 && content.slot() < modifiable.getSlots()) {
Expand Down Expand Up @@ -125,7 +172,6 @@ private static void extractContainer(Container container, List<SlotStack> conten
ItemStack stack = container.getItem(slot);
if (stack.isEmpty()) continue;
contents.add(new SlotStack(slot, stack.copy()));
container.setItem(slot, ItemStack.EMPTY);
}
}

Expand All @@ -138,11 +184,16 @@ private static void extractHandler(IItemHandler handler, List<SlotStack> content
}

@Nullable
private static IItemHandler itemHandlerOf(@Nullable BlockEntity blockEntity) {
private static IItemHandler itemHandlerOf(@Nullable BlockEntity blockEntity, @Nullable Level level) {
// 外部仓储通过组件引用全局数据,不能在规划时读取或清空实际仓储。
if (blockEntity instanceof StorageBlockEntity) return null;
if (blockEntity instanceof IItemHandlerHolder holder) {
return holder.getItemHandler();
}
return blockEntity instanceof IItemHandler handler ? handler : null;
if (blockEntity instanceof IItemHandler handler) return handler;
if (blockEntity == null || level == null) return null;
return level.getCapability(Capabilities.ItemHandler.BLOCK, blockEntity.getBlockPos(),
blockEntity.getBlockState(), blockEntity, null);
}

private static CompoundTag configOf(BlockEntity blockEntity, HolderLookup.Provider registries) {
Expand All @@ -167,6 +218,10 @@ private static void stripSerializedHandlerItems(CompoundTag config) {
private static void stripSerializedHandlerItems(Tag tag) {
if (tag instanceof CompoundTag compound) {
compound.remove("SlotItem");
compound.remove("Items");
if (compound.contains("components", Tag.TAG_COMPOUND)) {
compound.getCompound("components").remove("minecraft:container");
}
for (String key : List.copyOf(compound.getAllKeys())) {
Tag child = compound.get(key);
if (child != null) {
Expand Down
Loading
Loading