Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2bca23d75d | |||
| b47543d166 | |||
| a340925d98 | |||
| b8e53adf40 | |||
| 44544c598f | |||
| 0be7322c2c | |||
| a521e827db | |||
| bcee2ec427 | |||
| 17648633fe | |||
| fcbebd4ffc | |||
| 9e41d543f5 | |||
| 81cc0b804d | |||
| e1fc9908b3 | |||
| 9ed1535477 | |||
| 1ef345d4a4 | |||
| ff7d1b9719 | |||
| 88c9370e4f | |||
| f2aae3ef0f | |||
| 12739f1e66 | |||
| 81d2170ada | |||
| 0f469e9df6 | |||
| 0f34f09b32 | |||
| 8e54a8fed9 | |||
| ca007a3737 | |||
| 92b6650022 | |||
| e1cd3bba25 | |||
| 689bf6e8d9 | |||
| c8a5049d71 | |||
| 10a1a6d855 | |||
| d9bb81a00f | |||
| 39e038d916 | |||
| 575a625f75 | |||
| 89ea923c43 | |||
| 5d818eb03e | |||
| 12ca8d109a | |||
| e34126458b | |||
| 0ac918c363 | |||
| b6160e40bc | |||
| cf103b06c1 | |||
| f0d0595c8f | |||
| b756d68be1 | |||
| 60b07e5ca5 | |||
| 7c99fca789 | |||
| ab393b0ed1 | |||
| 957bc4c5cc | |||
| 133ed1f09d | |||
| e90dd2f9c6 | |||
| 9719c7ffc3 | |||
| 319d92a371 | |||
| db9ec2b070 | |||
| 5d33005aaf | |||
| 87cf070b33 | |||
| 3a0552c56e | |||
| b1a55f3a79 | |||
| 226e9596ee | |||
| 5cab9c8799 | |||
| 1d2ac29742 | |||
| cbe6012b98 | |||
| 8a0dd192e5 | |||
| 1842febf86 | |||
| a97b35f3d0 | |||
| 00d4c20d9f | |||
| d2b69671f5 | |||
| 1394ab0863 | |||
| 5efc085693 | |||
| 359e3f7e63 | |||
| fa3e41e687 | |||
| 4e86c92720 | |||
| 159f4c7f14 | |||
| aff94cec8c | |||
| 07dfa3db2e | |||
| e0e139900f | |||
| 9942f2d32c | |||
| 858826d1fa | |||
| 90ad345672 | |||
| 9a81ebfa50 | |||
| da9fa3d697 | |||
| ee7fe9f40d | |||
| 2184d03d0b | |||
| cae1621613 | |||
| e8574d03ea | |||
| d28f33d198 | |||
| 7df5bf4076 | |||
| 66760865a3 | |||
| e4a08ba99d | |||
| f11e9e2a4c | |||
| 7a469c1a1d | |||
| e256a4f664 | |||
| 73cc3f8998 | |||
| 9c9a49f9e7 | |||
| 44c0931c02 | |||
| 874f46ed4d | |||
| b7949e4134 | |||
| ea95913ec8 | |||
| 423ab81813 | |||
| 33d7f02323 | |||
| 4e42b17e81 | |||
| fc0f8eab56 | |||
| 41b7900706 | |||
| 7656157b0d |
@@ -21,7 +21,9 @@ jobs:
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
|
||||
- name: Build with Gradle
|
||||
- name: Generate Resources
|
||||
run: ./gradlew generateData
|
||||
- name: Build
|
||||
run: ./gradlew build
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
||||
@@ -23,10 +23,14 @@ jobs:
|
||||
run: chmod +x gradlew
|
||||
- name: Validate no assets
|
||||
run: test ! -d ./src/generated
|
||||
- name: Generate resources
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew generateData
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew generateData build
|
||||
run: ./gradlew build
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
|
||||
@@ -72,19 +72,41 @@ The API for Applied Energistics 2. It is open source to discuss changes, improve
|
||||
|
||||
### Maven
|
||||
|
||||
We use Github Packages as maven repository now. You can use the following snippet as example on how to add a repository to your gradle build file.
|
||||
Our authoritative Maven repository is Github Packages, which you can also use in your builds. Use of Github Packages
|
||||
[requires special setup](https://docs.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-gradle-for-use-with-github-packages#authenticating-to-github-packages)
|
||||
to authenticate with your personal access token.
|
||||
|
||||
AE2 is also available without authentication from Modmaven.
|
||||
|
||||
You can use the following snippet as example on how to add a repository to your gradle build file.
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name "AE2"
|
||||
url "https://maven.pkg.github.com/AppliedEnergistics/Applied-Energistics-2"
|
||||
name "Modmaven"
|
||||
url "https://modmaven.k-4u.nl/"
|
||||
// For Gradle 5.1 and above, limit it to just AE2
|
||||
content {
|
||||
includeGroup 'appeng'
|
||||
}
|
||||
}
|
||||
|
||||
// Required for libblockattributes
|
||||
maven {
|
||||
name = "BuildCraft"
|
||||
url = "https://mod-buildcraft.com/maven"
|
||||
content {
|
||||
includeGroup "alexiil.mc.lib"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
When compiling against the AE2 API you can use gradle dependencies, just add
|
||||
|
||||
dependencies {
|
||||
compileOnly "appeng:appliedenergistics2:VERSION:api"
|
||||
modCompileOnly "appeng:appliedenergistics2-fabric:VERSION:api"
|
||||
|
||||
// Include only if you want AE2 at runtime
|
||||
modRuntimeOnly "appeng:appliedenergistics2-fabric:VERSION"
|
||||
}
|
||||
|
||||
or add the `compileOnly` line to your existing dependencies task to your build.gradle.
|
||||
|
||||
+2
-2
@@ -144,13 +144,13 @@ dependencies {
|
||||
modApi "teamreborn:energy:${tr_energy_version}"
|
||||
include "teamreborn:energy:${tr_energy_version}"
|
||||
|
||||
modCompileOnly("me.shedaniel:RoughlyEnoughItems:5.0.2-unstable") {
|
||||
modCompileOnly("me.shedaniel:RoughlyEnoughItems:${rei_version}") {
|
||||
exclude group: "net.fabricmc.fabric-api"
|
||||
}
|
||||
modCompileOnly("mcp.mobius.waila:Hwyla:1.16.1-1.9.22-75") {
|
||||
exclude group: "net.fabricmc.fabric-api"
|
||||
}
|
||||
modRuntime("me.shedaniel:RoughlyEnoughItems:5.0.2-unstable") {
|
||||
modRuntime("me.shedaniel:RoughlyEnoughItems:${rei_version}") {
|
||||
exclude group: "net.fabricmc.fabric-api"
|
||||
}
|
||||
modRuntime("TechReborn:TechReborn-1.16:3.5.1+build.101") {
|
||||
|
||||
+4
-3
@@ -11,10 +11,10 @@ org.gradle.jvmargs=-Xmx2G
|
||||
|
||||
minecraft_version=1.16.2
|
||||
yarn_mappings=1.16.2+build.6
|
||||
loader_version=0.9.1+build.205
|
||||
loader_version=0.9.2+build.206
|
||||
|
||||
#Fabric api
|
||||
fabric_version=0.17.2+build.396-1.16
|
||||
fabric_version=0.20.1+build.401-1.16
|
||||
|
||||
loom_version=0.4-SNAPSHOT
|
||||
|
||||
@@ -23,8 +23,9 @@ kotlin_version=1.3.61
|
||||
fabric_kotlin_version=1.3.61+build.1
|
||||
|
||||
# Dependencies
|
||||
libblockattributes_version=0.8.0-pre.19
|
||||
libblockattributes_version=0.8.0
|
||||
tr_energy_version=0.1.0
|
||||
rei_version=5.2.10
|
||||
|
||||
#########################################################
|
||||
# Deployment #
|
||||
|
||||
@@ -33,8 +33,8 @@ dependencies {
|
||||
compileOnly "mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}:api"
|
||||
|
||||
// Runtime, Mods
|
||||
// FIXME 1.16.2 runtimeOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}")
|
||||
// FIXME 1.16.2 runtimeOnly fg.deobf("mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}")
|
||||
runtimeOnly fg.deobf("mezz.jei:jei-${jei_minecraft_version}:${jei_version}")
|
||||
runtimeOnly fg.deobf("mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}")
|
||||
//runtimeOnly fg.deobf("team.chisel.ctm:CTM:${ctm_version}")
|
||||
|
||||
// unit test dependencies
|
||||
|
||||
@@ -82,11 +82,6 @@ public interface IRegistryContainer {
|
||||
*/
|
||||
IPlayerRegistry players();
|
||||
|
||||
/**
|
||||
* get access to the world-gen api.
|
||||
*/
|
||||
IWorldGen worldgen();
|
||||
|
||||
/**
|
||||
* Register your IPart models before using them.
|
||||
*/
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2013 AlgorithmX2
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package appeng.api.features;
|
||||
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public interface IWorldGen {
|
||||
|
||||
void enableWorldGenForDimension(WorldGenType type, Identifier dimID);
|
||||
|
||||
void disableWorldGenForDimension(WorldGenType type, Identifier dimID);
|
||||
|
||||
boolean isWorldGenEnabled(WorldGenType type, ServerWorld w);
|
||||
|
||||
enum WorldGenType {
|
||||
CERTUS_QUARTZ, CHARGED_CERTUS_QUARTZ, METEORITES
|
||||
}
|
||||
}
|
||||
@@ -23,13 +23,23 @@
|
||||
|
||||
package appeng.api.implementations.items;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Material;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IGrowableCrystal {
|
||||
|
||||
ItemStack triggerGrowth(ItemStack is);
|
||||
|
||||
float getMultiplier(Block blk, Material mat);
|
||||
/**
|
||||
* Gets the crystal growth multiplier based on the material it is submerged in.
|
||||
*
|
||||
* @param state The blockstate of the block the crystal is currently in.
|
||||
* @return The multiplier for the growth tick progress. Zero if the crystal
|
||||
* cannot grow in the current material.
|
||||
*/
|
||||
float getMultiplier(BlockState state, @Nullable World world, @Nullable BlockPos pos);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
|
||||
import net.minecraft.Bootstrap;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
@@ -15,9 +18,13 @@ import appeng.data.providers.tags.ToolTagProviders;
|
||||
|
||||
public class Entrypoint implements PreLaunchEntrypoint {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
public static void dump() throws Exception {
|
||||
Path output = Paths.get("../src/generated/resources");
|
||||
|
||||
LOGGER.info("Writing generated resources to {}", output.toAbsolutePath());
|
||||
|
||||
DataGenerator generator = new DataGenerator(output, Collections.emptyList());
|
||||
generator.install(new BlockDropProvider(output));
|
||||
generator.install(new SlabStairRecipes(output));
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class MEAttributes {
|
||||
return null;
|
||||
}
|
||||
|
||||
return attribute.getFirstOrNull(world, be.getPos().offset(side), SearchOptions.inDirection(side.getOpposite()));
|
||||
return attribute.getFirstOrNull(world, be.getPos(), SearchOptions.inDirection(side.getOpposite()));
|
||||
}
|
||||
|
||||
// Convenience function to get an attribute of the block that is in front of a
|
||||
|
||||
@@ -161,4 +161,9 @@ public class CrankBlock extends AEBaseTileBlock<CrankBlockEntity> {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasCustomRotation() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemPlacementContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.state.StateManager;
|
||||
import net.minecraft.state.property.IntProperty;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.DyeColor;
|
||||
import net.minecraft.util.Hand;
|
||||
@@ -80,8 +82,12 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implemen
|
||||
|
||||
private static final ICableBusContainer NULL_CABLE_BUS = new NullCableBusContainer();
|
||||
|
||||
private static final IntProperty LIGHT_LEVEL = IntProperty.of("light_level", 0, 15);
|
||||
|
||||
public CableBusBlock() {
|
||||
super(defaultProps(AEMaterials.GLASS).nonOpaque().dropsNothing().dynamicBounds());
|
||||
super(defaultProps(AEMaterials.GLASS).nonOpaque().dropsNothing().dynamicBounds()
|
||||
.lightLevel(state -> state.get(LIGHT_LEVEL)));
|
||||
setDefaultState(getDefaultState().with(LIGHT_LEVEL, 0));
|
||||
}
|
||||
|
||||
static {
|
||||
@@ -134,16 +140,13 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implemen
|
||||
// OPPOSITE!?
|
||||
}
|
||||
|
||||
// FIXME Dynamic light seems unsupported (?) Must maybe use blockstates... :|
|
||||
// FIXME FABRIC @Override
|
||||
// FIXME FABRIC public int getLightValue(final BlockState state, final BlockView world, final BlockPos pos) {
|
||||
// FIXME FABRIC if (state.getBlock() != this) {
|
||||
// FIXME FABRIC return state.getLuminance();
|
||||
// FIXME FABRIC }
|
||||
// FIXME FABRIC return this.cb(world, pos).getLightValue();
|
||||
// FIXME FABRIC }
|
||||
@Override
|
||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||
super.appendProperties(builder);
|
||||
builder.add(LIGHT_LEVEL);
|
||||
}
|
||||
|
||||
// FIXME: Must hook isClimbing ourselves
|
||||
// FIXME: Must hook isClimbing ourselves
|
||||
// FIXME FABRIC @Override
|
||||
// FIXME FABRIC public boolean isLadder(BlockState state, WorldView world, BlockPos pos, LivingEntity entity) {
|
||||
// FIXME FABRIC return this.cb(world, pos).isLadder(entity);
|
||||
@@ -399,4 +402,13 @@ public class CableBusBlock extends AEBaseTileBlock<CableBusBlockEntity> implemen
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BlockState updateBlockStateFromTileEntity(BlockState currentState, CableBusBlockEntity te) {
|
||||
if (currentState.getBlock() != this) {
|
||||
return currentState;
|
||||
}
|
||||
int lightLevel = te.getCableBus().getLightValue();
|
||||
return super.updateBlockStateFromTileEntity(currentState, te).with(LIGHT_LEVEL, lightLevel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
@@ -58,6 +59,7 @@ import net.minecraft.util.Identifier;
|
||||
import alexiil.mc.lib.attributes.fluid.render.FluidRenderFace;
|
||||
import alexiil.mc.lib.attributes.fluid.render.FluidVolumeRenderer;
|
||||
import alexiil.mc.lib.attributes.fluid.volume.FluidVolume;
|
||||
import me.shedaniel.math.Rectangle;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
@@ -803,4 +805,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends HandledScr
|
||||
}
|
||||
}
|
||||
|
||||
public List<Rectangle> getExclusionZones() {
|
||||
return Lists.newArrayList(new Rectangle(x, y, backgroundWidth, backgroundHeight));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.client.me.SlotME;
|
||||
|
||||
/**
|
||||
* A proxy for a slot that will always return an itemstack with size 1, if there
|
||||
* is an item in the slot. Used to prevent the default item count from
|
||||
@@ -21,9 +19,9 @@ import appeng.client.me.SlotME;
|
||||
*/
|
||||
class Size1Slot extends Slot {
|
||||
|
||||
private final SlotME delegate;
|
||||
private final Slot delegate;
|
||||
|
||||
public Size1Slot(SlotME delegate) {
|
||||
public Size1Slot(Slot delegate) {
|
||||
super(delegate.inventory, -1, delegate.x, delegate.y);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,9 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
|
||||
this.searchField.setMaxLength(25);
|
||||
this.searchField.setEditableColor(0xFFFFFF);
|
||||
this.searchField.setVisible(true);
|
||||
this.searchField.setFocused(true);
|
||||
this.searchField.setChangedListener(str -> this.refreshList());
|
||||
this.addChild(this.searchField);
|
||||
this.changeFocus(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -128,11 +130,8 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
|
||||
|
||||
@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.refreshList();
|
||||
}
|
||||
if (btn == 1 && this.searchField.isMouseOver(xCoord, yCoord)) {
|
||||
this.searchField.setText("");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -170,11 +169,7 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
|
||||
if (character == ' ' && this.searchField.getText().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (this.searchField.charTyped(character, key)) {
|
||||
this.refreshList();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return super.charTyped(character, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,6 +28,8 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import me.shedaniel.math.Rectangle;
|
||||
|
||||
import appeng.api.config.SearchBoxMode;
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.SortDir;
|
||||
@@ -519,4 +521,14 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
|
||||
this.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Rectangle> getExclusionZones() {
|
||||
List<Rectangle> zones = super.getExclusionZones();
|
||||
// Button toolbar on the left
|
||||
zones.add(new Rectangle(x - 18, y + 8, 18, 160));
|
||||
// View-cells on the right
|
||||
zones.add(new Rectangle(x + 197, y, 46, 128));
|
||||
return zones;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,10 +18,14 @@
|
||||
|
||||
package appeng.client.gui.implementations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import me.shedaniel.math.Rectangle;
|
||||
|
||||
import appeng.api.config.FuzzyMode;
|
||||
import appeng.api.config.RedstoneMode;
|
||||
import appeng.api.config.SchedulingMode;
|
||||
@@ -146,4 +150,11 @@ public class UpgradeableScreen<T extends UpgradeableContainer> extends AEBaseScr
|
||||
return this.bc instanceof ImportBusPart ? GuiText.ImportBus : GuiText.ExportBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Rectangle> getExclusionZones() {
|
||||
List<Rectangle> zones = super.getExclusionZones();
|
||||
zones.add(new Rectangle(x - 18, y + 8, 18, 60));
|
||||
return zones;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -48,9 +48,9 @@ public class WirelessScreen extends AEBaseScreen<WirelessContainer> {
|
||||
this.textRenderer.draw(matrices, GuiText.inventory.text(), 8, this.backgroundHeight - 96 + 3, 4210752);
|
||||
|
||||
if (handler.getRange() > 0) {
|
||||
final String firstMessage = GuiText.Range.text() + ": " + (handler.getRange() / 10.0) + " m";
|
||||
final String secondMessage = GuiText.PowerUsageRate.text() + ": "
|
||||
+ Platform.formatPowerLong(handler.getDrain(), true);
|
||||
final Text firstMessage = GuiText.Range.withSuffix(": " + (handler.getRange() / 10.0) + " m");
|
||||
final Text secondMessage = GuiText.PowerUsageRate
|
||||
.withSuffix(": " + Platform.formatPowerLong(handler.getDrain(), true));
|
||||
|
||||
final int strWidth = Math.max(this.textRenderer.getWidth(firstMessage),
|
||||
this.textRenderer.getWidth(secondMessage));
|
||||
|
||||
@@ -41,11 +41,6 @@ import appeng.fluids.util.FluidSorters;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.prioritylist.IPartitionList;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class FluidRepo {
|
||||
private final IItemList<IAEFluidStack> list = Api.instance().storage().getStorageChannel(IFluidStorageChannel.class)
|
||||
.createList();
|
||||
|
||||
@@ -21,23 +21,22 @@ package appeng.client.me;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.SimpleInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.fluids.container.slots.IMEFluidSlot;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class SlotFluidME extends Slot implements IMEFluidSlot {
|
||||
|
||||
private static final Inventory EMPTY_INVENTORY = new SimpleInventory(0);
|
||||
|
||||
private final InternalFluidSlotME slot;
|
||||
|
||||
public SlotFluidME(InternalFluidSlotME slot) {
|
||||
super(null, 0, slot.getxPosition(), slot.getyPosition());
|
||||
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
@@ -69,7 +68,7 @@ public class SlotFluidME extends Slot implements IMEFluidSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStack(final ItemStack par1ItemStack) {
|
||||
public void setStack(final ItemStack stack) {
|
||||
|
||||
}
|
||||
|
||||
@@ -85,7 +84,7 @@ public class SlotFluidME extends Slot implements IMEFluidSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTakeItems(final PlayerEntity par1PlayerEntity) {
|
||||
public boolean canTakeItems(final PlayerEntity player) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
package appeng.client.me;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.SimpleInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
|
||||
@@ -26,16 +28,18 @@ import appeng.api.storage.data.IAEItemStack;
|
||||
|
||||
public class SlotME extends Slot {
|
||||
|
||||
private final InternalSlotME mySlot;
|
||||
private static final Inventory EMPTY_INVENTORY = new SimpleInventory(0);
|
||||
|
||||
public SlotME(final InternalSlotME me) {
|
||||
super(null, 0, me.getxPosition(), me.getyPosition());
|
||||
this.mySlot = me;
|
||||
private final InternalSlotME slot;
|
||||
|
||||
public SlotME(final InternalSlotME slot) {
|
||||
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
public IAEItemStack getAEStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
return this.mySlot.getAEStack();
|
||||
if (this.slot.hasPower()) {
|
||||
return this.slot.getAEStack();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -47,15 +51,15 @@ public class SlotME extends Slot {
|
||||
|
||||
@Override
|
||||
public ItemStack getStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
return this.mySlot.getStack();
|
||||
if (this.slot.hasPower()) {
|
||||
return this.slot.getStack();
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
if (this.slot.hasPower()) {
|
||||
return !this.getStack().isEmpty();
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -20,7 +20,6 @@ package appeng.client.render.cablebus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -30,6 +29,10 @@ import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
@@ -61,10 +64,15 @@ import appeng.api.util.AEColor;
|
||||
@Environment(EnvType.CLIENT)
|
||||
public class CableBusBakedModel implements BakedModel, FabricBakedModel {
|
||||
|
||||
private static final Mesh EMPTY_MESH = consumer -> {
|
||||
};
|
||||
|
||||
private static final Renderer RENDERER = RendererAccess.INSTANCE.getRenderer();
|
||||
|
||||
// FIXME: This entire cache seems dumb as shit
|
||||
private static final Map<CableBusRenderState, Mesh> CABLE_MODEL_CACHE = new HashMap<>();
|
||||
// The number of meshes overall that will be cached
|
||||
private static final int CACHE_MESH_COUNT = 100;
|
||||
|
||||
private final LoadingCache<CableBusRenderState, Mesh> cableModelCache;
|
||||
|
||||
private final CableBuilder cableBuilder;
|
||||
|
||||
@@ -80,6 +88,15 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
|
||||
this.facadeBuilder = facadeBuilder;
|
||||
this.partModels = partModels;
|
||||
this.particleTexture = particleTexture;
|
||||
this.cableModelCache = CacheBuilder.newBuilder()//
|
||||
.maximumSize(CACHE_MESH_COUNT)//
|
||||
.build(new CacheLoader<CableBusRenderState, Mesh>() {
|
||||
@Override
|
||||
public Mesh load(CableBusRenderState renderState) {
|
||||
Mesh mesh = buildCableModel(renderState);
|
||||
return mesh != null ? mesh : EMPTY_MESH;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,8 +126,8 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
|
||||
}
|
||||
|
||||
// First, handle the cable at the center of the cable bus
|
||||
final Mesh cableModel = CABLE_MODEL_CACHE.computeIfAbsent(renderState, this::buildCableModel);
|
||||
if (cableModel != null) {
|
||||
final Mesh cableModel = cableModelCache.getUnchecked(renderState);
|
||||
if (cableModel != EMPTY_MESH) {
|
||||
context.meshConsumer().accept(cableModel);
|
||||
}
|
||||
|
||||
@@ -359,10 +376,6 @@ public class CableBusBakedModel implements BakedModel, FabricBakedModel {
|
||||
return ModelOverrideList.EMPTY;
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
CABLE_MODEL_CACHE.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVanillaAdapter() {
|
||||
return false;
|
||||
|
||||
@@ -23,7 +23,6 @@ public class CableBusModelLoader implements ModelResourceProvider {
|
||||
public UnbakedModel loadModelResource(Identifier resourceId, ModelProviderContext context)
|
||||
throws ModelProviderException {
|
||||
if (CABLE_BUS_MODEL.equals(resourceId)) {
|
||||
CableBusBakedModel.clearCache();
|
||||
return new CableBusModel(partModels);
|
||||
} else {
|
||||
return null;
|
||||
|
||||
@@ -258,7 +258,9 @@ public class FacadeBuilder {
|
||||
|
||||
for (Box box : holeStrips) {
|
||||
emitter.fromVanilla(quad.getVertexData(), 0, false);
|
||||
emitter.cullFace(cullFace);
|
||||
// Keep the cull-face for faces that are flush with the outer block-face on the
|
||||
// side the facade is attached to, but clear it for anything that faces inwards
|
||||
emitter.cullFace(cullFace == side ? side : null);
|
||||
emitter.nominalFace(quad.getFace());
|
||||
interpolator.setInputQuad(emitter);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
|
||||
import net.minecraft.client.util.math.Vector3f;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Quaternion;
|
||||
@@ -93,10 +92,6 @@ public class QuadRotator implements RenderContext.QuadTransform {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME FABRIC: Wait for Grondags response about this one
|
||||
MutableQuadViewImpl quadImpl = (MutableQuadViewImpl) quad;
|
||||
quadImpl.lightFace(rotation.rotate(quad.lightFace()));
|
||||
|
||||
// Transform the nominal face, setting the cull face will also overwrite the
|
||||
// nominialFace,
|
||||
// hence saving both first and the order here.
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package appeng.client.render.tesr;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
@@ -9,12 +11,12 @@ import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||
import net.minecraft.client.render.item.ItemRenderer;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.client.texture.SpriteAtlasTexture;
|
||||
import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.Direction;
|
||||
@@ -197,9 +199,12 @@ public final class InscriberTESR extends BlockEntityRenderer<InscriberBlockEntit
|
||||
|
||||
ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
|
||||
|
||||
// heuristic to scale items down much further than blocks
|
||||
boolean renderAsCube = (stack.getItem() instanceof BlockItem);
|
||||
if (!renderAsCube) {
|
||||
// heuristic to scale items down much further than blocks,
|
||||
// the assumption here is that the generated item models will return their faces
|
||||
// for direction=null, while a block-model will have their faces for
|
||||
// cull-faces, but not direction=null
|
||||
BakedModel model = itemRenderer.getModels().getModel(stack);
|
||||
if (!model.getQuads(null, null, new Random()).isEmpty()) {
|
||||
ms.scale(0.5f, 0.5f, 0.5f);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.LimitedFixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.SingleItemSlot;
|
||||
|
||||
import appeng.api.config.SecurityPermissions;
|
||||
import appeng.api.config.Settings;
|
||||
@@ -43,7 +45,7 @@ import appeng.api.networking.security.IActionHost;
|
||||
import appeng.container.AEBaseContainer;
|
||||
import appeng.container.ContainerLocator;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.CompressedNBTPacket;
|
||||
import appeng.core.sync.packets.MEInterfaceUpdatePacket;
|
||||
import appeng.helpers.DualityInterface;
|
||||
import appeng.helpers.IInterfaceHost;
|
||||
import appeng.helpers.InventoryAction;
|
||||
@@ -57,8 +59,6 @@ import appeng.util.Platform;
|
||||
import appeng.util.helpers.ItemHandlerUtil;
|
||||
import appeng.util.inv.AdaptorFixedInv;
|
||||
import appeng.util.inv.WrapperCursorItemHandler;
|
||||
import appeng.util.inv.WrapperFilteredItemHandler;
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
|
||||
public final class InterfaceTerminalContainer extends AEBaseContainer {
|
||||
|
||||
@@ -177,7 +177,7 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
|
||||
|
||||
if (!this.data.isEmpty()) {
|
||||
try {
|
||||
NetworkHandler.instance().sendTo(new CompressedNBTPacket(this.data),
|
||||
NetworkHandler.instance().sendTo(new MEInterfaceUpdatePacket(this.data),
|
||||
(ServerPlayerEntity) this.getPlayerInv().player);
|
||||
} catch (final IOException e) {
|
||||
// :P
|
||||
@@ -196,35 +196,37 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
|
||||
|
||||
final InventoryAdaptor playerHand = new AdaptorFixedInv(new WrapperCursorItemHandler(player.inventory));
|
||||
|
||||
final FixedItemInv theSlot = new WrapperFilteredItemHandler(inv.server.getSubInv(slot, slot + 1),
|
||||
new PatternSlotFilter());
|
||||
final InventoryAdaptor interfaceSlot = new AdaptorFixedInv(theSlot);
|
||||
// Create a wrapper around the targetted slot that will only allow insertions of
|
||||
// patterns
|
||||
LimitedFixedItemInv limitedSlotInv = inv.server.createLimitedFixedInv();
|
||||
limitedSlotInv.getAllRule().filterInserts(this::isValidPattern);
|
||||
SingleItemSlot theSlot = limitedSlotInv.getSlot(slot);
|
||||
|
||||
switch (action) {
|
||||
case PICKUP_OR_SET_DOWN:
|
||||
|
||||
if (hasItemInHand) {
|
||||
ItemStack inSlot = theSlot.getInvStack(0);
|
||||
ItemStack inSlot = theSlot.get();
|
||||
if (inSlot.isEmpty()) {
|
||||
player.inventory.setCursorStack(interfaceSlot.addItems(player.inventory.getCursorStack()));
|
||||
player.inventory.setCursorStack(theSlot.insert(player.inventory.getCursorStack()));
|
||||
} else {
|
||||
inSlot = inSlot.copy();
|
||||
final ItemStack inHand = player.inventory.getCursorStack().copy();
|
||||
|
||||
ItemHandlerUtil.setStackInSlot(theSlot, 0, ItemStack.EMPTY);
|
||||
theSlot.set(ItemStack.EMPTY);
|
||||
player.inventory.setCursorStack(ItemStack.EMPTY);
|
||||
|
||||
player.inventory.setCursorStack(interfaceSlot.addItems(inHand.copy()));
|
||||
player.inventory.setCursorStack(theSlot.insert(inHand.copy()));
|
||||
|
||||
if (player.inventory.getCursorStack().isEmpty()) {
|
||||
player.inventory.setCursorStack(inSlot);
|
||||
} else {
|
||||
player.inventory.setCursorStack(inHand);
|
||||
ItemHandlerUtil.setStackInSlot(theSlot, 0, inSlot);
|
||||
theSlot.set(inSlot);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ItemHandlerUtil.setStackInSlot(theSlot, 0, playerHand.addItems(theSlot.getInvStack(0)));
|
||||
theSlot.set(playerHand.addItems(theSlot.get()));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -233,18 +235,18 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
|
||||
if (hasItemInHand) {
|
||||
ItemStack extra = playerHand.removeItems(1, ItemStack.EMPTY, null);
|
||||
if (!extra.isEmpty()) {
|
||||
extra = interfaceSlot.addItems(extra);
|
||||
extra = theSlot.insert(extra);
|
||||
}
|
||||
if (!extra.isEmpty()) {
|
||||
playerHand.addItems(extra);
|
||||
}
|
||||
} else if (!is.isEmpty()) {
|
||||
ItemStack extra = interfaceSlot.removeItems((is.getCount() + 1) / 2, ItemStack.EMPTY, null);
|
||||
ItemStack extra = theSlot.extract((is.getCount() + 1) / 2);
|
||||
if (!extra.isEmpty()) {
|
||||
extra = playerHand.addItems(extra);
|
||||
}
|
||||
if (!extra.isEmpty()) {
|
||||
interfaceSlot.addItems(extra);
|
||||
theSlot.insert(extra);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,8 +254,7 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
|
||||
case SHIFT_CLICK:
|
||||
|
||||
final InventoryAdaptor playerInv = InventoryAdaptor.getAdaptor(player);
|
||||
|
||||
ItemHandlerUtil.setStackInSlot(theSlot, 0, playerInv.addItems(theSlot.getInvStack(0)));
|
||||
theSlot.set(playerInv.addItems(theSlot.get()));
|
||||
|
||||
break;
|
||||
case MOVE_REGION:
|
||||
@@ -279,6 +280,10 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidPattern(ItemStack stack) {
|
||||
return !stack.isEmpty() && stack.getItem() instanceof EncodedPatternItem;
|
||||
}
|
||||
|
||||
private void regenList(final CompoundTag data) {
|
||||
this.byId.clear();
|
||||
this.diList.clear();
|
||||
@@ -369,15 +374,4 @@ public final class InterfaceTerminalContainer extends AEBaseContainer {
|
||||
}
|
||||
}
|
||||
|
||||
private static class PatternSlotFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
return !stack.isEmpty() && stack.getItem() instanceof EncodedPatternItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,9 +143,11 @@ public class QuartzKnifeContainer extends AEBaseContainer {
|
||||
|
||||
private void makePlate() {
|
||||
if (Platform.isServer()) {
|
||||
if (!this.takeStack(1).isEmpty()) {
|
||||
if (!inSlot.getSlot(0).extract(1).isEmpty()) {
|
||||
final ItemStack item = QuartzKnifeContainer.this.toolInv.getItemStack();
|
||||
final ItemStack before = item.copy();
|
||||
// FIXME FABRIC: Quartz Knife currently is not damageable due to recipe
|
||||
// remainder concerns
|
||||
item.damage(1, QuartzKnifeContainer.this.getPlayerInv().player, p -> {
|
||||
QuartzKnifeContainer.this.getPlayerInv()
|
||||
.setStack(QuartzKnifeContainer.this.getPlayerInv().selectedSlot, ItemStack.EMPTY);
|
||||
|
||||
@@ -165,7 +165,7 @@ public class RestrictedInputSlot extends AppEngSlot {
|
||||
case ORE:
|
||||
return GrinderRecipes.isValidIngredient(p.player.world, stack);
|
||||
case FUEL:
|
||||
return FuelRegistry.INSTANCE.get(stack.getItem()) > 0;
|
||||
return FuelRegistry.INSTANCE.get(stack.getItem()) != null;
|
||||
case POWERED_TOOL:
|
||||
return Platform.isChargeable(stack);
|
||||
case QE_SINGULARITY:
|
||||
|
||||
@@ -25,14 +25,14 @@ import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import appeng.api.config.CondenserOutput;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
@@ -50,6 +50,7 @@ import appeng.core.config.DoubleOption;
|
||||
import appeng.core.config.EnumOption;
|
||||
import appeng.core.config.IntegerOption;
|
||||
import appeng.core.config.StringListOption;
|
||||
import appeng.core.config.StringOption;
|
||||
import appeng.core.settings.TickRates;
|
||||
import appeng.util.EnumCycler;
|
||||
|
||||
@@ -81,6 +82,13 @@ public final class AEConfig {
|
||||
result.save(); // Save a default file
|
||||
} else {
|
||||
result.load();
|
||||
|
||||
// Re-save immediately to write-out new defaults
|
||||
try {
|
||||
result.save();
|
||||
} catch (Exception e) {
|
||||
AELog.warn(e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -137,7 +145,6 @@ public final class AEConfig {
|
||||
|
||||
// Meteors
|
||||
private int meteoriteMaximumSpawnHeight;
|
||||
private Set<String> meteoriteDimensionWhitelist;
|
||||
|
||||
// Wireless
|
||||
private double wirelessBaseCost;
|
||||
@@ -175,7 +182,6 @@ public final class AEConfig {
|
||||
this.oreDoublePercentage = (float) commonConfig.oreDoublePercentage.get();
|
||||
|
||||
this.meteoriteMaximumSpawnHeight = commonConfig.meteoriteMaximumSpawnHeight.get();
|
||||
this.meteoriteDimensionWhitelist = new HashSet<>(commonConfig.meteoriteDimensionWhitelist.get());
|
||||
|
||||
this.wirelessBaseCost = commonConfig.wirelessBaseCost.get();
|
||||
this.wirelessCostMultiplier = commonConfig.wirelessCostMultiplier.get();
|
||||
@@ -389,8 +395,21 @@ public final class AEConfig {
|
||||
return this.meteoriteMaximumSpawnHeight;
|
||||
}
|
||||
|
||||
public Set<String> getMeteoriteDimensionWhitelist() {
|
||||
return this.meteoriteDimensionWhitelist;
|
||||
public List<String> getMeteoriteBiomeBlacklist() {
|
||||
return commonConfig.meteoriteBiomeBlacklist.get();
|
||||
}
|
||||
|
||||
public List<String> getQuartzOreBiomeBlacklist() {
|
||||
return commonConfig.quartzOreBiomeBlacklist.get();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getImprovedFluidTag() {
|
||||
return Strings.emptyToNull(commonConfig.improvedFluidTag.get());
|
||||
}
|
||||
|
||||
public float getImprovedFluidMultiplier() {
|
||||
return (float) commonConfig.improvedFluidMultiplier.get();
|
||||
}
|
||||
|
||||
// Setters keep visibility as low as possible.
|
||||
@@ -478,10 +497,11 @@ public final class AEConfig {
|
||||
public final DoubleOption spawnChargedChance;
|
||||
public final IntegerOption quartzOresPerCluster;
|
||||
public final IntegerOption quartzOresClusterAmount;
|
||||
public final StringListOption quartzOreBiomeBlacklist;
|
||||
|
||||
// Meteors
|
||||
public final IntegerOption meteoriteMaximumSpawnHeight;
|
||||
public final StringListOption meteoriteDimensionWhitelist;
|
||||
public final StringListOption meteoriteBiomeBlacklist;
|
||||
|
||||
// Wireless
|
||||
public final DoubleOption wirelessBaseCost;
|
||||
@@ -504,6 +524,11 @@ public final class AEConfig {
|
||||
public final IntegerOption condenserMatterBallsPower;
|
||||
public final IntegerOption condenserSingularityPower;
|
||||
|
||||
// In-World Purification
|
||||
// Settings for improved speed depending on fluid the crystal is in
|
||||
public final StringOption improvedFluidTag;
|
||||
public final DoubleOption improvedFluidMultiplier;
|
||||
|
||||
public final Map<TickRates, IntegerOption> tickRateMin = new HashMap<>();
|
||||
public final Map<TickRates, IntegerOption> tickRateMax = new HashMap<>();
|
||||
|
||||
@@ -562,13 +587,13 @@ public final class AEConfig {
|
||||
|
||||
this.spawnChargedChance = worldGen.addDouble("spawnChargedChance", 0.08, 0.0, 1.0);
|
||||
this.meteoriteMaximumSpawnHeight = worldGen.addInt("meteoriteMaximumSpawnHeight", 180);
|
||||
List<String> defaultDimensionWhitelist = new ArrayList<>();
|
||||
defaultDimensionWhitelist.add(DimensionType.OVERWORLD_REGISTRY_KEY.getValue().toString());
|
||||
this.meteoriteDimensionWhitelist = worldGen.addStringList("meteoriteDimensionWhitelist",
|
||||
defaultDimensionWhitelist);
|
||||
this.meteoriteBiomeBlacklist = worldGen.addStringList("meteoriteBiomeBlacklist", new ArrayList<>(),
|
||||
"Biome IDs in which meteorites should NOT be generated (i.e. minecraft:plains).");
|
||||
|
||||
this.quartzOresPerCluster = worldGen.addInt("quartzOresPerCluster", 4);
|
||||
this.quartzOresClusterAmount = worldGen.addInt("quartzOresClusterAmount", 20);
|
||||
this.quartzOreBiomeBlacklist = worldGen.addStringList("quartzOreBiomeBlacklist", new ArrayList<>(),
|
||||
"Biome IDs in which quartz ores should NOT be generated (i.e. minecraft:plains).");
|
||||
|
||||
ConfigSection wireless = root.subsection("wireless");
|
||||
this.wirelessBaseCost = wireless.addDouble("wirelessBaseCost", 8.0);
|
||||
@@ -598,6 +623,14 @@ public final class AEConfig {
|
||||
tickRateMin.put(tickRate, tickrates.addInt(tickRate.name() + "Min", tickRate.getDefaultMin()));
|
||||
tickRateMax.put(tickRate, tickrates.addInt(tickRate.name() + "Max", tickRate.getDefaultMax()));
|
||||
}
|
||||
|
||||
ConfigSection inWorldPurification = root.subsection("inWorldPurification",
|
||||
"Settings for in-world purification of crystals.");
|
||||
|
||||
improvedFluidTag = inWorldPurification.addString("improvedFluidTag", "",
|
||||
"A fluid tag that identifies fluids that improve crystal purification speed. Does not affect purification with water/lava.");
|
||||
improvedFluidMultiplier = inWorldPurification.addDouble("improvedFluidMultiplier", 2.0, 1.0, 10.0,
|
||||
"The speed multiplier to use when the crystals are submerged in the improved fluid.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,14 +30,8 @@ import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
|
||||
import team.reborn.energy.Energy;
|
||||
import team.reborn.energy.EnergyHandler;
|
||||
import team.reborn.energy.EnergyHolder;
|
||||
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.definitions.IBlocks;
|
||||
@@ -45,8 +39,6 @@ import appeng.api.definitions.IItems;
|
||||
import appeng.api.definitions.IParts;
|
||||
import appeng.api.features.IRegistryContainer;
|
||||
import appeng.api.features.IWirelessTermHandler;
|
||||
import appeng.api.features.IWorldGen;
|
||||
import appeng.api.implementations.items.IAEItemPowerStorage;
|
||||
import appeng.api.movable.IMovableRegistry;
|
||||
import appeng.api.networking.IGridCacheRegistry;
|
||||
import appeng.api.networking.crafting.ICraftingGrid;
|
||||
@@ -57,7 +49,6 @@ import appeng.api.networking.spatial.ISpatialCache;
|
||||
import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.networking.ticking.ITickManager;
|
||||
import appeng.api.parts.CableRenderMode;
|
||||
import appeng.block.AEBaseBlockItemChargeable;
|
||||
import appeng.bootstrap.IBootstrapComponent;
|
||||
import appeng.bootstrap.components.ITileEntityRegistrationComponent;
|
||||
import appeng.client.render.effects.ParticleTypes;
|
||||
@@ -351,21 +342,6 @@ public abstract class AppEngBase implements AppEng {
|
||||
*/
|
||||
mr.whiteListBlockEntity(AEBaseBlockEntity.class);
|
||||
|
||||
/*
|
||||
* world gen
|
||||
*/
|
||||
for (final IWorldGen.WorldGenType type : IWorldGen.WorldGenType.values()) {
|
||||
// FIXME: registries.worldgen().disableWorldGenForProviderID( type,
|
||||
// StorageWorldProvider.class );
|
||||
|
||||
registries.worldgen().disableWorldGenForDimension(type, DimensionType.THE_NETHER_REGISTRY_KEY.getValue());
|
||||
}
|
||||
|
||||
// whitelist from config
|
||||
for (final String dimension : AEConfig.instance().getMeteoriteDimensionWhitelist()) {
|
||||
registries.worldgen().enableWorldGenForDimension(IWorldGen.WorldGenType.METEORITES,
|
||||
new Identifier(dimension));
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerParticleTypes() {
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
package appeng.core;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.fabricmc.fabric.api.event.registry.RegistryEntryAddedCallback;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.BuiltinRegistries;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.gen.GenerationStep;
|
||||
import net.minecraft.world.gen.decorator.Decorator;
|
||||
@@ -54,11 +61,21 @@ public final class AppEngBootstrap {
|
||||
ConfiguredFeature<?, ?> quartzOreFeature = registerQuartzOreFeature();
|
||||
ConfiguredFeature<?, ?> chargedQuartzOreFeature = registerChargedQuartzOreFeature();
|
||||
|
||||
// add to all standard biomes
|
||||
// TODO: This means we'll not add these things to newly created biomes
|
||||
BuiltinRegistries.BIOME.forEach(b -> {
|
||||
addMeteoriteWorldGen(b);
|
||||
addQuartzWorldGen(b, quartzOreFeature, chargedQuartzOreFeature);
|
||||
Set<String> meteoriteBiomeBlacklist = new HashSet<>(AEConfig.instance().getMeteoriteBiomeBlacklist());
|
||||
Set<String> quartzOreBiomeBlacklist = new HashSet<>(AEConfig.instance().getQuartzOreBiomeBlacklist());
|
||||
|
||||
// Add features to all existing biomes
|
||||
for (Map.Entry<RegistryKey<Biome>, Biome> entry : BuiltinRegistries.BIOME.getEntries()) {
|
||||
Identifier id = entry.getKey().getValue();
|
||||
Biome b = entry.getValue();
|
||||
addMeteoriteWorldGen(id, b, meteoriteBiomeBlacklist);
|
||||
addQuartzWorldGen(id, b, quartzOreFeature, chargedQuartzOreFeature, quartzOreBiomeBlacklist);
|
||||
}
|
||||
|
||||
// Listen to added biomes for post-processing
|
||||
RegistryEntryAddedCallback.event(BuiltinRegistries.BIOME).register((i, id, biome) -> {
|
||||
addMeteoriteWorldGen(id, biome, meteoriteBiomeBlacklist);
|
||||
addQuartzWorldGen(id, biome, quartzOreFeature, chargedQuartzOreFeature, quartzOreBiomeBlacklist);
|
||||
});
|
||||
|
||||
registerDimension();
|
||||
@@ -78,12 +95,19 @@ public final class AppEngBootstrap {
|
||||
MeteoriteStructure.CONFIGURED_INSTANCE);
|
||||
}
|
||||
|
||||
private static void addMeteoriteWorldGen(Biome b) {
|
||||
private static void addMeteoriteWorldGen(Identifier id, Biome b, Set<String> biomeBlacklist) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.METEORITE_WORLD_GEN)) {
|
||||
AELog.debug("Not generating meteorites in %s because the feature is disabled", id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (b.getCategory() == Biome.Category.THEEND || b.getCategory() == Biome.Category.NETHER) {
|
||||
AELog.debug("Not generating meteorites in %s because it's of category %s", id, b.getCategory());
|
||||
return;
|
||||
}
|
||||
|
||||
if (biomeBlacklist.contains(id.toString())) {
|
||||
AELog.debug("Not generating meteorites in %s because the biome is blacklisted in the config", id);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,14 +115,24 @@ public final class AppEngBootstrap {
|
||||
modifier.addStructureFeature(MeteoriteStructure.CONFIGURED_INSTANCE);
|
||||
}
|
||||
|
||||
private static void addQuartzWorldGen(Biome b, ConfiguredFeature<?, ?> quartzOre,
|
||||
ConfiguredFeature<?, ?> chargedQuartz) {
|
||||
private static void addQuartzWorldGen(Identifier id, Biome b, ConfiguredFeature<?, ?> quartzOre,
|
||||
ConfiguredFeature<?, ?> chargedQuartz, Set<String> biomeBlacklist) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.CERTUS_QUARTZ_WORLD_GEN)) {
|
||||
AELog.debug("Not generating quartz-ore in %s because the feature is disabled", id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (b.getCategory() == Biome.Category.THEEND || b.getCategory() == Biome.Category.NETHER) {
|
||||
AELog.debug("Not generating quartz ore in %s because it's of category %s", id, b.getCategory());
|
||||
return;
|
||||
}
|
||||
|
||||
if (biomeBlacklist.contains(id.toString())) {
|
||||
AELog.debug("Not generating quartz-ore in %s because the biome is blacklisted in the config", id);
|
||||
return;
|
||||
}
|
||||
|
||||
BiomeModifier modifier = new BiomeModifier(b);
|
||||
|
||||
modifier.addFeature(GenerationStep.Feature.UNDERGROUND_ORES, quartzOre);
|
||||
|
||||
if (AEConfig.instance().isFeatureEnabled(AEFeature.CHARGED_CERTUS_ORE)) {
|
||||
|
||||
@@ -30,6 +30,7 @@ import net.minecraft.block.Material;
|
||||
import net.minecraft.block.SlabBlock;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.entity.EntityDimensions;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.SpawnGroup;
|
||||
import net.minecraft.sound.BlockSoundGroup;
|
||||
|
||||
@@ -267,17 +268,19 @@ public final class ApiBlocks implements IBlocks {
|
||||
this.chiseledQuartzBlock = deco.block("chiseled_quartz_block", () -> new AEDecorativeBlock(QUARTZ_PROPERTIES))
|
||||
.build();
|
||||
|
||||
this.quartzGlass = registry.features(AEFeature.QUARTZ_GLASS)
|
||||
.block("quartz_glass", () -> new QuartzGlassBlock(glassProps()))
|
||||
.rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
|
||||
rendering.renderType(RenderLayer.getCutout());
|
||||
}
|
||||
}).build();
|
||||
AbstractBlock.TypedContextPredicate<EntityType<?>> neverAllowSpawn = (p1, p2, p3, p4) -> false;
|
||||
this.quartzGlass = registry.features(AEFeature.QUARTZ_GLASS).block("quartz_glass", () -> {
|
||||
return new QuartzGlassBlock(glassProps().allowsSpawning(neverAllowSpawn));
|
||||
}).rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
|
||||
rendering.renderType(RenderLayer.getCutout());
|
||||
}
|
||||
}).build();
|
||||
this.quartzVibrantGlass = deco
|
||||
.block("quartz_vibrant_glass", () -> new QuartzLampBlock(glassProps().lightLevel(15)))
|
||||
.block("quartz_vibrant_glass",
|
||||
() -> new QuartzLampBlock(glassProps().lightLevel(15).allowsSpawning(neverAllowSpawn)))
|
||||
.addFeatures(AEFeature.DECORATIVE_LIGHTS, AEFeature.QUARTZ_GLASS)
|
||||
.rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
|
||||
@@ -55,6 +55,7 @@ import appeng.hooks.BlockToolDispenseItemBehavior;
|
||||
import appeng.hooks.MatterCannonDispenseItemBehavior;
|
||||
import appeng.items.materials.MaterialType;
|
||||
import appeng.items.misc.CrystalSeedItem;
|
||||
import appeng.items.misc.CrystalSeedRendering;
|
||||
import appeng.items.misc.EncodedPatternItem;
|
||||
import appeng.items.misc.PaintBallItem;
|
||||
import appeng.items.misc.PaintBallItemRendering;
|
||||
@@ -140,12 +141,12 @@ public final class ApiItems implements IItems {
|
||||
private final AEColoredItemDefinition coloredLumenPaintBall;
|
||||
|
||||
// unsupported dev tools
|
||||
private IItemDefinition toolEraser;
|
||||
private IItemDefinition toolMeteoritePlacer;
|
||||
private IItemDefinition toolDebugCard;
|
||||
private IItemDefinition toolReplicatorCard;
|
||||
private final IItemDefinition toolEraser;
|
||||
private final IItemDefinition toolMeteoritePlacer;
|
||||
private final IItemDefinition toolDebugCard;
|
||||
private final IItemDefinition toolReplicatorCard;
|
||||
|
||||
private IItemDefinition dummyFluidItem;
|
||||
private final IItemDefinition dummyFluidItem;
|
||||
|
||||
public ApiItems(FeatureFactory registry, ApiMaterials materials) {
|
||||
FeatureFactory certusTools = registry.features(AEFeature.CERTUS_QUARTZ_TOOLS);
|
||||
@@ -305,28 +306,19 @@ public final class ApiItems implements IItems {
|
||||
this.certusCrystalSeed = registry
|
||||
.item("certus_crystal_seed",
|
||||
props -> new CrystalSeedItem(props, materials.purifiedCertusQuartzCrystal().item()))
|
||||
.bootstrap(item -> new IClientSetupComponent() {
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void setup() {
|
||||
// Expose the growth of the seed to the model system
|
||||
FabricModelPredicateProviderRegistry.register(item, AppEng.makeId("growth"),
|
||||
(is, w, p) -> CrystalSeedItem.getGrowthTicks(is)
|
||||
/ (float) CrystalSeedItem.GROWTH_TICKS_REQUIRED);
|
||||
}
|
||||
}).features(AEFeature.CRYSTAL_SEEDS).build();
|
||||
.bootstrap(CrystalSeedRendering::new).features(AEFeature.CRYSTAL_SEEDS).build();
|
||||
this.fluixCrystalSeed = registry
|
||||
.item("fluix_crystal_seed",
|
||||
props -> new CrystalSeedItem(props, materials.purifiedFluixCrystal().item()))
|
||||
.features(AEFeature.CRYSTAL_SEEDS).build();
|
||||
.bootstrap(CrystalSeedRendering::new).features(AEFeature.CRYSTAL_SEEDS).build();
|
||||
this.netherQuartzSeed = registry
|
||||
.item("nether_quartz_seed",
|
||||
props -> new CrystalSeedItem(props, materials.purifiedNetherQuartzCrystal().item()))
|
||||
.features(AEFeature.CRYSTAL_SEEDS).build();
|
||||
.bootstrap(CrystalSeedRendering::new).features(AEFeature.CRYSTAL_SEEDS).build();
|
||||
|
||||
GrowingCrystalEntity.TYPE = registry
|
||||
.<GrowingCrystalEntity>entity("growing_crystal", GrowingCrystalEntity::new, SpawnGroup.MISC)
|
||||
.customize(builder -> builder.dimensions(EntityDimensions.fixed(0.25F, 0.25F))).build();
|
||||
.customize(builder -> builder.dimensions(EntityDimensions.fixed(0.25F, 0.4F))).build();
|
||||
|
||||
// rv1
|
||||
this.encodedPattern = registry.item("encoded_pattern", EncodedPatternItem::new)
|
||||
|
||||
@@ -58,6 +58,14 @@ public class ConfigSection {
|
||||
return option;
|
||||
}
|
||||
|
||||
public StringOption addString(String id, String defaultValue) {
|
||||
return addString(id, defaultValue, comment);
|
||||
}
|
||||
|
||||
public StringOption addString(String id, String defaultValue, String comment) {
|
||||
return addOption(new StringOption(this, id, comment, defaultValue));
|
||||
}
|
||||
|
||||
public IntegerOption addInt(String id, int defaultValue) {
|
||||
return addInt(id, defaultValue, comment);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package appeng.core.config;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
public class StringOption extends BaseOption {
|
||||
|
||||
private final String defaultValue;
|
||||
private String currentValue;
|
||||
|
||||
public StringOption(ConfigSection parent, String id, String comment, String defaultValue) {
|
||||
super(parent, id, comment);
|
||||
this.defaultValue = defaultValue;
|
||||
this.currentValue = this.defaultValue;
|
||||
}
|
||||
|
||||
public String get() {
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
public void set(String value) {
|
||||
Preconditions.checkNotNull(value);
|
||||
if (value.equals(currentValue)) {
|
||||
return;
|
||||
}
|
||||
currentValue = value;
|
||||
parent.markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonElement write() {
|
||||
return new JsonPrimitive(currentValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void read(JsonElement element) {
|
||||
if (!element.isJsonPrimitive()) {
|
||||
throw new ConfigValidationException(this, "Expected a JSON primitive: " + element);
|
||||
}
|
||||
JsonPrimitive primitive = element.getAsJsonPrimitive();
|
||||
if (!primitive.isString()) {
|
||||
throw new ConfigValidationException(this, "Expected a JSON string, but found: " + primitive);
|
||||
}
|
||||
|
||||
this.currentValue = primitive.getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDifferentFromDefault() {
|
||||
return !currentValue.equals(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultAsString() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentValueAsString() {
|
||||
return currentValue;
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import appeng.api.events.LocatableEventAnnounce;
|
||||
import appeng.api.events.LocatableEventAnnounce.LocatableEvent;
|
||||
import appeng.api.features.ILocatable;
|
||||
import appeng.api.features.ILocatableRegistry;
|
||||
import appeng.core.AELog;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public final class LocatableRegistry implements ILocatableRegistry {
|
||||
@@ -39,8 +40,10 @@ public final class LocatableRegistry implements ILocatableRegistry {
|
||||
}
|
||||
|
||||
if (change == LocatableEvent.REGISTER) {
|
||||
AELog.debug("Registering locatable %s: %s", target.getLocatableSerial(), target);
|
||||
this.set.put(target.getLocatableSerial(), target);
|
||||
} else if (change == LocatableEvent.UNREGISTER) {
|
||||
AELog.debug("Unregistering locatable %s: %s", target.getLocatableSerial(), target);
|
||||
this.set.remove(target.getLocatableSerial());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,7 +25,6 @@ import appeng.api.features.IP2PTunnelRegistry;
|
||||
import appeng.api.features.IPlayerRegistry;
|
||||
import appeng.api.features.IRegistryContainer;
|
||||
import appeng.api.features.IWirelessTermRegistry;
|
||||
import appeng.api.features.IWorldGen;
|
||||
import appeng.api.movable.IMovableRegistry;
|
||||
import appeng.api.networking.IGridCacheRegistry;
|
||||
import appeng.api.parts.IPartModels;
|
||||
@@ -99,11 +98,6 @@ public class RegistryContainer implements IRegistryContainer {
|
||||
return this.playerRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWorldGen worldgen() {
|
||||
return WorldGenRegistry.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPartModels partModels() {
|
||||
return this.partModels;
|
||||
|
||||
@@ -1,89 +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.features.registries;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import appeng.api.features.IWorldGen;
|
||||
|
||||
public final class WorldGenRegistry implements IWorldGen {
|
||||
|
||||
public static final WorldGenRegistry INSTANCE = new WorldGenRegistry();
|
||||
private final TypeSet[] types;
|
||||
|
||||
private WorldGenRegistry() {
|
||||
|
||||
this.types = new TypeSet[WorldGenType.values().length];
|
||||
|
||||
for (final WorldGenType type : WorldGenType.values()) {
|
||||
this.types[type.ordinal()] = new TypeSet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableWorldGenForDimension(final WorldGenType type, final Identifier dimensionID) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Bad Type Passed");
|
||||
}
|
||||
|
||||
this.types[type.ordinal()].enabledDimensions.add(dimensionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableWorldGenForDimension(final WorldGenType type, final Identifier dimensionID) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Bad Type Passed");
|
||||
}
|
||||
|
||||
this.types[type.ordinal()].badDimensions.add(dimensionID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorldGenEnabled(final WorldGenType type, final ServerWorld w) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Bad Type Passed");
|
||||
}
|
||||
|
||||
if (w == null) {
|
||||
throw new IllegalArgumentException("Bad Provider Passed");
|
||||
}
|
||||
|
||||
Identifier id = w.getRegistryKey().getValue();
|
||||
final boolean isBadDimension = this.types[type.ordinal()].badDimensions.contains(id);
|
||||
final boolean isGoodDimension = this.types[type.ordinal()].enabledDimensions.contains(id);
|
||||
|
||||
if (isBadDimension) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isGoodDimension && type == WorldGenType.METEORITES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class TypeSet {
|
||||
final HashSet<Identifier> badDimensions = new HashSet<>();
|
||||
final HashSet<Identifier> enabledDimensions = new HashSet<>();
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import appeng.core.sync.packets.BlockTransitionEffectPacket;
|
||||
import appeng.core.sync.packets.ClickPacket;
|
||||
import appeng.core.sync.packets.CompassRequestPacket;
|
||||
import appeng.core.sync.packets.CompassResponsePacket;
|
||||
import appeng.core.sync.packets.CompressedNBTPacket;
|
||||
import appeng.core.sync.packets.ConfigButtonPacket;
|
||||
import appeng.core.sync.packets.ConfigValuePacket;
|
||||
import appeng.core.sync.packets.CraftRequestPacket;
|
||||
@@ -39,6 +38,7 @@ import appeng.core.sync.packets.ItemTransitionEffectPacket;
|
||||
import appeng.core.sync.packets.JEIRecipePacket;
|
||||
import appeng.core.sync.packets.LightningPacket;
|
||||
import appeng.core.sync.packets.MEFluidInventoryUpdatePacket;
|
||||
import appeng.core.sync.packets.MEInterfaceUpdatePacket;
|
||||
import appeng.core.sync.packets.MEInventoryUpdatePacket;
|
||||
import appeng.core.sync.packets.MatterCannonPacket;
|
||||
import appeng.core.sync.packets.PaintedEntityPacket;
|
||||
@@ -99,7 +99,7 @@ public class BasePacketHandler {
|
||||
|
||||
PACKET_ASSEMBLER_ANIMATION(AssemblerAnimationPacket.class, AssemblerAnimationPacket::new),
|
||||
|
||||
PACKET_COMPRESSED_NBT(CompressedNBTPacket.class, CompressedNBTPacket::new),
|
||||
PACKET_ME_INTERFACE_UPDATE(MEInterfaceUpdatePacket.class, MEInterfaceUpdatePacket::new),
|
||||
|
||||
PACKET_PAINTED_ENTITY(PaintedEntityPacket.class, PaintedEntityPacket::new),
|
||||
|
||||
|
||||
@@ -18,15 +18,26 @@
|
||||
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.Recipe;
|
||||
import net.minecraft.recipe.RecipeSerializer;
|
||||
import net.minecraft.recipe.ShapedRecipe;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
|
||||
@@ -41,11 +52,14 @@ import appeng.api.networking.storage.IStorageGrid;
|
||||
import appeng.api.storage.IMEMonitor;
|
||||
import appeng.api.storage.channels.IItemStorageChannel;
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
import appeng.container.implementations.PatternTermContainer;
|
||||
import appeng.core.Api;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.BasePacketHandler;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
import appeng.helpers.IContainerCraftingPacket;
|
||||
import appeng.items.storage.ViewCellItem;
|
||||
import appeng.mixins.IngredientAccessor;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.helpers.ItemHandlerUtil;
|
||||
import appeng.util.inv.AdaptorFixedInv;
|
||||
@@ -55,151 +69,303 @@ import appeng.util.prioritylist.IPartitionList;
|
||||
|
||||
public class JEIRecipePacket extends BasePacket {
|
||||
|
||||
private ItemStack[][] recipe;
|
||||
/**
|
||||
* Transmit only a recipe ID.
|
||||
*/
|
||||
private static final int INLINE_RECIPE_NONE = 1;
|
||||
|
||||
/**
|
||||
* Transmit the information about the recipe we actually need. This is
|
||||
* explicitly limited since this is untrusted client->server info.
|
||||
*/
|
||||
private static final int INLINE_RECIPE_SHAPED = 2;
|
||||
|
||||
private Identifier recipeId;
|
||||
/**
|
||||
* This is optional, in case the client already knows it could not resolve the
|
||||
* recipe id.
|
||||
*/
|
||||
@Nullable
|
||||
private Recipe<?> recipe;
|
||||
private boolean crafting;
|
||||
|
||||
public JEIRecipePacket(final PacketByteBuf stream) {
|
||||
final CompoundTag comp = stream.readCompoundTag();
|
||||
if (comp != null) {
|
||||
this.recipe = new ItemStack[9][];
|
||||
for (int x = 0; x < this.recipe.length; x++) {
|
||||
final ListTag list = comp.getList("#" + x, 10);
|
||||
if (list.size() > 0) {
|
||||
this.recipe[x] = new ItemStack[list.size()];
|
||||
for (int y = 0; y < list.size(); y++) {
|
||||
this.recipe[x][y] = ItemStack.fromTag(list.getCompound(y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.crafting = stream.readBoolean();
|
||||
final String id = stream.readString(Short.MAX_VALUE);
|
||||
this.recipeId = new Identifier(id);
|
||||
|
||||
// api
|
||||
public JEIRecipePacket(final CompoundTag recipe) {
|
||||
final PacketByteBuf data = new PacketByteBuf(Unpooled.buffer());
|
||||
|
||||
data.writeInt(this.getPacketID());
|
||||
|
||||
data.writeCompoundTag(recipe);
|
||||
|
||||
this.configureWrite(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverPacketData(final INetworkInfo manager, final PlayerEntity player) {
|
||||
final ServerPlayerEntity pmp = (ServerPlayerEntity) player;
|
||||
final ScreenHandler con = pmp.currentScreenHandler;
|
||||
|
||||
if (!(con instanceof IContainerCraftingPacket)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final IContainerCraftingPacket cct = (IContainerCraftingPacket) con;
|
||||
final IGridNode node = cct.getNetworkNode();
|
||||
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final IGrid grid = node.getGrid();
|
||||
if (grid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final IStorageGrid inv = grid.getCache(IStorageGrid.class);
|
||||
final IEnergyGrid energy = grid.getCache(IEnergyGrid.class);
|
||||
final ISecurityGrid security = grid.getCache(ISecurityGrid.class);
|
||||
final ICraftingGrid crafting = grid.getCache(ICraftingGrid.class);
|
||||
final FixedItemInv craftMatrix = cct.getInventoryByName("crafting");
|
||||
final FixedItemInv playerInventory = cct.getInventoryByName("player");
|
||||
|
||||
if (inv != null && this.recipe != null && security != null) {
|
||||
final IMEMonitor<IAEItemStack> storage = inv
|
||||
.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class));
|
||||
final IPartitionList<IAEItemStack> filter = ViewCellItem.createFilter(cct.getViewCells());
|
||||
|
||||
for (int x = 0; x < craftMatrix.getSlotCount(); x++) {
|
||||
ItemStack currentItem = craftMatrix.getInvStack(x);
|
||||
|
||||
// prepare slots
|
||||
if (!currentItem.isEmpty()) {
|
||||
// already the correct item?
|
||||
ItemStack newItem = this.canUseInSlot(x, currentItem);
|
||||
|
||||
// put away old item
|
||||
if (newItem != currentItem && security.hasPermission(player, SecurityPermissions.INJECT)) {
|
||||
final IAEItemStack in = AEItemStack.fromItemStack(currentItem);
|
||||
final IAEItemStack out = cct.useRealItems()
|
||||
? Platform.poweredInsert(energy, storage, in, cct.getActionSource())
|
||||
: null;
|
||||
if (out != null) {
|
||||
currentItem = out.createItemStack();
|
||||
} else {
|
||||
currentItem = ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentItem.isEmpty() && this.recipe[x] != null) {
|
||||
// for each variant
|
||||
for (int y = 0; y < this.recipe[x].length && currentItem.isEmpty(); y++) {
|
||||
final IAEItemStack request = AEItemStack.fromItemStack(this.recipe[x][y]);
|
||||
if (request != null) {
|
||||
// try ae
|
||||
if ((filter == null || filter.isListed(request))
|
||||
&& security.hasPermission(player, SecurityPermissions.EXTRACT)) {
|
||||
request.setStackSize(1);
|
||||
IAEItemStack out;
|
||||
|
||||
if (cct.useRealItems()) {
|
||||
out = Platform.poweredExtraction(energy, storage, request, cct.getActionSource());
|
||||
} else {
|
||||
// Query the crafting grid if there is a pattern providing the item
|
||||
if (!crafting.getCraftingFor(request, null, 0, null).isEmpty()) {
|
||||
out = request;
|
||||
} else {
|
||||
// Fall back using an existing item
|
||||
out = storage.extractItems(request, Actionable.SIMULATE, cct.getActionSource());
|
||||
}
|
||||
}
|
||||
|
||||
if (out != null) {
|
||||
currentItem = out.createItemStack();
|
||||
}
|
||||
}
|
||||
|
||||
// try inventory
|
||||
if (currentItem.isEmpty()) {
|
||||
AdaptorFixedInv ad = new AdaptorFixedInv(playerInventory);
|
||||
|
||||
if (cct.useRealItems()) {
|
||||
currentItem = ad.removeItems(1, this.recipe[x][y], null);
|
||||
} else {
|
||||
currentItem = ad.simulateRemove(1, this.recipe[x][y], null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemHandlerUtil.setStackInSlot(craftMatrix, x, currentItem);
|
||||
}
|
||||
con.onContentChanged(new WrapperInvItemHandler(craftMatrix));
|
||||
int inlineRecipeType = stream.readVarInt();
|
||||
switch (inlineRecipeType) {
|
||||
case INLINE_RECIPE_NONE:
|
||||
break;
|
||||
case INLINE_RECIPE_SHAPED:
|
||||
recipe = RecipeSerializer.SHAPED.read(this.recipeId, stream);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid inline recipe type.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param slot
|
||||
* @param is itemstack
|
||||
* @return is if it can be used, else EMPTY
|
||||
* Sends a recipe identified by the given recipe ID to the server for either
|
||||
* filling a crafting grid or a pattern.
|
||||
*/
|
||||
private ItemStack canUseInSlot(int slot, ItemStack is) {
|
||||
if (this.recipe[slot] != null) {
|
||||
for (ItemStack option : this.recipe[slot]) {
|
||||
if (is.isItemEqual(option)) {
|
||||
return is;
|
||||
public JEIRecipePacket(final Identifier recipeId, final boolean crafting) {
|
||||
PacketByteBuf data = createCommonHeader(recipeId, crafting, INLINE_RECIPE_NONE);
|
||||
this.configureWrite(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a recipe to the server for either filling a crafting grid or a pattern.
|
||||
* <p>
|
||||
* Prefer the id-based constructor above whereever possible.
|
||||
*/
|
||||
public JEIRecipePacket(final ShapedRecipe recipe, final boolean crafting) {
|
||||
PacketByteBuf data = createCommonHeader(recipe.getId(), crafting, INLINE_RECIPE_SHAPED);
|
||||
RecipeSerializer.SHAPED.write(data, recipe);
|
||||
this.configureWrite(data);
|
||||
}
|
||||
|
||||
private PacketByteBuf createCommonHeader(Identifier recipeId, boolean crafting, int inlineRecipeType) {
|
||||
final PacketByteBuf data = new PacketByteBuf(Unpooled.buffer());
|
||||
|
||||
data.writeInt(this.getPacketID());
|
||||
data.writeBoolean(crafting);
|
||||
data.writeIdentifier(recipeId);
|
||||
data.writeVarInt(inlineRecipeType);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Servside handler for this packet.
|
||||
* <p>
|
||||
* Makes use of {@link Preconditions#checkArgument(boolean)} as the
|
||||
* {@link BasePacketHandler} is catching them and in general these cases should
|
||||
* never happen except in an error case and should be logged then.
|
||||
*/
|
||||
@Override
|
||||
public void serverPacketData(final INetworkInfo manager, final PlayerEntity player) {
|
||||
// Setup and verification
|
||||
final ServerPlayerEntity pmp = (ServerPlayerEntity) player;
|
||||
final ScreenHandler con = pmp.currentScreenHandler;
|
||||
Preconditions.checkArgument(con instanceof IContainerCraftingPacket);
|
||||
|
||||
Recipe<?> recipe = player.getEntityWorld().getRecipeManager().get(this.recipeId).orElse(null);
|
||||
if (recipe == null && this.recipe != null) {
|
||||
// Certain recipes (i.e. AE2 facades) are represented in JEI as ShapedRecipe's,
|
||||
// while in reality they
|
||||
// are special recipes. Those recipes are sent across the wire...
|
||||
recipe = this.recipe;
|
||||
}
|
||||
Preconditions.checkArgument(recipe != null);
|
||||
|
||||
final IContainerCraftingPacket cct = (IContainerCraftingPacket) con;
|
||||
final IGridNode node = cct.getNetworkNode();
|
||||
|
||||
Preconditions.checkArgument(node != null);
|
||||
|
||||
final IGrid grid = node.getGrid();
|
||||
Preconditions.checkArgument(grid != null);
|
||||
|
||||
final IStorageGrid inv = grid.getCache(IStorageGrid.class);
|
||||
Preconditions.checkArgument(inv != null);
|
||||
|
||||
final ISecurityGrid security = grid.getCache(ISecurityGrid.class);
|
||||
Preconditions.checkArgument(security != null);
|
||||
|
||||
final IEnergyGrid energy = grid.getCache(IEnergyGrid.class);
|
||||
final ICraftingGrid crafting = grid.getCache(ICraftingGrid.class);
|
||||
final FixedItemInv craftMatrix = cct.getInventoryByName("crafting");
|
||||
final FixedItemInv playerInventory = cct.getInventoryByName("player");
|
||||
|
||||
final IMEMonitor<IAEItemStack> storage = inv
|
||||
.getInventory(Api.instance().storage().getStorageChannel(IItemStorageChannel.class));
|
||||
final IPartitionList<IAEItemStack> filter = ViewCellItem.createFilter(cct.getViewCells());
|
||||
final DefaultedList<Ingredient> ingredients = this.ensure3by3CraftingMatrix(recipe);
|
||||
|
||||
// Handle each slot
|
||||
for (int x = 0; x < craftMatrix.getSlotCount(); x++) {
|
||||
ItemStack currentItem = craftMatrix.getInvStack(x);
|
||||
Ingredient ingredient = ingredients.get(x);
|
||||
|
||||
// prepare slots
|
||||
if (!currentItem.isEmpty()) {
|
||||
// already the correct item? True, skip everything else
|
||||
ItemStack newItem = this.canUseInSlot(ingredient, currentItem);
|
||||
|
||||
// put away old item, if not correct
|
||||
if (newItem != currentItem && security.hasPermission(player, SecurityPermissions.INJECT)) {
|
||||
final IAEItemStack in = AEItemStack.fromItemStack(currentItem);
|
||||
final IAEItemStack out = cct.useRealItems()
|
||||
? Platform.poweredInsert(energy, storage, in, cct.getActionSource())
|
||||
: null;
|
||||
if (out != null) {
|
||||
currentItem = out.createItemStack();
|
||||
} else {
|
||||
currentItem = ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find item or pattern from the network
|
||||
if (currentItem.isEmpty() && security.hasPermission(player, SecurityPermissions.EXTRACT)) {
|
||||
IAEItemStack out;
|
||||
|
||||
if (cct.useRealItems()) {
|
||||
IAEItemStack request = findBestMatchingItemStack(ingredient, filter, storage, cct);
|
||||
out = request != null
|
||||
? Platform.poweredExtraction(energy, storage, request.setStackSize(1),
|
||||
cct.getActionSource())
|
||||
: null;
|
||||
} else {
|
||||
out = findBestMatchingPattern(ingredient, filter, crafting, storage, cct);
|
||||
if (out == null) {
|
||||
out = findBestMatchingItemStack(ingredient, filter, storage, cct);
|
||||
}
|
||||
if (out == null && getMatchingStacks(ingredient).length > 0) {
|
||||
out = AEItemStack.fromItemStack(getMatchingStacks(ingredient)[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (out != null) {
|
||||
currentItem = out.createItemStack();
|
||||
}
|
||||
}
|
||||
|
||||
// If still nothing, search the player inventory.
|
||||
if (currentItem.isEmpty()) {
|
||||
ItemStack[] matchingStacks = getMatchingStacks(ingredient);
|
||||
for (ItemStack matchingStack : matchingStacks) {
|
||||
if (currentItem.isEmpty()) {
|
||||
AdaptorFixedInv ad = new AdaptorFixedInv(playerInventory);
|
||||
|
||||
if (cct.useRealItems()) {
|
||||
currentItem = ad.removeItems(1, matchingStack, null);
|
||||
} else {
|
||||
currentItem = ad.simulateRemove(1, matchingStack, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemHandlerUtil.setStackInSlot(craftMatrix, x, currentItem);
|
||||
}
|
||||
|
||||
if (!this.crafting) {
|
||||
this.handleProcessing(con, cct, recipe);
|
||||
}
|
||||
|
||||
con.onContentChanged(new WrapperInvItemHandler(craftMatrix));
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static ItemStack[] getMatchingStacks(Ingredient ingredient) {
|
||||
IngredientAccessor accessor = (IngredientAccessor) (Object) ingredient;
|
||||
// accessor.callCacheMatchingStacks();
|
||||
if (ingredient.isEmpty()) {
|
||||
return new ItemStack[0];
|
||||
}
|
||||
ItemStack[] stacks = accessor.getMatchingStacks();
|
||||
if (stacks.length == 1 && stacks[0].isEmpty()) {
|
||||
return new ItemStack[0];
|
||||
}
|
||||
return stacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand any recipe to a 3x3 matrix.
|
||||
* <p>
|
||||
* Will throw an {@link IllegalArgumentException} in case it has more than 9 or
|
||||
* a shaped recipe is either wider or higher than 3. ingredients.
|
||||
*/
|
||||
private DefaultedList<Ingredient> ensure3by3CraftingMatrix(Recipe<?> recipe) {
|
||||
DefaultedList<Ingredient> ingredients = recipe.getPreviewInputs();
|
||||
DefaultedList<Ingredient> expandedIngredients = DefaultedList.ofSize(9, Ingredient.EMPTY);
|
||||
|
||||
Preconditions.checkArgument(ingredients.size() <= 9);
|
||||
|
||||
// shaped recipes can be smaller than 3x3, expand to 3x3 to match the crafting
|
||||
// matrix
|
||||
if (recipe instanceof ShapedRecipe) {
|
||||
ShapedRecipe shapedRecipe = (ShapedRecipe) recipe;
|
||||
int width = shapedRecipe.getWidth();
|
||||
int height = shapedRecipe.getHeight();
|
||||
Preconditions.checkArgument(width <= 3 && height <= 3);
|
||||
|
||||
for (int h = 0; h < height; h++) {
|
||||
for (int w = 0; w < width; w++) {
|
||||
int source = w + h * width;
|
||||
int target = w + h * 3;
|
||||
Ingredient i = ingredients.get(source);
|
||||
expandedIngredients.set(target, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
// Anything else should be a flat list
|
||||
else {
|
||||
for (int i = 0; i < ingredients.size(); i++) {
|
||||
expandedIngredients.set(i, ingredients.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
return expandedIngredients;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param is itemstack
|
||||
* @return is if it can be used, else EMPTY
|
||||
*/
|
||||
private ItemStack canUseInSlot(Ingredient ingredient, ItemStack is) {
|
||||
return Arrays.stream(getMatchingStacks(ingredient)).filter(p -> p.isItemEqual(is)).findFirst()
|
||||
.orElse(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first matching itemstack with the highest stored amount.
|
||||
*/
|
||||
private IAEItemStack findBestMatchingItemStack(Ingredient ingredients, IPartitionList<IAEItemStack> filter,
|
||||
IMEMonitor<IAEItemStack> storage, IContainerCraftingPacket cct) {
|
||||
return Arrays.stream(getMatchingStacks(ingredients)).map(AEItemStack::fromItemStack) //
|
||||
.filter(r -> r != null && (filter == null || filter.isListed(r))) //
|
||||
.map(s -> {
|
||||
// Determine the stored count
|
||||
IAEItemStack stored = storage.extractItems(s.copy().setStackSize(Long.MAX_VALUE),
|
||||
Actionable.SIMULATE, cct.getActionSource());
|
||||
return Pair.of(s, stored != null ? stored.getStackSize() : 0);
|
||||
}).min((left, right) -> Long.compare(right.getSecond(), left.getSecond()))//
|
||||
.map(Pair::getFirst).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This tries to find the first pattern matching the list of ingredients.
|
||||
* <p>
|
||||
* As additional condition, it sorts by the stored amount to return the one with
|
||||
* the highest stored amount.
|
||||
*/
|
||||
private IAEItemStack findBestMatchingPattern(Ingredient ingredients, IPartitionList<IAEItemStack> filter,
|
||||
ICraftingGrid crafting, IMEMonitor<IAEItemStack> storage, IContainerCraftingPacket cct) {
|
||||
return Arrays.stream(getMatchingStacks(ingredients)).map(AEItemStack::fromItemStack)
|
||||
.filter(r -> r != null && (filter == null || filter.isListed(r)))
|
||||
.map(s -> s.setCraftable(!crafting.getCraftingFor(s, null, 0, null).isEmpty()))
|
||||
.filter(IAEItemStack::isCraftable).map(s -> {
|
||||
final IAEItemStack stored = storage.extractItems(s, Actionable.SIMULATE, cct.getActionSource());
|
||||
return s.setStackSize(stored != null ? stored.getStackSize() : 0);
|
||||
}).min((left, right) -> {
|
||||
final int craftable = Boolean.compare(left.isCraftable(), right.isCraftable());
|
||||
return craftable != 0 ? craftable : Long.compare(right.getStackSize(), left.getStackSize());
|
||||
}).orElse(null);
|
||||
}
|
||||
|
||||
private void handleProcessing(ScreenHandler con, IContainerCraftingPacket cct, Recipe<?> recipe) {
|
||||
if (con instanceof PatternTermContainer) {
|
||||
PatternTermContainer patternTerm = (PatternTermContainer) con;
|
||||
if (!patternTerm.craftingMode) {
|
||||
final FixedItemInv output = cct.getInventoryByName("output");
|
||||
ItemHandlerUtil.setStackInSlot(output, 0, recipe.getOutput());
|
||||
ItemHandlerUtil.setStackInSlot(output, 1, ItemStack.EMPTY);
|
||||
ItemHandlerUtil.setStackInSlot(output, 2, ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,13 +19,9 @@
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -41,7 +37,6 @@ import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
import appeng.fluids.client.gui.FluidTerminalScreen;
|
||||
@@ -55,8 +50,6 @@ import appeng.fluids.util.AEFluidStack;
|
||||
public class MEFluidInventoryUpdatePacket extends BasePacket {
|
||||
private static final int UNCOMPRESSED_PACKET_BYTE_LIMIT = 16 * 1024 * 1024;
|
||||
private static final int OPERATION_BYTE_LIMIT = 2 * 1024;
|
||||
private static final int TEMP_BUFFER_SIZE = 1024;
|
||||
private static final int STREAM_MASK = 0xff;
|
||||
|
||||
// input.
|
||||
@Nullable
|
||||
@@ -66,47 +59,18 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
|
||||
|
||||
@Nullable
|
||||
private final PacketByteBuf data;
|
||||
@Nullable
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
private int writtenBytes = 0;
|
||||
private boolean empty = true;
|
||||
|
||||
public MEFluidInventoryUpdatePacket(final PacketByteBuf stream) {
|
||||
this.data = null;
|
||||
this.compressFrame = null;
|
||||
this.list = new LinkedList<>();
|
||||
this.ref = stream.readByte();
|
||||
|
||||
try (final GZIPInputStream gzReader = new GZIPInputStream(new InputStream() {
|
||||
@Override
|
||||
public int read() {
|
||||
if (stream.readableBytes() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return stream.readByte() & STREAM_MASK;
|
||||
}
|
||||
})) {
|
||||
|
||||
final PacketByteBuf uncompressed = new PacketByteBuf(Unpooled.buffer(stream.readableBytes()));
|
||||
final byte[] tmp = new byte[TEMP_BUFFER_SIZE];
|
||||
|
||||
while (gzReader.available() != 0) {
|
||||
final int bytes = gzReader.read(tmp);
|
||||
|
||||
if (bytes > 0) {
|
||||
uncompressed.writeBytes(tmp, 0, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
while (uncompressed.readableBytes() > 0) {
|
||||
this.list.add(AEFluidStack.fromPacket(uncompressed));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to decompress packet.", e);
|
||||
while (stream.readableBytes() > 0) {
|
||||
this.list.add(AEFluidStack.fromPacket(stream));
|
||||
}
|
||||
|
||||
this.empty = this.list.isEmpty();
|
||||
}
|
||||
|
||||
@@ -121,14 +85,6 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
|
||||
this.data = new PacketByteBuf(Unpooled.buffer(OPERATION_BYTE_LIMIT));
|
||||
this.data.writeInt(this.getPacketID());
|
||||
this.data.writeByte(this.ref);
|
||||
|
||||
this.compressFrame = new GZIPOutputStream(new OutputStream() {
|
||||
@Override
|
||||
public void write(final int value) {
|
||||
MEFluidInventoryUpdatePacket.this.data.writeByte(value);
|
||||
}
|
||||
});
|
||||
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
@@ -145,28 +101,19 @@ public class MEFluidInventoryUpdatePacket extends BasePacket {
|
||||
@Nullable
|
||||
@Override
|
||||
public Packet<?> toPacket(NetworkSide direction) {
|
||||
try {
|
||||
this.compressFrame.close();
|
||||
|
||||
this.configureWrite(this.data);
|
||||
return super.toPacket(direction);
|
||||
} catch (final IOException e) {
|
||||
AELog.debug(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
this.configureWrite(this.data);
|
||||
return super.toPacket(direction);
|
||||
}
|
||||
|
||||
public void appendFluid(final IAEFluidStack fs) throws IOException, BufferOverflowException {
|
||||
final PacketByteBuf tmp = new PacketByteBuf(Unpooled.buffer(OPERATION_BYTE_LIMIT));
|
||||
fs.writeToPacket(tmp);
|
||||
|
||||
this.compressFrame.flush();
|
||||
if (this.writtenBytes + tmp.readableBytes() > UNCOMPRESSED_PACKET_BYTE_LIMIT) {
|
||||
throw new BufferOverflowException();
|
||||
} else {
|
||||
this.writtenBytes += tmp.readableBytes();
|
||||
this.compressFrame.write(tmp.array(), 0, tmp.readableBytes());
|
||||
this.data.writeBytes(tmp.array(), 0, tmp.readableBytes());
|
||||
this.empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-44
@@ -18,13 +18,7 @@
|
||||
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
@@ -34,62 +28,30 @@ import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import appeng.client.gui.implementations.InterfaceTerminalScreen;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
|
||||
//TODO, this is pointless, NBT is already compressed when written to a PacketBuffer.
|
||||
public class CompressedNBTPacket extends BasePacket {
|
||||
public class MEInterfaceUpdatePacket extends BasePacket {
|
||||
|
||||
// input.
|
||||
private final CompoundTag in;
|
||||
// output...
|
||||
private final PacketByteBuf data;
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
public CompressedNBTPacket(final PacketByteBuf stream) {
|
||||
public MEInterfaceUpdatePacket(final PacketByteBuf stream) {
|
||||
this.data = null;
|
||||
this.compressFrame = null;
|
||||
|
||||
try (DataInputStream inStream = new DataInputStream(new GZIPInputStream(new InputStream() {
|
||||
|
||||
@Override
|
||||
public int read() {
|
||||
if (stream.readableBytes() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return stream.readByte() & 0xff;
|
||||
}
|
||||
}))) {
|
||||
this.in = NbtIo.read(inStream);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to decompress packet.", e);
|
||||
}
|
||||
this.in = stream.readCompoundTag();
|
||||
}
|
||||
|
||||
// api
|
||||
public CompressedNBTPacket(final CompoundTag din) throws IOException {
|
||||
|
||||
public MEInterfaceUpdatePacket(final CompoundTag din) throws IOException {
|
||||
this.in = null;
|
||||
this.data = new PacketByteBuf(Unpooled.buffer(2048));
|
||||
this.data.writeInt(this.getPacketID());
|
||||
|
||||
this.in = din;
|
||||
|
||||
this.compressFrame = new GZIPOutputStream(new OutputStream() {
|
||||
|
||||
@Override
|
||||
public void write(final int value) {
|
||||
CompressedNBTPacket.this.data.writeByte(value);
|
||||
}
|
||||
});
|
||||
|
||||
NbtIo.write(din, new DataOutputStream(this.compressFrame));
|
||||
this.compressFrame.close();
|
||||
|
||||
this.data.writeCompoundTag(din);
|
||||
this.configureWrite(this.data);
|
||||
}
|
||||
|
||||
@@ -19,13 +19,9 @@
|
||||
package appeng.core.sync.packets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -45,7 +41,6 @@ import appeng.client.gui.implementations.CraftConfirmScreen;
|
||||
import appeng.client.gui.implementations.CraftingCPUScreen;
|
||||
import appeng.client.gui.implementations.MEMonitorableScreen;
|
||||
import appeng.client.gui.implementations.NetworkStatusScreen;
|
||||
import appeng.core.AELog;
|
||||
import appeng.core.sync.BasePacket;
|
||||
import appeng.core.sync.network.INetworkInfo;
|
||||
import appeng.util.item.AEItemStack;
|
||||
@@ -53,8 +48,6 @@ import appeng.util.item.AEItemStack;
|
||||
public class MEInventoryUpdatePacket extends BasePacket {
|
||||
private static final int UNCOMPRESSED_PACKET_BYTE_LIMIT = 16 * 1024 * 1024;
|
||||
private static final int OPERATION_BYTE_LIMIT = 2 * 1024;
|
||||
private static final int TEMP_BUFFER_SIZE = 1024;
|
||||
private static final int STREAM_MASK = 0xff;
|
||||
|
||||
// input.
|
||||
@Nullable
|
||||
@@ -64,48 +57,18 @@ public class MEInventoryUpdatePacket extends BasePacket {
|
||||
|
||||
@Nullable
|
||||
private final PacketByteBuf data;
|
||||
@Nullable
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
private int writtenBytes = 0;
|
||||
private boolean empty = true;
|
||||
|
||||
public MEInventoryUpdatePacket(final PacketByteBuf stream) {
|
||||
this.data = null;
|
||||
this.compressFrame = null;
|
||||
this.list = new ArrayList<>();
|
||||
this.ref = stream.readByte();
|
||||
|
||||
// int originalBytes = stream.readableBytes();
|
||||
|
||||
try (GZIPInputStream gzReader = new GZIPInputStream(new InputStream() {
|
||||
@Override
|
||||
public int read() {
|
||||
if (stream.readableBytes() <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return stream.readByte() & STREAM_MASK;
|
||||
}
|
||||
})) {
|
||||
final PacketByteBuf uncompressed = new PacketByteBuf(Unpooled.buffer(stream.readableBytes()));
|
||||
final byte[] tmp = new byte[TEMP_BUFFER_SIZE];
|
||||
|
||||
while (gzReader.available() != 0) {
|
||||
final int bytes = gzReader.read(tmp);
|
||||
|
||||
if (bytes > 0) {
|
||||
uncompressed.writeBytes(tmp, 0, bytes);
|
||||
}
|
||||
}
|
||||
|
||||
while (uncompressed.readableBytes() > 0) {
|
||||
this.list.add(AEItemStack.fromPacket(uncompressed));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to decompress packet.", e);
|
||||
while (stream.readableBytes() > 0) {
|
||||
this.list.add(AEItemStack.fromPacket(stream));
|
||||
}
|
||||
|
||||
this.empty = this.list.isEmpty();
|
||||
}
|
||||
|
||||
@@ -120,14 +83,6 @@ public class MEInventoryUpdatePacket extends BasePacket {
|
||||
this.data = new PacketByteBuf(Unpooled.buffer(OPERATION_BYTE_LIMIT));
|
||||
this.data.writeInt(this.getPacketID());
|
||||
this.data.writeByte(this.ref);
|
||||
|
||||
this.compressFrame = new GZIPOutputStream(new OutputStream() {
|
||||
@Override
|
||||
public void write(final int value) {
|
||||
MEInventoryUpdatePacket.this.data.writeByte(value);
|
||||
}
|
||||
});
|
||||
|
||||
this.list = null;
|
||||
}
|
||||
|
||||
@@ -156,28 +111,19 @@ public class MEInventoryUpdatePacket extends BasePacket {
|
||||
@Nullable
|
||||
@Override
|
||||
public Packet<?> toPacket(NetworkSide direction) {
|
||||
try {
|
||||
this.compressFrame.close();
|
||||
|
||||
this.configureWrite(this.data);
|
||||
return super.toPacket(direction);
|
||||
} catch (final IOException e) {
|
||||
AELog.debug(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
this.configureWrite(this.data);
|
||||
return super.toPacket(direction);
|
||||
}
|
||||
|
||||
public void appendItem(final IAEItemStack is) throws IOException, BufferOverflowException {
|
||||
final PacketByteBuf tmp = new PacketByteBuf(Unpooled.buffer(OPERATION_BYTE_LIMIT));
|
||||
is.writeToPacket(tmp);
|
||||
|
||||
this.compressFrame.flush();
|
||||
if (this.writtenBytes + tmp.readableBytes() > UNCOMPRESSED_PACKET_BYTE_LIMIT) {
|
||||
throw new BufferOverflowException();
|
||||
} else {
|
||||
this.writtenBytes += tmp.readableBytes();
|
||||
this.compressFrame.write(tmp.array(), 0, tmp.readableBytes());
|
||||
this.data.writeBytes(tmp.array(), 0, tmp.readableBytes());
|
||||
this.empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Material;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import appeng.helpers.AEMaterials;
|
||||
|
||||
public class QuartzGlassBlock extends AbstractGlassBlock {
|
||||
|
||||
public QuartzGlassBlock(Settings props) {
|
||||
@@ -33,8 +31,7 @@ public class QuartzGlassBlock extends AbstractGlassBlock {
|
||||
|
||||
@Override
|
||||
public boolean isSideInvisible(BlockState state, BlockState adjacentBlockState, Direction side) {
|
||||
final Material mat = adjacentBlockState.getMaterial();
|
||||
if (mat == Material.GLASS || mat == AEMaterials.GLASS) {
|
||||
if (adjacentBlockState.getBlock() instanceof QuartzGlassBlock) {
|
||||
if (adjacentBlockState.getRenderType() == state.getRenderType()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ public abstract class AEBaseItemEntity extends ItemEntity implements ICustomEnti
|
||||
this.yaw = this.random.nextFloat() * 360.0F;
|
||||
this.setVelocity(this.random.nextDouble() * 0.2D - 0.1D, 0.2D, this.random.nextDouble() * 0.2D - 0.1D);
|
||||
this.setStack(stack);
|
||||
// FIXME FABRIC Needs replacement hook this.lifespan =
|
||||
// stack.getEntityLifespan(world);
|
||||
}
|
||||
|
||||
protected List<Entity> getCheckedEntitiesWithinAABBExcludingEntity(final Box region) {
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
package appeng.entity;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Material;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.features.AEFeature;
|
||||
@@ -35,12 +36,29 @@ import appeng.client.EffectType;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.items.misc.CrystalSeedItem;
|
||||
import appeng.util.Platform;
|
||||
import appeng.mixins.ItemEntityAccessor;
|
||||
|
||||
public final class GrowingCrystalEntity extends AEBaseItemEntity {
|
||||
public class GrowingCrystalEntity extends AEBaseItemEntity {
|
||||
|
||||
public static EntityType<GrowingCrystalEntity> TYPE;
|
||||
|
||||
// Growth tick progress per tick by number of adjacent accelerators
|
||||
// Expressed as 1/1000th of a growth tick, applied to progress_1000
|
||||
// each time this entity ticks.
|
||||
private static final int[] GROWTH_TICK_PROGRESS = { //
|
||||
1, // no accelerators
|
||||
40, // 1 accelerator
|
||||
92, // 2 accelerators
|
||||
159, // 3 accelerators
|
||||
247, // 4 accelerators
|
||||
361, // 5 accelerators
|
||||
509 // 6 accelerators
|
||||
};
|
||||
|
||||
/**
|
||||
* The accumulated progress towards a single growth tick of the crystal in
|
||||
* 1/1000th of a growth tick.
|
||||
*/
|
||||
private int progress_1000 = 0;
|
||||
|
||||
public GrowingCrystalEntity(EntityType<? extends GrowingCrystalEntity> type, World world) {
|
||||
@@ -49,135 +67,152 @@ public final class GrowingCrystalEntity extends AEBaseItemEntity {
|
||||
|
||||
public GrowingCrystalEntity(final World w, final double x, final double y, final double z, final ItemStack is) {
|
||||
super(TYPE, w, x, y, z, is);
|
||||
this.setCovetedItem();
|
||||
// FIXME FABRIC This does not actually fix despawning, we need to Mixin,
|
||||
// probably.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.IN_WORLD_PURIFICATION)) {
|
||||
return;
|
||||
// Prevent the entity from despawning
|
||||
ItemEntityAccessor accessor = (ItemEntityAccessor) this;
|
||||
if (!this.world.isClient && accessor.getAge() >= 1000) {
|
||||
accessor.setAge(0);
|
||||
}
|
||||
|
||||
super.tick();
|
||||
|
||||
final ItemStack is = this.getStack();
|
||||
final Item gc = is.getItem();
|
||||
|
||||
if (gc instanceof IGrowableCrystal) // if it changes this just stops being an issue...
|
||||
{
|
||||
final int j = MathHelper.floor(this.getX());
|
||||
final int i = MathHelper.floor((this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0D);
|
||||
final int k = MathHelper.floor(this.getZ());
|
||||
if (!(gc instanceof IGrowableCrystal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BlockState state = this.world.getBlockState(new BlockPos(j, i, k));
|
||||
final Material mat = state.getMaterial();
|
||||
final IGrowableCrystal cry = (IGrowableCrystal) is.getItem();
|
||||
applyGrowthTick((IGrowableCrystal) gc, is);
|
||||
}
|
||||
|
||||
final float multiplier = cry.getMultiplier(state.getBlock(), mat);
|
||||
final int speed = (int) Math.max(1, this.getSpeed(j, i, k) * multiplier);
|
||||
private void applyGrowthTick(IGrowableCrystal cry, ItemStack is) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.IN_WORLD_PURIFICATION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isClient = Platform.isClient();
|
||||
final int x = MathHelper.floor(this.getX());
|
||||
final int y = MathHelper.floor((this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0D);
|
||||
final int z = MathHelper.floor(this.getZ());
|
||||
|
||||
if (mat.isLiquid()) {
|
||||
if (isClient) {
|
||||
this.progress_1000++;
|
||||
} else {
|
||||
this.progress_1000 += speed;
|
||||
}
|
||||
} else {
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
final BlockState state = this.world.getBlockState(pos);
|
||||
|
||||
final float multiplier = cry.getMultiplier(state, world, pos);
|
||||
|
||||
if (multiplier <= 0) {
|
||||
// Crystal is in unsuitable material, reset progress and quit
|
||||
this.progress_1000 = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
final int progressPerTick = (int) Math.max(1, this.getSpeed(pos) * multiplier);
|
||||
|
||||
if (world.isClient()) {
|
||||
// On the client, we reuse the growth-tick-progress
|
||||
// as a tick-counter for particle effects
|
||||
int len = getTicksBetweenParticleEffects(progressPerTick);
|
||||
if (++this.progress_1000 >= len) {
|
||||
this.progress_1000 = 0;
|
||||
AppEng.instance().spawnEffect(EffectType.Vibrant, this.world, this.getX(), this.getY() + 0.2,
|
||||
this.getZ(), null);
|
||||
}
|
||||
} else {
|
||||
this.progress_1000 += progressPerTick;
|
||||
|
||||
if (isClient) {
|
||||
int len = 40;
|
||||
if (this.progress_1000 >= 1000) {
|
||||
// We need to copy the stack or the change detection will not work and not sync
|
||||
// this new stack to the client
|
||||
ItemStack newItem = is.copy();
|
||||
|
||||
if (speed > 2) {
|
||||
len = 20;
|
||||
}
|
||||
|
||||
if (speed > 90) {
|
||||
len = 15;
|
||||
}
|
||||
|
||||
if (speed > 150) {
|
||||
len = 10;
|
||||
}
|
||||
|
||||
if (speed > 240) {
|
||||
len = 7;
|
||||
}
|
||||
|
||||
if (speed > 360) {
|
||||
len = 3;
|
||||
}
|
||||
|
||||
if (speed > 500) {
|
||||
len = 1;
|
||||
}
|
||||
|
||||
if (this.progress_1000 >= len) {
|
||||
this.progress_1000 = 0;
|
||||
AppEng.instance().spawnEffect(EffectType.Vibrant, this.world, this.getX(), this.getY() + 0.2,
|
||||
this.getZ(), null);
|
||||
}
|
||||
} else {
|
||||
if (this.progress_1000 > 1000) {
|
||||
// If we did not use a while loop here, the fastest growth for a crystal
|
||||
// would be limited to a minimum of 30 seconds (based on 600 required growth
|
||||
// ticks).
|
||||
// Should a crystal decide to use a high multiplier for a certain material,
|
||||
// it should be possible to go faster.
|
||||
do {
|
||||
newItem = cry.triggerGrowth(newItem);
|
||||
this.progress_1000 -= 1000;
|
||||
// We need to copy the stack or the change detection will not work and not sync
|
||||
// this new stack to the client
|
||||
ItemStack newItem = cry.triggerGrowth(is.copy());
|
||||
this.setStack(newItem);
|
||||
}
|
||||
// We assume that if the item changes, the process is complete and we can break
|
||||
} while (this.progress_1000 >= 1000 && newItem.getItem() == is.getItem());
|
||||
|
||||
this.setStack(newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getSpeed(final int x, final int y, final int z) {
|
||||
final int per = 80;
|
||||
final float mul = 0.3f;
|
||||
|
||||
int qty = 0;
|
||||
|
||||
if (this.isAccelerated(x + 1, y, z)) {
|
||||
qty += per + qty * mul;
|
||||
private static int getTicksBetweenParticleEffects(int progressPerTick) {
|
||||
if (progressPerTick > 500) {
|
||||
return 1; // 20 times per second
|
||||
} else if (progressPerTick > 360) {
|
||||
return 3;
|
||||
} else if (progressPerTick > 240) {
|
||||
return 7;
|
||||
} else if (progressPerTick > 150) {
|
||||
return 10;
|
||||
} else if (progressPerTick > 90) {
|
||||
return 15;
|
||||
} else if (progressPerTick > 2) {
|
||||
return 20;
|
||||
} else {
|
||||
return 40; // Every 2 seconds
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x, y + 1, z)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x, y, z + 1)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x - 1, y, z)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x, y - 1, z)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
if (this.isAccelerated(x, y, z - 1)) {
|
||||
qty += per + qty * mul;
|
||||
}
|
||||
|
||||
return qty;
|
||||
}
|
||||
|
||||
private boolean isAccelerated(final int x, final int y, final int z) {
|
||||
final BlockEntity te = this.world.getBlockEntity(new BlockPos(x, y, z));
|
||||
/**
|
||||
* Gets the extra progress per tick in 1/1000th of a growth tick based on the
|
||||
* surrounding accelerators.
|
||||
*/
|
||||
private int getSpeed(BlockPos pos) {
|
||||
int acceleratorCount = getAcceleratorCount(pos);
|
||||
|
||||
if (acceleratorCount < 0) {
|
||||
return GROWTH_TICK_PROGRESS[0];
|
||||
} else if (acceleratorCount >= GROWTH_TICK_PROGRESS.length) {
|
||||
return GROWTH_TICK_PROGRESS[GROWTH_TICK_PROGRESS.length - 1];
|
||||
} else {
|
||||
return GROWTH_TICK_PROGRESS[acceleratorCount];
|
||||
}
|
||||
}
|
||||
|
||||
private int getAcceleratorCount(BlockPos pos) {
|
||||
int count = 0;
|
||||
|
||||
BlockPos.Mutable testPos = new BlockPos.Mutable();
|
||||
for (Direction direction : Direction.values()) {
|
||||
if (this.isPoweredAccelerator(testPos.set(pos, direction))) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private boolean isPoweredAccelerator(BlockPos pos) {
|
||||
final BlockEntity te = this.world.getBlockEntity(pos);
|
||||
|
||||
return te instanceof ICrystalGrowthAccelerator && ((ICrystalGrowthAccelerator) te).isPowered();
|
||||
}
|
||||
|
||||
// Don't let seeds "float" on water surface
|
||||
@Override
|
||||
public void applyBuoyancy() {
|
||||
ItemStack item = getStack();
|
||||
|
||||
// Make ungrown seeds sink, and fully grown seeds bouyant allowing for
|
||||
// automation based around dropping seeds between 5 CGAs, then catchiung
|
||||
// them on their way up.
|
||||
if (item.getItem() instanceof CrystalSeedItem) {
|
||||
Vec3d v = this.getVelocity();
|
||||
|
||||
// Apply a much smaller acceleration to make them slowly sink
|
||||
double yAccel = this.hasNoGravity() ? 0 : -0.002;
|
||||
|
||||
// Apply the x/z slow-down, and the y acceleration
|
||||
this.setVelocity(v.x * 0.99, v.y + yAccel, v.z * 0.99);
|
||||
|
||||
return;
|
||||
}
|
||||
super.applyBuoyancy();
|
||||
|
||||
@@ -38,15 +38,18 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
|
||||
private final int facades = 6;
|
||||
private final CableBusStorage storage;
|
||||
private final Runnable changeCallback;
|
||||
|
||||
public FacadeContainer(final CableBusStorage cbs) {
|
||||
public FacadeContainer(final CableBusStorage cbs, Runnable changeCallback) {
|
||||
this.storage = cbs;
|
||||
this.changeCallback = changeCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addFacade(final IFacadePart a) {
|
||||
if (this.getFacade(a.getSide()) == null) {
|
||||
this.storage.setFacade(a.getSide().ordinal(), a);
|
||||
this.notifyChange();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -57,6 +60,7 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
if (side != null && side != AEPartLocation.INTERNAL) {
|
||||
if (this.storage.getFacade(side.ordinal()) != null) {
|
||||
this.storage.setFacade(side.ordinal(), null);
|
||||
this.notifyChange();
|
||||
if (host != null) {
|
||||
host.markForUpdate();
|
||||
}
|
||||
@@ -85,6 +89,7 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
this.storage.setFacade(x, newFacades[x]);
|
||||
}
|
||||
this.notifyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,4 +181,9 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void notifyChange() {
|
||||
this.changeCallback.run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import net.minecraft.screen.slot.SlotActionType;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import me.shedaniel.math.Rectangle;
|
||||
|
||||
import appeng.api.config.Settings;
|
||||
import appeng.api.config.SortDir;
|
||||
import appeng.api.config.SortOrder;
|
||||
@@ -331,4 +333,11 @@ public class FluidTerminalScreen extends AEBaseMEScreen<FluidTerminalContainer>
|
||||
return "guis/terminal.png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Rectangle> getExclusionZones() {
|
||||
List<Rectangle> zones = super.getExclusionZones();
|
||||
zones.add(new Rectangle(x - 18, y, 18, 40));
|
||||
return zones;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ public class FluidSlotWidget extends CustomSlotWidget {
|
||||
// The tooltip area coincides with the area of the slot
|
||||
int x = getTooltipAreaX();
|
||||
int y = getTooltipAreaY();
|
||||
int width = getTooltipAreaX();
|
||||
int height = getTooltipAreaY();
|
||||
int width = getTooltipAreaWidth();
|
||||
int height = getTooltipAreaHeight();
|
||||
fs.getFluidStack().renderGuiRect(x, y, x + width, y + height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public class FluidExportBusPart extends SharedFluidBusPart {
|
||||
// we'll deduct 1/1000th from storage.
|
||||
long remainderMillibuckets = remainder.getAmount_F().asInt(1000, RoundingMode.DOWN);
|
||||
|
||||
toExtract.setStackSize(remainderMillibuckets);
|
||||
toExtract.decStackSize(remainderMillibuckets);
|
||||
inv.extractItems(toExtract, Actionable.MODULATE, this.source);
|
||||
|
||||
return TickRateModulation.FASTER;
|
||||
|
||||
@@ -141,7 +141,7 @@ public class FluidImportBusPart extends SharedFluidBusPart {
|
||||
|
||||
return TickRateModulation.IDLE;
|
||||
} catch (GridAccessException e) {
|
||||
e.printStackTrace();
|
||||
// skip
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2020 Team Appliedenergistics, 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.integration.modules.jei;
|
||||
|
||||
import me.shedaniel.rei.api.AutoTransferHandler;
|
||||
import me.shedaniel.rei.api.RecipeDisplay;
|
||||
import me.shedaniel.rei.api.TransferRecipeDisplay;
|
||||
|
||||
import appeng.container.implementations.CraftingTermContainer;
|
||||
|
||||
public class CraftingRecipeTransferHandler extends RecipeTransferHandler<CraftingTermContainer> {
|
||||
|
||||
public CraftingRecipeTransferHandler(Class<CraftingTermContainer> containerClass) {
|
||||
super(containerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AutoTransferHandler.Result doTransferRecipe(CraftingTermContainer container, RecipeDisplay recipe,
|
||||
AutoTransferHandler.Context context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCrafting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -108,6 +108,8 @@ class FacadeRegistryGenerator implements LiveRecipeGenerator<DefaultShapedDispla
|
||||
ingredients.set(7, Ingredient.ofStacks(cableAnchor));
|
||||
ingredients.set(4, Ingredient.ofStacks(textureItem));
|
||||
|
||||
result.setCount(4);
|
||||
|
||||
return new DefaultShapedDisplay(new ShapedRecipe(id, "", 3, 3, ingredients, result));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2020 Team Appliedenergistics, 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.integration.modules.jei;
|
||||
|
||||
import me.shedaniel.rei.api.AutoTransferHandler;
|
||||
import me.shedaniel.rei.api.RecipeDisplay;
|
||||
import me.shedaniel.rei.api.TransferRecipeDisplay;
|
||||
import me.shedaniel.rei.plugin.DefaultPlugin;
|
||||
|
||||
import appeng.container.implementations.PatternTermContainer;
|
||||
|
||||
public class PatternRecipeTransferHandler extends RecipeTransferHandler<PatternTermContainer> {
|
||||
|
||||
PatternRecipeTransferHandler(Class<PatternTermContainer> containerClass) {
|
||||
super(containerClass);
|
||||
}
|
||||
|
||||
protected AutoTransferHandler.Result doTransferRecipe(PatternTermContainer container, RecipeDisplay recipe,
|
||||
AutoTransferHandler.Context context) {
|
||||
|
||||
if (container.isCraftingMode() && recipe.getRecipeCategory() != DefaultPlugin.CRAFTING) {
|
||||
return AutoTransferHandler.Result.createFailed("jei.appliedenergistics2.requires_processing_mode");
|
||||
}
|
||||
|
||||
if (recipe.getResultingEntries().isEmpty()) {
|
||||
return AutoTransferHandler.Result.createFailed("jei.appliedenergistics2.no_output");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCrafting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,27 +18,27 @@
|
||||
|
||||
package appeng.integration.modules.jei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.ShapedRecipe;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
|
||||
import me.shedaniel.rei.api.AutoTransferHandler;
|
||||
import me.shedaniel.rei.api.EntryStack;
|
||||
import me.shedaniel.rei.api.RecipeDisplay;
|
||||
import me.shedaniel.rei.api.TransferRecipeDisplay;
|
||||
|
||||
import appeng.container.slot.CraftingMatrixSlot;
|
||||
import appeng.container.slot.FakeCraftingMatrixSlot;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.JEIRecipePacket;
|
||||
import appeng.mixins.SlotMixin;
|
||||
import appeng.util.Platform;
|
||||
import appeng.helpers.IContainerCraftingPacket;
|
||||
|
||||
class RecipeTransferHandler<T extends ScreenHandler> implements AutoTransferHandler {
|
||||
abstract class RecipeTransferHandler<T extends ScreenHandler & IContainerCraftingPacket>
|
||||
implements AutoTransferHandler {
|
||||
|
||||
private final Class<T> containerClass;
|
||||
|
||||
@@ -47,67 +47,85 @@ class RecipeTransferHandler<T extends ScreenHandler> implements AutoTransferHand
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result handle(Context context) {
|
||||
if (!(context.getRecipe() instanceof TransferRecipeDisplay)) {
|
||||
return Result.createNotApplicable();
|
||||
public AutoTransferHandler.Result handle(AutoTransferHandler.Context context) {
|
||||
RecipeDisplay recipe = context.getRecipe();
|
||||
|
||||
if (!containerClass.isInstance(context.getContainerScreen().getScreenHandler())) {
|
||||
return AutoTransferHandler.Result.createNotApplicable();
|
||||
}
|
||||
|
||||
ScreenHandler container = context.getContainerScreen().getScreenHandler();
|
||||
T container = containerClass.cast(context.getContainerScreen().getScreenHandler());
|
||||
|
||||
if (!containerClass.isInstance(container)) {
|
||||
return Result.createNotApplicable();
|
||||
final Identifier recipeId = recipe.getRecipeLocation().orElse(null);
|
||||
|
||||
// Check that the recipe can actually be looked up via the manager, i.e. our
|
||||
// facade recipes
|
||||
// have an ID, but are never registered with the recipe manager.
|
||||
boolean canSendReference = true;
|
||||
if (recipeId == null || !context.getMinecraft().world.getRecipeManager().get(recipeId).isPresent()) {
|
||||
canSendReference = false;
|
||||
}
|
||||
|
||||
if (!context.isActuallyCrafting()) {
|
||||
// This is just to check whether the button is enabled
|
||||
return Result.createSuccessful();
|
||||
if (recipe instanceof TransferRecipeDisplay) {
|
||||
TransferRecipeDisplay trd = (TransferRecipeDisplay) recipe;
|
||||
if (trd.getWidth() > 3 || trd.getHeight() > 3) {
|
||||
return AutoTransferHandler.Result.createFailed("jei.appliedenergistics2.recipe_too_large");
|
||||
}
|
||||
} else if (recipe.getInputEntries().size() > 9) {
|
||||
return AutoTransferHandler.Result.createFailed("jei.appliedenergistics2.recipe_too_large");
|
||||
}
|
||||
|
||||
TransferRecipeDisplay transferRecipe = (TransferRecipeDisplay) context.getRecipe();
|
||||
final AutoTransferHandler.Result error = doTransferRecipe(container, recipe, context);
|
||||
|
||||
final CompoundTag recipe = new CompoundTag();
|
||||
if (error != null) {
|
||||
return error;
|
||||
}
|
||||
|
||||
List<List<EntryStack>> ingredients = transferRecipe.getInputEntries();
|
||||
for (int i = 0; i < ingredients.size(); i++) {
|
||||
List<EntryStack> ingredientEntry = ingredients.get(i);
|
||||
|
||||
// Vanilla will pack ingredients if the recipe is less than 3x3
|
||||
int x = i % transferRecipe.getWidth();
|
||||
int y = (i - x) / transferRecipe.getWidth();
|
||||
int slotIndex = 3 * y + x;
|
||||
|
||||
for (final Slot slot : container.slots) {
|
||||
if (slot instanceof CraftingMatrixSlot || slot instanceof FakeCraftingMatrixSlot) {
|
||||
int containerSlotInvIdx = ((SlotMixin) slot).getIndex();
|
||||
if (containerSlotInvIdx == slotIndex) {
|
||||
final ListTag tags = new ListTag();
|
||||
final List<ItemStack> list = new ArrayList<>();
|
||||
|
||||
// prefer pure crystals.
|
||||
for (EntryStack stack : ingredientEntry) {
|
||||
if (Platform.isRecipePrioritized(stack.getItemStack())) {
|
||||
list.add(0, stack.getItemStack());
|
||||
} else {
|
||||
list.add(stack.getItemStack());
|
||||
}
|
||||
}
|
||||
|
||||
for (final ItemStack is : list) {
|
||||
final CompoundTag tag = new CompoundTag();
|
||||
is.toTag(tag);
|
||||
tags.add(tag);
|
||||
}
|
||||
|
||||
recipe.put("#" + containerSlotInvIdx, tags);
|
||||
break;
|
||||
if (context.isActuallyCrafting()) {
|
||||
if (canSendReference) {
|
||||
NetworkHandler.instance().sendToServer(new JEIRecipePacket(recipeId, isCrafting()));
|
||||
} else {
|
||||
// To avoid earlier problems of too large packets being sent that crashed the
|
||||
// client,
|
||||
// as a fallback when the recipe ID could not be resolved, we'll just send the
|
||||
// displayed
|
||||
// items.
|
||||
DefaultedList<Ingredient> flatIngredients = DefaultedList.ofSize(9, Ingredient.EMPTY);
|
||||
ItemStack output = null;
|
||||
for (EntryStack entryStack : recipe.getResultingEntries().get(0)) {
|
||||
if (entryStack.getType() == EntryStack.Type.ITEM) {
|
||||
output = entryStack.getItemStack();
|
||||
}
|
||||
}
|
||||
if (output == null || output.isEmpty()) {
|
||||
return AutoTransferHandler.Result.createFailed("jei.appliedenergistics2.no_output");
|
||||
}
|
||||
|
||||
// Now map the actual ingredients into the output/input
|
||||
for (int i = 0; i < recipe.getInputEntries().size(); i++) {
|
||||
List<EntryStack> inputEntry = recipe.getInputEntries().get(i);
|
||||
if (inputEntry.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
EntryStack first = inputEntry.get(0);
|
||||
if (i < flatIngredients.size()) {
|
||||
ItemStack displayedIngredient = first.getItemStack();
|
||||
if (displayedIngredient != null) {
|
||||
flatIngredients.set(i, Ingredient.method_26964(Stream.of(displayedIngredient)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ShapedRecipe fallbackRecipe = new ShapedRecipe(recipeId, "", 3, 3, flatIngredients, output);
|
||||
NetworkHandler.instance().sendToServer(new JEIRecipePacket(fallbackRecipe, isCrafting()));
|
||||
}
|
||||
}
|
||||
|
||||
NetworkHandler.instance().sendToServer(new JEIRecipePacket(recipe));
|
||||
|
||||
return Result.createFailed(""); // this will return to the screen
|
||||
return Result.createSuccessful().blocksFurtherHandling();
|
||||
}
|
||||
|
||||
protected abstract AutoTransferHandler.Result doTransferRecipe(T container, RecipeDisplay recipe,
|
||||
AutoTransferHandler.Context context);
|
||||
|
||||
protected abstract boolean isCrafting();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package appeng.integration.modules.jei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -31,7 +32,6 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import me.shedaniel.math.Rectangle;
|
||||
import me.shedaniel.rei.api.BaseBoundsHandler;
|
||||
import me.shedaniel.rei.api.DisplayHelper;
|
||||
import me.shedaniel.rei.api.EntryRegistry;
|
||||
@@ -123,8 +123,8 @@ public class ReiPlugin implements REIPluginV0 {
|
||||
@Override
|
||||
public void registerOthers(RecipeHelper recipeHelper) {
|
||||
// Allow recipe transfer from JEI to crafting and pattern terminal
|
||||
recipeHelper.registerAutoCraftingHandler(new RecipeTransferHandler<>(CraftingTermContainer.class));
|
||||
recipeHelper.registerAutoCraftingHandler(new RecipeTransferHandler<>(PatternTermContainer.class));
|
||||
recipeHelper.registerAutoCraftingHandler(new CraftingRecipeTransferHandler(CraftingTermContainer.class));
|
||||
recipeHelper.registerAutoCraftingHandler(new PatternRecipeTransferHandler(PatternTermContainer.class));
|
||||
|
||||
recipeHelper.removeAutoCraftButton(GrinderRecipeCategory.UID);
|
||||
recipeHelper.removeAutoCraftButton(InscriberRecipeCategory.UID);
|
||||
@@ -158,7 +158,7 @@ public class ReiPlugin implements REIPluginV0 {
|
||||
|
||||
baseBoundsHandler.registerExclusionZones(AEBaseScreen.class, () -> {
|
||||
AEBaseScreen<?> screen = (AEBaseScreen<?>) MinecraftClient.getInstance().currentScreen;
|
||||
return ImmutableList.of(new Rectangle(screen.getX(), screen.getY(), screen.width, screen.height));
|
||||
return screen != null ? screen.getExclusionZones() : Collections.emptyList();
|
||||
});
|
||||
|
||||
}
|
||||
@@ -226,7 +226,7 @@ public class ReiPlugin implements REIPluginV0 {
|
||||
ItemStack stack = entryStack.getItemStack();
|
||||
|
||||
if (items.dummyFluidItem().isSameAs(stack) || items.facade().isSameAs(stack) // REI will add a broken facade
|
||||
// with no NBT
|
||||
// with no NBT
|
||||
|| blocks.multiPart().isSameAs(stack) || blocks.matrixFrame().isSameAs(stack)
|
||||
|| blocks.paint().isSameAs(stack)) {
|
||||
return true;
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
|
||||
package appeng.integration.modules.jei;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import me.shedaniel.rei.api.REIHelper;
|
||||
import me.shedaniel.rei.gui.widget.TextFieldWidget;
|
||||
|
||||
import appeng.integration.abstraction.IRei;
|
||||
|
||||
@@ -29,7 +31,7 @@ class ReiRuntimeAdapter implements IRei {
|
||||
private final REIHelper runtime;
|
||||
|
||||
ReiRuntimeAdapter() {
|
||||
this.runtime = REIHelper.getInstance();
|
||||
this.runtime = Preconditions.checkNotNull(REIHelper.getInstance(), "REI helper was null");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,11 +41,18 @@ class ReiRuntimeAdapter implements IRei {
|
||||
|
||||
@Override
|
||||
public String getSearchText() {
|
||||
return Strings.nullToEmpty(this.runtime.getSearchTextField().getText());
|
||||
TextFieldWidget searchField = this.runtime.getSearchTextField();
|
||||
if (searchField == null) {
|
||||
return "";
|
||||
}
|
||||
return Strings.nullToEmpty(searchField.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSearchText(String searchText) {
|
||||
this.runtime.getSearchTextField().setText(Strings.nullToEmpty(searchText));
|
||||
TextFieldWidget searchField = this.runtime.getSearchTextField();
|
||||
if (searchField != null) {
|
||||
searchField.setText(Strings.nullToEmpty(searchText));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ package appeng.integration.modules.waila.tile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.item.TooltipContext;
|
||||
@@ -45,6 +47,7 @@ import appeng.tile.misc.ChargerBlockEntity;
|
||||
public final class ChargerWailaDataProvider extends BaseWailaDataProvider {
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void appendBody(List<Text> tooltip, IDataAccessor accessor, IPluginConfig config) {
|
||||
|
||||
final BlockEntity te = accessor.getBlockEntity();
|
||||
|
||||
@@ -26,23 +26,30 @@ import com.google.common.base.Preconditions;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Material;
|
||||
import net.fabricmc.fabric.api.tag.TagRegistry;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.item.TooltipContext;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.FluidState;
|
||||
import net.minecraft.item.ItemConvertible;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.tag.FluidTags;
|
||||
import net.minecraft.tag.Tag;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.implementations.items.IGrowableCrystal;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.localization.ButtonToolTips;
|
||||
import appeng.entity.GrowingCrystalEntity;
|
||||
import appeng.hooks.AECustomEntityItem;
|
||||
@@ -69,9 +76,15 @@ public class CrystalSeedItem extends AEBaseItem implements IGrowableCrystal, AEC
|
||||
*/
|
||||
private final ItemConvertible grownItem;
|
||||
|
||||
private final Tag<Fluid> improvedFluidTag;
|
||||
|
||||
public CrystalSeedItem(Settings properties, ItemConvertible grownItem) {
|
||||
super(properties);
|
||||
this.grownItem = Preconditions.checkNotNull(grownItem);
|
||||
|
||||
String improvedFluidTagName = AEConfig.instance().getImprovedFluidTag();
|
||||
this.improvedFluidTag = improvedFluidTagName != null ? TagRegistry.fluid(new Identifier(improvedFluidTagName))
|
||||
: null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -97,8 +110,21 @@ public class CrystalSeedItem extends AEBaseItem implements IGrowableCrystal, AEC
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMultiplier(final Block blk, final Material mat) {
|
||||
return 0.5f;
|
||||
public float getMultiplier(BlockState state, @Nullable World world, @Nullable BlockPos pos) {
|
||||
|
||||
// Check for the improved fluid tag and return the improved multiplier
|
||||
FluidState fluidState = state.getFluidState();
|
||||
if (improvedFluidTag != null && fluidState.isIn(improvedFluidTag)) {
|
||||
return AEConfig.instance().getImprovedFluidMultiplier();
|
||||
}
|
||||
|
||||
// Check for the normal supported fluid
|
||||
if (world != null && world.getRegistryKey() == World.NETHER) {
|
||||
// In the nether, use Lava as the "normal" fluid
|
||||
return fluidState.isIn(FluidTags.LAVA) ? 1 : 0;
|
||||
} else {
|
||||
return fluidState.isIn(FluidTags.WATER) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package appeng.items.misc;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
|
||||
import net.minecraft.item.Item;
|
||||
|
||||
import appeng.bootstrap.components.IClientSetupComponent;
|
||||
import appeng.core.AppEng;
|
||||
|
||||
/**
|
||||
* Exposes a predicate "growth", which is used in the item model to
|
||||
* differentiate the growth stages.
|
||||
*/
|
||||
public class CrystalSeedRendering implements IClientSetupComponent {
|
||||
private final Item item;
|
||||
|
||||
public CrystalSeedRendering(Item item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Environment(EnvType.CLIENT)
|
||||
public void setup() {
|
||||
// Expose the growth of the seed to the model system
|
||||
FabricModelPredicateProviderRegistry.register(item, AppEng.makeId("growth"),
|
||||
(is, w, p) -> CrystalSeedItem.getGrowthTicks(is) / (float) CrystalSeedItem.GROWTH_TICKS_REQUIRED);
|
||||
}
|
||||
}
|
||||
@@ -320,21 +320,21 @@ public class ColorApplicatorItem extends AEBasePoweredItem
|
||||
return w.setBlockState(pos, newState);
|
||||
}
|
||||
|
||||
if (blk instanceof CableBusBlock && p != null) {
|
||||
return ((CableBusBlock) blk).recolorBlock(w, pos, side, newColor.dye, p);
|
||||
}
|
||||
|
||||
BlockEntity be = w.getBlockEntity(pos);
|
||||
if (be instanceof IColorableTile) {
|
||||
IColorableTile ct = (IColorableTile) be;
|
||||
AEColor c = ct.getColor();
|
||||
if (c != newColor) {
|
||||
ct.recolourBlock(side, newColor, null);
|
||||
ct.recolourBlock(side, newColor, p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (blk instanceof CableBusBlock && p != null) {
|
||||
return ((CableBusBlock) blk).recolorBlock(w, pos, side, newColor.dye, p);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,17 +92,13 @@ public class QuartzWrenchItem extends AEBaseItem implements IAEWrench, AEToolIte
|
||||
}
|
||||
|
||||
if (block instanceof AEBaseBlock) {
|
||||
if (Platform.isClient()) {
|
||||
// TODO 1.10-R - if we return FAIL on client, action will not be sent to server.
|
||||
// Fix that in all Block#onItemUseFirst overrides.
|
||||
return !world.isClient ? ActionResult.SUCCESS : ActionResult.PASS;
|
||||
}
|
||||
|
||||
AEBaseBlock aeBlock = (AEBaseBlock) block;
|
||||
if (aeBlock.rotateAroundFaceAxis(world, pos, context.getSide())) {
|
||||
player.swingHand(context.getHand());
|
||||
return !world.isClient ? ActionResult.SUCCESS : ActionResult.FAIL;
|
||||
if (!world.isClient) {
|
||||
AEBaseBlock aeBlock = (AEBaseBlock) block;
|
||||
if (aeBlock.rotateAroundFaceAxis(world, pos, context.getSide())) {
|
||||
player.swingHand(context.getHand());
|
||||
}
|
||||
}
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
@@ -176,7 +176,6 @@ public class Grid implements IGrid {
|
||||
}
|
||||
|
||||
gridNode.getGridProxy().gridChanged();
|
||||
// postEventTo( gridNode, networkChanged );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -502,7 +502,7 @@ public class EnergyGridCache implements IEnergyGrid {
|
||||
private void removeRequester(IAEPowerStorage requester) {
|
||||
Preconditions.checkState(!ongoingInjectOperation,
|
||||
"Cannot modify energy requesters while energy is being injected.");
|
||||
this.requesters.add(requester);
|
||||
this.requesters.remove(requester);
|
||||
}
|
||||
|
||||
private void addProvider(IAEPowerStorage provider) {
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.Iterator;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.events.LocatableEventAnnounce;
|
||||
@@ -157,12 +156,16 @@ public class QuantumCluster implements ILocatable, IAECluster {
|
||||
if (qc != null) {
|
||||
final World theWorld = qc.center.getWorld();
|
||||
if (!qc.isDestroyed) {
|
||||
ChunkPos cPos = new ChunkPos(qc.center.getPos());
|
||||
if (theWorld.getChunkManager().isChunkLoaded(cPos.x, cPos.z)) {
|
||||
// In future versions, we might actually want to delay the entire registration
|
||||
// until the center
|
||||
// tile begins ticking normally.
|
||||
if (theWorld.isChunkLoaded(qc.center.getPos())) {
|
||||
final World cur = theWorld.getServer().getWorld(theWorld.getRegistryKey());
|
||||
|
||||
final BlockEntity te = theWorld.getBlockEntity(qc.center.getPos());
|
||||
return te != qc.center || theWorld != cur;
|
||||
} else {
|
||||
AELog.warn("Found a registered QNB with serial %s whose chunk seems to be unloaded: %s", qe, qc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,4 +278,17 @@ public class QuantumCluster implements ILocatable, IAECluster {
|
||||
private void setRing(final QuantumBridgeBlockEntity[] ring) {
|
||||
this.Ring = ring;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (center == null) {
|
||||
return "QuantumCluster{no-center}";
|
||||
}
|
||||
|
||||
World world = center.getWorld();
|
||||
BlockPos pos = center.getPos();
|
||||
|
||||
return "QuantumCluster{" + world + "," + pos + "}";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package appeng.mixins;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
|
||||
@Mixin(Ingredient.class)
|
||||
public interface IngredientAccessor {
|
||||
|
||||
@Invoker
|
||||
void callCacheMatchingStacks();
|
||||
|
||||
@Accessor
|
||||
ItemStack[] getMatchingStacks();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package appeng.mixins;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
|
||||
@Mixin(ItemEntity.class)
|
||||
public interface ItemEntityAccessor {
|
||||
|
||||
@Accessor
|
||||
int getAge();
|
||||
|
||||
@Accessor
|
||||
void setAge(int age);
|
||||
|
||||
}
|
||||
@@ -1,13 +1,21 @@
|
||||
package appeng.mixins.spatial;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.util.registry.BuiltinRegistries;
|
||||
import net.minecraft.util.registry.RegistryKey;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.Biomes;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
||||
import appeng.spatial.SpatialStorageBiome;
|
||||
import appeng.spatial.SpatialStorageDimensionIds;
|
||||
|
||||
@@ -18,10 +26,21 @@ import appeng.spatial.SpatialStorageDimensionIds;
|
||||
@Mixin(Biomes.class)
|
||||
public class BiomesMixin {
|
||||
|
||||
@Unique
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
@Shadow
|
||||
private static Int2ObjectMap<RegistryKey<Biome>> BIOMES;
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void registerBiomes(CallbackInfo ci) {
|
||||
BuiltinRegistries.add(BuiltinRegistries.BIOME, SpatialStorageDimensionIds.BIOME_KEY.getValue(),
|
||||
SpatialStorageBiome.INSTANCE);
|
||||
int rawId = BuiltinRegistries.BIOME.getRawId(SpatialStorageBiome.INSTANCE);
|
||||
RegistryKey<Biome> prev = BIOMES.put(rawId, SpatialStorageDimensionIds.BIOME_KEY);
|
||||
if (prev != null) {
|
||||
LOGGER.warn("Biome with raw-id {} was already registered: {}", rawId, prev);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package appeng.mixins.tags;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.tag.FluidTags;
|
||||
import net.minecraft.tag.RequiredTagList;
|
||||
import net.minecraft.tag.Tag;
|
||||
import net.minecraft.tag.TagGroup;
|
||||
|
||||
@Mixin(FluidTags.class)
|
||||
public interface FluidTagsAccessor {
|
||||
@@ -15,4 +18,9 @@ public interface FluidTagsAccessor {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@Accessor("REQUIRED_TAGS")
|
||||
static RequiredTagList<Fluid> getRequiredTags() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,7 +82,6 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
|
||||
private final EnumSet<LayerFlags> myLayerFlags = EnumSet.noneOf(LayerFlags.class);
|
||||
private YesNo hasRedstone = YesNo.UNDECIDED;
|
||||
private IPartHost tcb;
|
||||
// TODO 1.10.2-R - does somebody seriously want to make parts TESR??? Hope not.
|
||||
private boolean requiresDynamicRender = false;
|
||||
private boolean inWorld = false;
|
||||
// Cached collision shape for living entities
|
||||
@@ -125,7 +124,7 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
|
||||
|
||||
@Override
|
||||
public IFacadeContainer getFacadeContainer() {
|
||||
return new FacadeContainer(this);
|
||||
return new FacadeContainer(this, this::invalidateShapes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1095,11 +1094,7 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
|
||||
}
|
||||
}
|
||||
|
||||
VoxelShape shape = VoxelShapes.empty();
|
||||
for (final Box bx : boxes) {
|
||||
shape = VoxelShapes.union(shape, VoxelShapes.cuboid(bx));
|
||||
}
|
||||
return shape;
|
||||
return VoxelShapeCache.get(boxes);
|
||||
}
|
||||
|
||||
private void invalidateShapes() {
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2015, 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.parts;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
|
||||
import net.minecraft.util.function.BooleanBiFunction;
|
||||
import net.minecraft.util.math.Box;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.util.shape.VoxelShapes;
|
||||
|
||||
/**
|
||||
* While creation of a {@link net.minecraft.util.shape.VoxelShape} with
|
||||
* {@link net.minecraft.util.shape.VoxelShapes#cuboid(Box)} is fast enough,
|
||||
* combining voxel shapes with
|
||||
* {@link net.minecraft.util.shape.VoxelShapes#union(VoxelShape, VoxelShape)} or
|
||||
* any other combination method, as well as {@link VoxelShape#simplify()} are
|
||||
* <b>extremely slow</b>. For example: Creating a VoxelShape for a list of 5
|
||||
* bounding boxes 10,000 times takes about 1.7 seconds.
|
||||
*
|
||||
* <p>
|
||||
* To reduce the impact of this on cables, we introduce a global voxel shape
|
||||
* cache so that cables can share their combined voxel shapes better.
|
||||
*/
|
||||
final class VoxelShapeCache {
|
||||
|
||||
// Why using a List here should not make much of a difference vs. using a Set:
|
||||
// The part's bounding box depends on the side it is attached to, and the sides
|
||||
// are iterated over in a fixed order, meaning the order of bounding boxes
|
||||
// should
|
||||
// be the same for a same set of parts.
|
||||
private static final LoadingCache<List<Box>, VoxelShape> CACHE = CacheBuilder.newBuilder()//
|
||||
.maximumSize(10000L)//
|
||||
.build(new CacheLoader<List<Box>, VoxelShape>() {
|
||||
@Override
|
||||
public VoxelShape load(List<Box> key) {
|
||||
return create(key);
|
||||
}
|
||||
});
|
||||
|
||||
private VoxelShapeCache() {
|
||||
}
|
||||
|
||||
public static VoxelShape get(List<Box> boxes) {
|
||||
return CACHE.getUnchecked(boxes);
|
||||
}
|
||||
|
||||
private static VoxelShape create(List<Box> boxes) {
|
||||
if (boxes.isEmpty()) {
|
||||
return VoxelShapes.empty();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
VoxelShape shape = VoxelShapes.cuboid(boxes.get(i));
|
||||
for (; i < boxes.size(); i++) {
|
||||
Box box = boxes.get(i);
|
||||
shape = VoxelShapes.combine(shape, VoxelShapes.cuboid(box), BooleanBiFunction.OR);
|
||||
}
|
||||
return shape.simplify();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import java.util.Random;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.AutomaticItemPlacementContext;
|
||||
@@ -281,50 +280,62 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
|
||||
}
|
||||
|
||||
private static boolean spawnItemEntity(ServerWorld w, BlockEntity 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 centerY = te.getPos().getY();
|
||||
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;
|
||||
// Create an ItemEntity already at the position of the plane.
|
||||
// We don't know the final position, but need it for its size.
|
||||
Entity entity = new ItemEntity(w, centerX, centerY, centerZ, is.copy());
|
||||
|
||||
// Replace it if there is a custom entity
|
||||
if (is.getItem() instanceof AECustomEntityItem) {
|
||||
Entity result = ((AECustomEntityItem) is.getItem()).replaceItemEntity(w, (ItemEntity) entity, is);
|
||||
// Destroy the old one, in case it's spawned somehow and replace with the new
|
||||
// one.
|
||||
if (result != entity) {
|
||||
entity.remove();
|
||||
entity = result;
|
||||
}
|
||||
}
|
||||
|
||||
// When spawning downwards, we have to take into account that it spawns it at
|
||||
// their "feet" and not center like x or z. So we move it up to be flush with
|
||||
// the plane
|
||||
final double additionalYOffset = side.yOffset == -1 ? 1 - entity.getHeight() : 0;
|
||||
|
||||
// Calculate the maximum spawn area so an entity hitbox will always be inside
|
||||
// the block.
|
||||
final double spawnAreaHeight = Math.max(0, 1 - entity.getHeight());
|
||||
final double spawnAreaWidth = Math.max(0, 1 - entity.getWidth());
|
||||
|
||||
// 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 offsetX = (side.xOffset == 0) //
|
||||
? ((RANDOM_OFFSET.nextFloat() * spawnAreaWidth) - spawnAreaWidth / 2)
|
||||
: (side.xOffset * (.525 + entity.getWidth() / 2));
|
||||
final double offsetY = (side.yOffset == 0) //
|
||||
? (RANDOM_OFFSET.nextFloat() * spawnAreaHeight)
|
||||
: ((side.yOffset) + additionalYOffset);
|
||||
final double offsetZ = (side.zOffset == 0) //
|
||||
? ((RANDOM_OFFSET.nextFloat() * spawnAreaWidth) - spawnAreaWidth / 2)
|
||||
: (side.zOffset * (.525 + entity.getWidth() / 2));
|
||||
|
||||
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());
|
||||
ei.setVelocity(side.xOffset * .1, side.yOffset * 0.1, side.zOffset * 0.1);
|
||||
// Set to correct position and slow the motion down a bit
|
||||
entity.setPos(absoluteX, absoluteY, absoluteZ);
|
||||
entity.setVelocity(side.xOffset * .1, side.yOffset * 0.1, side.zOffset * 0.1);
|
||||
|
||||
Entity result;
|
||||
if (is.getItem() instanceof AECustomEntityItem) {
|
||||
result = ((AECustomEntityItem) is.getItem()).replaceItemEntity(w, ei, is);
|
||||
if (result != ei) {
|
||||
ei.remove();
|
||||
}
|
||||
} else {
|
||||
result = ei;
|
||||
}
|
||||
|
||||
if (!w.spawnEntity(result)) {
|
||||
result.remove();
|
||||
// Try to spawn it and destroy it in case it's not possible
|
||||
if (!w.spawnEntity(entity)) {
|
||||
entity.remove();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
Vendored
+23
-25
@@ -19,11 +19,8 @@
|
||||
package appeng.thirdparty.codechicken.lib.model.pipeline.transformers;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.EncodingFormat;
|
||||
import net.fabricmc.fabric.impl.client.indigo.renderer.mesh.MutableQuadViewImpl;
|
||||
|
||||
import appeng.thirdparty.codechicken.lib.math.InterpHelper;
|
||||
|
||||
@@ -39,16 +36,11 @@ public class QuadReInterpolator implements RenderContext.QuadTransform {
|
||||
|
||||
private final InterpHelper interpHelper = new InterpHelper();
|
||||
|
||||
private final MutableQuadViewImpl bufferQuad = new MutableQuadViewImpl() {
|
||||
{
|
||||
data = new int[EncodingFormat.TOTAL_STRIDE];
|
||||
}
|
||||
private final int[] originalSpriteColor = new int[4];
|
||||
|
||||
@Override
|
||||
public QuadEmitter emit() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
private final float[] originalSpriteU = new float[4];
|
||||
|
||||
private final float[] originalSpriteV = new float[4];
|
||||
|
||||
public QuadReInterpolator() {
|
||||
super();
|
||||
@@ -63,7 +55,13 @@ public class QuadReInterpolator implements RenderContext.QuadTransform {
|
||||
quad.posByIndex(1, xIdx), quad.posByIndex(1, yIdx), //
|
||||
quad.posByIndex(2, xIdx), quad.posByIndex(2, yIdx), //
|
||||
quad.posByIndex(3, xIdx), quad.posByIndex(3, yIdx));
|
||||
quad.copyTo(bufferQuad);
|
||||
|
||||
// Save the original properties of the quad's vertices
|
||||
for (int i = 0; i < 4; i++) {
|
||||
originalSpriteColor[i] = quad.spriteColor(i, 0);
|
||||
originalSpriteU[i] = quad.spriteU(i, 0);
|
||||
originalSpriteV[i] = quad.spriteV(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,10 +87,10 @@ public class QuadReInterpolator implements RenderContext.QuadTransform {
|
||||
* reference.
|
||||
*/
|
||||
public void interpColorFrom(MutableQuadView quad, int vertexIndex) {
|
||||
int p1 = bufferQuad.spriteColor(0, 0);
|
||||
int p2 = bufferQuad.spriteColor(1, 0);
|
||||
int p3 = bufferQuad.spriteColor(2, 0);
|
||||
int p4 = bufferQuad.spriteColor(3, 0);
|
||||
int p1 = this.originalSpriteColor[0];
|
||||
int p2 = this.originalSpriteColor[1];
|
||||
int p3 = this.originalSpriteColor[2];
|
||||
int p4 = this.originalSpriteColor[3];
|
||||
if (p1 == p2 && p2 == p3 && p3 == p4) {
|
||||
return; // Don't bother for uniformly colored quads
|
||||
}
|
||||
@@ -118,16 +116,16 @@ public class QuadReInterpolator implements RenderContext.QuadTransform {
|
||||
* reference.
|
||||
*/
|
||||
public void interpUVFrom(MutableQuadView quad, int vertexIndex) {
|
||||
float p1 = bufferQuad.spriteU(0, 0);
|
||||
float p2 = bufferQuad.spriteU(1, 0);
|
||||
float p3 = bufferQuad.spriteU(2, 0);
|
||||
float p4 = bufferQuad.spriteU(3, 0);
|
||||
float p1 = originalSpriteU[0];
|
||||
float p2 = originalSpriteU[1];
|
||||
float p3 = originalSpriteU[2];
|
||||
float p4 = originalSpriteU[3];
|
||||
float u = interpHelper.interpolate(p1, p2, p3, p4);
|
||||
|
||||
p1 = bufferQuad.spriteV(0, 0);
|
||||
p2 = bufferQuad.spriteV(1, 0);
|
||||
p3 = bufferQuad.spriteV(2, 0);
|
||||
p4 = bufferQuad.spriteV(3, 0);
|
||||
p1 = originalSpriteV[0];
|
||||
p2 = originalSpriteV[1];
|
||||
p3 = originalSpriteV[2];
|
||||
p4 = originalSpriteV[3];
|
||||
float v = interpHelper.interpolate(p1, p2, p3, p4);
|
||||
quad.sprite(vertexIndex, 0, u, v);
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ public class AEBaseBlockEntity extends BlockEntity implements IOrientable, IComm
|
||||
this.renderFragment |= 1;
|
||||
} else {
|
||||
// TODO: Optimize Network Load
|
||||
if (this.world != null) {
|
||||
if (this.world != null && !this.isRemoved() && !notLoaded()) {
|
||||
boolean alreadyUpdated = false;
|
||||
// Let the block update it's own state with our internal state changes
|
||||
BlockState currentState = getCachedState();
|
||||
@@ -298,6 +298,7 @@ public class AEBaseBlockEntity extends BlockEntity implements IOrientable, IComm
|
||||
this.up = inUp;
|
||||
this.markForUpdate();
|
||||
Platform.notifyBlocksOfNeighbors(this.world, this.pos);
|
||||
this.saveChanges();
|
||||
}
|
||||
|
||||
public void onPlacement(ItemPlacementContext context) {
|
||||
|
||||
@@ -59,6 +59,13 @@ public abstract class AEBaseInvBlockEntity extends AEBaseBlockEntity implements
|
||||
|
||||
public abstract @Nonnull FixedItemInv getInternalInventory();
|
||||
|
||||
/**
|
||||
* Inventory offered to other mods accessing this block externally.
|
||||
*/
|
||||
public @Nonnull FixedItemInv getExternalInventory() {
|
||||
return getInternalInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag toTag(final CompoundTag data) {
|
||||
super.toTag(data);
|
||||
@@ -95,7 +102,7 @@ public abstract class AEBaseInvBlockEntity extends AEBaseBlockEntity implements
|
||||
ItemStack added);
|
||||
|
||||
protected @Nonnull FixedItemInv getItemHandlerForSide(@Nonnull Direction side) {
|
||||
return this.getInternalInventory();
|
||||
return this.getExternalInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,7 +114,7 @@ public abstract class AEBaseInvBlockEntity extends AEBaseBlockEntity implements
|
||||
private void offerItemInventory(AttributeList<?> to) {
|
||||
Direction searchDirection = to.getSearchDirection();
|
||||
if (searchDirection == null) {
|
||||
to.offer(getInternalInventory());
|
||||
to.offer(getExternalInventory());
|
||||
} else {
|
||||
Direction side = searchDirection.getOpposite();
|
||||
to.offer(getItemHandlerForSide(side));
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.block.BlockState;
|
||||
@@ -38,6 +40,7 @@ import net.minecraft.world.World;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.LimitedFixedItemInv;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
@@ -78,8 +81,6 @@ import appeng.util.Platform;
|
||||
import appeng.util.helpers.ItemHandlerUtil;
|
||||
import appeng.util.inv.InvOperation;
|
||||
import appeng.util.inv.WrapperChainedItemHandler;
|
||||
import appeng.util.inv.WrapperFilteredItemHandler;
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
import appeng.util.item.AEItemStack;
|
||||
|
||||
public class MolecularAssemblerBlockEntity extends AENetworkInvBlockEntity
|
||||
@@ -90,8 +91,8 @@ public class MolecularAssemblerBlockEntity extends AENetworkInvBlockEntity
|
||||
private final CraftingInventory craftingInv;
|
||||
private final AppEngInternalInventory gridInv = new AppEngInternalInventory(this, 9 + 1, 1);
|
||||
private final AppEngInternalInventory patternInv = new AppEngInternalInventory(this, 1, 1);
|
||||
private final FixedItemInv gridInvExt = new WrapperFilteredItemHandler(this.gridInv, new CraftingGridFilter());
|
||||
private final FixedItemInv internalInv = new WrapperChainedItemHandler(this.gridInv, this.patternInv);
|
||||
private final LimitedFixedItemInv gridInvExt;
|
||||
private final IConfigManager settings;
|
||||
private final UpgradeInventory upgrades;
|
||||
private boolean isPowered = false;
|
||||
@@ -116,6 +117,20 @@ public class MolecularAssemblerBlockEntity extends AENetworkInvBlockEntity
|
||||
this.upgrades = new DefinitionUpgradeInventory(assembler, this, this.getUpgradeSlots());
|
||||
this.craftingInv = new CraftingInventory(new ContainerNull(), 3, 3);
|
||||
|
||||
gridInvExt = gridInv.createLimitedFixedInv();
|
||||
// Limit the input slots to 1 of the respective crafting ingredient
|
||||
for (int i = 0; i < 9; i++) {
|
||||
int slot = i;
|
||||
gridInvExt.getRule(slot).disallowExtraction().limitInsertionCount(1)
|
||||
.filterInserts(stack -> isValidIngredientForSlot(slot, stack));
|
||||
}
|
||||
// Output slot
|
||||
gridInvExt.getRule(9).disallowInsertion();
|
||||
}
|
||||
|
||||
private boolean isValidIngredientForSlot(int slot, ItemStack stack) {
|
||||
return this.myPlan != null && !ItemHandlerUtil.isEmpty(this.patternInv)
|
||||
&& this.myPlan.isValidItemForSlot(slot, stack, MolecularAssemblerBlockEntity.this.getWorld());
|
||||
}
|
||||
|
||||
private int getUpgradeSlots() {
|
||||
@@ -310,8 +325,9 @@ public class MolecularAssemblerBlockEntity extends AENetworkInvBlockEntity
|
||||
return this.internalInv;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected FixedItemInv getItemHandlerForSide(Direction side) {
|
||||
public FixedItemInv getExternalInventory() {
|
||||
return this.gridInvExt;
|
||||
}
|
||||
|
||||
@@ -554,28 +570,4 @@ public class MolecularAssemblerBlockEntity extends AENetworkInvBlockEntity
|
||||
return this.animationStatus;
|
||||
}
|
||||
|
||||
private class CraftingGridFilter implements IAEItemFilter {
|
||||
private boolean hasPattern() {
|
||||
return MolecularAssemblerBlockEntity.this.myPlan != null
|
||||
&& !ItemHandlerUtil.isEmpty(MolecularAssemblerBlockEntity.this.patternInv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return slot == 9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
if (slot >= 9) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.hasPattern()) {
|
||||
return MolecularAssemblerBlockEntity.this.myPlan.isValidItemForSlot(slot, stack,
|
||||
MolecularAssemblerBlockEntity.this.getWorld());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,10 @@ public abstract class AENetworkInvBlockEntity extends AEBaseInvBlockEntity imple
|
||||
@Override
|
||||
public void markRemoved() {
|
||||
super.markRemoved();
|
||||
// if the cached block state is not current, the following method may call
|
||||
// markForUpdate
|
||||
// and cause the block state to be changed back to non-air
|
||||
resetBlock();
|
||||
this.getProxy().remove();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import net.minecraft.util.math.Direction;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.LimitedFixedItemInv;
|
||||
|
||||
import appeng.api.implementations.tiles.ICrankable;
|
||||
import appeng.recipes.handlers.GrinderOptionalResult;
|
||||
@@ -39,18 +40,21 @@ import appeng.util.InventoryAdaptor;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.inv.AdaptorFixedInv;
|
||||
import appeng.util.inv.InvOperation;
|
||||
import appeng.util.inv.WrapperFilteredItemHandler;
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
|
||||
public class GrinderBlockEntity extends AEBaseInvBlockEntity implements ICrankable {
|
||||
private static final int SLOT_PROCESSING = 6;
|
||||
|
||||
private final AppEngInternalInventory inv = new AppEngInternalInventory(this, 7);
|
||||
private final FixedItemInv invExt = new WrapperFilteredItemHandler(this.inv, new GrinderFilter());
|
||||
private final LimitedFixedItemInv invExt;
|
||||
private int points;
|
||||
|
||||
public GrinderBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
|
||||
invExt = inv.createLimitedFixedInv();
|
||||
invExt.getAllRule().disallowExtraction().disallowInsertion();
|
||||
invExt.getSubRule(3, 6).allowExtraction();
|
||||
invExt.getSubRule(0, 3).filterInserts(stack -> GrinderRecipes.isValidIngredient(world, stack)).allowInsertion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,20 +165,4 @@ public class GrinderBlockEntity extends AEBaseInvBlockEntity implements ICrankab
|
||||
return this.getUp() == directionToCrank;
|
||||
}
|
||||
|
||||
private class GrinderFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slotIndex, int amount) {
|
||||
return slotIndex >= 3 && slotIndex <= 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slotIndex, ItemStack stack) {
|
||||
if (!GrinderRecipes.isValidIngredient(world, stack)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return slotIndex >= 0 && slotIndex <= 2;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -137,6 +139,12 @@ public class ChargerBlockEntity extends AENetworkPowerBlockEntity implements ICr
|
||||
|
||||
@Override
|
||||
public FixedItemInv getInternalInventory() {
|
||||
return inv;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FixedItemInv getExternalInventory() {
|
||||
return externalInv;
|
||||
}
|
||||
|
||||
@@ -255,7 +263,7 @@ public class ChargerBlockEntity extends AENetworkPowerBlockEntity implements ICr
|
||||
return true;
|
||||
}
|
||||
|
||||
private class ChargerInvFilter implements IAEItemFilter {
|
||||
private static class ChargerInvFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, final int i, final ItemStack itemstack) {
|
||||
final IItemDefinition cert = Api.instance().definitions().materials().certusQuartzCrystal();
|
||||
|
||||
@@ -138,7 +138,7 @@ public class CondenserBlockEntity extends AEBaseInvBlockEntity implements IConfi
|
||||
}
|
||||
|
||||
private boolean canAddOutput(final ItemStack output) {
|
||||
return this.outputSlot.getInsertable().attemptInsertion(output, Simulation.SIMULATE).isEmpty();
|
||||
return this.outputSlot.getInsertable().wouldAccept(output);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +147,7 @@ public class CondenserBlockEntity extends AEBaseInvBlockEntity implements IConfi
|
||||
* @param output to be added output
|
||||
*/
|
||||
private void addOutput(final ItemStack output) {
|
||||
this.outputSlot.getInsertable().attemptInsertion(output, Simulation.ACTION);
|
||||
this.outputSlot.getInsertable().insert(output);
|
||||
}
|
||||
|
||||
FixedItemInv getOutputSlot() {
|
||||
|
||||
@@ -25,6 +25,8 @@ import java.util.List;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -36,6 +38,7 @@ import net.minecraft.world.World;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.LimitedFixedItemInv;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
@@ -65,8 +68,6 @@ import appeng.util.ConfigManager;
|
||||
import appeng.util.IConfigManagerHost;
|
||||
import appeng.util.inv.InvOperation;
|
||||
import appeng.util.inv.WrapperChainedItemHandler;
|
||||
import appeng.util.inv.WrapperFilteredItemHandler;
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
import appeng.util.item.AEItemStack;
|
||||
|
||||
/**
|
||||
@@ -91,15 +92,17 @@ public class InscriberBlockEntity extends AENetworkPowerBlockEntity
|
||||
private final AppEngInternalInventory bottomItemHandler = new AppEngInternalInventory(this, 1, 1);
|
||||
private final AppEngInternalInventory sideItemHandler = new AppEngInternalInventory(this, 2, 1);
|
||||
|
||||
private final FixedItemInv topItemHandlerExtern;
|
||||
private final FixedItemInv bottomItemHandlerExtern;
|
||||
private final FixedItemInv sideItemHandlerExtern;
|
||||
private final LimitedFixedItemInv topItemHandlerExtern;
|
||||
private final LimitedFixedItemInv bottomItemHandlerExtern;
|
||||
private final LimitedFixedItemInv sideItemHandlerExtern;
|
||||
|
||||
private InscriberRecipe cachedTask = null;
|
||||
|
||||
private final FixedItemInv inv = new WrapperChainedItemHandler(this.topItemHandler, this.bottomItemHandler,
|
||||
this.sideItemHandler);
|
||||
|
||||
private final FixedItemInv externalInv;
|
||||
|
||||
public InscriberBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
|
||||
@@ -113,10 +116,30 @@ public class InscriberBlockEntity extends AENetworkPowerBlockEntity
|
||||
|
||||
this.sideItemHandler.setMaxStackSize(1, 64);
|
||||
|
||||
final IAEItemFilter filter = new ItemHandlerFilter();
|
||||
this.topItemHandlerExtern = new WrapperFilteredItemHandler(this.topItemHandler, filter);
|
||||
this.bottomItemHandlerExtern = new WrapperFilteredItemHandler(this.bottomItemHandler, filter);
|
||||
this.sideItemHandlerExtern = new WrapperFilteredItemHandler(this.sideItemHandler, filter);
|
||||
this.topItemHandlerExtern = this.topItemHandler.createLimitedFixedInv();
|
||||
this.topItemHandlerExtern.getAllRule().filterInserts(this::canInsertIntoTopOrBottom)
|
||||
.filterExtracts(stack -> !isSmash());
|
||||
|
||||
this.bottomItemHandlerExtern = this.bottomItemHandler.createLimitedFixedInv();
|
||||
this.bottomItemHandlerExtern.getAllRule().filterInserts(this::canInsertIntoTopOrBottom)
|
||||
.filterExtracts(stack -> !isSmash());
|
||||
|
||||
this.sideItemHandlerExtern = this.sideItemHandler.createLimitedFixedInv();
|
||||
this.sideItemHandlerExtern.getRule(0).disallowExtraction().filterInserts(stack -> !isSmash());
|
||||
this.sideItemHandlerExtern.getRule(1).filterExtracts(stack -> !isSmash()).disallowInsertion();
|
||||
|
||||
this.externalInv = new WrapperChainedItemHandler(this.topItemHandlerExtern, this.bottomItemHandlerExtern,
|
||||
this.sideItemHandlerExtern);
|
||||
}
|
||||
|
||||
private boolean canInsertIntoTopOrBottom(ItemStack stack) {
|
||||
if (isSmash()) {
|
||||
return false;
|
||||
}
|
||||
if (Api.instance().definitions().materials().namePress().isSameAs(stack)) {
|
||||
return true;
|
||||
}
|
||||
return InscriberRecipes.isValidOptionalIngredient(getWorld(), stack);
|
||||
}
|
||||
|
||||
private int getUpgradeSlots() {
|
||||
@@ -212,6 +235,12 @@ public class InscriberBlockEntity extends AENetworkPowerBlockEntity
|
||||
return this.inv;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FixedItemInv getExternalInventory() {
|
||||
return this.externalInv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChangeInventory(final FixedItemInv inv, final int slot, final InvOperation mc,
|
||||
final ItemStack removed, final ItemStack added) {
|
||||
@@ -276,7 +305,7 @@ public class InscriberBlockEntity extends AENetworkPowerBlockEntity
|
||||
if (out != null) {
|
||||
final ItemStack outputCopy = out.getOutput().copy();
|
||||
|
||||
if (this.sideItemHandler.setInvStack(1, outputCopy, Simulation.ACTION)) {
|
||||
if (this.sideItemHandler.getSlot(1).insert(outputCopy).isEmpty()) {
|
||||
this.setProcessingTime(0);
|
||||
if (out.getProcessType() == InscriberProcessType.PRESS) {
|
||||
this.topItemHandler.setInvStack(0, ItemStack.EMPTY, Simulation.ACTION);
|
||||
@@ -325,7 +354,7 @@ public class InscriberBlockEntity extends AENetworkPowerBlockEntity
|
||||
final InscriberRecipe out = this.getTask();
|
||||
if (out != null) {
|
||||
final ItemStack outputCopy = out.getOutput().copy();
|
||||
if (this.sideItemHandler.setInvStack(1, outputCopy, Simulation.SIMULATE)) {
|
||||
if (this.sideItemHandler.getSlot(1).wouldAccept(outputCopy)) {
|
||||
this.setSmash(true);
|
||||
this.finalStep = 0;
|
||||
this.markForUpdate();
|
||||
@@ -403,42 +432,4 @@ public class InscriberBlockEntity extends AENetworkPowerBlockEntity
|
||||
this.processingTime = processingTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an item handler that exposes the inscribers inventory while providing
|
||||
* simulation capabilities that do not reset the progress if there's already an
|
||||
* item in a slot. Previously, the progress of the inscriber was reset when
|
||||
* another mod attempted insertion of items when there were already items in the
|
||||
* slot.
|
||||
*/
|
||||
private class ItemHandlerFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
if (InscriberBlockEntity.this.isSmash()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return inv == InscriberBlockEntity.this.topItemHandler || inv == InscriberBlockEntity.this.bottomItemHandler
|
||||
|| slot == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
// output slot
|
||||
if (slot == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (InscriberBlockEntity.this.isSmash()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inv == InscriberBlockEntity.this.topItemHandler || inv == InscriberBlockEntity.this.bottomItemHandler) {
|
||||
if (Api.instance().definitions().materials().namePress().isSameAs(stack)) {
|
||||
return true;
|
||||
}
|
||||
return InscriberRecipes.isValidOptionalIngredient(getWorld(), stack);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package appeng.tile.misc;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -78,7 +80,7 @@ public final class InscriberRecipes {
|
||||
name += " " + tag.getString(MaterialItem.TAG_INSCRIBE_NAME);
|
||||
}
|
||||
|
||||
final Ingredient startingItem = Ingredient.ofStacks(input.copy());
|
||||
final Ingredient startingItem = Ingredient.method_26964(Stream.of(input.copy()));
|
||||
final ItemStack renamedItem = input.copy();
|
||||
|
||||
if (!name.isEmpty()) {
|
||||
@@ -90,8 +92,8 @@ public final class InscriberRecipes {
|
||||
final InscriberProcessType type = InscriberProcessType.INSCRIBE;
|
||||
|
||||
return new InscriberRecipe(NAMEPLATE_RECIPE_ID, "", startingItem, renamedItem,
|
||||
plateA.isEmpty() ? Ingredient.EMPTY : Ingredient.ofStacks(plateA),
|
||||
plateB.isEmpty() ? Ingredient.EMPTY : Ingredient.ofStacks(plateB), type);
|
||||
plateA.isEmpty() ? Ingredient.EMPTY : Ingredient.method_26964(Stream.of(plateA)),
|
||||
plateB.isEmpty() ? Ingredient.EMPTY : Ingredient.method_26964(Stream.of(plateB)), type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,7 @@ import net.minecraft.util.math.Direction;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.LimitedFixedItemInv;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.networking.IGridNode;
|
||||
@@ -49,8 +50,6 @@ import appeng.tile.grid.AENetworkInvBlockEntity;
|
||||
import appeng.tile.inventory.AppEngInternalInventory;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.inv.InvOperation;
|
||||
import appeng.util.inv.WrapperFilteredItemHandler;
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
|
||||
public class VibrationChamberBlockEntity extends AENetworkInvBlockEntity implements IGridTickable {
|
||||
public static final double POWER_PER_TICK = 5;
|
||||
@@ -58,7 +57,7 @@ public class VibrationChamberBlockEntity extends AENetworkInvBlockEntity impleme
|
||||
public static final int MAX_BURN_SPEED = 200;
|
||||
public static final double DILATION_SCALING = 25.0; // x4 ~ 40 AE/t at max
|
||||
private final AppEngInternalInventory inv = new AppEngInternalInventory(this, 1);
|
||||
private final FixedItemInv invExt = new WrapperFilteredItemHandler(this.inv, new FuelSlotFilter());
|
||||
private final LimitedFixedItemInv invExt;
|
||||
|
||||
private int burnSpeed = 100;
|
||||
private double burnTime = 0;
|
||||
@@ -71,6 +70,10 @@ public class VibrationChamberBlockEntity extends AENetworkInvBlockEntity impleme
|
||||
super(tileEntityTypeIn);
|
||||
this.getProxy().setIdlePowerUsage(0);
|
||||
this.getProxy().setFlags();
|
||||
|
||||
invExt = inv.createLimitedFixedInv();
|
||||
invExt.getAllRule().filterInserts(stack -> FuelRegistry.INSTANCE.get(stack.getItem()) != null)
|
||||
.filterExtracts(stack -> FuelRegistry.INSTANCE.get(stack.getItem()) == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,8 +141,8 @@ public class VibrationChamberBlockEntity extends AENetworkInvBlockEntity impleme
|
||||
private boolean canEatFuel() {
|
||||
final ItemStack is = this.inv.getInvStack(0);
|
||||
if (!is.isEmpty()) {
|
||||
final int newBurnTime = FuelRegistry.INSTANCE.get(is.getItem());
|
||||
if (newBurnTime > 0 && is.getCount() > 0) {
|
||||
final Integer newBurnTime = FuelRegistry.INSTANCE.get(is.getItem());
|
||||
if (newBurnTime != null && is.getCount() > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -210,8 +213,8 @@ public class VibrationChamberBlockEntity extends AENetworkInvBlockEntity impleme
|
||||
private void eatFuel() {
|
||||
final ItemStack is = this.inv.getInvStack(0);
|
||||
if (!is.isEmpty()) {
|
||||
final int newBurnTime = FuelRegistry.INSTANCE.get(is.getItem());
|
||||
if (newBurnTime > 0 && is.getCount() > 0) {
|
||||
final Integer newBurnTime = FuelRegistry.INSTANCE.get(is.getItem());
|
||||
if (newBurnTime != null && is.getCount() > 0) {
|
||||
this.setBurnTime(this.getBurnTime() + newBurnTime);
|
||||
this.setMaxBurnTime(this.getBurnTime());
|
||||
|
||||
@@ -270,15 +273,4 @@ public class VibrationChamberBlockEntity extends AENetworkInvBlockEntity impleme
|
||||
this.burnTime = burnTime;
|
||||
}
|
||||
|
||||
private static class FuelSlotFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return FuelRegistry.INSTANCE.get(inv.getInvStack(slot).getItem()) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
return FuelRegistry.INSTANCE.get(stack.getItem()) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import net.minecraft.world.World;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.LimitedFixedItemInv;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.PowerMultiplier;
|
||||
@@ -51,18 +52,20 @@ import appeng.tile.inventory.AppEngInternalInventory;
|
||||
import appeng.util.IWorldCallable;
|
||||
import appeng.util.Platform;
|
||||
import appeng.util.inv.InvOperation;
|
||||
import appeng.util.inv.WrapperFilteredItemHandler;
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
|
||||
public class SpatialIOPortBlockEntity extends AENetworkInvBlockEntity implements IWorldCallable<Void> {
|
||||
|
||||
private final AppEngInternalInventory inv = new AppEngInternalInventory(this, 2);
|
||||
private final FixedItemInv invExt = new WrapperFilteredItemHandler(this.inv, new SpatialIOFilter());
|
||||
private final LimitedFixedItemInv invExt;
|
||||
private YesNo lastRedstoneState = YesNo.UNDECIDED;
|
||||
|
||||
public SpatialIOPortBlockEntity(BlockEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
this.getProxy().setFlags(GridFlags.REQUIRE_CHANNEL);
|
||||
|
||||
invExt = inv.createLimitedFixedInv();
|
||||
invExt.getRule(0).disallowExtraction().allowInsertion().filterInserts(this::isSpatialCell);
|
||||
invExt.getRule(1).disallowInsertion().allowExtraction();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -186,16 +189,4 @@ public class SpatialIOPortBlockEntity extends AENetworkInvBlockEntity implements
|
||||
|
||||
}
|
||||
|
||||
private class SpatialIOFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return slot == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
return (slot == 0 && SpatialIOPortBlockEntity.this.isSpatialCell(stack));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import net.minecraft.world.World;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.LimitedFixedItemInv;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
import appeng.api.config.FullnessMode;
|
||||
@@ -74,8 +75,6 @@ import appeng.util.helpers.ItemHandlerUtil;
|
||||
import appeng.util.inv.AdaptorFixedInv;
|
||||
import appeng.util.inv.InvOperation;
|
||||
import appeng.util.inv.WrapperChainedItemHandler;
|
||||
import appeng.util.inv.WrapperFilteredItemHandler;
|
||||
import appeng.util.inv.filter.AEItemFilters;
|
||||
|
||||
public class IOPortBlockEntity extends AENetworkInvBlockEntity
|
||||
implements IUpgradeableHost, IConfigManagerHost, IGridTickable {
|
||||
@@ -88,10 +87,8 @@ public class IOPortBlockEntity extends AENetworkInvBlockEntity
|
||||
private final AppEngInternalInventory outputCells = new AppEngInternalInventory(this, NUMBER_OF_CELL_SLOTS);
|
||||
private final FixedItemInv combinedInventory = new WrapperChainedItemHandler(this.inputCells, this.outputCells);
|
||||
|
||||
private final FixedItemInv inputCellsExt = new WrapperFilteredItemHandler(this.inputCells,
|
||||
AEItemFilters.INSERT_ONLY);
|
||||
private final FixedItemInv outputCellsExt = new WrapperFilteredItemHandler(this.outputCells,
|
||||
AEItemFilters.EXTRACT_ONLY);
|
||||
private final LimitedFixedItemInv inputCellsExt;
|
||||
private final LimitedFixedItemInv outputCellsExt;
|
||||
|
||||
private final UpgradeInventory upgrades;
|
||||
private final IActionSource mySrc;
|
||||
@@ -111,6 +108,12 @@ public class IOPortBlockEntity extends AENetworkInvBlockEntity
|
||||
|
||||
final Block ioPortBlock = Api.instance().definitions().blocks().iOPort().maybeBlock().get();
|
||||
this.upgrades = new BlockUpgradeInventory(ioPortBlock, this, NUMBER_OF_UPGRADE_SLOTS);
|
||||
|
||||
inputCellsExt = inputCells.createLimitedFixedInv();
|
||||
inputCellsExt.getAllRule().disallowExtraction();
|
||||
|
||||
outputCellsExt = outputCells.createLimitedFixedInv();
|
||||
outputCellsExt.getAllRule().disallowInsertion();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2017, 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.util.inv;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import alexiil.mc.lib.attributes.Simulation;
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
import alexiil.mc.lib.attributes.item.ItemStackUtil;
|
||||
import alexiil.mc.lib.attributes.item.filter.ItemFilter;
|
||||
import alexiil.mc.lib.attributes.item.impl.DelegatingFixedItemInv;
|
||||
|
||||
import appeng.util.inv.filter.IAEItemFilter;
|
||||
|
||||
// FIXME: Needs to be double checked, LBA has better ways of doing this
|
||||
public class WrapperFilteredItemHandler extends DelegatingFixedItemInv {
|
||||
private final IAEItemFilter filter;
|
||||
|
||||
public WrapperFilteredItemHandler(@Nonnull FixedItemInv handler, @Nonnull IAEItemFilter filter) {
|
||||
super(handler);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setInvStack(int slot, ItemStack to, Simulation simulation) {
|
||||
ItemStack current = this.getInvStack(slot);
|
||||
boolean same = ItemStackUtil.areEqualIgnoreAmounts(current, to);
|
||||
boolean isExtracting = !current.isEmpty() && (!same || to.getCount() < current.getCount());
|
||||
boolean isInserting = !to.isEmpty() && (!same || to.getCount() > current.getCount());
|
||||
|
||||
if (isExtracting) {
|
||||
// We may be extracting by "exchanging" the current item for something else,
|
||||
// or we might be setting it to air
|
||||
int extractAmount = current.getCount();
|
||||
if (same && !to.isEmpty()) {
|
||||
extractAmount -= to.getCount();
|
||||
}
|
||||
|
||||
if (!filter.allowExtract(delegate, slot, extractAmount)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isInserting) {
|
||||
if (!filter.allowInsert(delegate, slot, to)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return super.setInvStack(slot, to, simulation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValidForSlot(int slot, ItemStack stack) {
|
||||
return (stack.isEmpty() || this.getFilterForSlot(slot).matches(stack)) && super.isItemValidForSlot(slot, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemFilter getFilterForSlot(int slot) {
|
||||
ItemFilter parentFilter = super.getFilterForSlot(slot);
|
||||
ItemFilter thisFilter = stack -> filter.allowInsert(delegate, slot, stack);
|
||||
return thisFilter.and(parentFilter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* This file is part of Applied Energistics 2.
|
||||
* Copyright (c) 2013 - 2017, 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.util.inv.filter;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import alexiil.mc.lib.attributes.item.FixedItemInv;
|
||||
|
||||
public class AEItemFilters {
|
||||
public static final IAEItemFilter INSERT_ONLY = new InsertOnlyFilter();
|
||||
public static final IAEItemFilter EXTRACT_ONLY = new ExtractOnlyFilter();
|
||||
|
||||
private AEItemFilters() {
|
||||
}
|
||||
|
||||
private static class InsertOnlyFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExtractOnlyFilter implements IAEItemFilter {
|
||||
@Override
|
||||
public boolean allowExtract(FixedItemInv inv, int slot, int amount) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowInsert(FixedItemInv inv, int slot, ItemStack stack) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import net.minecraft.nbt.CompoundTag;
|
||||
import appeng.api.config.FuzzyMode;
|
||||
|
||||
final class AESharedItemStack implements Comparable<AESharedItemStack> {
|
||||
|
||||
private final ItemStack itemStack;
|
||||
private final int itemId;
|
||||
private final int itemDamage;
|
||||
@@ -97,7 +98,8 @@ final class AESharedItemStack implements Comparable<AESharedItemStack> {
|
||||
return damageValue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return System.identityHashCode(this.getDefinition().getTag())
|
||||
- System.identityHashCode(b.getDefinition().getTag());
|
||||
}
|
||||
|
||||
private int makeHashCode() {
|
||||
@@ -183,4 +185,5 @@ final class AESharedItemStack implements Comparable<AESharedItemStack> {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
"SlotMixin",
|
||||
"TntAccessor",
|
||||
"ServerWorldCustomItemEntityMixin",
|
||||
"BootstrapMixin"
|
||||
"BootstrapMixin",
|
||||
"ItemEntityAccessor",
|
||||
"IngredientAccessor"
|
||||
],
|
||||
"client": [
|
||||
"spatial.SkyRenderMixin",
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"gui.appliedenergistics2.Gray": "Grey",
|
||||
"gui.appliedenergistics2.LightGray": "Light Grey",
|
||||
"gui.appliedenergistics2.inWorldCraftingPresses": "Crafting Presses are found in the centre of meteorites which can be found in around the world, they can be located by using a meteorite compass.",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIAuto": "JEI Synchronised Auto",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIStandard": "JEI Synchronised Standard",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIAuto": "REI Synchronised Auto",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIStandard": "REI Synchronised Standard",
|
||||
"gui.tooltips.appliedenergistics2.TerminalStyle_Small": "Small Centered Terminal",
|
||||
"gui.tooltips.appliedenergistics2.TerminalStyle_Tall": "Tall Centered Terminal",
|
||||
"item.appliedenergistics2.color_applicator": "Colour Applicator"
|
||||
|
||||
@@ -380,10 +380,10 @@
|
||||
"gui.tooltips.appliedenergistics2.SearchMode": "Search Box Mode",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_Auto": "Auto Search",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_AutoKeep": "Auto Search Keep",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIAuto": "JEI Synchronized Auto",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIAutoKeep": "JEI Synchronized Auto Keep",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIStandard": "JEI Synchronized Standard",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIStandardKeep": "JEI Synchronized Standard Keep",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIAuto": "REI Synchronized Auto",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIAutoKeep": "REI Synchronized Auto Keep",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIStandard": "REI Synchronized Standard",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_JEIStandardKeep": "REI Synchronized Standard Keep",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_Standard": "Standard Search",
|
||||
"gui.tooltips.appliedenergistics2.SearchMode_StandardKeep": "Standard Search Keep",
|
||||
"gui.tooltips.appliedenergistics2.Singularity": "Condense Into Singularities\n%s per item",
|
||||
@@ -705,5 +705,9 @@
|
||||
"waila.appliedenergistics2.P2POutput": "Linked (Output Side)",
|
||||
"waila.appliedenergistics2.P2PUnlinked": "Unlinked",
|
||||
"waila.appliedenergistics2.Showing": "Showing",
|
||||
"waila.appliedenergistics2.Unlocked": "Unlocked"
|
||||
"waila.appliedenergistics2.Unlocked": "Unlocked",
|
||||
"jei.appliedenergistics2.missing_id": "Cannot identify recipe",
|
||||
"jei.appliedenergistics2.recipe_too_large": "Recipe larger than 3x3",
|
||||
"jei.appliedenergistics2.requires_processing_mode": "Requires processing mode",
|
||||
"jei.appliedenergistics2.no_output": "Recipe has no output"
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"block.appliedenergistics2.chest": "ME箱子",
|
||||
"block.appliedenergistics2.chiseled_quartz_block": "錾制赛特斯石英块",
|
||||
"block.appliedenergistics2.chiseled_quartz_slab": "錾制赛特斯石英台阶",
|
||||
"block.appliedenergistics2.chiseled_quartz_stairs": "竖纹赛特斯石英楼梯",
|
||||
"block.appliedenergistics2.chiseled_quartz_stairs": "錾制赛特斯石英楼梯",
|
||||
"block.appliedenergistics2.condenser": "物质聚合器",
|
||||
"block.appliedenergistics2.controller": "ME控制器",
|
||||
"block.appliedenergistics2.crafting_accelerator": "并行处理单元",
|
||||
@@ -77,7 +77,7 @@
|
||||
"block.appliedenergistics2.fluid_interface": "ME流体接口",
|
||||
"block.appliedenergistics2.fluix_block": "福鲁伊克斯块",
|
||||
"block.appliedenergistics2.fluix_slab": "福鲁伊克斯台阶",
|
||||
"block.appliedenergistics2.fluix_stairs": "錾制赛特斯石英楼梯",
|
||||
"block.appliedenergistics2.fluix_stairs": "福鲁伊克斯楼梯",
|
||||
"block.appliedenergistics2.grindstone": "石英磨具",
|
||||
"block.appliedenergistics2.inscriber": "压印器",
|
||||
"block.appliedenergistics2.interface": "ME接口",
|
||||
@@ -92,11 +92,11 @@
|
||||
"block.appliedenergistics2.quartz_glass": "石英玻璃",
|
||||
"block.appliedenergistics2.quartz_growth_accelerator": "晶体催生器",
|
||||
"block.appliedenergistics2.quartz_ore": "赛特斯石英矿石",
|
||||
"block.appliedenergistics2.quartz_pillar": "赛特斯竖纹石英块",
|
||||
"block.appliedenergistics2.quartz_pillar": "竖纹赛特斯石英块",
|
||||
"block.appliedenergistics2.quartz_pillar_slab": "竖纹赛特斯石英台阶",
|
||||
"block.appliedenergistics2.quartz_pillar_stairs": "赛特斯石英楼梯",
|
||||
"block.appliedenergistics2.quartz_pillar_stairs": "竖纹赛特斯石英楼梯",
|
||||
"block.appliedenergistics2.quartz_slab": "赛特斯石英台阶",
|
||||
"block.appliedenergistics2.quartz_stairs": "福鲁伊克斯楼梯",
|
||||
"block.appliedenergistics2.quartz_stairs": "赛特斯石英楼梯",
|
||||
"block.appliedenergistics2.quartz_vibrant_glass": "聚能石英玻璃",
|
||||
"block.appliedenergistics2.security_station": "ME安全终端",
|
||||
"block.appliedenergistics2.sky_compass": "陨石罗盘",
|
||||
@@ -407,28 +407,28 @@
|
||||
"item.appliedenergistics2.annihilation_plane": "ME破坏面板",
|
||||
"item.appliedenergistics2.basic_card": "基础卡",
|
||||
"item.appliedenergistics2.biometric_card": "身份卡",
|
||||
"item.appliedenergistics2.black_covered_cable": "黑色 ME包层线缆",
|
||||
"item.appliedenergistics2.black_covered_dense_cable": "黑色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.black_glass_cable": "黑色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.black_lumen_paint_ball": "黑色 光通 染色球",
|
||||
"item.appliedenergistics2.black_paint_ball": "黑色 染色球",
|
||||
"item.appliedenergistics2.black_smart_cable": "黑色 ME智能线缆",
|
||||
"item.appliedenergistics2.black_smart_dense_cable": "黑色 ME致密线缆",
|
||||
"item.appliedenergistics2.black_covered_cable": "ME包层线缆(黑色)",
|
||||
"item.appliedenergistics2.black_covered_dense_cable": "ME致密包层线缆(黑色)",
|
||||
"item.appliedenergistics2.black_glass_cable": "ME玻璃线缆(黑色)",
|
||||
"item.appliedenergistics2.black_lumen_paint_ball": "光通染色球(黑色)",
|
||||
"item.appliedenergistics2.black_paint_ball": "染色球(黑色)",
|
||||
"item.appliedenergistics2.black_smart_cable": "ME智能线缆(黑色)",
|
||||
"item.appliedenergistics2.black_smart_dense_cable": "ME致密线缆(黑色)",
|
||||
"item.appliedenergistics2.blank_pattern": "空白样板",
|
||||
"item.appliedenergistics2.blue_covered_cable": "蓝色 ME包层线缆",
|
||||
"item.appliedenergistics2.blue_covered_dense_cable": "蓝色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.blue_glass_cable": "蓝色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.blue_lumen_paint_ball": "蓝色 光通 染色球",
|
||||
"item.appliedenergistics2.blue_paint_ball": "蓝色 染色球",
|
||||
"item.appliedenergistics2.blue_smart_cable": "蓝色 ME智能线缆",
|
||||
"item.appliedenergistics2.blue_smart_dense_cable": "蓝色 ME致密线缆",
|
||||
"item.appliedenergistics2.brown_covered_cable": "棕色 ME包层线缆",
|
||||
"item.appliedenergistics2.brown_covered_dense_cable": "棕色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.brown_glass_cable": "棕色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.brown_lumen_paint_ball": "棕色 光通 染色球",
|
||||
"item.appliedenergistics2.brown_paint_ball": "棕色 染色球",
|
||||
"item.appliedenergistics2.brown_smart_cable": "棕色 ME智能线缆",
|
||||
"item.appliedenergistics2.brown_smart_dense_cable": "棕色 ME致密线缆",
|
||||
"item.appliedenergistics2.blue_covered_cable": "ME包层线缆(蓝色)",
|
||||
"item.appliedenergistics2.blue_covered_dense_cable": "ME致密包层线缆(蓝色)",
|
||||
"item.appliedenergistics2.blue_glass_cable": "ME玻璃线缆(蓝色)",
|
||||
"item.appliedenergistics2.blue_lumen_paint_ball": "光通染色球(蓝色)",
|
||||
"item.appliedenergistics2.blue_paint_ball": "染色球(蓝色)",
|
||||
"item.appliedenergistics2.blue_smart_cable": "ME智能线缆(蓝色)",
|
||||
"item.appliedenergistics2.blue_smart_dense_cable": "ME致密线缆(蓝色)",
|
||||
"item.appliedenergistics2.brown_covered_cable": "ME包层线缆(棕色)",
|
||||
"item.appliedenergistics2.brown_covered_dense_cable": "棕色 ME致密包层线缆(棕色)",
|
||||
"item.appliedenergistics2.brown_glass_cable": "ME玻璃线缆(棕色)",
|
||||
"item.appliedenergistics2.brown_lumen_paint_ball": "光通染色球(棕色)",
|
||||
"item.appliedenergistics2.brown_paint_ball": "染色球(棕色)",
|
||||
"item.appliedenergistics2.brown_smart_cable": "ME智能线缆(棕色)",
|
||||
"item.appliedenergistics2.brown_smart_dense_cable": "ME致密线缆(棕色)",
|
||||
"item.appliedenergistics2.cable_anchor": "线缆锚",
|
||||
"item.appliedenergistics2.cable_fluid_interface": "ME流体接口",
|
||||
"item.appliedenergistics2.cable_interface": "ME接口",
|
||||
@@ -458,13 +458,13 @@
|
||||
"item.appliedenergistics2.crafting_monitor": "ME合成监控器",
|
||||
"item.appliedenergistics2.crafting_terminal": "ME合成终端",
|
||||
"item.appliedenergistics2.creative_storage_cell": "创造型ME存储元件",
|
||||
"item.appliedenergistics2.cyan_covered_cable": "青色 ME包层线缆",
|
||||
"item.appliedenergistics2.cyan_covered_dense_cable": "青色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.cyan_glass_cable": "青色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.cyan_lumen_paint_ball": "青色 光通 染色球",
|
||||
"item.appliedenergistics2.cyan_paint_ball": "青色 染色球",
|
||||
"item.appliedenergistics2.cyan_smart_cable": "青色 ME智能线缆",
|
||||
"item.appliedenergistics2.cyan_smart_dense_cable": "青色 ME致密线缆",
|
||||
"item.appliedenergistics2.cyan_covered_cable": "ME包层线缆(青色)",
|
||||
"item.appliedenergistics2.cyan_covered_dense_cable": "ME致密包层线缆(青色)",
|
||||
"item.appliedenergistics2.cyan_glass_cable": "ME玻璃线缆(青色)",
|
||||
"item.appliedenergistics2.cyan_lumen_paint_ball": "光通染色球(青色)",
|
||||
"item.appliedenergistics2.cyan_paint_ball": "染色球(青色)",
|
||||
"item.appliedenergistics2.cyan_smart_cable": "ME智能线缆(青色)",
|
||||
"item.appliedenergistics2.cyan_smart_dense_cable": "ME致密线缆(青色)",
|
||||
"item.appliedenergistics2.dark_monitor": "暗色照明面板",
|
||||
"item.appliedenergistics2.debug_card": "Dev.调试卡",
|
||||
"item.appliedenergistics2.debug_replicator_card": "Dev.复制卡",
|
||||
@@ -477,7 +477,7 @@
|
||||
"item.appliedenergistics2.entropy_manipulator": "熵变机械臂",
|
||||
"item.appliedenergistics2.export_bus": "ME输出总线",
|
||||
"item.appliedenergistics2.facade": "线缆伪装板",
|
||||
"item.appliedenergistics2.fe_p2p_tunnel": "FE P2P通道",
|
||||
"item.appliedenergistics2.fe_p2p_tunnel": "P2P通道-FE",
|
||||
"item.appliedenergistics2.flour": "面粉",
|
||||
"item.appliedenergistics2.fluid_annihilation_plane": "ME流体破坏面板",
|
||||
"item.appliedenergistics2.16k_fluid_cell_component": "16k-ME流体存储组件",
|
||||
@@ -488,43 +488,43 @@
|
||||
"item.appliedenergistics2.fluid_formation_plane": "ME流体成型面板",
|
||||
"item.appliedenergistics2.fluid_import_bus": "ME流体输入总线",
|
||||
"item.appliedenergistics2.fluid_level_emitter": "ME流体标准发信器",
|
||||
"item.appliedenergistics2.fluid_p2p_tunnel": "流体 P2P通道",
|
||||
"item.appliedenergistics2.fluid_storage_bus": "ME流体储存总线",
|
||||
"item.appliedenergistics2.fluid_p2p_tunnel": "P2P通道-流体",
|
||||
"item.appliedenergistics2.fluid_storage_bus": "ME流体存储总线",
|
||||
"item.appliedenergistics2.16k_fluid_storage_cell": "16k-ME流体储存元件",
|
||||
"item.appliedenergistics2.1k_fluid_storage_cell": "1k-ME流体储存元件",
|
||||
"item.appliedenergistics2.4k_fluid_storage_cell": "4k-ME流体储存元件",
|
||||
"item.appliedenergistics2.64k_fluid_storage_cell": "64k-ME流体储存元件",
|
||||
"item.appliedenergistics2.fluid_terminal": "ME流体终端",
|
||||
"item.appliedenergistics2.fluix_covered_cable": "Fluix默认色 ME包层线缆",
|
||||
"item.appliedenergistics2.fluix_covered_dense_cable": "Fluix默认色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.fluix_covered_cable": "ME包层线缆(Fluix默认色)",
|
||||
"item.appliedenergistics2.fluix_covered_dense_cable": "ME致密包层线缆(Fluix默认色)",
|
||||
"item.appliedenergistics2.fluix_crystal": "福鲁伊克斯水晶",
|
||||
"item.appliedenergistics2.fluix_crystal_seed": "福鲁伊克斯种子",
|
||||
"item.appliedenergistics2.fluix_dust": "福鲁伊克斯粉",
|
||||
"item.appliedenergistics2.fluix_glass_cable": "Fluix默认色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.fluix_lumen_paint_ball": "Fluix默认色 光通 染色球",
|
||||
"item.appliedenergistics2.fluix_paint_ball": "Fluix默认色 染色球",
|
||||
"item.appliedenergistics2.fluix_glass_cable": "ME玻璃线缆(Fluix默认色)",
|
||||
"item.appliedenergistics2.fluix_lumen_paint_ball": "光通染色球(Fluix默认色)",
|
||||
"item.appliedenergistics2.fluix_paint_ball": "色球(Fluix默认色)",
|
||||
"item.appliedenergistics2.fluix_pearl": "福鲁伊克斯珍珠",
|
||||
"item.appliedenergistics2.fluix_smart_cable": "Fluix默认色 ME智能线缆",
|
||||
"item.appliedenergistics2.fluix_smart_dense_cable": "Fluix默认色 ME致密线缆",
|
||||
"item.appliedenergistics2.fluix_smart_cable": "ME智能线缆(Fluix默认色)",
|
||||
"item.appliedenergistics2.fluix_smart_dense_cable": "ME致密线缆(Fluix默认色)",
|
||||
"item.appliedenergistics2.formation_core": "成型核心",
|
||||
"item.appliedenergistics2.formation_plane": "ME成型面板",
|
||||
"item.appliedenergistics2.fuzzy_card": "模糊卡",
|
||||
"item.appliedenergistics2.gold_dust": "金粉",
|
||||
"item.appliedenergistics2.gray_covered_cable": "灰色 ME包层线缆",
|
||||
"item.appliedenergistics2.gray_covered_dense_cable": "灰色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.gray_glass_cable": "灰色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.gray_lumen_paint_ball": "灰色 光通 染色球",
|
||||
"item.appliedenergistics2.gray_paint_ball": "灰色 染色球",
|
||||
"item.appliedenergistics2.gray_smart_cable": "灰色 ME智能线缆",
|
||||
"item.appliedenergistics2.gray_smart_dense_cable": "灰色 ME致密线缆",
|
||||
"item.appliedenergistics2.green_covered_cable": "绿色 ME包层线缆",
|
||||
"item.appliedenergistics2.green_covered_dense_cable": "绿色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.green_glass_cable": "绿色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.green_lumen_paint_ball": "绿色 光通 染色球",
|
||||
"item.appliedenergistics2.green_paint_ball": "绿色 染色球",
|
||||
"item.appliedenergistics2.green_smart_cable": "绿色 ME智能线缆",
|
||||
"item.appliedenergistics2.green_smart_dense_cable": "绿色 ME致密线缆",
|
||||
"item.appliedenergistics2.ic2_p2p_tunnel": "EU P2P通道",
|
||||
"item.appliedenergistics2.gray_covered_cable": "ME包层线缆(灰色)",
|
||||
"item.appliedenergistics2.gray_covered_dense_cable": "ME致密包层线缆(灰色)",
|
||||
"item.appliedenergistics2.gray_glass_cable": "ME玻璃线缆(灰色)",
|
||||
"item.appliedenergistics2.gray_lumen_paint_ball": "光通染色球(灰色)",
|
||||
"item.appliedenergistics2.gray_paint_ball": "染色球(灰色)",
|
||||
"item.appliedenergistics2.gray_smart_cable": "ME智能线缆(灰色)",
|
||||
"item.appliedenergistics2.gray_smart_dense_cable": "ME致密线缆(灰色)",
|
||||
"item.appliedenergistics2.green_covered_cable": "ME包层线缆(绿色)",
|
||||
"item.appliedenergistics2.green_covered_dense_cable": "ME致密包层线缆(绿色)",
|
||||
"item.appliedenergistics2.green_glass_cable": "ME玻璃线缆(绿色)",
|
||||
"item.appliedenergistics2.green_lumen_paint_ball": "光通染色球(绿色)",
|
||||
"item.appliedenergistics2.green_paint_ball": "染色球(绿色)",
|
||||
"item.appliedenergistics2.green_smart_cable": "ME智能线缆(绿色)",
|
||||
"item.appliedenergistics2.green_smart_dense_cable": "ME致密线缆(绿色)",
|
||||
"item.appliedenergistics2.ic2_p2p_tunnel": "P2P通道-EU",
|
||||
"item.appliedenergistics2.identity_annihilation_plane": "ME精准破坏面板",
|
||||
"item.appliedenergistics2.import_bus": "ME输入总线",
|
||||
"item.appliedenergistics2.interface_terminal": "ME接口终端",
|
||||
@@ -532,44 +532,44 @@
|
||||
"item.appliedenergistics2.inverted_toggle_bus": "ME反相触发总线",
|
||||
"item.appliedenergistics2.inverter_card": "反相卡",
|
||||
"item.appliedenergistics2.iron_dust": "铁粉",
|
||||
"item.appliedenergistics2.item_p2p_tunnel": "物品 P2P通道",
|
||||
"item.appliedenergistics2.item_p2p_tunnel": "P2P通道-物品",
|
||||
"item.appliedenergistics2.level_emitter": "ME标准发信器",
|
||||
"item.appliedenergistics2.light_blue_covered_cable": "浅蓝色 ME包层线缆",
|
||||
"item.appliedenergistics2.light_blue_covered_dense_cable": "浅蓝色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.light_blue_glass_cable": "浅蓝色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.light_blue_lumen_paint_ball": "浅蓝色 光通 染色球",
|
||||
"item.appliedenergistics2.light_blue_paint_ball": "浅蓝色 染色球",
|
||||
"item.appliedenergistics2.light_blue_smart_cable": "浅蓝色 ME智能线缆",
|
||||
"item.appliedenergistics2.light_blue_smart_dense_cable": "浅蓝色 ME致密线缆",
|
||||
"item.appliedenergistics2.light_gray_covered_cable": "浅灰色 ME包层线缆",
|
||||
"item.appliedenergistics2.light_gray_covered_dense_cable": "浅灰色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.light_gray_glass_cable": "浅灰色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.light_gray_lumen_paint_ball": "浅灰色 光通 染色球",
|
||||
"item.appliedenergistics2.light_gray_paint_ball": "浅灰色 染色球",
|
||||
"item.appliedenergistics2.light_gray_smart_cable": "浅灰色 ME智能线缆",
|
||||
"item.appliedenergistics2.light_gray_smart_dense_cable": "浅灰色 ME致密线缆",
|
||||
"item.appliedenergistics2.light_p2p_tunnel": "光 P2P通道",
|
||||
"item.appliedenergistics2.lime_covered_cable": "柠檬色 ME包层线缆",
|
||||
"item.appliedenergistics2.lime_covered_dense_cable": "柠檬色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.lime_glass_cable": "柠檬色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.lime_lumen_paint_ball": "柠檬色 光通 染色球",
|
||||
"item.appliedenergistics2.lime_paint_ball": "柠檬色 染色球",
|
||||
"item.appliedenergistics2.lime_smart_cable": "柠檬色 ME智能线缆",
|
||||
"item.appliedenergistics2.lime_smart_dense_cable": "柠檬色 ME致密线缆",
|
||||
"item.appliedenergistics2.light_blue_covered_cable": "ME包层线缆(浅蓝色)",
|
||||
"item.appliedenergistics2.light_blue_covered_dense_cable": "ME致密包层线缆(浅蓝色)",
|
||||
"item.appliedenergistics2.light_blue_glass_cable": "ME玻璃线缆(浅蓝色)",
|
||||
"item.appliedenergistics2.light_blue_lumen_paint_ball": "光通染色球(浅蓝色)",
|
||||
"item.appliedenergistics2.light_blue_paint_ball": "染色球(浅蓝色)",
|
||||
"item.appliedenergistics2.light_blue_smart_cable": "ME智能线缆(浅蓝色)",
|
||||
"item.appliedenergistics2.light_blue_smart_dense_cable": "ME致密线缆(浅蓝色)",
|
||||
"item.appliedenergistics2.light_gray_covered_cable": "ME包层线缆(浅灰色)",
|
||||
"item.appliedenergistics2.light_gray_covered_dense_cable": "ME致密包层线缆(浅灰色)",
|
||||
"item.appliedenergistics2.light_gray_glass_cable": "ME玻璃线缆(浅灰色)",
|
||||
"item.appliedenergistics2.light_gray_lumen_paint_ball": "光通染色球(浅灰色)",
|
||||
"item.appliedenergistics2.light_gray_paint_ball": "染色球(浅灰色)",
|
||||
"item.appliedenergistics2.light_gray_smart_cable": "ME智能线缆(浅灰色)",
|
||||
"item.appliedenergistics2.light_gray_smart_dense_cable": "ME致密线缆(浅灰色)",
|
||||
"item.appliedenergistics2.light_p2p_tunnel": "P2P通道-光",
|
||||
"item.appliedenergistics2.lime_covered_cable": "ME包层线缆(柠檬色)",
|
||||
"item.appliedenergistics2.lime_covered_dense_cable": "ME致密包层线缆(柠檬色)",
|
||||
"item.appliedenergistics2.lime_glass_cable": "ME玻璃线缆(柠檬色)",
|
||||
"item.appliedenergistics2.lime_lumen_paint_ball": "光通染色球(柠檬色)",
|
||||
"item.appliedenergistics2.lime_paint_ball": "染色球(柠檬色)",
|
||||
"item.appliedenergistics2.lime_smart_cable": "ME智能线缆(柠檬色)",
|
||||
"item.appliedenergistics2.lime_smart_dense_cable": "ME致密线缆(柠檬色)",
|
||||
"item.appliedenergistics2.logic_processor": "逻辑处理器",
|
||||
"item.appliedenergistics2.logic_processor_asm": "半成品-逻辑处理器",
|
||||
"item.appliedenergistics2.logic_processor_press": "逻辑压印模板",
|
||||
"item.appliedenergistics2.printed_logic_processor": "逻辑电路板",
|
||||
"item.appliedenergistics2.magenta_covered_cable": "品红色 ME包层线缆",
|
||||
"item.appliedenergistics2.magenta_covered_dense_cable": "品红色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.magenta_glass_cable": "品红色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.magenta_lumen_paint_ball": "品红色 光通 染色球",
|
||||
"item.appliedenergistics2.magenta_paint_ball": "品红色 染色球",
|
||||
"item.appliedenergistics2.magenta_smart_cable": "品红色 ME智能线缆",
|
||||
"item.appliedenergistics2.magenta_smart_dense_cable": "品红色 ME致密线缆",
|
||||
"item.appliedenergistics2.magenta_covered_cable": "ME包层线缆(品红色)",
|
||||
"item.appliedenergistics2.magenta_covered_dense_cable": "ME致密包层线缆(品红色)",
|
||||
"item.appliedenergistics2.magenta_glass_cable": "ME玻璃线缆(品红色)",
|
||||
"item.appliedenergistics2.magenta_lumen_paint_ball": "光通染色球(品红色)",
|
||||
"item.appliedenergistics2.magenta_paint_ball": "染色球(品红色)",
|
||||
"item.appliedenergistics2.magenta_smart_cable": "ME智能线缆(品红色)",
|
||||
"item.appliedenergistics2.magenta_smart_dense_cable": "ME致密线缆(品红色)",
|
||||
"item.appliedenergistics2.matter_ball": "物质球",
|
||||
"item.appliedenergistics2.matter_cannon": "物质炮",
|
||||
"item.appliedenergistics2.me_p2p_tunnel": "ME P2P通道",
|
||||
"item.appliedenergistics2.me_p2p_tunnel": "P2P通道-ME",
|
||||
"item.appliedenergistics2.memory_card": "内存卡",
|
||||
"item.appliedenergistics2.monitor": "亮色照明面板",
|
||||
"item.appliedenergistics2.name_press": "名称压印模板",
|
||||
@@ -583,43 +583,43 @@
|
||||
"item.appliedenergistics2.nether_quartz_sword": "下界石英剑",
|
||||
"item.appliedenergistics2.nether_quartz_wrench": "下界石英扳手",
|
||||
"item.appliedenergistics2.network_tool": "网络工具",
|
||||
"item.appliedenergistics2.orange_covered_cable": "橙色 ME包层线缆",
|
||||
"item.appliedenergistics2.orange_covered_dense_cable": "橙色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.orange_glass_cable": "橙色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.orange_lumen_paint_ball": "橙色 光通 染色球",
|
||||
"item.appliedenergistics2.orange_paint_ball": "橙色 染色球",
|
||||
"item.appliedenergistics2.orange_smart_cable": "橙色 ME智能线缆",
|
||||
"item.appliedenergistics2.orange_smart_dense_cable": "橙色 ME致密线缆",
|
||||
"item.appliedenergistics2.orange_covered_cable": "ME包层线缆(橙色)",
|
||||
"item.appliedenergistics2.orange_covered_dense_cable": "ME致密包层线缆(橙色)",
|
||||
"item.appliedenergistics2.orange_glass_cable": "ME玻璃线缆(橙色)",
|
||||
"item.appliedenergistics2.orange_lumen_paint_ball": "光通染色球(橙色)",
|
||||
"item.appliedenergistics2.orange_paint_ball": "染色球(橙色)",
|
||||
"item.appliedenergistics2.orange_smart_cable": "ME智能线缆(橙色)",
|
||||
"item.appliedenergistics2.orange_smart_dense_cable": "ME致密线缆(橙色)",
|
||||
"item.appliedenergistics2.pattern_terminal": "ME样板终端",
|
||||
"item.appliedenergistics2.pink_covered_cable": "粉色 ME包层线缆",
|
||||
"item.appliedenergistics2.pink_covered_dense_cable": "粉色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.pink_glass_cable": "粉色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.pink_lumen_paint_ball": "粉色 光通 染色球",
|
||||
"item.appliedenergistics2.pink_paint_ball": "粉色 染色球",
|
||||
"item.appliedenergistics2.pink_smart_cable": "粉色 ME智能线缆",
|
||||
"item.appliedenergistics2.pink_smart_dense_cable": "粉色 ME致密线缆",
|
||||
"item.appliedenergistics2.pink_covered_cable": "ME包层线缆(粉色)",
|
||||
"item.appliedenergistics2.pink_covered_dense_cable": "ME致密包层线缆(粉色)",
|
||||
"item.appliedenergistics2.pink_glass_cable": "ME玻璃线缆(粉色)",
|
||||
"item.appliedenergistics2.pink_lumen_paint_ball": "光通染色球(粉色)",
|
||||
"item.appliedenergistics2.pink_paint_ball": "染色球(粉色)",
|
||||
"item.appliedenergistics2.pink_smart_cable": "ME智能线缆(粉色)",
|
||||
"item.appliedenergistics2.pink_smart_dense_cable": "ME致密线缆(粉色)",
|
||||
"item.appliedenergistics2.portable_cell": "便携元件",
|
||||
"item.appliedenergistics2.purified_certus_quartz_crystal": "高纯赛特斯石英水晶",
|
||||
"item.appliedenergistics2.purified_fluix_crystal": "高纯福鲁伊克斯水晶",
|
||||
"item.appliedenergistics2.purified_nether_quartz_crystal": "高纯下界石英水晶",
|
||||
"item.appliedenergistics2.purple_covered_cable": "紫色 ME包层线缆",
|
||||
"item.appliedenergistics2.purple_covered_dense_cable": "紫色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.purple_glass_cable": "紫色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.purple_lumen_paint_ball": "紫色 光通 染色球",
|
||||
"item.appliedenergistics2.purple_paint_ball": "紫色 染色球",
|
||||
"item.appliedenergistics2.purple_smart_cable": "紫色 ME智能线缆",
|
||||
"item.appliedenergistics2.purple_smart_dense_cable": "紫色 ME致密线缆",
|
||||
"item.appliedenergistics2.purple_covered_cable": "ME包层线缆(紫色)",
|
||||
"item.appliedenergistics2.purple_covered_dense_cable": "ME致密包层线缆(紫色)",
|
||||
"item.appliedenergistics2.purple_glass_cable": "ME玻璃线缆(紫色)",
|
||||
"item.appliedenergistics2.purple_lumen_paint_ball": "光通染色球(紫色)",
|
||||
"item.appliedenergistics2.purple_paint_ball": "染色球(紫色)",
|
||||
"item.appliedenergistics2.purple_smart_cable": "ME智能线缆(紫色)",
|
||||
"item.appliedenergistics2.purple_smart_dense_cable": "ME致密线缆(紫色)",
|
||||
"item.appliedenergistics2.quantum_entangled_singularity": "量子缠绕态奇点",
|
||||
"item.appliedenergistics2.quartz_fiber": "石英纤维",
|
||||
"item.appliedenergistics2.red_covered_cable": "红色 ME包层线缆",
|
||||
"item.appliedenergistics2.red_covered_dense_cable": "红色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.red_glass_cable": "红色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.red_lumen_paint_ball": "红色 光通 染色球",
|
||||
"item.appliedenergistics2.red_paint_ball": "红色 染色球",
|
||||
"item.appliedenergistics2.red_smart_cable": "红色 ME智能线缆",
|
||||
"item.appliedenergistics2.red_smart_dense_cable": "红色 ME致密线缆",
|
||||
"item.appliedenergistics2.red_covered_cable": "ME包层线缆(红色)",
|
||||
"item.appliedenergistics2.red_covered_dense_cable": "ME致密包层线缆(红色)",
|
||||
"item.appliedenergistics2.red_glass_cable": "ME玻璃线缆(红色)",
|
||||
"item.appliedenergistics2.red_lumen_paint_ball": "光通染色球(红色)",
|
||||
"item.appliedenergistics2.red_paint_ball": "染色球(红色)",
|
||||
"item.appliedenergistics2.red_smart_cable": "ME智能线缆(红色)",
|
||||
"item.appliedenergistics2.red_smart_dense_cable": "ME致密线缆(红色)",
|
||||
"item.appliedenergistics2.redstone_card": "红石卡",
|
||||
"item.appliedenergistics2.redstone_p2p_tunnel": "红石 P2P通道",
|
||||
"item.appliedenergistics2.redstone_p2p_tunnel": "P2P通道-红石",
|
||||
"item.appliedenergistics2.semi_dark_monitor": "照明面板",
|
||||
"item.appliedenergistics2.silicon": "硅",
|
||||
"item.appliedenergistics2.silicon_press": "硅压印模板",
|
||||
@@ -642,24 +642,24 @@
|
||||
"item.appliedenergistics2.terminal": "ME终端",
|
||||
"item.appliedenergistics2.toggle_bus": "ME触发总线",
|
||||
"item.appliedenergistics2.view_cell": "显示元件",
|
||||
"item.appliedenergistics2.white_covered_cable": "白色 ME包层线缆",
|
||||
"item.appliedenergistics2.white_covered_dense_cable": "白色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.white_glass_cable": "白色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.white_lumen_paint_ball": "白色 光通 染色球",
|
||||
"item.appliedenergistics2.white_paint_ball": "白色 染色球",
|
||||
"item.appliedenergistics2.white_smart_cable": "白色 ME智能线缆",
|
||||
"item.appliedenergistics2.white_smart_dense_cable": "白色 ME致密线缆",
|
||||
"item.appliedenergistics2.white_covered_cable": "ME包层线缆(白色)",
|
||||
"item.appliedenergistics2.white_covered_dense_cable": "ME致密包层线缆(白色)",
|
||||
"item.appliedenergistics2.white_glass_cable": "ME玻璃线缆(白色)",
|
||||
"item.appliedenergistics2.white_lumen_paint_ball": "光通染色球(白色)",
|
||||
"item.appliedenergistics2.white_paint_ball": "染色球(白色)",
|
||||
"item.appliedenergistics2.white_smart_cable": "ME智能线缆(白色)",
|
||||
"item.appliedenergistics2.white_smart_dense_cable": "ME致密线缆(白色)",
|
||||
"item.appliedenergistics2.wireless_booster": "无线信号增幅器",
|
||||
"item.appliedenergistics2.wireless_receiver": "无线接收器",
|
||||
"item.appliedenergistics2.wireless_terminal": "无线终端",
|
||||
"item.appliedenergistics2.wooden_gear": "木齿轮",
|
||||
"item.appliedenergistics2.yellow_covered_cable": "黄色 ME包层线缆",
|
||||
"item.appliedenergistics2.yellow_covered_dense_cable": "黄色 ME致密包层线缆",
|
||||
"item.appliedenergistics2.yellow_glass_cable": "黄色 ME玻璃线缆",
|
||||
"item.appliedenergistics2.yellow_lumen_paint_ball": "黄色 光通 染色球",
|
||||
"item.appliedenergistics2.yellow_paint_ball": "黄色 染色球",
|
||||
"item.appliedenergistics2.yellow_smart_cable": "黄色 ME智能线缆",
|
||||
"item.appliedenergistics2.yellow_smart_dense_cable": "黄色 ME致密线缆",
|
||||
"item.appliedenergistics2.yellow_covered_cable": "ME包层线缆(黄色)",
|
||||
"item.appliedenergistics2.yellow_covered_dense_cable": "ME致密包层线缆(黄色)",
|
||||
"item.appliedenergistics2.yellow_glass_cable": "ME玻璃线缆(黄色)",
|
||||
"item.appliedenergistics2.yellow_lumen_paint_ball": "光通染色球(黄色)",
|
||||
"item.appliedenergistics2.yellow_paint_ball": "染色球(黄色)",
|
||||
"item.appliedenergistics2.yellow_smart_cable": "ME智能线缆(黄色)",
|
||||
"item.appliedenergistics2.yellow_smart_dense_cable": "ME致密线缆(黄色)",
|
||||
"itemGroup.appliedenergistics2": "应用能源2",
|
||||
"itemGroup.appliedenergistics2.facades": "应用能源2-伪装板",
|
||||
"key.appliedenergistics2.category": "Applied Energistics 2",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"display": {
|
||||
"icon": {
|
||||
"item": "appliedenergistics2:facade"
|
||||
"item": "appliedenergistics2:facade",
|
||||
"nbt": "{item:\"minecraft:stone\"}"
|
||||
},
|
||||
"title": {
|
||||
"translate": "achievement.ae2.Facade"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"sources": "https://github.com/AppliedEnergistics/Applied-Energistics-2/"
|
||||
},
|
||||
"license": "LGPL",
|
||||
"icon": "assets/appliedenergistics2/icon.png",
|
||||
"icon": "assets/appliedenergistics2/logo.png",
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"client": ["appeng.core.AppEngClientStartup"],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user