Compare commits

...

26 Commits

Author SHA1 Message Date
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
yueh 662dbca3e1 Fixes #4508: Correctly construct the sparse lists. (#4511)
* Fixes #4508: Correctly construct the sparse lists.

Also renamed all uncondensed getters to sparse and all condensed to the simple ones.

* Apply suggestions from code review

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

* Streamlined collapsing the sparse lists

* Extracted helper to condense stacks

* Sort lists desc by stack size

Co-authored-by: shartte <shartte@users.noreply.github.com>
2020-07-27 11:21:06 +02:00
Sebastian Hartte 6cb6c21495 Mention spotlessApply. 2020-07-26 23:29:34 +02:00
Sebastian Hartte 79e9a3913a Update README.md to reflect that the data generation needs to be run. 2020-07-26 23:29:01 +02:00
shartte 7e89317dd5 Fix substitutions not being correctly recognized. (#4507) 2020-07-26 22:25:18 +02:00
shartte 59e40ccbd9 Fixes mouse handling for right-clicks to clear the search box and middle-click for crafting. (#4505) 2020-07-26 16:30:53 +02:00
yueh 774f88ee90 Clear searchfield on rightclick (#4503) 2020-07-26 15:28:52 +02:00
yueh 0528879833 Moved datagens to appeng.datagen (#4502) 2020-07-26 15:28:18 +02:00
yueh b6110e4f4a Remove all maven repos except modmaven (#4501)
Also upgrades gradle to 4.10.3
2020-07-26 15:27:32 +02:00
yueh 5b82e59264 Removed superfluous crash enhancement (#4498) 2020-07-26 12:42:48 +02:00
yueh 3a4b171443 Fixes #4468: Default to ae serverside (#4496) 2020-07-25 16:05:58 +02:00
yueh 2ac27fd9ce Fixes patterns always returning a recipe. (#4495) 2020-07-24 22:39:38 +02:00
shartte d01aa28cdc Use standard mechanics for damaging the quartz knife. (#4494) 2020-07-24 16:39:32 +02:00
shartte 21aa5ce33b Don't use PacketBuffer#readString since it's client-only. (#4489)
Fixes #4488
2020-07-22 10:22:28 +02:00
shartte f7ef6eb772 Same method name as in superclass leads to ForgeGradle reobf problems. (#4491)
Fixes #4490
2020-07-22 10:22:00 +02:00
shartte 10037a9ac5 Correct link to CurseForge page 2020-07-21 18:39:48 +02:00
yueh 888de430ba Also test for generated asset cache 2020-07-20 22:27:01 +02:00
63 changed files with 806 additions and 939 deletions
+5 -3
View File
@@ -21,13 +21,15 @@ jobs:
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Clean gradle
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
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
+5 -3
View File
@@ -21,13 +21,15 @@ jobs:
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Clean gradle
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
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
+5 -3
View File
@@ -21,18 +21,20 @@ jobs:
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- name: Clean gradle
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
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
+5 -5
View File
@@ -33,16 +33,16 @@ 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
run: test -d ./src/generated -a -f ./src/generated/resources/.cache/cache
- name: Build with Gradle
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 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,14 @@ 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 publish --no-daemon --max-workers 1
- name: Prepare artifact metadata
id: prepare_artifact_metadata
run: |
+9 -8
View File
@@ -45,7 +45,7 @@ A Mod about Matter, Energy and using them to conquer the world..
## Downloads
Downloads can be found on [CurseForge](http://www.curse.com/mc-mods/minecraft/223794-applied-energistics-2) or on the [official website](http://ae-mod.info/Downloads/).
Downloads can be found on [CurseForge](https://www.curseforge.com/minecraft/mc-mods/applied-energistics-2) or on the [official website](http://ae-mod.info/Downloads/).
## Installation
@@ -103,7 +103,7 @@ However the dependency might need to be wrapped in `fg.deobf()` like `runtimeOnl
1. Clone this repository via
- SSH `git clone git@github.com:AppliedEnergistics/Applied-Energistics-2.git` or
- HTTPS `git clone https://github.com/AppliedEnergistics/Applied-Energistics-2.git`
2. Build using the gradle `build` task. Jar will be in `build/libs`
2. Build using the `gradlew runData build` command. Jar will be in `build/libs`
3. For core developer: Setup IDE
- IntelliJ: Import as gradle project
- Eclipse: Import as gradle project or execute gradle task `eclipse` and potentially `genEclipseRuns`
@@ -132,12 +132,13 @@ Here are a few things to keep in mind that will help get your PR approved.
* SSH `git clone git@github.com:<your username>/Applied-Energistics-2.git` or
* HTTPS `git clone https://github.com/<your username>/Applied-Energistics-2.git`
3. Change code base
4. Add changes to git `git add -A`
5. Commit changes to your clone `git commit -m "<summary of made changes>"`
6. Push to your fork `git push`
7. Create a Pull-Request on GitHub
8. Wait for review
9. Squash commits for cleaner history
4. Run `gradlew spotlessApply` to apply automatic code formatting
5. Add changes to git `git add -A`
6. Commit changes to your clone `git commit -m "<summary of made changes>"`
7. Push to your fork `git push`
8. Create a Pull-Request on GitHub
9. Wait for review
10. Squash commits for cleaner history
If you are only doing single file pull requests, GitHub supports using a quick way without the need of cloning your fork. Also read up about [synching](https://help.github.com/articles/syncing-a-fork) if you plan to contribute on regular basis.
-45
View File
@@ -23,51 +23,6 @@ repositories {
name 'modmaven'
url "https://modmaven.k-4u.nl/"
}
maven {
name "Mobius"
url "http://mobiusstrip.eu/maven"
}
maven {
name = "JEI repo"
url "http://dvs1.progwml6.com/files/maven"
}
maven {
name = "Tesla repo"
url "http://maven.mcmoddev.com"
}
maven {
name = "IC2 repo"
url = "http://maven.ic2.player.to"
}
maven {
name = "CoFH Maven"
url = "http://maven.covers1624.net"
}
maven { // TheOneProbe
name 'tterrag maven'
url "http://maven.tterrag.com/"
}
maven {
name 'mcjty'
url "http://maven.k-4u.nl/"
}
maven { // CraftTweaker
name 'jared maven'
url "http://maven.blamejared.com/"
}
maven {
name = "CurseForge"
url = "https://minecraft.curseforge.com/api/maven/"
}
}
dependencies {
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
@@ -23,6 +23,8 @@
package appeng.api.networking.crafting;
import java.util.List;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
@@ -60,24 +62,65 @@ public interface ICraftingPatternDetails {
boolean isCraftable();
/**
* Equal itemstacks will be aggregated into one, respectively 3*64 will be
* returned as one stack of 192, up to 576 of a single type.
* <p>
* This should be the preferred way to deal with the list of inputs.
* <p>
* The list will be sorted in descending order by stack size. However there is
* no guarantee about maintaining the placement order of the inputs in case of
* equal values.
*
* @return an immutable list of inputs without nulls
*/
List<IAEItemStack> getInputs();
/**
* Equal itemstacks will be aggregated into one, respectively 2*32 will be
* returned as one stack of 64, up to 192 of a single type.
* <p>
* This should be the preferred way to deal with the list of outputs.
* <p>
*
* The list will be sorted in descending order by stack size. However there is
* no guarantee about maintaining the placement order of the outputs in case of
* equal values.
*
* @return an immutable list of outputs without nulls
*/
List<IAEItemStack> getOutputs();
/**
* A sparse list representing the placement order of a crafting grid, left to
* right, then top to bottom.
* <p>
* Only use when absolutely necessary, always prefer
* {@link ICraftingPatternDetails#getInputs()}
* <p>
* This will contain exactly 9 entries.
* <p>
* This can return a copy from the internal structure, so there are no
* guarantees about modifications.
*
* @return a list of the inputs, will include nulls.
*/
IAEItemStack[] getInputs();
/**
* @return a list of the inputs, will be clean
*/
IAEItemStack[] getCondensedInputs();
/**
* @return a list of the outputs, will be clean
*/
IAEItemStack[] getCondensedOutputs();
IAEItemStack[] getSparseInputs();
/**
* A sparse list representing the placement order of the respective output
* slots.
* <p>
* Only use when absolutely necessary, always prefer
* {@link ICraftingPatternDetails#getOutputs()}
* <p>
* This will either contain 1 entry for crafting patterns or 3 for processing.
* <p>
* This can return a copy from the internal structure, so there are no
* guarantees about modifications.
*
* @return a list of the outputs, will include nulls.
*/
IAEItemStack[] getOutputs();
IAEItemStack[] getSparseOutputs();
/**
* @return if this pattern is enabled to support substitutions.
+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);
}
}
@@ -295,12 +295,15 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
@Override
public boolean mouseClicked(final double xCoord, final double yCoord, final int btn) {
if (this.searchField.mouseClicked(xCoord, yCoord, btn)) {
if (btn == 1 && this.searchField.isMouseOver(xCoord, yCoord)) {
this.searchField.setText("");
this.repo.setSearchString("");
this.repo.updateView();
this.setScrollBar();
}
return true;
}
// Right-clicking on the search field should clear it
if (this.searchField.isMouseOver(xCoord, yCoord) && btn == 1) {
this.searchField.setText("");
this.repo.setSearchString("");
this.repo.updateView();
this.setScrollBar();
return true;
}
@@ -58,20 +58,6 @@ public class AETextField extends TextFieldWidget {
this._fontPad = (int) fontRenderer.getCharWidth('_');
}
@Override
public boolean mouseClicked(final double xPos, final double yPos, final int button) {
if (!super.mouseClicked(xPos, yPos, button)) {
return false;
}
final boolean requiresFocus = this.isMouseOver(xPos, yPos);
if (!this.isFocused()) {
this.setFocused2(requiresFocus);
}
return true;
}
public void selectAll() {
this.setCursorPosition(0);
this.setSelectionPos(this.getMaxStringLength());
@@ -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;
}
@@ -37,7 +37,7 @@ public class NumberBox extends TextFieldWidget {
final Class<?> type, LongConsumer changeListener) {
super(fontRenderer, x, y, width, height, "0");
this.setText("0");
setResponder(this::onTextChanged);
setResponder(this::handleTextChanged);
this.lastValue = 0;
this.changeListener = changeListener;
if (type == int.class || type == Integer.class) {
@@ -47,7 +47,11 @@ public class NumberBox extends TextFieldWidget {
}
}
private void onTextChanged(String text) {
// NOTE: This method MUST NOT BE NAMED like a method in the superclass because
// of a ForgeGradle remapping bug
// since it'll not remap this method's name, but it will remap the name of the
// method reference above.
private void handleTextChanged(String text) {
if (text.isEmpty()) {
setText("0"); // Will call onTextChanged recursively
return;
@@ -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;
}
}
@@ -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) {
@@ -18,9 +18,6 @@
package appeng.container.implementations;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
@@ -264,21 +261,13 @@ public class PatternTermContainer extends MEMonitorableContainer
return new ItemStack[] { out };
}
} else {
final List<ItemStack> list = new ArrayList<>(3);
boolean hasValue = false;
final ItemStack[] list = new ItemStack[3];
for (final OptionalFakeSlot outputSlot : this.outputSlots) {
final ItemStack out = outputSlot.getStack();
if (!out.isEmpty() && out.getCount() > 0) {
list.add(out);
hasValue = true;
}
}
if (hasValue) {
return list.toArray(new ItemStack[list.size()]);
for (int i = 0; i < this.outputSlots.length; i++) {
final ItemStack out = this.outputSlots[i].getStack();
list[i] = out;
}
return list;
}
return null;
+1 -1
View File
@@ -96,7 +96,7 @@ public final class AEConfig {
private boolean useColoredCraftingStatus;
private boolean disableColoredCableRecipesInJEI;
private int craftingCalculationTimePerTick;
private PowerUnits selectedPowerUnit;
private PowerUnits selectedPowerUnit = PowerUnits.AE;
// GUI Buttons
private final int[] craftByStacks = new int[4];
@@ -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;
}
}
-4
View File
@@ -44,7 +44,6 @@ import net.minecraftforge.client.model.geometry.IModelGeometry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.ModDimension;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.CrashReportExtender;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
@@ -79,7 +78,6 @@ 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.crash.ModCrashEnhancement;
import appeng.core.features.registries.PartModels;
import appeng.core.stats.AdvancementTriggers;
import appeng.core.sync.network.NetworkHandler;
@@ -117,8 +115,6 @@ public final class AppEng {
proxy = DistExecutor.safeRunForDist(() -> ClientHelper::new, () -> ServerHelper::new);
CrashReportExtender.registerCrashCallable(new ModCrashEnhancement());
CreativeTab.init();
new FacadeItemGroup(); // This call has a side-effect (adding it to the creative screen)
@@ -428,9 +428,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));
@@ -1,38 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.core.crash;
import net.minecraftforge.fml.common.ICrashCallable;
import net.minecraftforge.versions.forge.ForgeVersion;
import appeng.core.AEConfig;
public class ModCrashEnhancement implements ICrashCallable {
@Override
public String getLabel() {
return "AE2 Version";
}
@Override
public String call() throws Exception {
return AEConfig.CHANNEL + ' ' + AEConfig.VERSION + " for Forge " + ForgeVersion.getVersion();
}
}
@@ -32,6 +32,15 @@ import appeng.core.sync.network.INetworkInfo;
import appeng.core.sync.network.NetworkHandler;
public abstract class BasePacket {
/**
* Sadly {@link PacketBuffer#readString()} gets inlined by Proguard which means
* it's not available on the Server. This field has the default string length
* that is used for writeString, which then also should be used for readString
* when it has no special length requirements.
*/
public static final int MAX_STRING_LENGTH = 32767;
private PacketBuffer p;
public void serverPacketData(final INetworkInfo manager, final PlayerEntity player) {
@@ -57,8 +57,8 @@ public class ConfigValuePacket extends BasePacket {
private final String Value;
public ConfigValuePacket(final PacketBuffer stream) {
this.Name = stream.readString();
this.Value = stream.readString();
this.Name = stream.readString(MAX_STRING_LENGTH);
this.Value = stream.readString(MAX_STRING_LENGTH);
}
// api
@@ -85,7 +85,7 @@ public class CraftingTreeNode {
}
boolean notRecursive(final ICraftingPatternDetails details) {
IAEItemStack[] o = details.getCondensedOutputs();
Collection<IAEItemStack> o = details.getOutputs();
for (final IAEItemStack i : o) {
if (i.equals(this.what)) {
@@ -93,7 +93,7 @@ public class CraftingTreeNode {
}
}
o = details.getCondensedInputs();
o = details.getInputs();
for (final IAEItemStack i : o) {
if (i.equals(this.what)) {
@@ -64,10 +64,10 @@ public class CraftingTreeProcess {
final World world = job.getWorld();
if (details.isCraftable()) {
final IAEItemStack[] list = details.getInputs();
final IAEItemStack[] list = details.getSparseInputs();
final CraftingInventory ic = new CraftingInventory(new ContainerNull(), 3, 3);
final IAEItemStack[] is = details.getInputs();
final IAEItemStack[] is = details.getSparseInputs();
for (int x = 0; x < ic.getSizeInventory(); x++) {
ic.setInventorySlotContents(x, is[x] == null ? ItemStack.EMPTY : is[x].createItemStack());
}
@@ -82,11 +82,11 @@ public class CraftingTreeProcess {
}
}
for (final IAEItemStack part : details.getCondensedInputs()) {
for (final IAEItemStack part : details.getInputs()) {
final ItemStack g = part.createItemStack();
boolean isAnInput = false;
for (final IAEItemStack a : details.getCondensedOutputs()) {
for (final IAEItemStack a : details.getOutputs()) {
if (!g.isEmpty() && a != null && a.equals(g)) {
isAnInput = true;
}
@@ -114,7 +114,7 @@ public class CraftingTreeProcess {
} else {
// this is minor different then below, this slot uses the pattern, but kinda
// fudges it.
for (final IAEItemStack part : details.getCondensedInputs()) {
for (final IAEItemStack part : details.getInputs()) {
for (int x = 0; x < list.length; x++) {
final IAEItemStack comparePart = list[x];
if (part != null && part.equals(comparePart)) {
@@ -127,11 +127,11 @@ public class CraftingTreeProcess {
}
}
} else {
for (final IAEItemStack part : details.getCondensedInputs()) {
for (final IAEItemStack part : details.getInputs()) {
final ItemStack g = part.createItemStack();
boolean isAnInput = false;
for (final IAEItemStack a : details.getCondensedOutputs()) {
for (final IAEItemStack a : details.getOutputs()) {
if (!g.isEmpty() && a != null && a.equals(g)) {
isAnInput = true;
}
@@ -142,7 +142,7 @@ public class CraftingTreeProcess {
}
}
for (final IAEItemStack part : details.getCondensedInputs()) {
for (final IAEItemStack part : details.getInputs()) {
this.nodes.put(new CraftingTreeNode(cc, job, part.copy(), this, -1, depth + 1), part.getStackSize());
}
}
@@ -208,7 +208,7 @@ public class CraftingTreeProcess {
// assume its possible.
// add crafting results..
for (final IAEItemStack out : this.details.getCondensedOutputs()) {
for (final IAEItemStack out : this.details.getOutputs()) {
final IAEItemStack o = out.copy();
o.setStackSize(o.getStackSize() * i);
inv.injectItems(o, Actionable.MODULATE, src);
@@ -227,7 +227,7 @@ public class CraftingTreeProcess {
}
IAEItemStack getAmountCrafted(IAEItemStack what2) {
for (final IAEItemStack is : this.details.getCondensedOutputs()) {
for (final IAEItemStack is : this.details.getOutputs()) {
if (is.equals(what2)) {
what2 = what2.copy();
what2.setStackSize(is.getStackSize());
@@ -236,7 +236,7 @@ public class CraftingTreeProcess {
}
// more fuzzy!
for (final IAEItemStack is : this.details.getCondensedOutputs()) {
for (final IAEItemStack is : this.details.getOutputs()) {
if (is.getItem() == what2.getItem()
&& (is.getItem().isDamageable() || is.getItemDamage() == what2.getItemDamage())) {
what2 = is.copy();
@@ -1,4 +1,4 @@
package appeng.forge.data;
package appeng.datagen;
import net.minecraft.data.DataGenerator;
import net.minecraftforge.eventbus.api.SubscribeEvent;
@@ -6,8 +6,8 @@ import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
import appeng.core.AppEng;
import appeng.forge.data.providers.loot.BlockDropProvider;
import appeng.forge.data.providers.recipes.SlabStairRecipes;
import appeng.datagen.providers.loot.BlockDropProvider;
import appeng.datagen.providers.recipes.SlabStairRecipes;
@Mod.EventBusSubscriber(modid = AppEng.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class AE2DataGenerators {
@@ -1,4 +1,4 @@
package appeng.forge.data.providers;
package appeng.datagen.providers;
import net.minecraft.data.IDataProvider;
@@ -1,4 +1,4 @@
package appeng.forge.data.providers.loot;
package appeng.datagen.providers.loot;
import java.io.IOException;
import java.nio.file.Path;
@@ -33,7 +33,7 @@ import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
import net.minecraftforge.registries.ForgeRegistries;
import appeng.core.AppEng;
import appeng.forge.data.providers.IAE2DataProvider;
import appeng.datagen.providers.IAE2DataProvider;
public class BlockDropProvider extends BlockLootTables implements IAE2DataProvider {
private Map<Block, Function<Block, LootTable.Builder>> overrides = ImmutableMap.<Block, Function<Block, LootTable.Builder>>builder()
@@ -1,4 +1,4 @@
package appeng.forge.data.providers.recipes;
package appeng.datagen.providers.recipes;
import java.util.function.Consumer;
@@ -15,7 +15,7 @@ import net.minecraft.util.ResourceLocation;
import appeng.api.definitions.IBlockDefinition;
import appeng.core.AppEng;
import appeng.forge.data.providers.IAE2DataProvider;
import appeng.datagen.providers.IAE2DataProvider;
public class SlabStairRecipes extends RecipeProvider implements IAE2DataProvider {
@@ -46,6 +46,8 @@ public class ChunkLoaderTileEntity extends AEBaseTileEntity implements ITickable
@Override
public void remove() {
super.remove();
World world = getWorld();
if (world instanceof ServerWorld) {
ChunkPos chunkPos = new ChunkPos(getPos());
+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 {
@@ -266,12 +266,15 @@ public class FluidTerminalScreen extends AEBaseMEScreen<FluidTerminalContainer>
@Override
public boolean mouseClicked(final double xCoord, final double yCoord, final int btn) {
if (this.searchField.mouseClicked(xCoord, yCoord, btn)) {
if (btn == 1 && this.searchField.isMouseOver(xCoord, yCoord)) {
this.searchField.setText("");
this.repo.setSearchString("");
this.repo.updateView();
this.setScrollBar();
}
return true;
}
// Right-clicking on the search field should clear it
if (this.searchField.isMouseOver(xCoord, yCoord) && btn == 1) {
this.searchField.setText("");
this.repo.setSearchString("");
this.repo.updateView();
this.setScrollBar();
return true;
}
@@ -332,4 +335,5 @@ public class FluidTerminalScreen extends AEBaseMEScreen<FluidTerminalContainer>
protected String getBackground() {
return "guis/terminal.png";
}
}
@@ -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());
@@ -19,13 +19,17 @@
package appeng.helpers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.Item;
@@ -46,14 +50,21 @@ import appeng.util.Platform;
public class CraftingPatternDetails implements ICraftingPatternDetails, Comparable<CraftingPatternDetails> {
private static final int ALL_INPUT_LIMIT = 9;
private static final int CRAFTING_OUTPUT_LIMIT = 1;
private static final int PROCESSING_OUTPUT_LIMIT = 3;
private static final Comparator<IAEItemStack> COMPARE_BY_STACKSIZE = (left, right) -> Long
.compare(right.getStackSize(), left.getStackSize());
private final CraftingInventory crafting = new CraftingInventory(new ContainerNull(), 3, 3);
private final CraftingInventory testFrame = new CraftingInventory(new ContainerNull(), 3, 3);
private final ItemStack correctOutput;
private final ICraftingRecipe standardRecipe;
private final IAEItemStack[] condensedInputs;
private final IAEItemStack[] condensedOutputs;
private final IAEItemStack[] inputs;
private final IAEItemStack[] outputs;
private final List<IAEItemStack> inputs;
private final List<IAEItemStack> outputs;
private final IAEItemStack[] sparseInputs;
private final IAEItemStack[] sparseOutputs;
private final boolean isCraftable;
private final boolean canSubstitute;
private final Set<TestLookup> failCache = new HashSet<>();
@@ -79,7 +90,7 @@ public class CraftingPatternDetails implements ICraftingPatternDetails, Comparab
final List<IAEItemStack> in = new ArrayList<>();
final List<IAEItemStack> out = new ArrayList<>();
for (int x = 0; x < 9; x++) {
for (int x = 0; x < ALL_INPUT_LIMIT; x++) {
final IAEItemStack ais = ingredients.get(x);
final ItemStack gs = ais != null ? ais.createItemStack() : ItemStack.EMPTY;
@@ -109,70 +120,19 @@ public class CraftingPatternDetails implements ICraftingPatternDetails, Comparab
this.standardRecipe = null;
this.correctOutput = ItemStack.EMPTY;
for (int x = 0; x < 3; x++) {
for (int x = 0; x < PROCESSING_OUTPUT_LIMIT; x++) {
final IAEItemStack ais = products.get(x);
final ItemStack gs = ais.createItemStack();
if (!gs.isEmpty()) {
out.add(ais.copy());
}
out.add(ais != null ? ais.copy() : null);
}
}
this.inputs = in.toArray(new IAEItemStack[0]);
this.outputs = out.toArray(new IAEItemStack[0]);
final int outputLength = this.isCraftable ? CRAFTING_OUTPUT_LIMIT : PROCESSING_OUTPUT_LIMIT;
this.sparseInputs = in.toArray(new IAEItemStack[ALL_INPUT_LIMIT]);
this.sparseOutputs = out.toArray(new IAEItemStack[outputLength]);
final Map<IAEItemStack, IAEItemStack> tmpOutputs = new HashMap<>();
for (final IAEItemStack io : this.outputs) {
if (io == null) {
continue;
}
final IAEItemStack g = tmpOutputs.get(io);
if (g == null) {
tmpOutputs.put(io, io.copy());
} else {
g.add(io);
}
}
final Map<IAEItemStack, IAEItemStack> tmpInputs = new HashMap<>();
for (final IAEItemStack io : this.inputs) {
if (io == null) {
continue;
}
final IAEItemStack g = tmpInputs.get(io);
if (g == null) {
tmpInputs.put(io, io.copy());
} else {
g.add(io);
}
}
if (tmpOutputs.isEmpty() || tmpInputs.isEmpty()) {
throw new IllegalStateException("No pattern here!");
}
this.condensedInputs = new IAEItemStack[tmpInputs.size()];
int offset = 0;
for (final IAEItemStack io : tmpInputs.values()) {
this.condensedInputs[offset] = io;
offset++;
}
offset = 0;
this.condensedOutputs = new IAEItemStack[tmpOutputs.size()];
for (final IAEItemStack io : tmpOutputs.values()) {
this.condensedOutputs[offset] = io;
offset++;
}
this.inputs = this.condenseStacks(in);
this.outputs = this.condenseStacks(out);
}
private void markItemAs(final int slotIndex, final ItemStack i, final TestStatus b) {
@@ -213,8 +173,8 @@ public class CraftingPatternDetails implements ICraftingPatternDetails, Comparab
this.testFrame.setInventorySlotContents(slotIndex, i);
// If we cannot substitute, the items must match exactly
if (!canSubstitute && slotIndex < inputs.length) {
if (!inputs[slotIndex].isSameType(i)) {
if (!canSubstitute && slotIndex < sparseInputs.length) {
if (!sparseInputs[slotIndex].isSameType(i)) {
this.markItemAs(slotIndex, i, TestStatus.DECLINE);
return false;
}
@@ -240,25 +200,25 @@ public class CraftingPatternDetails implements ICraftingPatternDetails, Comparab
}
@Override
public IAEItemStack[] getInputs() {
public IAEItemStack[] getSparseInputs() {
return this.sparseInputs;
}
@Override
public List<IAEItemStack> getInputs() {
return this.inputs;
}
@Override
public IAEItemStack[] getCondensedInputs() {
return this.condensedInputs;
}
@Override
public IAEItemStack[] getCondensedOutputs() {
return this.condensedOutputs;
}
@Override
public IAEItemStack[] getOutputs() {
public List<IAEItemStack> getOutputs() {
return this.outputs;
}
@Override
public IAEItemStack[] getSparseOutputs() {
return this.sparseOutputs;
}
@Override
public boolean canSubstitute() {
return this.canSubstitute;
@@ -276,8 +236,8 @@ public class CraftingPatternDetails implements ICraftingPatternDetails, Comparab
}
}
if (this.outputs != null && this.outputs.length > 0) {
return this.outputs[0].createItemStack();
if (this.sparseOutputs != null && this.sparseOutputs.length > 0) {
return this.sparseOutputs[0].createItemStack();
}
return ItemStack.EMPTY;
@@ -344,6 +304,29 @@ public class CraftingPatternDetails implements ICraftingPatternDetails, Comparab
return false;
}
/**
* Merges all equal entries into a single one while adding their total stack
* sizes.
*
* @throws IllegalStateException if the result would be empty.
*
* @param collection the collection to condense
*
* @return a non empty list of condensed stacks.
*/
private List<IAEItemStack> condenseStacks(Collection<IAEItemStack> collection) {
final List<IAEItemStack> merged = collection.stream().filter(Objects::nonNull)
.collect(Collectors.toMap(Function.identity(), IAEItemStack::copy,
(left, right) -> left.setStackSize(left.getStackSize() + right.getStackSize())))
.values().stream().sorted(COMPARE_BY_STACKSIZE).collect(ImmutableList.toImmutableList());
if (merged.isEmpty()) {
throw new IllegalStateException("No pattern here!");
}
return merged;
}
private enum TestStatus {
ACCEPT, DECLINE, TEST
}
@@ -19,6 +19,7 @@
package appeng.items.misc;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -155,8 +156,8 @@ public class EncodedPatternItem extends AEBaseItem {
final boolean isCrafting = details.isCraftable();
final boolean substitute = details.canSubstitute();
final IAEItemStack[] in = details.getCondensedInputs();
final IAEItemStack[] out = details.getCondensedOutputs();
final Collection<IAEItemStack> in = details.getInputs();
final Collection<IAEItemStack> out = details.getOutputs();
final ITextComponent label = (isCrafting ? GuiText.Crafts.textComponent() : GuiText.Creates.textComponent())
.appendText(": ");
@@ -208,7 +209,7 @@ public class EncodedPatternItem extends AEBaseItem {
final ICraftingPatternDetails details = Api.instance().crafting().decodePattern(item, w);
out = details != null ? details.getOutputs()[0].createItemStack() : ItemStack.EMPTY;
out = details != null ? details.getOutputs().get(0).createItemStack() : ItemStack.EMPTY;
SIMPLE_CACHE.put(item, out);
return out;
@@ -226,7 +227,9 @@ public class EncodedPatternItem extends AEBaseItem {
final CompoundNBT tag = itemStack.getTag();
Preconditions.checkArgument(tag != null, "itemStack missing a NBT tag");
return new ResourceLocation(tag.getString(NBT_RECIPE_ID));
return tag.contains(NBT_RECIPE_ID, Constants.NBT.TAG_STRING)
? new ResourceLocation(tag.getString(NBT_RECIPE_ID))
: null;
}
public List<IAEItemStack> getIngredients(ItemStack itemStack) {
@@ -279,7 +282,7 @@ public class EncodedPatternItem extends AEBaseItem {
Preconditions.checkArgument(tag != null, "itemStack missing a NBT tag");
return getCraftingRecipeId(itemStack) == null && tag.getBoolean(NBT_SUBSITUTE);
return getCraftingRecipeId(itemStack) != null && tag.getBoolean(NBT_SUBSITUTE);
}
/**
@@ -72,10 +72,12 @@ public class QuartzCuttingKnifeItem extends AEBaseItem implements IGuiItem {
@Override
public ItemStack getContainerItem(final ItemStack itemStack) {
ItemStack copy = itemStack.copy();
copy.setDamage(itemStack.getDamage() + 1);
return copy;
ItemStack damagedStack = itemStack.copy();
if (damagedStack.attemptDamageItem(1, random, null)) {
return ItemStack.EMPTY;
} else {
return damagedStack;
}
}
@Override
@@ -429,7 +429,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
return null;
}
private boolean canCraft(final ICraftingPatternDetails details, final IAEItemStack[] condensedInputs) {
private boolean canCraft(final ICraftingPatternDetails details, final Collection<IAEItemStack> condensedInputs) {
for (IAEItemStack g : condensedInputs) {
if (details.isCraftable()) {
@@ -557,7 +557,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
final ICraftingPatternDetails details = e.getKey();
if (this.canCraft(details, details.getCondensedInputs())) {
if (this.canCraft(details, details.getInputs())) {
CraftingInventory ic = null;
for (final ICraftingMedium m : cc.getMediums(e.getKey())) {
@@ -567,7 +567,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
if (!m.isBusy()) {
if (ic == null) {
final IAEItemStack[] input = details.getInputs();
final IAEItemStack[] input = details.getSparseInputs();
double sum = 0;
for (final IAEItemStack anInput : input) {
@@ -663,7 +663,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
this.somethingChanged = true;
this.remainingOperations--;
for (final IAEItemStack out : details.getCondensedOutputs()) {
for (final IAEItemStack out : details.getOutputs()) {
this.postChange(out, this.machineSrc);
this.waitingFor.add(out.copy());
this.postCraftingStatusChange(out.copy());
@@ -896,7 +896,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
break;
case PENDING:
for (final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet()) {
for (IAEItemStack ais : t.getKey().getCondensedOutputs()) {
for (IAEItemStack ais : t.getKey().getOutputs()) {
ais = ais.copy();
ais.setStackSize(ais.getStackSize() * t.getValue().value);
list.add(ais);
@@ -915,7 +915,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
}
for (final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet()) {
for (IAEItemStack ais : t.getKey().getCondensedOutputs()) {
for (IAEItemStack ais : t.getKey().getOutputs()) {
ais = ais.copy();
ais.setStackSize(ais.getStackSize() * t.getValue().value);
list.add(ais);
@@ -960,7 +960,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU {
is.setStackSize(0);
for (final Entry<ICraftingPatternDetails, TaskProgress> t : this.tasks.entrySet()) {
for (final IAEItemStack ais : t.getKey().getCondensedOutputs()) {
for (final IAEItemStack ais : t.getKey().getOutputs()) {
if (ais.equals(is)) {
is.setStackSize(is.getStackSize() + ais.getStackSize() * t.getValue().value);
}
@@ -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) {
@@ -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;
}
}
}
@@ -113,13 +113,13 @@ public class PatternTerminalPart extends AbstractTerminalPart {
this.setCraftingRecipe(details.isCraftable());
this.setSubstitution(details.canSubstitute());
for (int x = 0; x < this.crafting.getSlots() && x < details.getInputs().length; x++) {
final IAEItemStack item = details.getInputs()[x];
for (int x = 0; x < this.crafting.getSlots() && x < details.getSparseInputs().length; x++) {
final IAEItemStack item = details.getSparseInputs()[x];
this.crafting.setStackInSlot(x, item == null ? ItemStack.EMPTY : item.createItemStack());
}
for (int x = 0; x < this.output.getSlots() && x < details.getOutputs().length; x++) {
final IAEItemStack item = details.getOutputs()[x];
for (int x = 0; x < this.output.getSlots() && x < details.getSparseOutputs().length; x++) {
final IAEItemStack item = details.getSparseOutputs()[x];
this.output.setStackInSlot(x, item == null ? ItemStack.EMPTY : item.createItemStack());
}
}
@@ -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;
@@ -21,6 +21,7 @@ import net.minecraftforge.registries.ForgeRegistryEntry;
import appeng.core.AEConfig;
import appeng.core.AppEng;
import appeng.core.sync.BasePacket;
public class GrinderRecipeSerializer extends ForgeRegistryEntry<IRecipeSerializer<?>>
implements IRecipeSerializer<GrinderRecipe> {
@@ -28,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() {
@@ -70,7 +71,7 @@ public class GrinderRecipeSerializer extends ForgeRegistryEntry<IRecipeSerialize
@Override
public GrinderRecipe read(ResourceLocation recipeId, PacketBuffer buffer) {
String group = buffer.readString();
String group = buffer.readString(BasePacket.MAX_STRING_LENGTH);
Ingredient ingredient = Ingredient.read(buffer);
int ingredientCount = buffer.readVarInt();
ItemStack result = buffer.readItemStack();
@@ -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;
@@ -15,6 +15,7 @@ import net.minecraftforge.registries.ForgeRegistryEntry;
import appeng.api.features.InscriberProcessType;
import appeng.core.AppEng;
import appeng.core.sync.BasePacket;
public class InscriberRecipeSerializer extends ForgeRegistryEntry<IRecipeSerializer<?>>
implements IRecipeSerializer<InscriberRecipe> {
@@ -22,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() {
@@ -67,7 +68,7 @@ public class InscriberRecipeSerializer extends ForgeRegistryEntry<IRecipeSeriali
@Nullable
@Override
public InscriberRecipe read(ResourceLocation recipeId, PacketBuffer buffer) {
String group = buffer.readString();
String group = buffer.readString(BasePacket.MAX_STRING_LENGTH);
Ingredient middle = Ingredient.read(buffer);
ItemStack result = buffer.readItemStack();
Ingredient top = Ingredient.read(buffer);
@@ -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;
}
@@ -65,6 +65,7 @@ import appeng.block.storage.DriveSlotsState;
import appeng.client.render.model.DriveModelData;
import appeng.container.implementations.DriveContainer;
import appeng.core.Api;
import appeng.core.sync.BasePacket;
import appeng.helpers.IPriorityHost;
import appeng.me.GridAccessException;
import appeng.me.helpers.MachineSource;
@@ -188,7 +189,7 @@ public class DriveTileEntity extends AENetworkInvTileEntity implements IChestOrD
int uniqueStrCount = data.readByte();
String[] uniqueStrs = new String[uniqueStrCount];
for (int i = 0; i < uniqueStrCount; i++) {
uniqueStrs[i] = data.readString();
uniqueStrs[i] = data.readString(BasePacket.MAX_STRING_LENGTH);
}
boolean changed = false;
@@ -1,7 +1,7 @@
{
"type": "appliedenergistics2:grinder",
"input": {
"tag": "appliedenergistics2:crystals/fluix"
"item": "appliedenergistics2:fluix_crystal"
},
"result": {
"primary": {