Fix AutoChecker inventory rules

Count every inventory block towards exactly one Schematic.Limited rule:
filled blocks towards a rule whose Content allows all their items, empty
blocks towards a rule without Content (unlimited if there is none). Each
rule's Amount now caps how many blocks it covers, instead of taking the
highest Amount of all rules for that block type.

Inventory blocks whose items fit no rule are now checked and reported,
items from different rules in one block are reported as mixed, and the
auto-fix trims or removes them accordingly.

Remove the hardcoded wargearseason26 wind charge handling and its 2048
limit, wind charges are configured via Limited rules now.

Log a warning for Limited rules that match no blocks, e.g. a misspelled
'Materials' key.

Fixes #458, #481, #502
This commit is contained in:
2026-10-15 17:53:06 +02:00
parent 2b42f0d13c
commit d727982ce0
7 changed files with 123 additions and 83 deletions
@@ -48,6 +48,7 @@ import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandHelp.*;
import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.togglePublic;
@@ -171,8 +172,8 @@ public class SchematicCommand extends SWCommand {
Map<BlockPos, Set<Material>> toBeCheckedInvs = new HashMap<>();
toBeCheckedInvs.putAll(result.getBlockScanResult().getForbiddenItems());
toBeCheckedInvs.putAll(result.getBlockScanResult().getForbiddenNbt());
Stream.of(result.getBlockScanResult().getForbiddenItems(), result.getBlockScanResult().getMixedItems(), result.getBlockScanResult().getForbiddenNbt())
.forEach(invs -> invs.forEach((pos, materials) -> toBeCheckedInvs.computeIfAbsent(pos, p -> new HashSet<>()).addAll(materials)));
for (Map.Entry<BlockPos, Set<Material>> entry : toBeCheckedInvs.entrySet()) {
BlockPos pos = entry.getKey();
@@ -197,16 +198,13 @@ public class SchematicCommand extends SWCommand {
clipboard.setBlock(vector, block.toBaseBlock(builder.build()));
}
for (Map.Entry<BlockPos, Map<Material, Integer>> posEntry : result.getBlockScanResult().getInventoryItemCounts().entrySet()) {
for (Map.Entry<BlockPos, Map<Material, Integer>> posEntry : result.getBlockScanResult().getTooManyItems().entrySet()) {
BlockPos pos = posEntry.getKey();
Material inventory = result.getBlockScanResult().getInventoryBlockType().get(pos);
Map<Material, Integer> itemCounts = result.getBlockScanResult().getInventoryItemCounts().get(pos);
for (Map.Entry<Material, Integer> itemEntry : posEntry.getValue().entrySet()) {
Material itemType = itemEntry.getKey();
Integer cap = type.Schematic.getItemAmount(inventory, itemType);
if (itemEntry.getValue() <= cap) {
continue;
}
int cap = itemEntry.getValue();
BlockVector3 vector = BlockVector3.at(pos.getX(), pos.getY(), pos.getZ());
BaseBlock block = clipboard.getFullBlock(vector);
@@ -215,7 +213,7 @@ public class SchematicCommand extends SWCommand {
List<CompoundTag> items = new ArrayList<>(tag.getList("Items", CompoundTag.class));
Collections.reverse(items); // To let the first item be in the inventory
List<CompoundTag> list = new ArrayList<>();
int diff = itemEntry.getValue() - cap;
int diff = itemCounts.get(itemType) - cap;
for (CompoundTag item : items) {
if (item == null) {
continue;