Compare commits

..
11 Commits
Author SHA1 Message Date
Glease e155c69b20 fix incomplete creative build 2022-08-20 19:27:33 +08:00
Glease 82622d1e15 this is nbt sensitive 2022-08-20 19:27:05 +08:00
boubou19 a168702151 Merge pull request #9 from GTNewHorizons/gtnhlib
Use ItemStackMap from GTNHLib
2022-08-14 00:25:52 +02:00
Jason Mitchell 73f113ed9b Use ItemStackMap from GTNHLib 2022-08-13 15:20:48 -07:00
Glease c19ac860d4 fix too lenient should skip check in ofBlocksTiered 2022-08-12 21:13:32 +08:00
Glease d33cdd79c4 apply spotless 2022-08-12 12:31:46 +08:00
Glease ed24f15033 migrate iterate to iterateV2 2022-08-12 12:25:03 +08:00
Glease 15c34061bc suppress even more logging 2022-08-12 12:07:30 +08:00
Glease 728f25114b suppress logging unless debug mode 2022-08-11 23:38:36 +08:00
Glease 4a8c154855 update README to reflect commit hash change 2022-08-09 11:13:33 +08:00
iouter f65010a547 Update zh_CN.lang (#8) 2022-08-08 20:47:41 +08:00
12 changed files with 131 additions and 607 deletions

No files matched your search

+2 -1
View File
@@ -30,4 +30,5 @@ The project is developed using IDEA. Please manually configure the build to not
## Current license
Due to me adding in ItemStackMap, which was derived from code from CodeChicken's LGPL mod NEI. This mod is effectively considered
licensed under LGPL in its entirety since commit ebef584b8c518f8202cfe0984fb28a6d23e52b3d.
licensed under LGPL in its entirety since commit ebef584b8c518f8202cfe0984fb28a6d23e52b3d or any squash commit containing it, e.g.
609e50428ee4e293f65f67f554a70b9fcfae97c4.
+2 -2
View File
@@ -1,4 +1,4 @@
//version: 1659365110
//version: 1659977784
/*
DO NOT CHANGE THIS FILE!
Also, you may replace this file at any time if there is an update available.
@@ -651,7 +651,7 @@ task updateBuildScript {
}
}
if (isNewBuildScriptVersionAvailable(projectDir.toString())) {
if (!project.getGradle().startParameter.isOffline() && isNewBuildScriptVersionAvailable(projectDir.toString())) {
if (autoUpdateBuildScript.toBoolean()) {
performBuildScriptUpdate(projectDir.toString())
} else {
+1 -1
View File
@@ -1,5 +1,5 @@
// Add your dependencies here
dependencies {
compile("com.github.GTNewHorizons:GTNHLib:0.0.1:dev")
}
+4 -1
View File
@@ -1,5 +1,8 @@
// Add any additional repositiroes for your dependencies here
repositories {
maven {
name = "GTNH"
url = "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
}
}
@@ -76,11 +76,9 @@ public class ConstructableUtility {
} else if (constructable instanceof ISurvivalConstructable) {
int built = ((ISurvivalConstructable) constructable)
.survivalConstruct(aStack, BUDGET, IItemSource.fromPlayer(playerMP), playerMP);
if (built > 0)
// TODO somehow notify extensions that their inventory might have been modified and need to be
// synced to client or saved
playerMP.inventory.markDirty();
else if (built == -1) {
if (built > 0) {
playerMP.addChatMessage(new ChatComponentTranslation("structurelib.autoplace.built_stat", built));
} else if (built == -1) {
playerMP.addChatMessage(new ChatComponentTranslation("structurelib.autoplace.complete"));
}
setLastUseTickToStackTag(aStack);
@@ -1,10 +1,11 @@
package com.gtnewhorizon.structurelib.structure;
import static com.gtnewhorizon.structurelib.StructureLib.DEBUG_MODE;
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.ignoreBlockUnloaded;
import static com.gtnewhorizon.structurelib.structure.IStructureWalker.skipBlockUnloaded;
import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
import java.util.Arrays;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
@@ -196,135 +197,73 @@ public interface IStructureDefinition<T> {
return false;
}
// change base position to base offset
basePositionA = -basePositionA;
basePositionB = -basePositionB;
basePositionC = -basePositionC;
int[] abc = new int[] {basePositionA, basePositionB, basePositionC};
int[] xyz = new int[3];
if (checkBlocksIfNotNullForceCheckAllIfTrue != null) {
boolean success;
if (checkBlocksIfNotNullForceCheckAllIfTrue) {
for (IStructureElement<T> element : elements) {
if (element.isNavigating()) {
abc[0] = (element.resetA() ? basePositionA : abc[0]) + element.getStepA();
abc[1] = (element.resetB() ? basePositionB : abc[1]) + element.getStepB();
abc[2] = (element.resetC() ? basePositionC : abc[2]) + element.getStepC();
} else {
extendedFacing.getWorldOffset(abc, xyz);
xyz[0] += basePositionX;
xyz[1] += basePositionY;
xyz[2] += basePositionZ;
StructureLib.LOGGER.info(
"Multi [{}, {}, {}] step @ {} {}",
basePositionX,
basePositionY,
basePositionZ,
Arrays.toString(xyz),
Arrays.toString(abc));
if (world.blockExists(xyz[0], xyz[1], xyz[2])) {
if (!element.check(object, world, xyz[0], xyz[1], xyz[2])) {
if (DEBUG_MODE) {
StructureLib.LOGGER.info("Multi [" + basePositionX + ", " + basePositionY + ", "
+ basePositionZ + "] failed @ " + Arrays.toString(xyz) + " "
+ Arrays.toString(abc));
}
return false;
}
} else {
if (DEBUG_MODE) {
StructureLib.LOGGER.info("Multi [" + basePositionX + ", " + basePositionY + ", "
+ basePositionZ + "] !blockExists @ " + Arrays.toString(xyz) + " "
+ Arrays.toString(abc));
}
return false;
}
abc[0] += 1;
}
}
success = StructureUtility.iterateV2(
elements,
world,
extendedFacing,
basePositionX,
basePositionY,
basePositionZ,
basePositionA,
basePositionB,
basePositionC,
(e, w, x, y, z) -> e.check(object, w, x, y, z),
"check");
} else {
for (IStructureElement<T> element : elements) {
if (element.isNavigating()) {
abc[0] = (element.resetA() ? basePositionA : abc[0]) + element.getStepA();
abc[1] = (element.resetB() ? basePositionB : abc[1]) + element.getStepB();
abc[2] = (element.resetC() ? basePositionC : abc[2]) + element.getStepC();
} else {
extendedFacing.getWorldOffset(abc, xyz);
xyz[0] += basePositionX;
xyz[1] += basePositionY;
xyz[2] += basePositionZ;
StructureLib.LOGGER.info(
"Multi [{}, {}, {}] step @ {} {}",
basePositionX,
basePositionY,
basePositionZ,
Arrays.toString(xyz),
Arrays.toString(abc));
if (world.blockExists(xyz[0], xyz[1], xyz[2])) {
if (!element.check(object, world, xyz[0], xyz[1], xyz[2])) {
if (DEBUG_MODE) {
StructureLib.LOGGER.info("Multi [" + basePositionX + ", " + basePositionY + ", "
+ basePositionZ + "] failed @ " + Arrays.toString(xyz) + " "
+ Arrays.toString(abc));
}
return false;
}
} else {
if (DEBUG_MODE) {
StructureLib.LOGGER.info("Multi [" + basePositionX + ", " + basePositionY + ", "
+ basePositionZ + "] !blockExists @ " + Arrays.toString(xyz) + " "
+ Arrays.toString(abc));
}
}
abc[0] += 1;
}
}
success = StructureUtility.iterateV2(
elements,
world,
extendedFacing,
basePositionX,
basePositionY,
basePositionZ,
basePositionA,
basePositionB,
basePositionC,
skipBlockUnloaded((e, w, x, y, z) -> e.check(object, w, x, y, z)),
"check force");
}
if (DEBUG_MODE) {
if (DEBUG_MODE && success) {
StructureLib.LOGGER.info(
"Multi [" + basePositionX + ", " + basePositionY + ", " + basePositionZ + "] pass");
}
return success;
} else {
if (hintsOnly) {
for (IStructureElement<T> element : elements) {
if (element.isNavigating()) {
abc[0] = (element.resetA() ? basePositionA : abc[0]) + element.getStepA();
abc[1] = (element.resetB() ? basePositionB : abc[1]) + element.getStepB();
abc[2] = (element.resetC() ? basePositionC : abc[2]) + element.getStepC();
} else {
extendedFacing.getWorldOffset(abc, xyz);
xyz[0] += basePositionX;
xyz[1] += basePositionY;
xyz[2] += basePositionZ;
element.spawnHint(object, world, xyz[0], xyz[1], xyz[2], trigger);
abc[0] += 1;
}
}
StructureUtility.iterateV2(
elements,
world,
extendedFacing,
basePositionX,
basePositionY,
basePositionZ,
basePositionA,
basePositionB,
basePositionC,
ignoreBlockUnloaded((e, w, x, y, z) -> {
e.spawnHint(object, world, x, y, z, trigger);
return true;
}),
"spawnHint");
} else {
for (IStructureElement<T> element : elements) {
if (element.isNavigating()) {
abc[0] = (element.resetA() ? basePositionA : abc[0]) + element.getStepA();
abc[1] = (element.resetB() ? basePositionB : abc[1]) + element.getStepB();
abc[2] = (element.resetC() ? basePositionC : abc[2]) + element.getStepC();
} else {
extendedFacing.getWorldOffset(abc, xyz);
xyz[0] += basePositionX;
xyz[1] += basePositionY;
xyz[2] += basePositionZ;
if (world.blockExists(xyz[0], xyz[1], xyz[2])) {
element.placeBlock(object, world, xyz[0], xyz[1], xyz[2], trigger);
}
abc[0] += 1;
}
}
StructureUtility.iterateV2(
elements,
world,
extendedFacing,
basePositionX,
basePositionY,
basePositionZ,
basePositionA,
basePositionB,
basePositionC,
ignoreBlockUnloaded((e, w, x, y, z) -> {
e.placeBlock(object, world, x, y, z, trigger);
return true;
}),
"placeBlock");
}
}
return true;
@@ -4,4 +4,36 @@ import net.minecraft.world.World;
public interface IStructureWalker<T> {
boolean visit(IStructureElement<T> element, World world, int x, int y, int z);
default boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z) {
return false;
}
static <T> IStructureWalker<T> ignoreBlockUnloaded(IStructureWalker<T> walker) {
return new IStructureWalker<T>() {
@Override
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z) {
return walker.visit(element, world, x, y, z);
}
@Override
public boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z) {
return walker.visit(element, world, x, y, z);
}
};
}
static <T> IStructureWalker<T> skipBlockUnloaded(IStructureWalker<T> walker) {
return new IStructureWalker<T>() {
@Override
public boolean visit(IStructureElement<T> element, World world, int x, int y, int z) {
return walker.visit(element, world, x, y, z);
}
@Override
public boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z) {
return true;
}
};
}
}
@@ -427,9 +427,16 @@ public class StructureUtility {
IItemSource s,
EntityPlayerMP actor,
Consumer<IChatComponent> chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
Pair<Block, Integer> hint = getHint(trigger);
if (hint == null) return PlaceResult.REJECT; // TODO or SKIP?
Block block = world.getBlock(x, y, z);
int meta = world.getBlockMetadata(x, y, z);
TIER tier = tierExtractor.convert(block, meta);
if (!Objects.equals(tier, notSet)) {
return Objects.equals(tier, tierExtractor.convert(hint.getKey(), hint.getValue()))
? PlaceResult.SKIP
: PlaceResult.REJECT;
}
return StructureUtility.survivalPlaceBlock(
hint.getKey(), hint.getValue(), world, x, y, z, s, actor, chatter);
}
@@ -2209,14 +2216,15 @@ public class StructureUtility {
xyz[1] += basePositionY;
xyz[2] += basePositionZ;
StructureLib.LOGGER.info(
"Multi [{}, {}, {}] {} step @ {} {}",
basePositionX,
basePositionY,
basePositionZ,
iterateType,
Arrays.toString(xyz),
Arrays.toString(abc));
if (DEBUG_MODE)
StructureLib.LOGGER.info(
"Multi [{}, {}, {}] {} step @ {} {}",
basePositionX,
basePositionY,
basePositionZ,
iterateType,
Arrays.toString(xyz),
Arrays.toString(abc));
if (world.blockExists(xyz[0], xyz[1], xyz[2])) {
if (!predicate.visit(element, world, xyz[0], xyz[1], xyz[2])) {
@@ -2243,7 +2251,7 @@ public class StructureUtility {
Arrays.toString(xyz),
Arrays.toString(abc));
}
return false;
if (!predicate.blockNotLoaded(element, world, xyz[0], xyz[1], xyz[2])) return false;
}
abc[0] += 1;
}
@@ -18,6 +18,7 @@
*/
package com.gtnewhorizon.structurelib.util;
import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
import com.gtnewhorizon.structurelib.util.InventoryUtility.ItemStackExtractor.APIType;
import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode;
import java.util.*;
@@ -375,7 +376,7 @@ public class InventoryUtility {
}
private static class ItemStackCounterImpl implements ItemStackCounter {
private final Map<ItemStack, Integer> store = new ItemStackMap<>();
private final Map<ItemStack, Integer> store = new ItemStackMap<>(true);
@Override
public void add(ItemStack stack, int stackSize) {
@@ -1,464 +0,0 @@
/*
* Copyright (c) 2021, glee8e, Code Chicken.
*
* This file is originally part of NotEnoughtItem by Code Chicken.
* It is adapted to implement the standard Map interface by glease
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.gtnewhorizon.structurelib.util;
import static net.minecraftforge.oredict.OreDictionary.WILDCARD_VALUE;
import com.google.common.base.Objects;
import com.google.common.collect.Iterators;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
/**
* A map class for ItemStack keys with wildcard damage/NBT. Optimised for lookup.
* <p>
* This map does NOT support null values or null keys! null will be silently ignored!
* <p>
* Originally created by CodeChicken for NotEnoughItems. Adapted to {@code Map<ItemStack, T>} interface by glee8e
* @author CodeChiken
* @author glee8e
*/
public final class ItemStackMap<T> extends AbstractMap<ItemStack, T> {
public static final NBTTagCompound WILDCARD_TAG;
static {
WILDCARD_TAG = new NBTTagCompound();
WILDCARD_TAG.setBoolean("*", true);
}
private final HashMap<Item, DetailMap> itemMap = new HashMap<>();
private int size;
static ItemStack newItemStack(Item item, int size, int damage, NBTTagCompound tag) {
ItemStack stack = new ItemStack(item, size, damage);
stack.stackTagCompound = tag;
return stack;
}
static int actualDamage(ItemStack stack) {
return Items.diamond.getDamage(stack);
}
static int getKeyType(int damage, NBTTagCompound tag) {
int i = 0;
if (isWildcard(damage)) i = 1;
if (isWildcard(tag)) i |= 2;
return i;
}
static ItemStack wildcard(Item item) {
return newItemStack(item, 1, WILDCARD_VALUE, WILDCARD_TAG);
}
static boolean isWildcard(int damage) {
return damage == WILDCARD_VALUE;
}
static boolean isWildcard(NBTTagCompound tag) {
return tag != null && tag.getBoolean("*");
}
@Override
public T get(Object key) {
if (!(key instanceof ItemStack)) return null;
ItemStack stack = ((ItemStack) key);
if (stack.getItem() == null) return null;
DetailMap map = itemMap.get(stack.getItem());
return map == null ? null : map.get(stack);
}
@Override
public T put(ItemStack key, T value) {
if (key == null || key.getItem() == null || value == null) return null;
return itemMap.computeIfAbsent(key.getItem(), k -> new DetailMap()).put(key, value);
}
@Override
public T remove(Object key) {
if (!(key instanceof ItemStack)) return null;
ItemStack stack = ((ItemStack) key);
if (stack.getItem() == null) return null;
DetailMap map = itemMap.get(stack.getItem());
return map == null ? null : map.remove(stack);
}
@Override
public boolean containsKey(Object key) {
if (!(key instanceof ItemStack)) return false;
ItemStack stack = ((ItemStack) key);
if (stack.getItem() == null) return false;
DetailMap map = itemMap.get(stack.getItem());
return map != null && map.get(stack) != null;
}
@Override
public void clear() {
itemMap.clear();
size = 0;
}
@Override
public Set<Map.Entry<ItemStack, T>> entrySet() {
return new SetView();
}
private static class StackMetaKey {
public final int damage;
public final NBTTagCompound tag;
public StackMetaKey(int damage, NBTTagCompound tag) {
this.damage = damage;
this.tag = tag;
}
public StackMetaKey(ItemStack key) {
this(actualDamage(key), key.stackTagCompound);
}
public int hashCode() {
return Objects.hashCode(damage, tag);
}
public boolean equals(Object o) {
if (!(o instanceof StackMetaKey)) return false;
StackMetaKey t = (StackMetaKey) o;
return damage == t.damage && Objects.equal(tag, t.tag);
}
}
private static class DetailIter<T> implements Iterator<Map.Entry<ItemStack, T>> {
private final Item owner;
private final ItemStackMap<T>.DetailMap backing;
@Nullable
private final Iterator<Map.Entry<Integer, T>> damageIter;
@Nullable
private final Iterator<Map.Entry<NBTTagCompound, T>> tagIter;
@Nullable
private final Iterator<Map.Entry<StackMetaKey, T>> metaIter;
private DetailIterState state = DetailIterState.NOT_STARTED;
private boolean removed = false;
private DetailIter(Map.Entry<Item, ItemStackMap<T>.DetailMap> input) {
this.owner = input.getKey();
this.backing = input.getValue();
damageIter =
backing.damageMap != null ? backing.damageMap.entrySet().iterator() : null;
tagIter = backing.tagMap != null ? backing.tagMap.entrySet().iterator() : null;
metaIter = backing.metaMap != null ? backing.metaMap.entrySet().iterator() : null;
}
private DetailIterState nextState() {
switch (state) {
case NOT_STARTED:
if (backing.hasWildcard) return DetailIterState.WILDCARD;
case WILDCARD:
case DAMAGE:
if (damageIter != null && damageIter.hasNext()) return DetailIterState.DAMAGE;
case TAG:
if (tagIter != null && tagIter.hasNext()) return DetailIterState.TAG;
case META:
if (metaIter != null && metaIter.hasNext()) return DetailIterState.META;
case DONE:
return DetailIterState.DONE;
default:
throw new IllegalStateException("Unexpected value: " + state);
}
}
@Override
public void remove() {
if (removed) throw new IllegalStateException("remove() called twice");
state.remove(this);
removed = true;
}
@Override
public boolean hasNext() {
return nextState() != DetailIterState.DONE;
}
@Override
public Map.Entry<ItemStack, T> next() {
DetailIterState nextState = nextState();
if (nextState == DetailIterState.DONE) throw new NoSuchElementException();
state = nextState;
removed = false;
return nextState.get(this);
}
private enum DetailIterState {
NOT_STARTED {
@Override
<T> Map.Entry<ItemStack, T> get(DetailIter<T> iter) {
throw new AssertionError("Should not call get on NOT_STARTED");
}
@Override
<T> void remove(DetailIter<T> iter) {
throw new IllegalStateException("next() never called");
}
},
WILDCARD {
@Override
<T> Map.Entry<ItemStack, T> get(DetailIter<T> iter) {
return new Map.Entry<ItemStack, T>() {
private final ItemStack key = wildcard(iter.owner);
@Override
public ItemStack getKey() {
return key;
}
@Override
public T getValue() {
return iter.backing.wildcard;
}
@Override
public T setValue(T value) {
return iter.backing.wildcard = value;
}
};
}
@Override
<T> void remove(DetailIter<T> iter) {
assert iter.backing.hasWildcard;
iter.backing.wildcard = null;
iter.backing.hasWildcard = false;
}
},
DAMAGE {
@Override
<T> Map.Entry<ItemStack, T> get(DetailIter<T> iter) {
assert iter.damageIter != null;
Map.Entry<Integer, T> entry = iter.damageIter.next();
return new ItemStackEntry<>(newItemStack(iter.owner, 1, entry.getKey(), WILDCARD_TAG), entry);
}
@Override
<T> void remove(DetailIter<T> iter) {
assert iter.damageIter != null;
iter.damageIter.remove();
}
},
TAG {
@Override
<T> Map.Entry<ItemStack, T> get(DetailIter<T> iter) {
assert iter.tagIter != null;
Map.Entry<NBTTagCompound, T> entry = iter.tagIter.next();
return new ItemStackEntry<>(newItemStack(iter.owner, 1, WILDCARD_VALUE, entry.getKey()), entry);
}
@Override
<T> void remove(DetailIter<T> iter) {
assert iter.tagIter != null;
iter.tagIter.remove();
}
},
META {
@Override
<T> Map.Entry<ItemStack, T> get(DetailIter<T> iter) {
assert iter.metaIter != null;
Map.Entry<StackMetaKey, T> entry = iter.metaIter.next();
return new ItemStackEntry<>(
newItemStack(iter.owner, 1, entry.getKey().damage, entry.getKey().tag), entry);
}
@Override
<T> void remove(DetailIter<T> iter) {
assert iter.metaIter != null;
iter.metaIter.remove();
}
},
DONE {
@Override
<T> Map.Entry<ItemStack, T> get(DetailIter<T> iter) {
throw new AssertionError("Should not call get on DONE");
}
@Override
<T> void remove(DetailIter<T> iter) {
throw new AssertionError("Should not call remove on DONE");
}
};
abstract <T> Map.Entry<ItemStack, T> get(DetailIter<T> iter);
abstract <T> void remove(DetailIter<T> iter);
private static class ItemStackEntry<T> implements Map.Entry<ItemStack, T> {
private final ItemStack key;
private final Map.Entry<?, T> entry;
public ItemStackEntry(ItemStack key, Map.Entry<?, T> entry) {
this.key = key;
this.entry = entry;
}
@Override
public ItemStack getKey() {
return key;
}
@Override
public T getValue() {
return entry.getValue();
}
@Override
public T setValue(T value) {
return entry.setValue(value);
}
}
}
}
private class DetailMap {
private boolean hasWildcard;
private T wildcard;
private HashMap<Integer, T> damageMap;
private HashMap<NBTTagCompound, T> tagMap;
private HashMap<StackMetaKey, T> metaMap;
private int size;
public T get(ItemStack key) {
if (wildcard != null) return wildcard;
if (damageMap != null) {
final T ret = damageMap.get(actualDamage(key));
if (ret != null) return ret;
}
if (tagMap != null) {
final T ret = tagMap.get(key.stackTagCompound);
if (ret != null) return ret;
}
if (metaMap != null) return metaMap.get(new StackMetaKey(key));
return null;
}
public T put(ItemStack key, T value) {
try {
switch (getKeyType(actualDamage(key), key.stackTagCompound)) {
case 0:
if (metaMap == null) metaMap = new HashMap<>();
return metaMap.put(new StackMetaKey(key), value);
case 1:
if (tagMap == null) tagMap = new HashMap<>();
return tagMap.put(key.stackTagCompound, value);
case 2:
if (damageMap == null) damageMap = new HashMap<>();
return damageMap.put(actualDamage(key), value);
case 3:
T ret = wildcard;
wildcard = value;
hasWildcard = true;
return ret;
}
} finally {
updateSize();
}
return null;
}
public T remove(ItemStack key) {
try {
switch (getKeyType(actualDamage(key), key.stackTagCompound)) {
case 0:
return metaMap != null ? metaMap.remove(new StackMetaKey(key)) : null;
case 1:
return tagMap != null ? tagMap.remove(key.stackTagCompound) : null;
case 2:
return damageMap != null ? damageMap.remove(actualDamage(key)) : null;
case 3:
T ret = wildcard;
wildcard = null;
hasWildcard = false;
return ret;
}
} finally {
updateSize();
}
return null;
}
private void updateSize() {
int newSize = (hasWildcard ? 1 : 0)
+ (metaMap != null ? metaMap.size() : 0)
+ (tagMap != null ? tagMap.size() : 0)
+ (damageMap != null ? damageMap.size() : 0);
if (newSize != size) {
ItemStackMap.this.size += newSize - size;
size = newSize;
}
}
}
private class SetView extends AbstractSet<Map.Entry<ItemStack, T>> {
@Override
public boolean contains(Object o) {
if (!(o instanceof Map.Entry)) return false;
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
return java.util.Objects.equals(get(entry.getKey()), entry.getValue());
}
@Override
public boolean add(Map.Entry<ItemStack, T> itemStackTEntry) {
return itemStackTEntry.getKey() != null
&& itemStackTEntry.getValue() != null
&& put(itemStackTEntry.getKey(), itemStackTEntry.getValue()) == null;
}
@Override
public boolean remove(Object o) {
if (!(o instanceof Map.Entry)) return false;
Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
return ItemStackMap.this.remove(entry.getKey(), entry.getValue());
}
@Nonnull
@Override
public Iterator<Map.Entry<ItemStack, T>> iterator() {
return Iterators.concat(Iterators.transform(itemMap.entrySet().iterator(), DetailIter::new));
}
@Override
public int size() {
return size;
}
}
}
@@ -28,6 +28,7 @@ item.structurelib.constructableTrigger.desc.3=(Sneak use on controller to build)
item.structurelib.constructableTrigger.desc.4=Quantity of schematics in item stack affects tier/mode/type
item.structurelib.constructableTrigger.too_fast=Please wait %d ticks before another autoplace...
structurelib.autoplace.built_stat=Built %s blocks
structurelib.autoplace.complete=§aThis multiblock has completed!
structurelib.autoplace.error.not_enabled=§cThis multiblock does not support autoplace in survival!
structurelib.autoplace.error.no_simple_block=§cSuggested to place §r%s§c but none was found
@@ -24,9 +24,14 @@ item.structurelib.constructableTrigger.name=多方块结构全息投影仪
item.structurelib.constructableTrigger.desc.0=可以显示多方块机器的结构
item.structurelib.constructableTrigger.desc.1=只能在多方块主机上使用,将会显示机器
item.structurelib.constructableTrigger.desc.2=结构的示意图。 (译者注:请搭高使用)
item.structurelib.constructableTrigger.desc.3= (创造模式下潜行右键可以直接完成搭建)
item.structurelib.constructableTrigger.desc.3= (潜行右键可以直接完成搭建)
item.structurelib.constructableTrigger.desc.4=此物品堆叠数量会影响显示的机器等级/模式/类型
item.structurelib.constructableTrigger.too_fast=Please wait %d ticks before another autoplace...
item.structurelib.constructableTrigger.too_fast=请在下一次自动搭建前等待%dtick...
structurelib.autoplace.complete=§a这个多方块结构已经完成自动搭建!
structurelib.autoplace.error.not_enabled=§c这个多方块结构不支持在生存模式下自动搭建!
structurelib.autoplace.error.no_simple_block=§c建议放置§r%s§c,但没有找到它
structurelib.autoplace.error.no_item_stack=§c建议使用§r%s§c放置方块,但没有找到它
structurelib.blockhint.desc.0=帮助你搭建机器
structurelib.blockhint.0.name=提示方块:1号