Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
208f7ffc41 | ||
|
|
88a6021546 | ||
|
|
a05267a566 | ||
|
|
dd3413dcaa | ||
|
|
34394ef8a5 | ||
|
|
7c0d3f4bd6 | ||
|
|
cd4f3617be | ||
|
|
256bc60d35 | ||
|
|
70426ab7b3 | ||
|
|
0030c02e9a | ||
|
|
7382db1bbd | ||
|
|
b669cbecf1 | ||
|
|
6283931667 | ||
|
|
3b3bc4b9ad |
No files matched your search
@@ -1,7 +1,7 @@
|
||||
javadoc {
|
||||
javadocTool = javaToolchains.javadocToolFor {
|
||||
// Last version with frames, but it also has search
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
languageVersion = JavaLanguageVersion.of(11)
|
||||
vendor = JvmVendorSpec.ADOPTIUM
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ javadoc {
|
||||
overview "src/main/javadoc/overview.html"
|
||||
links 'https://docs.oracle.com/javase/8/docs/api/'
|
||||
links 'https://skmedix.github.io/ForgeJavaDocs/javadoc/forge/1.7.10-10.13.4.1614/'
|
||||
addBooleanOption("-frames", true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
// Add your dependencies here
|
||||
|
||||
dependencies {
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.6.38:dev")
|
||||
implementation("com.github.GTNewHorizons:NotEnoughItems:2.7.64-GTNH:dev")
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.8.44:dev")
|
||||
implementation("com.github.GTNewHorizons:NotEnoughItems:2.8.48-GTNH:dev")
|
||||
|
||||
testImplementation(platform('org.junit:junit-bom:5.9.2'))
|
||||
testImplementation('org.junit.jupiter:junit-jupiter')
|
||||
|
||||
// runtimeOnlyNonPublishable("com.github.GTNewHorizons:GT5-Unofficial:5.09.51.391:dev") {
|
||||
// exclude group: "com.github.GTNewHorizons", module: "StructureLib"
|
||||
// }
|
||||
}
|
||||
@@ -43,6 +43,10 @@ developmentEnvironmentUserName = Developer
|
||||
# See https://github.com/bsideup/jabel for details on how this works.
|
||||
enableModernJavaSyntax = true
|
||||
|
||||
# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues,
|
||||
# and should *not* be used in most situations. -1 disables this.
|
||||
# forceToolchainVersion = -1
|
||||
|
||||
# Enables injecting missing generics into the decompiled source code for a better coding experience.
|
||||
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
|
||||
enableGenericInjection = true
|
||||
@@ -96,7 +100,9 @@ usesMixinDebug = false
|
||||
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
||||
mixinPlugin =
|
||||
|
||||
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
|
||||
# Specify the package that contains all of your Mixins. The package must exist or
|
||||
# the build will fail. If you have a package property defined in your mixins.<modid>.json,
|
||||
# it must match with this or the build will fail.
|
||||
mixinsPackage = mixins
|
||||
|
||||
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
||||
@@ -172,6 +178,12 @@ curseForgeRelations =
|
||||
# projects. New projects should not use this parameter.
|
||||
# customArchiveBaseName =
|
||||
|
||||
# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory.
|
||||
# runClientWorkingDirectory = run/client
|
||||
|
||||
# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory.
|
||||
# runServerWorkingDirectory = run/server
|
||||
|
||||
# Optional parameter to have the build automatically fail if an illegal version is used.
|
||||
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
|
||||
# The check is ONLY performed if the version is a git tag.
|
||||
@@ -201,3 +213,6 @@ curseForgeRelations =
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# ideaCheckSpotlessOnBuild = true
|
||||
|
||||
# Non-GTNH properties
|
||||
org.gradle.configuration-cache = true
|
||||
org.gradle.parallel = true
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/df211d3c3eefdc408b462041881bc575/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/b41931cf1e70bc8e08d7dd19c343ef00/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/df211d3c3eefdc408b462041881bc575/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/b41931cf1e70bc8e08d7dd19c343ef00/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/46949723aaa20c7b64d7ecfed7207034/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/d6690dfd71c4c91e08577437b5b2beb0/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/df211d3c3eefdc408b462041881bc575/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/b41931cf1e70bc8e08d7dd19c343ef00/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/3cd7045fca9a72cd9bc7d14a385e594c/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/552c7bffe0370c66410a51c55985b511/redirect
|
||||
toolchainVersion=25
|
||||
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -114,7 +114,6 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -172,7 +171,6 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@@ -212,8 +210,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
@@ -70,11 +70,10 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
@@ -17,7 +17,7 @@ pluginManagement {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '1.0.41'
|
||||
id 'com.gtnewhorizons.gtnhsettingsconvention' version '2.0.10'
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.keybind.SyncedKeybind;
|
||||
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
|
||||
import com.gtnewhorizon.structurelib.net.ErrorHintParticleMessage;
|
||||
import com.gtnewhorizon.structurelib.net.UpdateHintParticleMessage;
|
||||
|
||||
@@ -110,17 +108,6 @@ public class CommonProxy {
|
||||
}
|
||||
}
|
||||
|
||||
private static final SyncedKeybind MODE_SWAP_KEY = SyncedKeybind.createConfigurable(
|
||||
"item.structurelib.constructableTrigger.keys.cycleMode",
|
||||
"item.structurelib.constructableTrigger.keyCategory",
|
||||
0).registerGlobalListener((entityPlayerMP, syncedKeybind, isDown) -> {
|
||||
if (!isDown) return;
|
||||
final ItemStack held = entityPlayerMP.getHeldItem();
|
||||
if (held != null && held.getItem() instanceof ItemConstructableTrigger) {
|
||||
ItemConstructableTrigger.cycleMode(held);
|
||||
}
|
||||
});
|
||||
|
||||
public void displayConfigGUI(String category) {}
|
||||
|
||||
public static class ForgeEventHandler {
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
package com.gtnewhorizon.structurelib;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IStructureCompat {
|
||||
|
||||
void markTextureUsed(IIcon o);
|
||||
|
||||
boolean checkServerUtilitiesPermission(World world, EntityPlayer actor, int x, int z);
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class StructureLib {
|
||||
@Mod.Instance
|
||||
static StructureLib INSTANCE;
|
||||
@Mod.Instance(STRUCTURECOMPAT_MODID)
|
||||
public static Object COMPAT;
|
||||
static Object COMPAT;
|
||||
|
||||
static Block blockHint;
|
||||
static Item itemBlockHint;
|
||||
|
||||
@@ -14,8 +14,28 @@ import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation;
|
||||
|
||||
public interface IAlignmentLimits {
|
||||
|
||||
/**
|
||||
* Can be placed in any orientation.
|
||||
*/
|
||||
IAlignmentLimits UNLIMITED = (direction, rotation, flip) -> true;
|
||||
|
||||
/**
|
||||
* Must be standing upright; i.e., top side of the block facing up.
|
||||
*/
|
||||
IAlignmentLimits UPRIGHT = (direction, rotation, flip) -> direction.offsetY == 0
|
||||
&& (flip.isVerticallyFliped() ? rotation.isUpsideDown() : rotation.isNotRotated());
|
||||
|
||||
/**
|
||||
* Can be in any orientation except upside down; i.e., top side of the block facing down.
|
||||
*/
|
||||
IAlignmentLimits NOT_UPSIDE_DOWN = (direction, rotation, flip) -> direction.offsetY != 0
|
||||
|| (flip.isVerticallyFliped() ? !rotation.isNotRotated() : !rotation.isUpsideDown());
|
||||
|
||||
/**
|
||||
* Front side of the block must be facing up.
|
||||
*/
|
||||
IAlignmentLimits FACING_UP = (direction, rotation, flip) -> direction == ForgeDirection.UP;
|
||||
|
||||
boolean isNewExtendedFacingValid(ForgeDirection direction, Rotation rotation, Flip flip);
|
||||
|
||||
default boolean isNewExtendedFacingValid(ExtendedFacing alignment) {
|
||||
|
||||
@@ -57,12 +57,12 @@ public class ConstructableUtility {
|
||||
}
|
||||
|
||||
IConstructable constructable = null;
|
||||
if (tTileEntity instanceof IConstructableProvider aConstructableProvider)
|
||||
constructable = aConstructableProvider.getConstructable();
|
||||
else if (tTileEntity instanceof IConstructable aConstructable) {
|
||||
constructable = aConstructable;
|
||||
if (tTileEntity instanceof IConstructableProvider)
|
||||
constructable = ((IConstructableProvider) tTileEntity).getConstructable();
|
||||
else if (tTileEntity instanceof IConstructable) {
|
||||
constructable = (IConstructable) tTileEntity;
|
||||
} else if (IMultiblockInfoContainer.contains(tTileEntity.getClass())) {
|
||||
ExtendedFacing facing = tTileEntity instanceof IAlignment alignment ? alignment.getExtendedFacing()
|
||||
ExtendedFacing facing = tTileEntity instanceof IAlignment ? ((IAlignment) tTileEntity).getExtendedFacing()
|
||||
: ExtendedFacing.of(ForgeDirection.getOrientation(aSide));
|
||||
constructable = IMultiblockInfoContainer.<TileEntity>get(tTileEntity.getClass())
|
||||
.toConstructable(tTileEntity, facing);
|
||||
@@ -70,13 +70,14 @@ public class ConstructableUtility {
|
||||
|
||||
if (constructable == null) return false;
|
||||
|
||||
if (aPlayer instanceof EntityPlayerMP playerMP) {
|
||||
if (aPlayer instanceof EntityPlayerMP) {
|
||||
EntityPlayerMP playerMP = (EntityPlayerMP) aPlayer;
|
||||
// server side and sneaking (already checked above)
|
||||
// do construct
|
||||
if (aPlayer.capabilities.isCreativeMode) {
|
||||
constructable.construct(aStack, false);
|
||||
} else if (constructable instanceof ISurvivalConstructable aConstructable) {
|
||||
int built = aConstructable.survivalConstruct(
|
||||
} else if (constructable instanceof ISurvivalConstructable) {
|
||||
int built = ((ISurvivalConstructable) constructable).survivalConstruct(
|
||||
aStack,
|
||||
ConfigurationHandler.INSTANCE.getAutoPlaceBudget(),
|
||||
ISurvivalBuildEnvironment.create(IItemSource.fromPlayer(playerMP), playerMP));
|
||||
|
||||
@@ -50,6 +50,10 @@ public class BlockHint extends Block {
|
||||
|
||||
@Override
|
||||
public IIcon getIcon(int aSide, int aMeta) {
|
||||
// For numbered hints, top and bottom are blank
|
||||
if (aSide <= 1 && aMeta <= 11) {
|
||||
return hint[13];
|
||||
}
|
||||
return hint[aMeta];
|
||||
}
|
||||
|
||||
|
||||
@@ -164,40 +164,17 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
list.onGuiInit(this);
|
||||
autoCompleteList.onGuiInit(this);
|
||||
|
||||
addButton(
|
||||
new GuiButton(
|
||||
ADD_BTN,
|
||||
guiLeft + 12,
|
||||
guiTop + 157,
|
||||
47,
|
||||
20,
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.add")));
|
||||
addButton(
|
||||
new GuiButton(
|
||||
UNSET_BTN,
|
||||
guiLeft + 65,
|
||||
guiTop + 157,
|
||||
47,
|
||||
20,
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.unset")));
|
||||
addButton(
|
||||
new GuiButton(
|
||||
WIPE_BTN,
|
||||
guiLeft + 118,
|
||||
guiTop + 157,
|
||||
47,
|
||||
20,
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.wipe")));
|
||||
addButton(new GuiButton(ADD_BTN, guiLeft + 12, guiTop + 157, 47, 20, I18n.format(I18N_PREFIX + "add")));
|
||||
addButton(new GuiButton(UNSET_BTN, guiLeft + 65, guiTop + 157, 47, 20, I18n.format(I18N_PREFIX + "unset")));
|
||||
addButton(new GuiButton(WIPE_BTN, guiLeft + 118, guiTop + 157, 47, 20, I18n.format(I18N_PREFIX + "wipe")));
|
||||
|
||||
updateButtons();
|
||||
tooltipSplitCache.clear();
|
||||
info = StreamSupport
|
||||
.stream(
|
||||
Splitter.on("\\n").split(
|
||||
StatCollector.translateToLocal("item.structurelib.constructableTrigger.gui.info"))
|
||||
.spliterator(),
|
||||
Splitter.on("\\n").split(StatCollector.translateToLocal(I18N_PREFIX + "info")).spliterator(),
|
||||
false)
|
||||
.flatMap(line -> fontRendererObj.listFormattedStringToWidth(line, width * 3 / 5).stream())
|
||||
.flatMap(line -> fontRendererObj.listFormattedStringToWidth(line, width * 1 / 3).stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -241,8 +218,7 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
actionPerformed(but);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<GuiButton> getButtonList() {
|
||||
public List<GuiButton> getButtonList() {
|
||||
return buttonList;
|
||||
}
|
||||
|
||||
@@ -285,6 +261,11 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
switch (aKey) {
|
||||
case Keyboard.KEY_TAB:
|
||||
if (key.isFocused()) {
|
||||
if (autoCompleteList.getSelectedElement() != null) {
|
||||
key.setText(autoCompleteList.getSelectedElement());
|
||||
return;
|
||||
}
|
||||
|
||||
key.setFocused(false);
|
||||
value.setFocused(true);
|
||||
} else {
|
||||
@@ -322,11 +303,10 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (key.textboxKeyTyped(aChar, aKey)) {
|
||||
if (key.textboxKeyTyped(aChar, aKey) || value.textboxKeyTyped(aChar, aKey)) {
|
||||
updateButtons();
|
||||
return;
|
||||
}
|
||||
if (value.textboxKeyTyped(aChar, aKey)) return;
|
||||
super.keyTyped(aChar, aKey);
|
||||
}
|
||||
|
||||
@@ -337,7 +317,8 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
boolean existing = !StringUtils.isEmpty(keyText) && ChannelDataAccessor.hasSubChannel(trigger, keyText);
|
||||
getButtonList().get(ADD_BTN).displayString = existing ? I18n.format(I18N_PREFIX + "set")
|
||||
: I18n.format(I18N_PREFIX + "add");
|
||||
getButtonList().get(ADD_BTN).enabled = !StringUtils.isBlank(value.getText())
|
||||
getButtonList().get(ADD_BTN).enabled = !StringUtils.isBlank(key.getText())
|
||||
&& !StringUtils.isBlank(value.getText())
|
||||
&& Integer.parseInt(value.getText()) > 0;
|
||||
getButtonList().get(UNSET_BTN).enabled = existing && !StringUtils.isBlank(value.getText());
|
||||
|
||||
@@ -397,22 +378,10 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
int topLeftY = (this.height - this.getYSize()) / 2;
|
||||
drawTexturedModalRect(topLeftX, topLeftY, 0, 0, getXSize(), getYSize());
|
||||
list.drawScreen(mX, mY, partialTick);
|
||||
fontRendererObj.drawString(
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.title"),
|
||||
guiLeft + 12,
|
||||
guiTop + 9,
|
||||
0);
|
||||
fontRendererObj.drawString(
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.key"),
|
||||
guiLeft + 12,
|
||||
guiTop + 122,
|
||||
0);
|
||||
fontRendererObj.drawString(I18n.format(I18N_PREFIX + "title"), guiLeft + 12, guiTop + 9, 0);
|
||||
fontRendererObj.drawString(I18n.format(I18N_PREFIX + "key"), guiLeft + 12, guiTop + 122, 0);
|
||||
key.drawTextBox();
|
||||
fontRendererObj.drawString(
|
||||
I18n.format("item.structurelib.constructableTrigger.gui.value"),
|
||||
guiLeft + 12,
|
||||
guiTop + 142,
|
||||
0);
|
||||
fontRendererObj.drawString(I18n.format(I18N_PREFIX + "value"), guiLeft + 12, guiTop + 142, 0);
|
||||
value.drawTextBox();
|
||||
}
|
||||
|
||||
@@ -455,7 +424,7 @@ public class GuiScreenConfigureChannels extends GuiContainer implements IGuiScre
|
||||
tooltip.addAll(
|
||||
fontRendererObj.listFormattedStringToWidth(
|
||||
StatCollector.translateToLocalFormatted(
|
||||
"item.structurelib.constructableTrigger.gui.channels.from",
|
||||
I18N_PREFIX + "channels.from",
|
||||
Loader.instance().getIndexedModList().get(e.getKey()).getName()),
|
||||
maxLine));
|
||||
tooltip.addAll(
|
||||
|
||||
@@ -7,11 +7,9 @@ import static net.minecraft.util.StatCollector.translateToLocalFormatted;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.renderer.texture.IIconRegister;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.util.StatCollector;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
@@ -20,65 +18,22 @@ import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility;
|
||||
|
||||
public class ItemConstructableTrigger extends ModeToggleableItem {
|
||||
|
||||
private static final IIcon[] textures = new IIcon[3];
|
||||
public class ItemConstructableTrigger extends Item {
|
||||
|
||||
public ItemConstructableTrigger() {
|
||||
setUnlocalizedName("structurelib.constructableTrigger");
|
||||
setTextureName(MOD_ID + ":itemConstructableTrigger");
|
||||
setCreativeTab(StructureLib.creativeTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerIcons(IIconRegister register) {
|
||||
textures[0] = register.registerIcon(MOD_ID + ":constructableTrigger/BUILDING");
|
||||
textures[1] = register.registerIcon(MOD_ID + ":constructableTrigger/UPDATING");
|
||||
textures[2] = register.registerIcon(MOD_ID + ":constructableTrigger/REMOVING");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIcon getIcon(ItemStack stack, int renderPass, EntityPlayer player, ItemStack usingItem, int useRemaining) {
|
||||
return getIcon(stack, renderPass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIcon getIcon(ItemStack stack, int pass) {
|
||||
if (!stack.hasTagCompound() || !stack.getTagCompound().hasKey(TAG_MODE)) {
|
||||
return textures[0];
|
||||
}
|
||||
return textures[stack.getTagCompound().getInteger(TAG_MODE)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemStackDisplayName(ItemStack stack) {
|
||||
if (!stack.hasTagCompound() || !stack.getTagCompound().hasKey(TAG_MODE)) {
|
||||
return getDisplayName(0);
|
||||
}
|
||||
return getDisplayName(stack.getTagCompound().getInteger(TAG_MODE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIcon getIconIndex(ItemStack stack) {
|
||||
return getIcon(stack, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIcon getIconFromDamage(int damage) {
|
||||
return textures[damage];
|
||||
}
|
||||
|
||||
private String getDisplayName(int mode) {
|
||||
return StatCollector.translateToLocal("item.structurelib.constructableTrigger.name") + " - "
|
||||
+ StatCollector.translateToLocal("item.structurelib.constructableTrigger.modes." + mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack onItemRightClick(ItemStack stack, World world, EntityPlayer player) {
|
||||
if (!world.isRemote && getMovingObjectPositionFromPlayer(world, player, true) == null) {
|
||||
if (player.isSneaking()) {
|
||||
StructureLib.instance().proxy().displayConfigGUI("registries");
|
||||
} else {
|
||||
if (getMovingObjectPositionFromPlayer(world, player, true) == null) {
|
||||
// channel gui is opened from server and config gui from client
|
||||
if (!world.isRemote && !player.isSneaking()) {
|
||||
player.openGui(StructureLib.instance(), 0, world, player.inventory.currentItem, 0, 0);
|
||||
} else if (world.isRemote && player.isSneaking()) {
|
||||
StructureLib.instance().proxy().displayConfigGUI("registries");
|
||||
}
|
||||
}
|
||||
return super.onItemRightClick(stack, world, player);
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.gtnewhorizon.structurelib.item;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagInt;
|
||||
|
||||
public class ModeToggleableItem extends Item {
|
||||
|
||||
public enum TriggerMode {
|
||||
BUILDING,
|
||||
UPDATING,
|
||||
REMOVING
|
||||
}
|
||||
|
||||
public static TriggerMode getMode(ItemStack held) {
|
||||
if (held == null || !held.hasTagCompound() || !held.getTagCompound().hasKey(TAG_MODE)) {
|
||||
// default behavior
|
||||
return TriggerMode.BUILDING;
|
||||
}
|
||||
// get user-defined mode
|
||||
return TriggerMode.values()[held.getTagCompound().getInteger(TAG_MODE)];
|
||||
}
|
||||
|
||||
public static void cycleMode(ItemStack held) {
|
||||
if (held.getTagCompound() == null) held.setTagCompound(new NBTTagCompound());
|
||||
if (!held.getTagCompound().hasKey(TAG_MODE)) held.getTagCompound().setTag(TAG_MODE, new NBTTagInt(0));
|
||||
held.getTagCompound().setInteger(TAG_MODE, (held.getTagCompound().getInteger(TAG_MODE) + 1) % 3);
|
||||
}
|
||||
|
||||
protected static final String TAG_MODE = "mode";
|
||||
}
|
||||
@@ -319,6 +319,22 @@ public interface IStructureDefinition<T> {
|
||||
return walker.getBuilt();
|
||||
}
|
||||
|
||||
default void iterate(String piece, World world, ExtendedFacing extendedFacing, int basePositionX, int basePositionY,
|
||||
int basePositionZ, int basePositionA, int basePositionB, int basePositionC, IStructureWalker<T> predicate) {
|
||||
StructureUtility.iterateV2(
|
||||
getStructureFor(piece),
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
predicate,
|
||||
"customIterate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Low level utility.
|
||||
*
|
||||
@@ -348,47 +364,77 @@ public interface IStructureDefinition<T> {
|
||||
}
|
||||
|
||||
if (checkBlocksIfNotNullForceCheckAllIfTrue != null) {
|
||||
boolean success = StructureUtility.iterateV2(
|
||||
elements,
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
checkBlocksIfNotNullForceCheckAllIfTrue ? (e, w, x, y, z, a, b, c) -> e.check(object, w, x, y, z)
|
||||
: skipBlockUnloaded((e, w, x, y, z, a, b, c) -> e.check(object, w, x, y, z)),
|
||||
checkBlocksIfNotNullForceCheckAllIfTrue ? "check" : "check force");
|
||||
boolean success;
|
||||
if (checkBlocksIfNotNullForceCheckAllIfTrue) {
|
||||
success = StructureUtility.iterateV2(
|
||||
elements,
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
(e, w, x, y, z, a, b, c) -> e.check(object, w, x, y, z),
|
||||
"check");
|
||||
} else {
|
||||
success = StructureUtility.iterateV2(
|
||||
elements,
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
skipBlockUnloaded((e, w, x, y, z, a, b, c) -> e.check(object, w, x, y, z)),
|
||||
"check force");
|
||||
}
|
||||
if (StructureLibAPI.isDebugEnabled() && success) {
|
||||
StructureLib.LOGGER
|
||||
.info("Multi [" + basePositionX + ", " + basePositionY + ", " + basePositionZ + "] pass");
|
||||
}
|
||||
return success;
|
||||
} else {
|
||||
StructureUtility.iterateV2(
|
||||
elements,
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
hintsOnly ? ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
|
||||
e.spawnHint(object, world, x, y, z, trigger);
|
||||
if (ChannelDataAccessor.hasSubChannel(trigger, "show_error")
|
||||
&& !e.couldBeValid(object, world, x, y, z, trigger)) {
|
||||
StructureLibAPI.markHintParticleError(StructureLib.getCurrentPlayer(), world, x, y, z);
|
||||
}
|
||||
return true;
|
||||
}) : ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
|
||||
e.placeBlock(object, world, x, y, z, trigger);
|
||||
return true;
|
||||
}),
|
||||
hintsOnly ? "spawnHint" : "placeBlock");
|
||||
if (hintsOnly) {
|
||||
StructureUtility.iterateV2(
|
||||
elements,
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
|
||||
e.spawnHint(object, world, x, y, z, trigger);
|
||||
if (ChannelDataAccessor.hasSubChannel(trigger, StructureLibAPI.CHANNEL_SHOW_ERROR)
|
||||
&& !e.couldBeValid(object, world, x, y, z, trigger)) {
|
||||
StructureLibAPI.markHintParticleError(StructureLib.getCurrentPlayer(), world, x, y, z);
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
"spawnHint");
|
||||
} else {
|
||||
StructureUtility.iterateV2(
|
||||
elements,
|
||||
world,
|
||||
extendedFacing,
|
||||
basePositionX,
|
||||
basePositionY,
|
||||
basePositionZ,
|
||||
basePositionA,
|
||||
basePositionB,
|
||||
basePositionC,
|
||||
ignoreBlockUnloaded((e, w, x, y, z, a, b, c) -> {
|
||||
e.placeBlock(object, world, x, y, z, trigger);
|
||||
return true;
|
||||
}),
|
||||
"placeBlock");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE;
|
||||
import static com.gtnewhorizon.structurelib.item.ModeToggleableItem.TriggerMode.REMOVING;
|
||||
import static com.gtnewhorizon.structurelib.structure.StructureUtility.checkForRemoving;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@@ -23,7 +21,6 @@ import net.minecraft.util.IChatComponent;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
|
||||
import com.gtnewhorizon.structurelib.util.ItemStackPredicate;
|
||||
import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode;
|
||||
|
||||
@@ -140,14 +137,12 @@ public interface IStructureElement<T> {
|
||||
*/
|
||||
default PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
BlocksToPlace e = getBlocksToPlace(t, world, x, y, z, trigger, env);
|
||||
IItemSource source = env.getSource();
|
||||
EntityPlayer actor = env.getActor();
|
||||
Consumer<IChatComponent> chatter = env.getChatter();
|
||||
if (e != null) {
|
||||
PlaceResult skipOrRejectBasedOnCheck = checkForRemoving(mode, check(t, world, x, y, z), world, x, y, z);
|
||||
if (skipOrRejectBasedOnCheck != PlaceResult.ACCEPT) return skipOrRejectBasedOnCheck;
|
||||
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
|
||||
if (e.getStacks() == null) {
|
||||
ItemStack taken = source.takeOne(e.getPredicate(), true);
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
@@ -164,7 +159,7 @@ public interface IStructureElement<T> {
|
||||
chatter);
|
||||
}
|
||||
for (ItemStack stack : e.getStacks()) {
|
||||
if (mode != REMOVING && !source.takeOne(stack, true)) continue;
|
||||
if (!source.takeOne(stack, true)) continue;
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
stack,
|
||||
NBTMode.EXACT,
|
||||
|
||||
@@ -2,8 +2,25 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import net.minecraft.world.World;
|
||||
|
||||
interface IStructureWalker<T> {
|
||||
/**
|
||||
* A functional interface that is used to iterate over an arbitrary structure.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IStructureWalker<T> {
|
||||
|
||||
/**
|
||||
* Called once per structure element.
|
||||
*
|
||||
* @param element The current element
|
||||
* @param world The current world
|
||||
* @param x The absolute X position of the element in world coordinates
|
||||
* @param y The absolute Y position of the element in world coordinates
|
||||
* @param z The absolute Z position of the element in world coordinates
|
||||
* @param a The relative A position of the element in structure-local coordinates (pre transform)
|
||||
* @param b The relative B position of the element in structure-local coordinates (pre transform)
|
||||
* @param c The relative C position of the element in structure-local coordinates (pre transform)
|
||||
* @return False to stop iterating, true to continue.
|
||||
*/
|
||||
boolean visit(IStructureElement<T> element, World world, int x, int y, int z, int a, int b, int c);
|
||||
|
||||
default boolean blockNotLoaded(IStructureElement<T> element, World world, int x, int y, int z, int a, int b,
|
||||
|
||||
@@ -2,17 +2,32 @@ package com.gtnewhorizon.structurelib.structure;
|
||||
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.LOGGER;
|
||||
import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE;
|
||||
import static com.gtnewhorizon.structurelib.item.ModeToggleableItem.TriggerMode.*;
|
||||
import static java.lang.Integer.MIN_VALUE;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.*;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.init.Blocks;
|
||||
@@ -31,13 +46,11 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizon.structurelib.IStructureCompat;
|
||||
import com.gtnewhorizon.structurelib.StructureEvent.StructureElementVisitedEvent;
|
||||
import com.gtnewhorizon.structurelib.StructureLib;
|
||||
import com.gtnewhorizon.structurelib.StructureLibAPI;
|
||||
import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor;
|
||||
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
|
||||
import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger;
|
||||
import com.gtnewhorizon.structurelib.structure.IStructureElement.PlaceResult;
|
||||
import com.gtnewhorizon.structurelib.structure.adders.IBlockAdder;
|
||||
import com.gtnewhorizon.structurelib.structure.adders.ITileAdder;
|
||||
@@ -193,11 +206,7 @@ public class StructureUtility {
|
||||
|
||||
@Override
|
||||
public boolean placeBlock(Object o, World world, int x, int y, int z, ItemStack trigger) {
|
||||
placeRemoveOrUpdate(
|
||||
trigger,
|
||||
() -> world.setBlock(x, y, z, StructureLibAPI.getBlockHint(), 14, 2),
|
||||
() -> world.setBlock(x, y, z, StructureLibAPI.getBlockHint(), 14, 2),
|
||||
() -> world.setBlock(x, y, z, Blocks.air, 0, 2));
|
||||
world.setBlock(x, y, z, StructureLibAPI.getBlockHint(), 14, 2);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -210,16 +219,11 @@ public class StructureUtility {
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(Object o, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
if (mode != REMOVING && check(o, world, x, y, z)) return PlaceResult.SKIP;
|
||||
if (check(o, world, x, y, z)) return PlaceResult.SKIP;
|
||||
// user should place anything here.
|
||||
// maybe make this configurable, but for now we try to take some cobble from user
|
||||
if (env.getSource().takeOne(new ItemStack(Blocks.cobblestone), false)) {
|
||||
placeRemoveOrUpdate(
|
||||
trigger,
|
||||
() -> world.setBlock(x, y, z, Blocks.cobblestone, 0, 2),
|
||||
() -> world.setBlock(x, y, z, Blocks.cobblestone, 0, 2),
|
||||
() -> world.setBlock(x, y, z, Blocks.air, 0, 2));
|
||||
world.setBlock(x, y, z, Blocks.cobblestone, 0, 2);
|
||||
}
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
@@ -326,91 +330,28 @@ public class StructureUtility {
|
||||
public static PlaceResult survivalPlaceBlock(Block block, int meta, World world, int x, int y, int z, IItemSource s,
|
||||
EntityPlayer actor, Consumer<IChatComponent> chatter) {
|
||||
if (block == null) throw new NullPointerException();
|
||||
ItemConstructableTrigger.TriggerMode mode = BUILDING;
|
||||
if (actor.getHeldItem() != null && actor.getHeldItem().getItem() instanceof ItemConstructableTrigger) {
|
||||
// best effort lookup if the item in the player's hand is a trigger, and if it is, get the mode from the
|
||||
// ...trigger instead of assuming default behavior
|
||||
mode = ItemConstructableTrigger.getMode(actor.getHeldItem());
|
||||
}
|
||||
if (mode == BUILDING && !StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor))
|
||||
return PlaceResult.REJECT;
|
||||
if (mode == UPDATING) {
|
||||
if (!world.isAirBlock(x, y, z)) {
|
||||
if (world.getTileEntity(x, y, z) instanceof TileEntity) {
|
||||
// We're in updating mode and the block we're looking at might be important, so let's just leave it
|
||||
// alone
|
||||
// since it's probably not something we want to replace with something else
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
Block blockInWorld = world.getBlock(x, y, z);
|
||||
if (blockInWorld.isAssociatedBlock(block) && blockInWorld.getDamageValue(world, x, y, z) == meta) {
|
||||
// This is the block we are looking for, move along
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT;
|
||||
Item itemBlock = Item.getItemFromBlock(block);
|
||||
int itemMeta = itemBlock instanceof ISpecialItemBlock
|
||||
? ((ISpecialItemBlock) itemBlock).getItemMetaFromBlockMeta(block, meta)
|
||||
: meta;
|
||||
ItemStack stack = new ItemStack(itemBlock, 1, itemMeta);
|
||||
if (mode != REMOVING) {
|
||||
if (!s.takeOne(stack, true)) {
|
||||
if (chatter != null) chatter.accept(
|
||||
new ChatComponentTranslation(
|
||||
"structurelib.autoplace.error.no_simple_block",
|
||||
stack.func_151000_E()));
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
if (block instanceof ICustomBlockSetting) {
|
||||
ICustomBlockSetting blockCustom = (ICustomBlockSetting) block;
|
||||
blockCustom.setBlock(world, x, y, z, meta);
|
||||
} else {
|
||||
if (mode == UPDATING && !world.isAirBlock(x, y, z) && checkPermission(world, actor, x, y, z)) {
|
||||
// We're in updating mode and there's a block in our way (grr), so let's remove whatever is there
|
||||
// ...and drop it to the player
|
||||
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
|
||||
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
|
||||
if (!world.setBlock(x, y, z, Blocks.air, 0, 4) || !tryGiveOrDropItem(world, actor, toGive)) {
|
||||
// We either weren't able to give the player the block that was there, or we weren't able to
|
||||
// remove
|
||||
// the block, either way, we need to reject the update. Also, since we hid the block update from
|
||||
// the client in an effort to make the exchange as seamless as possible, we need to now notify
|
||||
// the client if we did successfully remove the block.
|
||||
if (world.isAirBlock(x, y, z)) world.notifyBlockChange(x, y, z, Blocks.air);
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
}
|
||||
if (!stack.copy()
|
||||
.tryPlaceItemIntoWorld(actor, world, x, y, z, ForgeDirection.UP.ordinal(), 0.5f, 0.5f, 0.5f)) {
|
||||
if (!s.takeOne(stack, true)) {
|
||||
if (chatter != null) chatter.accept(
|
||||
new ChatComponentTranslation(
|
||||
"structurelib.autoplace.error.no_simple_block",
|
||||
stack.func_151000_E()));
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
if (block instanceof ICustomBlockSetting) {
|
||||
ICustomBlockSetting blockCustom = (ICustomBlockSetting) block;
|
||||
blockCustom.setBlock(world, x, y, z, meta);
|
||||
} else if (!stack.copy()
|
||||
.tryPlaceItemIntoWorld(actor, world, x, y, z, ForgeDirection.UP.ordinal(), 0.5f, 0.5f, 0.5f)) {
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mode == REMOVING) {
|
||||
// We're in removing mode, so let's check some stuff
|
||||
if (world.isAirBlock(x, y, z)) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
|
||||
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
|
||||
if (!checkPermission(world, actor, x, y, z)) {
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
world.setBlockToAir(x, y, z);
|
||||
if (!tryGiveOrDropItem(world, actor, toGive)) {
|
||||
// We're in removing mode and something went wrong while trying to give the player the block we removed,
|
||||
// let's just fail for now
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
} else if (!s.takeOne(stack, false)) {
|
||||
// If the user didn't have the block in their inventory, and we're in some
|
||||
// other mode, let's check some stuff
|
||||
if (world.isAirBlock(x, y, z)) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
|
||||
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
|
||||
if (!s.takeOne(stack, false)) {
|
||||
// rollback
|
||||
world.setBlockToAir(x, y, z);
|
||||
}
|
||||
return PlaceResult.ACCEPT;
|
||||
@@ -503,90 +444,24 @@ public class StructureUtility {
|
||||
if (stack == null) throw new NullPointerException();
|
||||
if (stack.stackSize != 1) throw new IllegalArgumentException();
|
||||
if (!(stack.getItem() instanceof ItemBlock)) throw new IllegalArgumentException();
|
||||
ItemConstructableTrigger.TriggerMode mode = BUILDING;
|
||||
if (actor.getHeldItem() != null && actor.getHeldItem().getItem() instanceof ItemConstructableTrigger) {
|
||||
// best effort lookup if the item in the player's hand is a trigger, and if it is, get the mode from the
|
||||
// ...trigger instead of assuming default behavior
|
||||
mode = ItemConstructableTrigger.getMode(actor.getHeldItem());
|
||||
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT;
|
||||
if (!assumeStackPresent && !s.takeOne(stack, true)) {
|
||||
if (chatter != null) chatter.accept(
|
||||
new ChatComponentTranslation("structurelib.autoplace.error.no_item_stack", stack.func_151000_E()));
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
if (mode != REMOVING) {
|
||||
if (mode == BUILDING) {
|
||||
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
}
|
||||
if (mode == UPDATING) {
|
||||
if (!world.isAirBlock(x, y, z)) {
|
||||
if (world.getTileEntity(x, y, z) instanceof TileEntity) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
Block blockInWorld = world.getBlock(x, y, z);
|
||||
ItemStack blockInWorldItem = new ItemStack(blockInWorld);
|
||||
blockInWorldItem.setItemDamage(blockInWorld.getDamageValue(world, x, y, z));
|
||||
if (blockInWorldItem.isItemEqual(stack)) {
|
||||
// This is the block we are looking for, move along
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!assumeStackPresent && !s.takeOne(stack, true)) {
|
||||
if (chatter != null) chatter.accept(
|
||||
new ChatComponentTranslation(
|
||||
"structurelib.autoplace.error.no_item_stack",
|
||||
stack.func_151000_E()));
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
if (mode == UPDATING && !world.isAirBlock(x, y, z) && checkPermission(world, actor, x, y, z)) {
|
||||
// We're in updating mode and there's a block in our way (grr), so let's remove whatever is there
|
||||
// ...and drop it to the player
|
||||
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
|
||||
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
|
||||
if (!world.setBlock(x, y, z, Blocks.air, 0, 4) || !tryGiveOrDropItem(world, actor, toGive)) {
|
||||
// We either weren't able to give the player the block that was there, or we weren't able to remove
|
||||
// the block, either way, we need to reject the update. Also, since we hid the block update from
|
||||
// the client in an effort to make the exchange as seamless as possible, we need to now notify
|
||||
// the client if we did successfully remove the block.
|
||||
if (world.isAirBlock(x, y, z)) world.notifyBlockChange(x, y, z, Blocks.air);
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
}
|
||||
if (!stack.copy()
|
||||
.tryPlaceItemIntoWorld(actor, world, x, y, z, ForgeDirection.UP.ordinal(), 0.5f, 0.5f, 0.5f)) {
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
}
|
||||
if (mode == REMOVING) {
|
||||
if (world.isAirBlock(x, y, z)) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
// If we're in removing mode, we set it to air
|
||||
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
|
||||
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
|
||||
if (!checkPermission(world, actor, x, y, z)) {
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
if (!stack.copy().tryPlaceItemIntoWorld(actor, world, x, y, z, ForgeDirection.UP.ordinal(), 0.5f, 0.5f, 0.5f))
|
||||
return PlaceResult.REJECT;
|
||||
if (!s.takeOne(stack, false))
|
||||
// this is bad! probably an exploit somehow. Let's nullify the block we just placed instead
|
||||
world.setBlockToAir(x, y, z);
|
||||
if (!tryGiveOrDropItem(world, actor, toGive)) {
|
||||
// We were in removing mode and something went wrong while trying to give the player the block we
|
||||
// ...removed, let's just fail for now
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
} else if (!s.takeOne(stack, false)) {
|
||||
if (world.isAirBlock(x, y, z)) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
// If the user didn't have the item in their inventory, we set it to air
|
||||
ItemStack toGive = new ItemStack(world.getBlock(x, y, z));
|
||||
toGive.setItemDamage(world.getBlock(x, y, z).getDamageValue(world, x, y, z));
|
||||
world.setBlockToAir(x, y, z);
|
||||
}
|
||||
return PlaceResult.ACCEPT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a structure element that only allow air (or air equivalents, like Railcraft hidden blocks). You usually
|
||||
* don't need to call this yourselves. Use {@code -} in shape to automatically use this. Provided nonetheless in
|
||||
* case you want this as a fallback to something else.
|
||||
* don't need to call this yourselves. Use {@code -} in shape to automatically use this. Provided nontheless in case
|
||||
* you want this as a fallback to something else.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> IStructureElement<T> isAir() {
|
||||
@@ -595,8 +470,8 @@ public class StructureUtility {
|
||||
|
||||
/**
|
||||
* Return a structure element that allow anything but air (or air equivalents, like Railcraft hidden blocks). You
|
||||
* usually don't need to call this yourselves. Use {@code +} in shape to automatically use this. Provided
|
||||
* nonetheless in case you want this as a fallback to something else.
|
||||
* usually don't need to call this yourselves. Use {@code +} in shape to automatically use this. Provided nontheless
|
||||
* in case you want this as a fallback to something else.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> IStructureElement<T> notAir() {
|
||||
@@ -762,7 +637,7 @@ public class StructureUtility {
|
||||
* given tier, then player will be allowed to use multiple kinds of blocks, but their tier is guaranteed to be the
|
||||
* same.
|
||||
* <p>
|
||||
* <h4>WARNING</h4> <b>You SHOULD NOT return notSet from your tierExtractor.</b> If you do so, we will have this
|
||||
* <h3>WARNING</h3> <b>You SHOULD NOT return notSet from your tierExtractor.</b> If you do so, we will have this
|
||||
* chain of events:
|
||||
* <ul>
|
||||
* <li>at check start, tier is reset to notSet
|
||||
@@ -775,7 +650,7 @@ public class StructureUtility {
|
||||
* doing its business
|
||||
* <li>Player enjoy a (probably) hilariously shaped multi and (probably) reduced build cost.
|
||||
* </ul>
|
||||
* <h4>Example Implementation</h4>
|
||||
* <h3>Example Implementation</h3>
|
||||
* <p>
|
||||
* Assume you have 16 tier, each map to one particular block's 16 different meta. You will usually want something
|
||||
* like this
|
||||
@@ -834,7 +709,7 @@ public class StructureUtility {
|
||||
List<Pair<Block, Integer>> hints = allKnownTiers == null ? Collections.emptyList() : allKnownTiers;
|
||||
if (hints.stream().anyMatch(Objects::isNull)) throw new IllegalArgumentException();
|
||||
IStructureElementCheckOnly<T> check = ofBlocksTiered(tierExtractor, notSet, setter, getter);
|
||||
return new StructureElement_Bridge<>() {
|
||||
return new StructureElement_Bridge<T>() {
|
||||
|
||||
@Override
|
||||
public boolean check(T t, World world, int x, int y, int z) {
|
||||
@@ -859,11 +734,6 @@ public class StructureUtility {
|
||||
return Objects.equals(hintTier, worldTier);
|
||||
}
|
||||
|
||||
private boolean isInAllKnownTiers(Block b) {
|
||||
return allKnownTiers != null
|
||||
&& allKnownTiers.stream().anyMatch(pair -> pair.getLeft().isAssociatedBlock(b));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
|
||||
Pair<Block, Integer> hint = getHint(trigger);
|
||||
@@ -896,21 +766,13 @@ public class StructureUtility {
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
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 (mode == REMOVING) {
|
||||
if (!isInAllKnownTiers(block) && !world.isAirBlock(x, y, z)) {
|
||||
return PlaceResult.REJECT;
|
||||
}
|
||||
} else {
|
||||
if ((Objects.equals(tier, tierExtractor.convert(hint.getKey(), hint.getValue())))) {
|
||||
return PlaceResult.SKIP;
|
||||
}
|
||||
}
|
||||
if (Objects.equals(tier, tierExtractor.convert(hint.getKey(), hint.getValue())))
|
||||
return PlaceResult.SKIP;
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
hint.getKey(),
|
||||
hint.getValue(),
|
||||
@@ -999,9 +861,7 @@ public class StructureUtility {
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
PlaceResult skipOrRejectBasedOnCheck = checkForRemoving(mode, check(t, world, x, y, z), world, x, y, z);
|
||||
if (skipOrRejectBasedOnCheck != PlaceResult.ACCEPT) return skipOrRejectBasedOnCheck;
|
||||
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
|
||||
if (getBlock() == null) return PlaceResult.REJECT;
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
getBlock(),
|
||||
@@ -1088,9 +948,7 @@ public class StructureUtility {
|
||||
@Deprecated
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
PlaceResult skipOrRejectBasedOnCheck = checkForRemoving(mode, check(t, world, x, y, z), world, x, y, z);
|
||||
if (skipOrRejectBasedOnCheck != PlaceResult.ACCEPT) return skipOrRejectBasedOnCheck;
|
||||
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
|
||||
if (init()) return StructureUtility.survivalPlaceBlock(block, meta, world, x, y, z, s, actor, chatter);
|
||||
return fallback.survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
|
||||
}
|
||||
@@ -1098,9 +956,7 @@ public class StructureUtility {
|
||||
@Override
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
PlaceResult skipOrRejectBasedOnCheck = checkForRemoving(mode, check(t, world, x, y, z), world, x, y, z);
|
||||
if (skipOrRejectBasedOnCheck != PlaceResult.ACCEPT) return skipOrRejectBasedOnCheck;
|
||||
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
|
||||
if (init()) return StructureUtility.survivalPlaceBlock(
|
||||
block,
|
||||
meta,
|
||||
@@ -1728,15 +1584,8 @@ public class StructureUtility {
|
||||
@Deprecated
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
PlaceResult skipOrRejectBasedOnCheck = checkForRemoving(
|
||||
mode,
|
||||
world.getBlock(x, y, z) == defaultBlock && world.getBlockMetadata(x, y, z) == defaultMeta,
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z);
|
||||
if (skipOrRejectBasedOnCheck != PlaceResult.ACCEPT) return skipOrRejectBasedOnCheck;
|
||||
if (world.getBlock(x, y, z) == defaultBlock && world.getBlockMetadata(x, y, z) == defaultMeta)
|
||||
return PlaceResult.SKIP;
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
defaultBlock,
|
||||
defaultMeta,
|
||||
@@ -1781,15 +1630,8 @@ public class StructureUtility {
|
||||
@Deprecated
|
||||
public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger,
|
||||
AutoPlaceEnvironment env) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
PlaceResult skipOrRejectBasedOnCheck = checkForRemoving(
|
||||
mode,
|
||||
world.getBlock(x, y, z) == defaultBlock && world.getBlockMetadata(x, y, z) == defaultMeta,
|
||||
world,
|
||||
x,
|
||||
y,
|
||||
z);
|
||||
if (skipOrRejectBasedOnCheck != PlaceResult.ACCEPT) return skipOrRejectBasedOnCheck;
|
||||
if (world.getBlock(x, y, z) == defaultBlock && world.getBlockMetadata(x, y, z) == defaultMeta)
|
||||
return PlaceResult.SKIP;
|
||||
return StructureUtility.survivalPlaceBlock(
|
||||
defaultBlock,
|
||||
defaultMeta,
|
||||
@@ -3423,57 +3265,4 @@ public class StructureUtility {
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a creation, removal, or update operation at the given position
|
||||
*
|
||||
* @param trigger ItemStack for the trigger item
|
||||
* @param onCreate Operation to be performed when the mode of the trigger is set to building mode
|
||||
* @param onUpdate Operation to be performed when the mode of the trigger is set to updating mode
|
||||
* @param onRemove Operation to be performed when the mode of the trigger is set to removing mode
|
||||
*/
|
||||
public static void placeRemoveOrUpdate(ItemStack trigger, Runnable onCreate, Runnable onUpdate, Runnable onRemove) {
|
||||
ItemConstructableTrigger.TriggerMode mode = ItemConstructableTrigger.getMode(trigger);
|
||||
switch (mode) {
|
||||
case BUILDING:
|
||||
onCreate.run();
|
||||
break;
|
||||
case UPDATING:
|
||||
onUpdate.run();
|
||||
break;
|
||||
case REMOVING:
|
||||
onRemove.run();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean tryGiveOrDropItem(World world, EntityPlayer actor, ItemStack stack) {
|
||||
if (actor.inventory.addItemStackToInventory(stack)) {
|
||||
actor.inventoryContainer.detectAndSendChanges();
|
||||
return true;
|
||||
}
|
||||
EntityItem toSpawn = new EntityItem(world, actor.posX, actor.posY, actor.posZ, stack);
|
||||
// For some reason these things sometimes spawn with the velocity of an F1 car, so let's prevent that
|
||||
toSpawn.motionX = 0;
|
||||
toSpawn.motionY = 0;
|
||||
toSpawn.motionZ = 0;
|
||||
return world.spawnEntityInWorld(toSpawn);
|
||||
}
|
||||
|
||||
public static boolean checkPermission(World world, EntityPlayer actor, int x, int y, int z) {
|
||||
boolean res = true;
|
||||
if (StructureLib.COMPAT instanceof IStructureCompat isc) {
|
||||
res = isc.checkServerUtilitiesPermission(world, actor, x, z);
|
||||
}
|
||||
res = res && !world.getBlock(x, y, z).isAssociatedBlock(Blocks.bedrock);
|
||||
// maybe check mining level who knows :shrug:
|
||||
return res;
|
||||
}
|
||||
|
||||
public static PlaceResult checkForRemoving(ItemConstructableTrigger.TriggerMode mode, boolean checkResult,
|
||||
World world, int x, int y, int z) {
|
||||
if (mode != REMOVING && checkResult) return PlaceResult.SKIP;
|
||||
else if (mode != BUILDING && !checkResult && !world.isAirBlock(x, y, z)) return PlaceResult.REJECT;
|
||||
return PlaceResult.ACCEPT;
|
||||
}
|
||||
}
|
||||
@@ -133,16 +133,6 @@ StructureLib API documentation.
|
||||
Usually there is no reason to reimplement this on your own.
|
||||
</p>
|
||||
|
||||
<h2>{@link com.gtnewhorizon.structurelib.item.ModeToggleableItem}</h2>
|
||||
<p>
|
||||
This class is the base class for {@link com.gtnewhorizon.structurelib.item.ItemConstructableTrigger} that defines
|
||||
the <code>TriggerMode</code>s for the {@link com.gtnewhorizon.structurelib.item.ItemConstructableTrigger}. There are
|
||||
3 modes, <code>BUILDING</code>, <code>UPDATING</code>, and <code>REMOVING</code>. Each of these modes does as they
|
||||
say, where building will build a new multi from scratch, updating will remove existing an existing structure and
|
||||
replace it with new components (think upgrading glass on a multi, changing from a tier 1 to tier 2 of a multi, etc),
|
||||
and removing will just straight up remove the multi.
|
||||
</p>
|
||||
|
||||
<h2><a href="#channels" id="channels">Channels</a></h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -22,9 +22,6 @@ item.structurelib.frontRotationTool.desc.1=Rotates only the front panel,
|
||||
item.structurelib.frontRotationTool.desc.2=which allows structure rotation.
|
||||
|
||||
item.structurelib.constructableTrigger.name=Multiblock Structure Hologram Projector
|
||||
item.structurelib.constructableTrigger.modes.0=Building Mode
|
||||
item.structurelib.constructableTrigger.modes.1=Updating Mode
|
||||
item.structurelib.constructableTrigger.modes.2=Removing Mode
|
||||
item.structurelib.constructableTrigger.desc.0=Triggers Constructable Interface
|
||||
item.structurelib.constructableTrigger.desc.1=Shows multiblock construction schematic,
|
||||
item.structurelib.constructableTrigger.desc.2=use on the multiblock controller.
|
||||
@@ -37,17 +34,11 @@ item.structurelib.constructableTrigger.gui.title=Sub Channels
|
||||
item.structurelib.constructableTrigger.gui.key=Key:
|
||||
item.structurelib.constructableTrigger.gui.value=Value:
|
||||
item.structurelib.constructableTrigger.gui.add=Add
|
||||
item.structurelib.constructableTrigger.gui.set=Set
|
||||
item.structurelib.constructableTrigger.gui.unset=Unset
|
||||
item.structurelib.constructableTrigger.gui.wipe=§4Wipe
|
||||
item.structurelib.constructableTrigger.gui.error.show=Show Errors
|
||||
item.structurelib.constructableTrigger.gui.error.hide=Hide Errors
|
||||
item.structurelib.constructableTrigger.gui.gt_no_hatch.enable=No Hatch
|
||||
item.structurelib.constructableTrigger.gui.gt_no_hatch.disable=Hatches
|
||||
item.structurelib.constructableTrigger.keyCategory=Multiblock Structure Hologram Projector Keys
|
||||
item.structurelib.constructableTrigger.keys.cycleMode=Cycle Projector Mode
|
||||
item.structurelib.constructableTrigger.gui.set=Update
|
||||
item.structurelib.constructableTrigger.gui.unset=Remove
|
||||
item.structurelib.constructableTrigger.gui.wipe=§4Clear
|
||||
item.structurelib.constructableTrigger.gui.channels.from=§rMod: §9§o%s
|
||||
item.structurelib.constructableTrigger.gui.info=Many multiblocks support some degree of variation in its structure and use sub channels to indicate which variant to use.\n Sub channels are has a sequence of lower case characters as key and a positive integer as value. Most known sub channels should be available as typeahead completions.\nYou can also drag and drop items from NEI to set the corresponding sub channel value. These items all have a tooltip of §oIndicates value X for sub channel Y§r.
|
||||
item.structurelib.constructableTrigger.gui.info=Many multiblocks support some degree of variation in their structure and a sub channel allows indication of which variant to use.\n All sub channels have a sequence of lowercase characters as key and a positive integer as value. Most known sub channels should be available as typeahead completions.\n You can also drag and drop items from NEI to set the corresponding sub channel value. These items all have a tooltip of "§oIndicates§r §ovalue§r §oX§r §ofor§r §osub§r §ochannel§r §oY§r".
|
||||
|
||||
channels.structurelib.show_errors=When set, will highlight parts of the multiblock that is definitely wrong
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 273 B After Width: | Height: | Size: 176 B |
|
Before Width: | Height: | Size: 279 B After Width: | Height: | Size: 208 B |
|
Before Width: | Height: | Size: 296 B After Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 234 B |
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 196 B |
|
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 186 B |
|
Before Width: | Height: | Size: 285 B After Width: | Height: | Size: 186 B |
|
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 204 B |
|
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 184 B |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 198 B |
|
Before Width: | Height: | Size: 296 B After Width: | Height: | Size: 204 B |
|
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 255 B After Width: | Height: | Size: 133 B |
|
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 183 B |
|
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 197 B |
|
Before Width: | Height: | Size: 281 B After Width: | Height: | Size: 164 B |
|
Before Width: | Height: | Size: 386 B |
|
Before Width: | Height: | Size: 392 B |
|
Before Width: | Height: | Size: 365 B |
|
After Width: | Height: | Size: 667 B |