Compare commits

...

16 Commits

Author SHA1 Message Date
shartte 0632925653 Remove the use of SlotItemHandler since we are only faking an inventory-backed slot, (#4654)
we might as well use what we had used pre-2017, which is simply extending a normal Slot.
This should also fix #4652.
2020-08-29 21:50:06 +02:00
shartte 98b758e6f9 Fixes #4648: Inverted logic for the annihilation plane dropping no items. (#4649) 2020-08-28 16:28:34 +02:00
shartte faa00cd894 Backport Model Registration Changes (#4647)
* Fix Special Model Registration (#4577)

* Fixes #4575 by updating Forge (ModelRegistryEvent is a modbus event but was misflagged as not being one). And update Forge because their breaking change breaks our mod.

* Update gradle.properties

Co-authored-by: yueh <yueh@users.noreply.github.com>

* Update src/main/resources/META-INF/mods.toml

Co-authored-by: yueh <yueh@users.noreply.github.com>

Co-authored-by: yueh <yueh@users.noreply.github.com>

(cherry picked from commit 8733c2c11f)

* Strip pom.xml dependencies.

(cherry picked from commit 00d4c20d9f)
2020-08-28 15:57:47 +02:00
shartte 544491064d Fixes #4635: Actually remove requesters when removing requesters. (#4637) 2020-08-24 19:23:48 +02:00
shartte e533ae5f3f Added step to publish to modmaven (#4607) (#4630)
(cherry picked from commit 7e1bfdb5ac)

Co-authored-by: yueh <yueh@users.noreply.github.com>
2020-08-23 22:30:34 +02:00
shartte 98733844a6 Fixes #4602: Prevent encoding invalid patterns and handle corrupted patterns a little more gracefully. (#4608) (#4629)
(cherry picked from commit 1f9707e256)
2020-08-21 19:24:47 +02:00
shartte ef97381e5f Fixes #4574 by referencing only non-pure fluix crystals in the fluix dust grinder recipe. (#4579) 2020-08-09 12:28:43 +02:00
shartte 27b8c5f3ac Plane Connection Refactor (#4556) (#4565)
* Refactors all plane parts to use a common helper for
calculating connections to adjacent planes.
Also fixes problems with updating these connections on neighbor updates.

* Fix conflicting GuiSync ID.

* Slightly refactor PlaneConnectionHelper, and fix an issue where the bounding box was calculated incorrectly by using the wrong up-direction.

(cherry picked from commit 8617dc8340)
2020-08-05 22:39:04 +02:00
shartte 3043887915 Makes formation planes a bit more consistent and less violent. (#4553) (#4564)
* Makes formation planes a bit more consistent and less violent.

Items will now have a slower speed when spawning as well as a narrower area to avoid having them glitch into a wall and be teleported around

* Removed debug output, added clarifying parenthesis and extracted method.

* Fixes various other issues with the formation plane

Also removed now useless code

(cherry picked from commit 12e3fa9127)
2020-08-05 22:25:48 +02:00
yueh e0abe9b9a9 Fixes #4559: Use visual bounding box for overlay (#4562) 2020-08-05 22:08:48 +02:00
shartte e19991f1f9 Fixes #4547: Name clash between ITooltip#getWidth, ITooltip#getHeight and Vanilla Widget methods leads to missing methods at runtime, since the implementing methods will be remapped to SRG names, while referees of the interface will try to call the renamed methods by their name in the interface, leading to an AbstractMethodError. (#4558) 2020-08-05 18:21:13 +02:00
shartte 3d97b1e3ec Fixes #4551: Bounding box of annihilation planes is too small. (#4552) 2020-08-05 17:45:53 +02:00
yueh 6b1bccffb9 Apply the FE tunnel behaviour to the fluid tunnel (#4550) (#4555) 2020-08-04 23:37:15 +02:00
yueh 6fab7b91b7 Fixes 4529: Updated IPart to match new ICapabilityProvider (#4534) (#4536) 2020-08-01 21:57:26 +02:00
shartte 7b6bab4967 Fix #4521: Register RecipeTypes. (#4523) (#4525) 2020-07-31 20:34:44 +02:00
yueh 04766e5325 Limit gradle to 1 worker for 1.15 (#4526) 2020-07-31 18:51:41 +02:00
46 changed files with 713 additions and 753 deletions
+3 -3
View File
@@ -22,14 +22,14 @@ jobs:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Clean gradle
run: ./gradlew clean --no-daemon
run: ./gradlew clean --no-daemon --max-workers 1
- name: Validate no assets
run: test ! -d ./src/generated
- name: Generate assets
uses: GabrielBB/xvfb-action@v1.2
with:
run: ./gradlew runData --no-daemon
run: ./gradlew runData --no-daemon --max-workers 1
- name: Validate assets
run: test -d ./src/generated -a -f ./src/generated/resources/.cache/cache
- name: Build with Gradle
run: ./gradlew build --no-daemon
run: ./gradlew build --no-daemon --max-workers 1
+3 -3
View File
@@ -22,14 +22,14 @@ jobs:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Clean gradle
run: ./gradlew clean --no-daemon
run: ./gradlew clean --no-daemon --max-workers 1
- name: Validate no assets
run: test ! -d ./src/generated
- name: Generate assets
uses: GabrielBB/xvfb-action@v1.2
with:
run: ./gradlew runData --no-daemon
run: ./gradlew runData --no-daemon --max-workers 1
- name: Validate assets
run: test -d ./src/generated -a -f ./src/generated/resources/.cache/cache
- name: Build with Gradle
run: ./gradlew build --no-daemon
run: ./gradlew build --no-daemon --max-workers 1
+3 -3
View File
@@ -22,19 +22,19 @@ jobs:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Clean gradle
run: ./gradlew clean --no-daemon
run: ./gradlew clean --no-daemon --max-workers 1
- name: Validate no assets
run: test ! -d ./src/generated
- name: Generate assets
uses: GabrielBB/xvfb-action@v1.2
with:
run: ./gradlew runData --no-daemon
run: ./gradlew runData --no-daemon --max-workers 1
- name: Validate assets
run: test -d ./src/generated -a -f ./src/generated/resources/.cache/cache
- name: Build with Gradle
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: ./gradlew build --no-daemon
run: ./gradlew build --no-daemon --max-workers 1
- uses: actions/upload-artifact@v2
with:
name: dist
+12 -4
View File
@@ -33,7 +33,7 @@ jobs:
- name: Generate assets
uses: GabrielBB/xvfb-action@v1.2
with:
run: ./gradlew runData --no-daemon
run: ./gradlew runData --no-daemon --max-workers 1
- name: Validate assets
run: test -d ./src/generated -a -f ./src/generated/resources/.cache/cache
- name: Build with Gradle
@@ -42,7 +42,7 @@ jobs:
KEY_STORE_ALIAS: ${{ secrets.KEY_STORE_ALIAS }}
KEY_STORE_KEY_PASS: ${{ secrets.KEY_STORE_KEY_PASS }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew build --no-daemon
run: ./gradlew build --no-daemon --max-workers 1
- name: Upload to curseforge
env:
KEY_STORE_PASS: ${{ secrets.KEY_STORE_PASS }}
@@ -50,14 +50,22 @@ jobs:
KEY_STORE_KEY_PASS: ${{ secrets.KEY_STORE_KEY_PASS }}
CHANGELOG: ${{ github.event.release.body }}
CURSEFORGE: ${{ secrets.CURSEFORGE }}
run: ./gradlew curseforge --no-daemon
run: ./gradlew curseforge --no-daemon --max-workers 1
- name: Publish to github packages
env:
KEY_STORE_PASS: ${{ secrets.KEY_STORE_PASS }}
KEY_STORE_ALIAS: ${{ secrets.KEY_STORE_ALIAS }}
KEY_STORE_KEY_PASS: ${{ secrets.KEY_STORE_KEY_PASS }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew publish --no-daemon
run: ./gradlew publishMavenPublicationToGitHubPackagesRepository --no-daemon --max-workers 1
- name: Publish to modmaven
env:
KEY_STORE_PASS: ${{ secrets.KEY_STORE_PASS }}
KEY_STORE_ALIAS: ${{ secrets.KEY_STORE_ALIAS }}
KEY_STORE_KEY_PASS: ${{ secrets.KEY_STORE_KEY_PASS }}
MODMAVEN_USER: ${{ secrets.MODMAVEN_USER }}
MODMAVEN_PASSWORD: ${{ secrets.MODMAVEN_PASSWORD }}
run: ./gradlew publishMavenPublicationToModmavenRepository --no-daemon --max-workers 1
- name: Prepare artifact metadata
id: prepare_artifact_metadata
run: |
+15
View File
@@ -174,6 +174,13 @@ publishing {
groupId = project.group
artifactId = project.archivesBaseName
version = project.version
// ForgeGradle will generate wild dependency definitions, see https://github.com/MinecraftForge/ForgeGradle/issues/584
// Since we don't actually depend on anything, just remove the entire node.
pom.withXml {
asNode().remove(asNode().dependencies)
}
from components.java
artifact sourcesJar
artifact javadocJar
@@ -189,5 +196,13 @@ publishing {
name = "GitHubPackages"
url = "https://maven.pkg.github.com/AppliedEnergistics/Applied-Energistics-2"
}
maven {
credentials {
username System.getenv("MODMAVEN_USER")
password System.getenv("MODMAVEN_PASSWORD")
}
name = "modmaven"
url = "https://modmaven.k-4u.nl/artifactory/local-releases/"
}
}
}
@@ -53,6 +53,8 @@ public interface ICraftingHelper {
* @param stack If null, a new item will be created to hold the encoded pattern.
* Otherwise the given item must already contains an encoded
* pattern that will be overwritten.
* @throws IllegalArgumentException If either in or out contain only empty
* ItemStacks.
* @return A new encoded pattern, or the given stack with the pattern encoded in
* it.
*/
@@ -73,6 +75,8 @@ public interface ICraftingHelper {
* operation by the ME system.
* @param allowSubstitutes Controls whether the ME system will allow the use of
* equivalent items to craft this recipe.
* @throws IllegalArgumentException If either in or out contain only empty
* ItemStacks.
*/
ItemStack encodeCraftingPattern(@Nullable ItemStack stack, ICraftingRecipe recipe, ItemStack[] in, ItemStack out,
boolean allowSubstitutes);
+5 -2
View File
@@ -50,6 +50,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import appeng.api.networking.IGridNode;
@@ -346,10 +347,12 @@ public interface IPart extends ICustomCableConnection {
* capabilities on the cable bus will be forwarded to parts on the appropriate
* side.
*
* @see TileEntity#getCapability(Capability, net.minecraft.util.Direction)
* @see CapabilityProvider#getCapability(Capability,
* net.minecraft.util.Direction)
*
* @return The capability or null.
* @return The capability
*/
@Nonnull
default <T> LazyOptional<T> getCapability(Capability<T> capabilityClass) {
return LazyOptional.empty();
}
@@ -154,14 +154,14 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends ContainerS
protected void drawGuiSlot(CustomSlotWidget slot, int mouseX, int mouseY, float partialTicks) {
if (slot.isSlotEnabled()) {
final int left = slot.xPos();
final int top = slot.yPos();
final int right = left + slot.getWidth();
final int bottom = top + slot.getHeight();
final int left = slot.getTooltipAreaX();
final int top = slot.getTooltipAreaY();
final int right = left + slot.getTooltipAreaWidth();
final int bottom = top + slot.getTooltipAreaHeight();
slot.drawContent(getMinecraft(), mouseX, mouseY, partialTicks);
if (this.isPointInRegion(left, top, slot.getWidth(), slot.getHeight(), mouseX, mouseY)
if (this.isPointInRegion(left, top, slot.getTooltipAreaWidth(), slot.getTooltipAreaHeight(), mouseX, mouseY)
&& slot.canClick(getPlayer())) {
RenderSystem.colorMask(true, true, true, false);
this.fillGradient(left, top, right, bottom, -2130706433, -2130706433);
@@ -171,16 +171,16 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends ContainerS
}
private void drawTooltip(ITooltip tooltip, int mouseX, int mouseY) {
final int x = tooltip.xPos(); // ((GuiImgButton) c).x;
int y = tooltip.yPos(); // ((GuiImgButton) c).y;
final int x = tooltip.getTooltipAreaX();
int y = tooltip.getTooltipAreaY();
if (x < mouseX && x + tooltip.getWidth() > mouseX && tooltip.isVisible()) {
if (y < mouseY && y + tooltip.getHeight() > mouseY) {
if (x < mouseX && x + tooltip.getTooltipAreaWidth() > mouseX && tooltip.isTooltipAreaVisible()) {
if (y < mouseY && y + tooltip.getTooltipAreaHeight() > mouseY) {
if (y < 15) {
y = 15;
}
final String msg = tooltip.getMessage();
final String msg = tooltip.getTooltipMessage();
if (msg != null && !msg.isEmpty()) {
this.drawTooltip(x + 11, y + 4, msg);
}
@@ -275,8 +275,8 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends ContainerS
}
for (CustomSlotWidget slot : this.guiSlots) {
if (this.isPointInRegion(slot.xPos(), slot.yPos(), slot.getWidth(), slot.getHeight(), xCoord, yCoord)
&& slot.canClick(getPlayer())) {
if (this.isPointInRegion(slot.getTooltipAreaX(), slot.getTooltipAreaY(), slot.getTooltipAreaWidth(),
slot.getTooltipAreaHeight(), xCoord, yCoord) && slot.canClick(getPlayer())) {
slot.slotClicked(getPlayer().inventory.getItemStack(), btn);
}
}
@@ -8,19 +8,18 @@ import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.items.SlotItemHandler;
/**
* A proxy for a slot that will always return an itemstack with size 1, if there
* is an item in the slot. Used to prevent the default item count from
* rendering.
*/
class Size1Slot extends SlotItemHandler {
class Size1Slot extends Slot {
private final SlotItemHandler delegate;
private final Slot delegate;
public Size1Slot(SlotItemHandler delegate) {
super(delegate.getItemHandler(), delegate.getSlotIndex(), delegate.xPos, delegate.yPos);
public Size1Slot(Slot delegate) {
super(delegate.inventory, delegate.getSlotIndex(), delegate.xPos, delegate.yPos);
this.delegate = delegate;
}
@@ -24,7 +24,7 @@ import java.util.regex.Pattern;
import appeng.api.config.ActionItems;
import appeng.core.localization.ButtonToolTips;
public class ActionButton extends IconButton implements ITooltip {
public class ActionButton extends IconButton {
private static final Pattern PATTERN_NEW_LINE = Pattern.compile("\\n", Pattern.LITERAL);
private final int iconIndex;
@@ -34,32 +34,32 @@ public abstract class CustomSlotWidget extends AbstractGui implements ITooltip {
}
@Override
public String getMessage() {
public String getTooltipMessage() {
return null;
}
@Override
public int xPos() {
public int getTooltipAreaX() {
return this.x;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return 16;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return 16;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return false;
}
@@ -28,38 +28,38 @@ public interface ITooltip {
*
* @return tooltip message
*/
String getMessage();
String getTooltipMessage();
/**
* x Location for the object that triggers the tooltip.
*
* @return xPosition
*/
int xPos();
int getTooltipAreaX();
/**
* y Location for the object that triggers the tooltip.
*
* @return yPosition
*/
int yPos();
int getTooltipAreaY();
/**
* Width of the object that triggers the tooltip.
*
* @return width
*/
int getWidth();
int getTooltipAreaWidth();
/**
* Height for the object that triggers the tooltip.
*
* @return height
*/
int getHeight();
int getTooltipAreaHeight();
/**
* @return true if button being drawn
*/
boolean isVisible();
boolean isTooltipAreaVisible();
}
@@ -95,27 +95,32 @@ public abstract class IconButton extends Button implements ITooltip {
protected abstract int getIconIndex();
@Override
public int xPos() {
public String getTooltipMessage() {
return getMessage();
}
@Override
public int getTooltipAreaX() {
return this.x;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return this.halfSize ? 8 : 16;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return this.halfSize ? 8 : 16;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return this.visible;
}
@@ -76,7 +76,7 @@ public class ProgressBar extends Widget implements ITooltip {
}
@Override
public String getMessage() {
public String getTooltipMessage() {
if (this.fullMsg != null) {
return this.fullMsg;
}
@@ -86,27 +86,27 @@ public class ProgressBar extends Widget implements ITooltip {
}
@Override
public int xPos() {
public int getTooltipAreaX() {
return this.x - 2;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y - 2;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return this.width + 4;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return this.height + 4;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return true;
}
@@ -278,7 +278,7 @@ public class SettingToggleButton<T extends Enum<T>> extends IconButton {
}
@Override
public String getMessage() {
public String getTooltipMessage() {
ITextComponent displayName = null;
ITextComponent displayValue = null;
@@ -97,27 +97,32 @@ public class TabButton extends Button implements ITooltip {
}
@Override
public int xPos() {
public String getTooltipMessage() {
return getMessage();
}
@Override
public int getTooltipAreaX() {
return this.x;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return 22;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return 22;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return this.visible;
}
@@ -74,7 +74,7 @@ public class ToggleButton extends Button implements ITooltip {
}
@Override
public String getMessage() {
public String getTooltipMessage() {
if (this.displayName != null) {
String name = I18n.format(this.displayName);
String value = I18n.format(this.displayHint);
@@ -103,27 +103,27 @@ public class ToggleButton extends Button implements ITooltip {
}
@Override
public int xPos() {
public int getTooltipAreaX() {
return this.x;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return 16;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return 16;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return this.visible;
}
}
@@ -41,11 +41,6 @@ import appeng.fluids.util.FluidSorters;
import appeng.util.Platform;
import appeng.util.prioritylist.IPartitionList;
/**
* @author BrockWS
* @version rv6 - 22/05/2018
* @since rv6 22/05/2018
*/
public class FluidRepo {
private final IItemList<IAEFluidStack> list = Api.instance().storage().getStorageChannel(IFluidStorageChannel.class)
.createList();
+11 -12
View File
@@ -21,23 +21,22 @@ package appeng.client.me;
import javax.annotation.Nonnull;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.items.SlotItemHandler;
import appeng.api.storage.data.IAEFluidStack;
import appeng.fluids.container.slots.IMEFluidSlot;
/**
* @author BrockWS
* @version rv6 - 22/05/2018
* @since rv6 22/05/2018
*/
public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
public class SlotFluidME extends Slot implements IMEFluidSlot {
private InternalFluidSlotME slot;
private static final IInventory EMPTY_INVENTORY = new Inventory(0);
private final InternalFluidSlotME slot;
public SlotFluidME(InternalFluidSlotME slot) {
super(null, 0, slot.getxPosition(), slot.getyPosition());
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
this.slot = slot;
}
@@ -50,7 +49,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
}
@Override
public boolean isItemValid(final ItemStack par1ItemStack) {
public boolean isItemValid(final ItemStack stack) {
return false;
}
@@ -69,7 +68,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
}
@Override
public void putStack(final ItemStack par1ItemStack) {
public void putStack(final ItemStack stack) {
}
@@ -85,7 +84,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
}
@Override
public boolean canTakeStack(final PlayerEntity par1PlayerEntity) {
public boolean canTakeStack(final PlayerEntity player) {
return false;
}
}
+15 -11
View File
@@ -19,23 +19,27 @@
package appeng.client.me;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraftforge.items.SlotItemHandler;
import appeng.api.storage.data.IAEItemStack;
public class SlotME extends SlotItemHandler {
public class SlotME extends Slot {
private final InternalSlotME mySlot;
private static final IInventory EMPTY_INVENTORY = new Inventory(0);
public SlotME(final InternalSlotME me) {
super(null, 0, me.getxPosition(), me.getyPosition());
this.mySlot = me;
private final InternalSlotME slot;
public SlotME(final InternalSlotME slot) {
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
this.slot = slot;
}
public IAEItemStack getAEStack() {
if (this.mySlot.hasPower()) {
return this.mySlot.getAEStack();
if (this.slot.hasPower()) {
return this.slot.getAEStack();
}
return null;
}
@@ -47,15 +51,15 @@ public class SlotME extends SlotItemHandler {
@Override
public ItemStack getStack() {
if (this.mySlot.hasPower()) {
return this.mySlot.getStack();
if (this.slot.hasPower()) {
return this.slot.getStack();
}
return ItemStack.EMPTY;
}
@Override
public boolean getHasStack() {
if (this.mySlot.hasPower()) {
if (this.slot.hasPower()) {
return !this.getStack().isEmpty();
}
return false;
@@ -52,7 +52,7 @@ public class FormationPlaneContainer extends UpgradeableContainer {
return helper.open(player, locator);
}
@GuiSync(6)
@GuiSync(7)
public YesNo placeMode;
public FormationPlaneContainer(int id, final PlayerInventory ip, final FormationPlanePart te) {
@@ -261,13 +261,19 @@ public class PatternTermContainer extends MEMonitorableContainer
return new ItemStack[] { out };
}
} else {
boolean hasValue = false;
final ItemStack[] list = new ItemStack[3];
for (int i = 0; i < this.outputSlots.length; i++) {
final ItemStack out = this.outputSlots[i].getStack();
list[i] = out;
if (!out.isEmpty()) {
hasValue = true;
}
}
if (hasValue) {
return list;
}
return list;
}
return null;
@@ -1,18 +0,0 @@
package appeng.core;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.util.ResourceLocation;
public class AERecipeType<T extends IRecipe<?>> implements IRecipeType<T> {
private final String id;
public AERecipeType(ResourceLocation registryName) {
this.id = registryName.toString();
}
@Override
public String toString() {
return id;
}
}
-56
View File
@@ -19,7 +19,6 @@
package appeng.core;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
@@ -39,8 +38,6 @@ import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.feature.Feature;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.ModDimension;
import net.minecraftforge.eventbus.api.IEventBus;
@@ -56,29 +53,10 @@ import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
import net.minecraftforge.fml.event.server.FMLServerStoppingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import appeng.block.paint.PaintSplotchesModel;
import appeng.block.qnb.QnbFormedModel;
import appeng.bootstrap.components.IClientSetupComponent;
import appeng.bootstrap.components.IInitComponent;
import appeng.bootstrap.components.IPostInitComponent;
import appeng.capabilities.Capabilities;
import appeng.client.ClientHelper;
import appeng.client.render.DummyFluidItemModel;
import appeng.client.render.FacadeItemModel;
import appeng.client.render.SimpleModelLoader;
import appeng.client.render.cablebus.CableBusModelLoader;
import appeng.client.render.cablebus.P2PTunnelFrequencyModel;
import appeng.client.render.crafting.CraftingCubeModelLoader;
import appeng.client.render.crafting.EncodedPatternModelLoader;
import appeng.client.render.model.BiometricCardModel;
import appeng.client.render.model.ColorApplicatorModel;
import appeng.client.render.model.DriveModel;
import appeng.client.render.model.GlassModel;
import appeng.client.render.model.MemoryCardModel;
import appeng.client.render.model.SkyCompassModel;
import appeng.client.render.model.UVLModelLoader;
import appeng.client.render.spatial.SpatialPylonModel;
import appeng.core.features.registries.PartModels;
import appeng.core.stats.AdvancementTriggers;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.worlddata.WorldData;
@@ -90,7 +68,6 @@ import appeng.entity.TinyTNTPrimedRenderer;
import appeng.hooks.TickHandler;
import appeng.integration.Integrations;
import appeng.parts.PartPlacement;
import appeng.parts.automation.PlaneModelLoader;
import appeng.server.ServerHelper;
@Mod(AppEng.MOD_ID)
@@ -177,39 +154,6 @@ public final class AppEng {
RenderingRegistry.registerEntityRenderingHandler(ChargedQuartzEntity.TYPE,
m -> new ItemRenderer(m, Minecraft.getInstance().getItemRenderer()));
// TODO: Do not use the internal API
final ApiDefinitions definitions = Api.INSTANCE.definitions();
definitions.getRegistry().getBootstrapComponents(IClientSetupComponent.class)
.forEachRemaining(IClientSetupComponent::setup);
addBuiltInModel("glass", GlassModel::new);
addBuiltInModel("sky_compass", SkyCompassModel::new);
addBuiltInModel("dummy_fluid_item", DummyFluidItemModel::new);
addBuiltInModel("memory_card", MemoryCardModel::new);
addBuiltInModel("biometric_card", BiometricCardModel::new);
addBuiltInModel("drive", DriveModel::new);
addBuiltInModel("color_applicator", ColorApplicatorModel::new);
addBuiltInModel("spatial_pylon", SpatialPylonModel::new);
addBuiltInModel("paint_splotches", PaintSplotchesModel::new);
addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new);
addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
addBuiltInModel("facade", FacadeItemModel::new);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "encoded_pattern"),
EncodedPatternModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "part_plane"),
PlaneModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "crafting_cube"),
CraftingCubeModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "cable_bus"),
new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels()));
}
@OnlyIn(Dist.CLIENT)
private static <T extends IModelGeometry<T>> void addBuiltInModel(String id, Supplier<T> modelFactory) {
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, id),
new SimpleModelLoader<>(modelFactory));
}
@Nonnull
+54 -5
View File
@@ -18,6 +18,8 @@
package appeng.core;
import java.util.function.Supplier;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
@@ -48,6 +50,8 @@ import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.ParticleFactoryRegisterEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.geometry.IModelGeometry;
import net.minecraftforge.common.ModDimension;
import net.minecraftforge.common.extensions.IForgeContainerType;
import net.minecraftforge.event.RegistryEvent;
@@ -77,7 +81,10 @@ import appeng.api.networking.security.ISecurityGrid;
import appeng.api.networking.spatial.ISpatialCache;
import appeng.api.networking.storage.IStorageGrid;
import appeng.api.networking.ticking.ITickManager;
import appeng.block.paint.PaintSplotchesModel;
import appeng.block.qnb.QnbFormedModel;
import appeng.bootstrap.components.IBlockRegistrationComponent;
import appeng.bootstrap.components.IClientSetupComponent;
import appeng.bootstrap.components.IEntityRegistrationComponent;
import appeng.bootstrap.components.IItemColorRegistrationComponent;
import appeng.bootstrap.components.IItemRegistrationComponent;
@@ -116,6 +123,13 @@ import appeng.client.gui.implementations.UpgradeableScreen;
import appeng.client.gui.implementations.VibrationChamberScreen;
import appeng.client.gui.implementations.WirelessScreen;
import appeng.client.gui.implementations.WirelessTermScreen;
import appeng.client.render.DummyFluidItemModel;
import appeng.client.render.FacadeItemModel;
import appeng.client.render.SimpleModelLoader;
import appeng.client.render.cablebus.CableBusModelLoader;
import appeng.client.render.cablebus.P2PTunnelFrequencyModel;
import appeng.client.render.crafting.CraftingCubeModelLoader;
import appeng.client.render.crafting.EncodedPatternModelLoader;
import appeng.client.render.effects.ChargedOreFX;
import appeng.client.render.effects.CraftingFx;
import appeng.client.render.effects.EnergyFx;
@@ -125,8 +139,13 @@ import appeng.client.render.effects.MatterCannonFX;
import appeng.client.render.effects.ParticleTypes;
import appeng.client.render.effects.VibrantFX;
import appeng.client.render.model.BiometricCardModel;
import appeng.client.render.model.ColorApplicatorModel;
import appeng.client.render.model.DriveModel;
import appeng.client.render.model.GlassModel;
import appeng.client.render.model.MemoryCardModel;
import appeng.client.render.model.SkyCompassModel;
import appeng.client.render.model.UVLModelLoader;
import appeng.client.render.spatial.SpatialPylonModel;
import appeng.client.render.tesr.InscriberTESR;
import appeng.client.render.tesr.SkyChestTESR;
import appeng.container.AEBaseContainer;
@@ -195,11 +214,10 @@ import appeng.me.cache.PathGridCache;
import appeng.me.cache.SecurityCache;
import appeng.me.cache.SpatialPylonCache;
import appeng.me.cache.TickManagerCache;
import appeng.parts.automation.PlaneModelLoader;
import appeng.recipes.game.DisassembleRecipe;
import appeng.recipes.game.FacadeRecipe;
import appeng.recipes.handlers.GrinderRecipe;
import appeng.recipes.handlers.GrinderRecipeSerializer;
import appeng.recipes.handlers.InscriberRecipe;
import appeng.recipes.handlers.InscriberRecipeSerializer;
import appeng.server.AECommand;
import appeng.spatial.StorageCellBiome;
@@ -245,6 +263,40 @@ final class Registration {
@OnlyIn(Dist.CLIENT)
public void modelRegistryEvent(ModelRegistryEvent event) {
registerSpecialModels();
// TODO: Do not use the internal API
final ApiDefinitions definitions = Api.INSTANCE.definitions();
definitions.getRegistry().getBootstrapComponents(IClientSetupComponent.class)
.forEachRemaining(IClientSetupComponent::setup);
addBuiltInModel("glass", GlassModel::new);
addBuiltInModel("sky_compass", SkyCompassModel::new);
addBuiltInModel("dummy_fluid_item", DummyFluidItemModel::new);
addBuiltInModel("memory_card", MemoryCardModel::new);
addBuiltInModel("biometric_card", BiometricCardModel::new);
addBuiltInModel("drive", DriveModel::new);
addBuiltInModel("color_applicator", ColorApplicatorModel::new);
addBuiltInModel("spatial_pylon", SpatialPylonModel::new);
addBuiltInModel("paint_splotches", PaintSplotchesModel::new);
addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new);
addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
addBuiltInModel("facade", FacadeItemModel::new);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "encoded_pattern"),
EncodedPatternModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "part_plane"),
PlaneModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "crafting_cube"),
CraftingCubeModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "uvlightmap"), UVLModelLoader.INSTANCE);
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, "cable_bus"),
new CableBusModelLoader((PartModels) Api.INSTANCE.registries().partModels()));
}
@OnlyIn(Dist.CLIENT)
private static <T extends IModelGeometry<T>> void addBuiltInModel(String id, Supplier<T> modelFactory) {
ModelLoaderRegistry.registerLoader(new ResourceLocation(AppEng.MOD_ID, id),
new SimpleModelLoader<>(modelFactory));
}
/**
@@ -428,9 +480,6 @@ final class Registration {
public void registerRecipeSerializers(RegistryEvent.Register<IRecipeSerializer<?>> event) {
IForgeRegistry<IRecipeSerializer<?>> r = event.getRegistry();
GrinderRecipe.TYPE = new AERecipeType<>(GrinderRecipeSerializer.INSTANCE.getRegistryName());
InscriberRecipe.TYPE = new AERecipeType<>(InscriberRecipeSerializer.INSTANCE.getRegistryName());
FacadeItem facadeItem = (FacadeItem) Api.INSTANCE.definitions().items().facade().item();
r.registerAll(DisassembleRecipe.SERIALIZER, GrinderRecipeSerializer.INSTANCE,
InscriberRecipeSerializer.INSTANCE, FacadeRecipe.getSerializer(facadeItem));
@@ -115,7 +115,12 @@ public class ApiCrafting implements ICraftingHelper {
// We use the shared itemstack for an identity lookup.
IAEItemStack ais = Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(is);
return new CraftingPatternDetails(ais, world);
try {
return new CraftingPatternDetails(ais, world);
} catch (IllegalStateException e) {
AELog.warn("Could not decode an invalid pattern %s: %s", is, e);
return null;
}
}
private boolean attemptRecovery(EncodedPatternItem patternItem, ItemStack itemStack, World world) {
+1 -1
View File
@@ -49,7 +49,7 @@ public class FacadePart implements IFacadePart {
@Override
public void getBoxes(final IPartCollisionHelper ch, boolean livingEntity) {
if (livingEntity) {
if (livingEntity || !ch.isBBCollision()) {
// prevent weird snag behavior
ch.addBox(0.0, 0.0, 14, 16.0, 16.0, 16.0);
} else {
@@ -52,7 +52,8 @@ public class FluidSlotWidget extends CustomSlotWidget {
final float blue = (attributes.getColor() & 255) / 255.0F;
RenderSystem.color3f(red, green, blue);
blit(xPos(), yPos(), this.getBlitOffset(), getWidth(), getHeight(), sprite);
blit(getTooltipAreaX(), getTooltipAreaY(), this.getBlitOffset(), getTooltipAreaWidth(),
getTooltipAreaHeight(), sprite);
}
}
@@ -76,7 +77,7 @@ public class FluidSlotWidget extends CustomSlotWidget {
}
@Override
public String getMessage() {
public String getTooltipMessage() {
final IAEFluidStack fluid = this.getFluidStack();
if (fluid != null) {
return I18n.format(fluid.getFluidStack().getTranslationKey());
@@ -85,7 +86,7 @@ public class FluidSlotWidget extends CustomSlotWidget {
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return true;
}
@@ -85,7 +85,7 @@ public class FluidTankWidget extends Widget implements ITooltip {
}
@Override
public String getMessage() {
public String getTooltipMessage() {
final IAEFluidStack fluid = this.tank.getFluidInSlot(this.slot);
if (fluid != null && fluid.getStackSize() > 0) {
String desc = fluid.getFluid().getAttributes().getDisplayName(fluid.getFluidStack()).getFormattedText();
@@ -97,27 +97,27 @@ public class FluidTankWidget extends Widget implements ITooltip {
}
@Override
public int xPos() {
public int getTooltipAreaX() {
return this.x - 2;
}
@Override
public int yPos() {
public int getTooltipAreaY() {
return this.y - 2;
}
@Override
public int getWidth() {
public int getTooltipAreaWidth() {
return this.width + 4;
}
@Override
public int getHeight() {
public int getTooltipAreaHeight() {
return this.height + 4;
}
@Override
public boolean isVisible() {
public boolean isTooltipAreaVisible() {
return true;
}
@@ -48,7 +48,8 @@ public class OptionalFluidSlotWidget extends FluidSlotWidget {
} else {
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 0.4F);
}
GuiUtils.drawTexturedModalRect(guileft + this.xPos() - 1, guitop + this.yPos() - 1, this.srcX - 1,
this.srcY - 1, this.getWidth() + 2, this.getHeight() + 2, currentZIndex);
GuiUtils.drawTexturedModalRect(guileft + this.getTooltipAreaX() - 1, guitop + this.getTooltipAreaY() - 1,
this.srcX - 1, this.srcY - 1, this.getTooltipAreaWidth() + 2, this.getTooltipAreaHeight() + 2,
currentZIndex);
}
}
@@ -210,7 +210,7 @@ public class DualityFluidInterface
} else if (capabilityClass == Capabilities.STORAGE_MONITORABLE_ACCESSOR) {
return (LazyOptional<T>) LazyOptional.of(() -> this.accessor);
}
return null;
return LazyOptional.empty();
}
private boolean hasConfig() {
@@ -14,7 +14,6 @@ import net.minecraft.item.ItemStack;
import net.minecraft.tags.FluidTags;
import net.minecraft.tags.Tag;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
@@ -35,15 +34,12 @@ import appeng.api.networking.storage.IStorageGrid;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.core.Api;
import appeng.core.AppEng;
import appeng.core.settings.TickRates;
@@ -53,6 +49,7 @@ import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
import appeng.parts.BasicStatePart;
import appeng.parts.automation.PlaneConnectionHelper;
import appeng.parts.automation.PlaneConnections;
import appeng.parts.automation.PlaneModelData;
import appeng.parts.automation.PlaneModels;
@@ -73,115 +70,27 @@ public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridT
private final IActionSource mySrc = new MachineSource(this);
private final PlaneConnectionHelper connectionHelper = new PlaneConnectionHelper(this);
public FluidAnnihilationPlanePart(final ItemStack is) {
super(is);
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
int minX = 1;
int minY = 1;
int maxX = 15;
int maxY = 15;
final IPartHost host = this.getHost();
if (host != null) {
final TileEntity te = host.getTile();
final BlockPos pos = te.getPos();
final Direction e = bch.getWorldX();
final Direction u = bch.getWorldY();
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e.getOpposite())), this.getSide())) {
minX = 0;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) {
maxX = 16;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(u.getOpposite())), this.getSide())) {
minY = 0;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) {
maxY = 16;
}
}
bch.addBox(5, 5, 14, 11, 11, 15);
bch.addBox(minX, minY, 15, maxX, maxY, 16);
connectionHelper.getBoxes(bch);
}
public PlaneConnections getConnections() {
final Direction facingRight, facingUp;
AEPartLocation location = this.getSide();
switch (location) {
case UP:
facingRight = Direction.EAST;
facingUp = Direction.NORTH;
break;
case DOWN:
facingRight = Direction.WEST;
facingUp = Direction.NORTH;
break;
case NORTH:
facingRight = Direction.WEST;
facingUp = Direction.UP;
break;
case SOUTH:
facingRight = Direction.EAST;
facingUp = Direction.UP;
break;
case WEST:
facingRight = Direction.SOUTH;
facingUp = Direction.UP;
break;
case EAST:
facingRight = Direction.NORTH;
facingUp = Direction.UP;
break;
default:
case INTERNAL:
return PlaneConnections.of(false, false, false, false);
}
boolean left = false, right = false, down = false, up = false;
final IPartHost host = this.getHost();
if (host != null) {
final TileEntity te = host.getTile();
final BlockPos pos = te.getPos();
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingRight.getOpposite())),
this.getSide())) {
left = true;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingRight)), this.getSide())) {
right = true;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingUp.getOpposite())),
this.getSide())) {
down = true;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingUp)), this.getSide())) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
return connectionHelper.getConnections();
}
@Override
public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
this.refresh();
} else {
connectionHelper.updateConnections();
}
}
@@ -190,14 +99,6 @@ public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridT
return 1;
}
private boolean isAnnihilationPlane(final TileEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && p.getClass() == this.getClass();
}
return false;
}
private void refresh() {
try {
this.getProxy().getTick().alertDevice(this.getProxy().getNode());
@@ -309,14 +309,27 @@ public class EncodedPatternItem extends AEBaseItem {
final ListNBT tagIn = new ListNBT();
final ListNBT tagOut = new ListNBT();
boolean hasInput = false;
for (final ItemStack i : in) {
tagIn.add(createItemTag(i));
if (!i.isEmpty()) {
hasInput = true;
}
}
Preconditions.checkArgument(hasInput, "cannot encode a pattern that has no inputs.");
boolean hasNonEmptyOutput = false;
for (final ItemStack i : out) {
tagOut.add(createItemTag(i));
if (!i.isEmpty()) {
hasNonEmptyOutput = true;
}
}
// Patterns without any outputs are corrupt! Never encode such a pattern.
Preconditions.checkArgument(hasNonEmptyOutput, "cannot encode a pattern that has no output.");
encodedValue.put(EncodedPatternItem.NBT_INGREDIENTS, tagIn);
encodedValue.put(EncodedPatternItem.NBT_PRODUCTS, tagOut);
return encodedValue;
+1 -1
View File
@@ -502,7 +502,7 @@ public class EnergyGridCache implements IEnergyGrid {
private void removeRequester(IAEPowerStorage requester) {
Preconditions.checkState(!ongoingInjectOperation,
"Cannot modify energy requesters while energy is being injected.");
this.requesters.add(requester);
this.requesters.remove(requester);
}
private void addProvider(IAEPowerStorage provider) {
@@ -4,16 +4,13 @@ package appeng.parts.automation;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import appeng.api.config.Actionable;
import appeng.api.config.Settings;
import appeng.api.networking.security.IActionSource;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.cells.ICellContainer;
import appeng.api.storage.cells.ICellInventory;
@@ -30,6 +27,7 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
private boolean wasActive = false;
private int priority = 0;
protected boolean blocked = false;
private final PlaneConnectionHelper connectionHelper = new PlaneConnectionHelper(this);
public AbstractFormationPlanePart(ItemStack is) {
super(is);
@@ -64,103 +62,11 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
@Override
public void getBoxes(final IPartCollisionHelper bch) {
int minX = 1;
int minY = 1;
int maxX = 15;
int maxY = 15;
final IPartHost host = this.getHost();
if (host != null) {
final TileEntity te = host.getTile();
final BlockPos pos = te.getPos();
final Direction e = bch.getWorldX();
final Direction u = bch.getWorldY();
if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(e.getOpposite())), this.getSide())) {
minX = 0;
}
if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) {
maxX = 16;
}
if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(u.getOpposite())), this.getSide())) {
minY = 0;
}
if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(u)), this.getSide())) {
maxY = 16;
}
}
bch.addBox(5, 5, 14, 11, 11, 15);
bch.addBox(minX, minY, 15, maxX, maxY, 16);
connectionHelper.getBoxes(bch);
}
public PlaneConnections getConnections() {
final Direction facingRight, facingUp;
AEPartLocation location = this.getSide();
switch (location) {
case UP:
facingRight = Direction.EAST;
facingUp = Direction.NORTH;
break;
case DOWN:
facingRight = Direction.WEST;
facingUp = Direction.NORTH;
break;
case NORTH:
facingRight = Direction.WEST;
facingUp = Direction.UP;
break;
case SOUTH:
facingRight = Direction.EAST;
facingUp = Direction.UP;
break;
case WEST:
facingRight = Direction.SOUTH;
facingUp = Direction.UP;
break;
case EAST:
facingRight = Direction.NORTH;
facingUp = Direction.UP;
break;
default:
case INTERNAL:
return PlaneConnections.of(false, false, false, false);
}
boolean left = false, right = false, down = false, up = false;
final IPartHost host = this.getHost();
if (host != null) {
final TileEntity te = host.getTile();
final BlockPos pos = te.getPos();
if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(facingRight.getOpposite())),
this.getSide())) {
left = true;
}
if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(facingRight)), this.getSide())) {
right = true;
}
if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(facingUp.getOpposite())),
this.getSide())) {
down = true;
}
if (this.isTransitionPlane(te.getWorld().getTileEntity(pos.offset(facingUp)), this.getSide())) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
return connectionHelper.getConnections();
}
@Override
@@ -172,6 +78,8 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
final BlockPos tePos = te.getPos().offset(side.getFacing());
this.blocked = !w.getBlockState(tePos).getMaterial().isReplaceable();
} else {
connectionHelper.updateConnections();
}
}
@@ -180,14 +88,6 @@ public abstract class AbstractFormationPlanePart<T extends IAEStack<T>> extends
return 1;
}
protected boolean isTransitionPlane(final TileEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && this.getClass() == p.getClass();
}
return false;
}
@Override
public T extractItems(final T request, final Actionable mode, final IActionSource src) {
return null;
@@ -35,7 +35,6 @@ import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.Tag;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
@@ -58,9 +57,7 @@ import appeng.api.networking.storage.IStorageGrid;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.parts.IPartModel;
import appeng.api.storage.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEItemStack;
@@ -96,53 +93,31 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
private boolean isAccepting = true;
private boolean breaking = false;
private final PlaneConnectionHelper connectionHelper = new PlaneConnectionHelper(this);
public AnnihilationPlanePart(final ItemStack is) {
super(is);
}
@Override
public TickRateModulation call(final World world) throws Exception {
public TickRateModulation call(final World world) {
this.breaking = false;
return this.breakBlock(true);
}
@Override
public void getBoxes(final IPartCollisionHelper bch) {
int minX = 1;
int minY = 1;
int maxX = 15;
int maxY = 15;
final IPartHost host = this.getHost();
if (host != null) {
final TileEntity te = host.getTile();
final BlockPos pos = te.getPos();
final Direction e = bch.getWorldX();
final Direction u = bch.getWorldY();
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e.getOpposite())), this.getSide())) {
minX = 0;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) {
maxX = 16;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(u.getOpposite())), this.getSide())) {
minY = 0;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(e)), this.getSide())) {
maxY = 16;
}
// For collision, we're using a simplified bounding box
if (bch.isBBCollision()) {
// The smaller collision hitbox here is needed to allow for the entity collision
// event
bch.addBox(0, 0, 14, 16, 16, 15.5);
return;
}
bch.addBox(5, 5, 14, 11, 11, 15);
// The smaller collision hitbox here is needed to allow for the entity collision
// event
bch.addBox(minX, minY, 15, maxX, maxY, bch.isBBCollision() ? 15 : 16);
connectionHelper.getBoxes(bch);
}
/**
@@ -150,73 +125,15 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
* visually.
*/
public PlaneConnections getConnections() {
final Direction facingRight, facingUp;
AEPartLocation location = this.getSide();
switch (location) {
case UP:
facingRight = Direction.EAST;
facingUp = Direction.NORTH;
break;
case DOWN:
facingRight = Direction.WEST;
facingUp = Direction.NORTH;
break;
case NORTH:
facingRight = Direction.WEST;
facingUp = Direction.UP;
break;
case SOUTH:
facingRight = Direction.EAST;
facingUp = Direction.UP;
break;
case WEST:
facingRight = Direction.SOUTH;
facingUp = Direction.UP;
break;
case EAST:
facingRight = Direction.NORTH;
facingUp = Direction.UP;
break;
default:
case INTERNAL:
return PlaneConnections.of(false, false, false, false);
}
boolean left = false, right = false, down = false, up = false;
final IPartHost host = this.getHost();
if (host != null) {
final TileEntity te = host.getTile();
final BlockPos pos = te.getPos();
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingRight.getOpposite())),
this.getSide())) {
left = true;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingRight)), this.getSide())) {
right = true;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingUp.getOpposite())),
this.getSide())) {
down = true;
}
if (this.isAnnihilationPlane(te.getWorld().getTileEntity(pos.offset(facingUp)), this.getSide())) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
return connectionHelper.getConnections();
}
@Override
public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) {
if (pos.offset(this.getSide().getFacing()).equals(neighbor)) {
this.refresh();
} else {
connectionHelper.updateConnections();
}
}
@@ -362,14 +279,6 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
return changed;
}
protected boolean isAnnihilationPlane(final TileEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && p.getClass() == this.getClass();
}
return false;
}
@Override
@MENetworkEventSubscribe
public void chanRender(final MENetworkChannelsChanged c) {
@@ -493,7 +402,7 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
ItemStack harvestTool = createHarvestTool(state);
if (harvestTool == null) {
if (!state.getMaterial().isToolNotRequired()) {
if (state.getMaterial().isToolNotRequired()) {
harvestTool = ItemStack.EMPTY;
} else {
// In case the block does NOT allow us to harvest it without a tool, or the
@@ -21,26 +21,23 @@ package appeng.parts.automation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.DirectionalPlaceContext;
import net.minecraft.item.FireworkRocketItem;
import net.minecraft.item.FireworkStarItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.item.WallOrFloorItem;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Hand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
@@ -49,7 +46,6 @@ import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.items.IItemHandler;
import appeng.api.config.AccessRestriction;
@@ -64,7 +60,6 @@ import appeng.api.networking.events.MENetworkChannelsChanged;
import appeng.api.networking.events.MENetworkEventSubscribe;
import appeng.api.networking.events.MENetworkPowerStatusChange;
import appeng.api.networking.security.IActionSource;
import appeng.api.parts.IPartItem;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEInventoryHandler;
import appeng.api.storage.IStorageChannel;
@@ -89,6 +84,7 @@ import appeng.util.prioritylist.PrecisePriorityList;
public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack> {
private static final PlaneModels MODELS = new PlaneModels("part/formation_plane", "part/formation_plane_on");
private static final Random RANDOM_OFFSET = new Random();
@PartModels
public static List<IPartModel> getModels() {
@@ -222,12 +218,12 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
final BlockPos placePos = te.getPos().offset(side.getFacing());
if (w.getBlockState(placePos).getMaterial().isReplaceable()) {
if (placeBlock == YesNo.YES && (i instanceof BlockItem || i instanceof IPlantable
|| i instanceof FireworkStarItem || i instanceof FireworkRocketItem || i instanceof IPartItem)) {
if (placeBlock == YesNo.YES) {
final PlayerEntity player = Platform.getPlayer((ServerWorld) w);
Platform.configurePlayer(player, side, this.getTile());
Hand hand = player.getActiveHand();
player.setHeldItem(hand, is);
// Seems to work without...
// Hand hand = player.getActiveHand();
// player.setHeldItem(hand, is);
maxStorage = is.getCount();
worked = true;
@@ -235,84 +231,33 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
// The side the plane is attached to will be considered the look direction
// in terms of placing an item
Direction lookDirection = side.getFacing();
PlaneDirectionalPlaceContext context = new PlaneDirectionalPlaceContext(w, player, placePos,
lookDirection, is, lookDirection.getOpposite());
// FIXME No idea what any of this is _supposed_ to do, comment badly needed
if (i instanceof IPlantable || i instanceof WallOrFloorItem) {
boolean Worked = false;
i.onItemUse(context);
maxStorage -= is.getCount();
// Up or Down, Attempt 1??
if (side.xOffset == 0 && side.zOffset == 0) {
Worked = i.onItemUse(new DirectionalPlaceContext(w, placePos.offset(side.getFacing()),
lookDirection, is, side.getFacing())) == ActionResultType.SUCCESS;
}
// Up or Down, Attempt 2??
if (!Worked && side.xOffset == 0 && side.zOffset == 0) {
Worked = i.onItemUse(new DirectionalPlaceContext(w,
placePos.offset(side.getFacing().getOpposite()), lookDirection, is,
side.getFacing().getOpposite())) == ActionResultType.SUCCESS;
}
// Horizontal, attempt 1??
if (!Worked && side.yOffset == 0) {
Worked = i.onItemUse(new DirectionalPlaceContext(w, placePos.offset(Direction.DOWN),
lookDirection, is, Direction.DOWN)) == ActionResultType.SUCCESS;
}
if (!Worked) {
i.onItemUse(new DirectionalPlaceContext(w, placePos, lookDirection, is,
lookDirection.getOpposite()));
}
maxStorage -= is.getCount();
} else {
i.onItemUse(new DirectionalPlaceContext(w, placePos, lookDirection, is,
lookDirection.getOpposite()));
maxStorage -= is.getCount();
}
} else {
maxStorage = 1;
}
// Safe keeping
player.setHeldItem(hand, ItemStack.EMPTY);
// Seems to work without... Safe keeping
// player.setHeldItem(hand, ItemStack.EMPTY);
} else {
worked = true;
final int sum = this.countEntitesAround(w, placePos);
// Disable spawning once there is a certain amount of entities in an area.
if (sum < AEConfig.instance().getFormationPlaneEntityLimit()) {
worked = true;
if (type == Actionable.MODULATE) {
is.setCount((int) maxStorage);
final double x = (side.xOffset != 0 ? 0 : .7 * (Platform.getRandomFloat() - .5)) + side.xOffset
+ .5 + te.getPos().getX();
final double y = (side.yOffset != 0 ? 0 : .7 * (Platform.getRandomFloat() - .5)) + side.yOffset
+ .5 + te.getPos().getY();
final double z = (side.zOffset != 0 ? 0 : .7 * (Platform.getRandomFloat() - .5)) + side.zOffset
+ .5 + te.getPos().getZ();
final ItemEntity ei = new ItemEntity(w, x, y, z, is.copy());
Entity result = ei;
ei.setMotion(side.xOffset * 0.2, side.yOffset * 0.2, side.zOffset * 0.2);
if (is.getItem().hasCustomEntity(is)) {
result = is.getItem().createEntity(w, ei, is);
if (result != null) {
ei.remove();
} else {
result = ei;
}
}
if (!w.addEntity(result)) {
result.remove();
if (!spawnItemEntity(w, te, side, is)) {
// revert in case something prevents spawning.
worked = false;
}
}
} else {
worked = false;
}
}
}
@@ -331,6 +276,57 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
return input;
}
private static boolean spawnItemEntity(World w, TileEntity te, AEPartLocation side, ItemStack is) {
// the item offset based on the entity height plus some offset
final double itemOffset = .55 + EntityType.ITEM.getHeight();
// The center of the block the plane is located in
final double centerX = te.getPos().getX() + .5;
final double centerY = te.getPos().getY() + .5;
final double centerZ = te.getPos().getZ() + .5;
// When spawning downwards, we have to take the item height of 0.25 into account
// Otherwise it will get stuck and be spit out in a random direction as
// minecraft spawns it at its feet position and not center
final double additionalYOffset = side.yOffset == -1 ? -.3 : 0;
// Calculate the offsets to spawn it into the adjacent block, taking the sign
// into account.
// Spawn it 0.8 blocks away from the center pos when facing in this direction
// Every other direction will select a position in a .5 block area around the
// block center.
final double offsetX = (side.xOffset == 0) ? ((RANDOM_OFFSET.nextFloat() / 2) - .25)
: (side.xOffset * itemOffset);
final double offsetY = (side.yOffset == 0) ? ((RANDOM_OFFSET.nextFloat() / 2) - .25)
: ((side.yOffset * itemOffset) + additionalYOffset);
final double offsetZ = (side.zOffset == 0) ? ((RANDOM_OFFSET.nextFloat() / 2) - .25)
: (side.zOffset * itemOffset);
final double absoluteX = centerX + offsetX;
final double absoluteY = centerY + offsetY;
final double absoluteZ = centerZ + offsetZ;
final ItemEntity ei = new ItemEntity(w, absoluteX, absoluteY, absoluteZ, is.copy());
Entity result = ei;
ei.setMotion(side.xOffset * .1, side.yOffset * 0.1, side.zOffset * 0.1);
if (is.getItem().hasCustomEntity(is)) {
result = is.getItem().createEntity(w, ei, is);
if (result != null) {
ei.remove();
} else {
result = ei;
}
}
if (!w.addEntity(result)) {
result.remove();
return false;
}
return true;
}
@Override
public IStorageChannel<IAEItemStack> getChannel() {
return Api.instance().storage().getStorageChannel(IItemStorageChannel.class);
@@ -364,11 +360,69 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
return list.size();
}
private class ForcedItemUseContext extends ItemUseContext {
protected ForcedItemUseContext(World worldIn, @Nullable PlayerEntity player, Hand handIn, ItemStack heldItem,
BlockRayTraceResult rayTraceResultIn) {
super(worldIn, player, handIn, heldItem, rayTraceResultIn);
/**
* A custom {@link DirectionalPlaceContext} which also accepts a player needed
* various blocks like seeds.
* <p>
* Also removed {@link DirectionalPlaceContext#replacingClickedOnBlock} as this
* can cause a {@link StackOverflowError} for certain replaceable blocks.
*/
private static class PlaneDirectionalPlaceContext extends BlockItemUseContext {
private final Direction lookDirection;
public PlaneDirectionalPlaceContext(World world, PlayerEntity player, BlockPos pos, Direction lookDirection,
ItemStack itemStack, Direction facing) {
super(world, player, Hand.MAIN_HAND, itemStack, new BlockRayTraceResult(
new Vec3d(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D), facing, pos, false));
this.lookDirection = lookDirection;
}
public BlockPos getPos() {
return this.rayTraceResult.getPos();
}
public boolean canPlace() {
return this.world.getBlockState(this.rayTraceResult.getPos()).isReplaceable(this);
}
public Direction getNearestLookingDirection() {
return Direction.DOWN;
}
public Direction[] getNearestLookingDirections() {
switch (this.lookDirection) {
case DOWN:
default:
return new Direction[] { Direction.DOWN, Direction.NORTH, Direction.EAST, Direction.SOUTH,
Direction.WEST, Direction.UP };
case UP:
return new Direction[] { Direction.DOWN, Direction.UP, Direction.NORTH, Direction.EAST,
Direction.SOUTH, Direction.WEST };
case NORTH:
return new Direction[] { Direction.DOWN, Direction.NORTH, Direction.EAST, Direction.WEST,
Direction.UP, Direction.SOUTH };
case SOUTH:
return new Direction[] { Direction.DOWN, Direction.SOUTH, Direction.EAST, Direction.WEST,
Direction.UP, Direction.NORTH };
case WEST:
return new Direction[] { Direction.DOWN, Direction.WEST, Direction.SOUTH, Direction.UP,
Direction.NORTH, Direction.EAST };
case EAST:
return new Direction[] { Direction.DOWN, Direction.EAST, Direction.SOUTH, Direction.UP,
Direction.NORTH, Direction.WEST };
}
}
public Direction getPlacementHorizontalFacing() {
return this.lookDirection.getAxis() == Axis.Y ? Direction.NORTH : this.lookDirection;
}
public boolean func_225518_g_() {
return false;
}
public float getPlacementYaw() {
return (float) (this.lookDirection.getHorizontalIndex() * 90);
}
}
}
@@ -55,15 +55,6 @@ public class IdentityAnnihilationPlanePart extends AnnihilationPlanePart {
super(is);
}
@Override
protected boolean isAnnihilationPlane(final TileEntity blockTileEntity, final AEPartLocation side) {
if (blockTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) blockTileEntity).getPart(side);
return p != null && p.getClass() == this.getClass();
}
return false;
}
@Override
protected float calculateEnergyUsage(final ServerWorld w, final BlockPos pos, final List<ItemStack> items) {
final float requiredEnergy = super.calculateEnergyUsage(w, pos, items);
@@ -0,0 +1,160 @@
package appeng.parts.automation;
import javax.annotation.Nullable;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartHost;
import appeng.api.util.AEPartLocation;
import appeng.parts.AEBasePart;
/**
* Helps plane parts (annihilation, formation) with determining and checking for
* connections to adjacent plane parts of the same type to form a visually
* larger plane.
*/
public final class PlaneConnectionHelper {
private final AEBasePart part;
public PlaneConnectionHelper(AEBasePart part) {
this.part = part;
}
/**
* Gets on which sides this part has adjacent planes that it visually connects
* to
*/
public PlaneConnections getConnections() {
TileEntity hostTileEntity = getHostTileEntity();
AEPartLocation side = part.getSide();
final Direction facingRight, facingUp;
switch (side) {
case UP:
facingRight = Direction.EAST;
facingUp = Direction.NORTH;
break;
case DOWN:
facingRight = Direction.WEST;
facingUp = Direction.NORTH;
break;
case NORTH:
facingRight = Direction.WEST;
facingUp = Direction.UP;
break;
case SOUTH:
facingRight = Direction.EAST;
facingUp = Direction.UP;
break;
case WEST:
facingRight = Direction.SOUTH;
facingUp = Direction.UP;
break;
case EAST:
facingRight = Direction.NORTH;
facingUp = Direction.UP;
break;
default:
case INTERNAL:
return PlaneConnections.of(false, false, false, false);
}
boolean left = false, right = false, down = false, up = false;
if (hostTileEntity != null) {
World world = hostTileEntity.getWorld();
BlockPos pos = hostTileEntity.getPos();
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(facingRight.getOpposite())))) {
left = true;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(facingRight)))) {
right = true;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(facingUp.getOpposite())))) {
down = true;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(facingUp)))) {
up = true;
}
}
return PlaneConnections.of(up, right, down, left);
}
/**
* Get the bounding boxes of this plane parts components.
*/
public void getBoxes(IPartCollisionHelper bch) {
int minX = 1;
int minY = 1;
int maxX = 15;
int maxY = 15;
TileEntity hostTile = getHostTileEntity();
if (hostTile != null) {
World world = hostTile.getWorld();
final BlockPos pos = hostTile.getPos();
final Direction e = bch.getWorldX();
final Direction u = bch.getWorldY();
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(e.getOpposite())))) {
minX = 0;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(e)))) {
maxX = 16;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(u.getOpposite())))) {
minY = 0;
}
if (isCompatiblePlaneAdjacent(world.getTileEntity(pos.offset(u)))) {
maxY = 16;
}
}
bch.addBox(5, 5, 14, 11, 11, 15);
bch.addBox(minX, minY, 15, maxX, maxY, 16);
}
/**
* Call this when an adjacent block has changed since the connections need to be
* recalculated.
*/
public void updateConnections() {
TileEntity hostTile = getHostTileEntity();
if (hostTile != null) {
hostTile.requestModelDataUpdate();
}
}
private boolean isCompatiblePlaneAdjacent(@Nullable TileEntity adjacentTileEntity) {
if (adjacentTileEntity instanceof IPartHost) {
final IPart p = ((IPartHost) adjacentTileEntity).getPart(part.getSide());
return p != null && p.getClass() == part.getClass();
}
return false;
}
private TileEntity getHostTileEntity() {
IPartHost host = part.getHost();
if (host != null) {
return host.getTile();
}
return null;
}
}
@@ -18,15 +18,10 @@
package appeng.parts.p2p;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nonnull;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
@@ -37,18 +32,18 @@ import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import appeng.api.config.PowerUnits;
import appeng.api.parts.IPartModel;
import appeng.items.parts.PartModels;
import appeng.me.GridAccessException;
public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implements IFluidHandler {
public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> {
private static final P2PModels MODELS = new P2PModels("part/p2p/p2p_tunnel_fluids");
private static final IFluidHandler NULL_FLUID_HANDLER = new NullFluidHandler();
private static final ThreadLocal<Deque<FluidP2PTunnelPart>> DEPTH = new ThreadLocal<>();;
private LazyOptional<IFluidHandler> cachedTank;
private int tmpUsed;
private final IFluidHandler inputHandler = new InputFluidHandler();
private final IFluidHandler outputHandler = new OutputFluidHandler();
public FluidP2PTunnelPart(final ItemStack is) {
super(is);
@@ -65,13 +60,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
@Override
public void onTunnelNetworkChange() {
this.cachedTank = null;
}
@Override
public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) {
this.cachedTank = null;
if (this.isOutput()) {
final FluidP2PTunnelPart in = this.getInput();
if (in != null) {
@@ -84,7 +76,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
@Override
public <T> LazyOptional<T> getCapability(Capability<T> capabilityClass) {
if (capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
return (LazyOptional<T>) LazyOptional.of(() -> this);
if (this.isOutput()) {
return (LazyOptional<T>) LazyOptional.of(() -> this.outputHandler);
}
return (LazyOptional<T>) LazyOptional.of(() -> this.inputHandler);
}
return super.getCapability(capabilityClass);
@@ -95,168 +90,173 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
return MODELS.getModel(this.isPowered(), this.isActive());
}
@Override
public int getTanks() {
return 0;
}
private IFluidHandler getAttachedFluidHandler() {
LazyOptional<IFluidHandler> fluidHandler = LazyOptional.empty();
if (this.isActive()) {
final TileEntity self = this.getTile();
final TileEntity te = self.getWorld().getTileEntity(self.getPos().offset(this.getSide().getFacing()));
@Override
@Nonnull
public FluidStack getFluidInTank(int tank) {
return FluidStack.EMPTY;
}
@Override
public int getTankCapacity(int tank) {
return 1000;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return false;
}
@Override
public int fill(FluidStack resource, FluidAction action) {
final Deque<FluidP2PTunnelPart> stack = this.getDepth();
for (final FluidP2PTunnelPart t : stack) {
if (t == this) {
return 0;
if (te != null) {
fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
this.getSide().getOpposite().getFacing());
}
}
return fluidHandler.orElse(NULL_FLUID_HANDLER);
}
stack.push(this);
private class InputFluidHandler implements IFluidHandler {
final List<FluidP2PTunnelPart> list = this.getOutputs(resource.getFluid());
int requestTotal = 0;
Iterator<FluidP2PTunnelPart> i = list.iterator();
while (i.hasNext()) {
final FluidP2PTunnelPart l = i.next();
final IFluidHandler tank = l.getTarget().orElse(null);
if (tank != null) {
l.tmpUsed = tank.fill(resource.copy(), FluidAction.SIMULATE);
} else {
l.tmpUsed = 0;
}
if (l.tmpUsed <= 0) {
i.remove();
} else {
requestTotal += l.tmpUsed;
}
@Override
public int getTanks() {
return 1;
}
if (requestTotal <= 0) {
if (stack.pop() != this) {
throw new IllegalStateException("Invalid Recursion detected.");
@Override
@Nonnull
public FluidStack getFluidInTank(int tank) {
return FluidStack.EMPTY;
}
@Override
public int getTankCapacity(int tank) {
return Integer.MAX_VALUE;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return true;
}
@Override
public int fill(FluidStack resource, FluidAction action) {
int total = 0;
try {
final int outputTunnels = FluidP2PTunnelPart.this.getOutputs().size();
final int amount = resource.getAmount();
if (outputTunnels == 0 || amount == 0) {
return 0;
}
final int amountPerOutput = Math.max(1, amount / outputTunnels);
int overflow = amountPerOutput == 0 ? amount : amount % amountPerOutput;
for (FluidP2PTunnelPart target : FluidP2PTunnelPart.this.getOutputs()) {
final IFluidHandler output = target.getAttachedFluidHandler();
final int toSend = amountPerOutput + overflow;
final FluidStack fillWithFluidStack = resource.copy();
fillWithFluidStack.setAmount(toSend);
final int received = output.fill(fillWithFluidStack, action);
overflow = toSend - received;
total += received;
}
if (action == FluidAction.EXECUTE) {
FluidP2PTunnelPart.this.queueTunnelDrain(PowerUnits.RF, total);
}
} catch (GridAccessException ignored) {
}
return total;
}
@Override
@Nonnull
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidStack.EMPTY;
}
@Override
@Nonnull
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidStack.EMPTY;
}
}
private class OutputFluidHandler implements IFluidHandler {
@Override
public int getTanks() {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTanks();
}
@Override
@Nonnull
public FluidStack getFluidInTank(int tank) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getFluidInTank(tank);
}
@Override
public int getTankCapacity(int tank) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTankCapacity(tank);
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().isFluidValid(tank, stack);
}
@Override
public int fill(FluidStack resource, FluidAction action) {
return 0;
}
if (action != FluidAction.EXECUTE) {
if (stack.pop() != this) {
throw new IllegalStateException("Invalid Recursion detected.");
}
return Math.min(resource.getAmount(), requestTotal);
@Override
@Nonnull
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(resource, action);
}
int available = resource.getAmount();
i = list.iterator();
int used = 0;
while (i.hasNext() && available > 0) {
final FluidP2PTunnelPart l = i.next();
final FluidStack insert = resource.copy();
insert.setAmount((int) Math.ceil(insert.getAmount() * ((double) l.tmpUsed / (double) requestTotal)));
if (insert.getAmount() > available) {
insert.setAmount(available);
}
final IFluidHandler tank = l.getTarget().orElse(null);
if (tank != null) {
l.tmpUsed = tank.fill(insert.copy(), action);
} else {
l.tmpUsed = 0;
}
available -= insert.getAmount();
used += l.tmpUsed;
@Override
@Nonnull
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(maxDrain, action);
}
if (stack.pop() != this) {
throw new IllegalStateException("Invalid Recursion detected.");
}
return used;
}
@Override
@Nonnull
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidStack.EMPTY;
}
private static class NullFluidHandler implements IFluidHandler {
@Override
@Nonnull
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidStack.EMPTY;
}
private Deque<FluidP2PTunnelPart> getDepth() {
Deque<FluidP2PTunnelPart> s = DEPTH.get();
if (s == null) {
DEPTH.set(s = new ArrayDeque<>());
@Override
public int getTanks() {
return 0;
}
return s;
}
private List<FluidP2PTunnelPart> getOutputs(final Fluid input) {
final List<FluidP2PTunnelPart> outs = new ArrayList<>();
try {
for (final FluidP2PTunnelPart l : this.getOutputs()) {
final IFluidHandler handler = l.getTarget().orElse(null);
if (handler != null) {
outs.add(l);
}
}
} catch (final GridAccessException e) {
// :P
@Override
@Nonnull
public FluidStack getFluidInTank(int tank) {
return FluidStack.EMPTY;
}
return outs;
}
private LazyOptional<IFluidHandler> getTarget() {
if (!this.getProxy().isActive()) {
return null;
@Override
public int getTankCapacity(int tank) {
return 0;
}
if (this.cachedTank != null) {
return this.cachedTank;
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return false;
}
final TileEntity te = this.getTile().getWorld()
.getTileEntity(this.getTile().getPos().offset(this.getSide().getFacing()));
if (te != null && te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
this.getSide().getFacing().getOpposite()).isPresent()) {
return this.cachedTank = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
this.getSide().getFacing().getOpposite());
@Override
public int fill(FluidStack resource, FluidAction action) {
return 0;
}
return null;
@Override
@Nonnull
public FluidStack drain(FluidStack resource, FluidAction action) {
return FluidStack.EMPTY;
}
@Override
@Nonnull
public FluidStack drain(int maxDrain, FluidAction action) {
return FluidStack.EMPTY;
}
}
}
@@ -14,9 +14,13 @@ import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import appeng.core.AppEng;
public class GrinderRecipe implements IRecipe<IInventory> {
public static IRecipeType<GrinderRecipe> TYPE;
public static final ResourceLocation TYPE_ID = new ResourceLocation(AppEng.MOD_ID, "grinder");
public static final IRecipeType<GrinderRecipe> TYPE = IRecipeType.register(TYPE_ID.toString());
private final ResourceLocation id;
private final String group;
@@ -29,7 +29,7 @@ public class GrinderRecipeSerializer extends ForgeRegistryEntry<IRecipeSerialize
public static final GrinderRecipeSerializer INSTANCE = new GrinderRecipeSerializer();
static {
INSTANCE.setRegistryName(AppEng.MOD_ID, "grinder");
INSTANCE.setRegistryName(GrinderRecipe.TYPE_ID);
}
private GrinderRecipeSerializer() {
@@ -11,10 +11,13 @@ import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import appeng.api.features.InscriberProcessType;
import appeng.core.AppEng;
public class InscriberRecipe implements IRecipe<IInventory> {
public static IRecipeType<InscriberRecipe> TYPE;
public static final ResourceLocation TYPE_ID = new ResourceLocation(AppEng.MOD_ID, "inscriber");
public static final IRecipeType<InscriberRecipe> TYPE = IRecipeType.register(TYPE_ID.toString());
private final ResourceLocation id;
private final String group;
@@ -23,7 +23,7 @@ public class InscriberRecipeSerializer extends ForgeRegistryEntry<IRecipeSeriali
public static final InscriberRecipeSerializer INSTANCE = new InscriberRecipeSerializer();
static {
INSTANCE.setRegistryName(AppEng.MOD_ID, "inscriber");
INSTANCE.setRegistryName(InscriberRecipe.TYPE_ID);
}
private InscriberRecipeSerializer() {
@@ -310,7 +310,7 @@ public class CableBusTileEntity extends AEBaseTileEntity implements AEMultiTile
IPart part = this.getPart(partLocation);
LazyOptional<T> result = part == null ? LazyOptional.empty() : part.getCapability(capabilityClass);
if (result != null) {
if (result.isPresent()) {
return result;
}
@@ -1,7 +1,7 @@
{
"type": "appliedenergistics2:grinder",
"input": {
"tag": "appliedenergistics2:crystals/fluix"
"item": "appliedenergistics2:fluix_crystal"
},
"result": {
"primary": {