Compare commits
60 Commits
v8.0.0-beta.1
...
metrics
| Author | SHA1 | Date | |
|---|---|---|---|
| 53f7046f93 | |||
| 44544c598f | |||
| bcee2ec427 | |||
| 9e41d543f5 | |||
| 81cc0b804d | |||
| e1fc9908b3 | |||
| 9ed1535477 | |||
| 1ef345d4a4 | |||
| ff7d1b9719 | |||
| 88c9370e4f | |||
| f2aae3ef0f | |||
| 12739f1e66 | |||
| 81d2170ada | |||
| 0f469e9df6 | |||
| 0f34f09b32 | |||
| 8e54a8fed9 | |||
| d9bb81a00f | |||
| 39e038d916 | |||
| 12ca8d109a | |||
| f0d0595c8f | |||
| b756d68be1 | |||
| 60b07e5ca5 | |||
| 7c99fca789 | |||
| ab393b0ed1 | |||
| 957bc4c5cc | |||
| 133ed1f09d | |||
| e90dd2f9c6 | |||
| 9719c7ffc3 | |||
| 319d92a371 | |||
| db9ec2b070 | |||
| 3a0552c56e | |||
| 8a0dd192e5 | |||
| a97b35f3d0 | |||
| 00d4c20d9f | |||
| 1394ab0863 | |||
| 5efc085693 | |||
| 159f4c7f14 | |||
| aff94cec8c | |||
| ee7fe9f40d | |||
| 2184d03d0b | |||
| 9c9a49f9e7 | |||
| 44c0931c02 | |||
| b7949e4134 | |||
| ea95913ec8 | |||
| 423ab81813 | |||
| 33d7f02323 | |||
| 4e42b17e81 | |||
| b8d4f0cffa | |||
| fc0f8eab56 | |||
| 7e1bfdb5ac | |||
| 41b7900706 | |||
| 1f9707e256 | |||
| 7656157b0d | |||
| 954ce1442e | |||
| ee67c5ea50 | |||
| 73735c5cd5 | |||
| c1713f1682 | |||
| f455fd1994 | |||
| 1657c88681 | |||
| fd67e0e5c6 |
@@ -55,7 +55,15 @@ jobs:
|
||||
KEY_STORE_ALIAS: ${{ secrets.KEY_STORE_ALIAS }}
|
||||
KEY_STORE_KEY_PASS: ${{ secrets.KEY_STORE_KEY_PASS }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: ./gradlew publish --no-daemon --max-workers 1
|
||||
run: ./gradlew publishMavenPublicationToGitHubPackagesRepository --no-daemon --max-workers 1
|
||||
- name: Publish to modmaven
|
||||
env:
|
||||
KEY_STORE_PASS: ${{ secrets.KEY_STORE_PASS }}
|
||||
KEY_STORE_ALIAS: ${{ secrets.KEY_STORE_ALIAS }}
|
||||
KEY_STORE_KEY_PASS: ${{ secrets.KEY_STORE_KEY_PASS }}
|
||||
MODMAVEN_USER: ${{ secrets.MODMAVEN_USER }}
|
||||
MODMAVEN_PASSWORD: ${{ secrets.MODMAVEN_PASSWORD }}
|
||||
run: ./gradlew publishMavenPublicationToModmavenRepository --no-daemon --max-workers 1
|
||||
- name: Prepare artifact metadata
|
||||
id: prepare_artifact_metadata
|
||||
run: |
|
||||
|
||||
@@ -72,12 +72,20 @@ 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'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,13 @@ publishing {
|
||||
groupId = project.group
|
||||
artifactId = project.archivesBaseName
|
||||
version = project.version
|
||||
|
||||
// ForgeGradle will generate wild dependency definitions, see https://github.com/MinecraftForge/ForgeGradle/issues/584
|
||||
// Since we don't actually depend on anything, just remove the entire node.
|
||||
pom.withXml {
|
||||
asNode().remove(asNode().dependencies)
|
||||
}
|
||||
|
||||
from components.java
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
@@ -205,5 +212,13 @@ publishing {
|
||||
name = "GitHubPackages"
|
||||
url = "https://maven.pkg.github.com/AppliedEnergistics/Applied-Energistics-2"
|
||||
}
|
||||
maven {
|
||||
credentials {
|
||||
username System.getenv("MODMAVEN_USER")
|
||||
password System.getenv("MODMAVEN_PASSWORD")
|
||||
}
|
||||
name = "modmaven"
|
||||
url = "https://modmaven.k-4u.nl/artifactory/local-releases/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -9,23 +9,24 @@ artifact_basename=appliedenergistics2
|
||||
# Minecraft Versions #
|
||||
#########################################################
|
||||
minecraft_release=1.16
|
||||
minecraft_version=1.16.1
|
||||
minecraft_version=1.16.2
|
||||
mcp_mappings=20200723-1.16.1
|
||||
forge_version=32.0.108
|
||||
forge_version=33.0.42
|
||||
|
||||
#########################################################
|
||||
# Provided APIs #
|
||||
#########################################################
|
||||
jei_version=7.0.0.6
|
||||
top_version=3.0.1-beta-4
|
||||
jei_minecraft_version=1.16.2
|
||||
jei_version=7.3.2.25
|
||||
top_version=3.0.3-beta-6
|
||||
hwyla_version=1.10.8-B72_1.15.2
|
||||
ctm_version=MC1.15.2-1.1.0.9
|
||||
|
||||
#########################################################
|
||||
# Deployment #
|
||||
#########################################################
|
||||
website_version=1.16.1
|
||||
curse_versions=1.16.1
|
||||
website_version=1.16.2
|
||||
curse_versions=1.16.2
|
||||
curseforge_project=223794
|
||||
|
||||
#########################################################
|
||||
|
||||
@@ -29,11 +29,11 @@ dependencies {
|
||||
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
|
||||
|
||||
// compile against provided APIs
|
||||
compileOnly "mezz.jei:jei-${minecraft_version}:${jei_version}:api"
|
||||
compileOnly "mezz.jei:jei-${jei_minecraft_version}:${jei_version}:api"
|
||||
compileOnly "mcjty.theoneprobe:TheOneProbe-${minecraft_release}:${minecraft_release}-${top_version}:api"
|
||||
|
||||
// Runtime, Mods
|
||||
runtimeOnly fg.deobf("mezz.jei:jei-${minecraft_version}:${jei_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}")
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ public interface ICraftingHelper {
|
||||
* @param stack If null, a new item will be created to hold the encoded pattern.
|
||||
* Otherwise the given item must already contains an encoded
|
||||
* pattern that will be overwritten.
|
||||
* @throws IllegalArgumentException If either in or out contain only empty
|
||||
* ItemStacks.
|
||||
* @return A new encoded pattern, or the given stack with the pattern encoded in
|
||||
* it.
|
||||
*/
|
||||
@@ -73,6 +75,8 @@ public interface ICraftingHelper {
|
||||
* operation by the ME system.
|
||||
* @param allowSubstitutes Controls whether the ME system will allow the use of
|
||||
* equivalent items to craft this recipe.
|
||||
* @throws IllegalArgumentException If either in or out contain only empty
|
||||
* ItemStacks.
|
||||
*/
|
||||
ItemStack encodeCraftingPattern(@Nullable ItemStack stack, ICraftingRecipe recipe, ItemStack[] in, ItemStack out,
|
||||
boolean allowSubstitutes);
|
||||
|
||||
@@ -23,13 +23,23 @@
|
||||
|
||||
package appeng.api.implementations.items;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.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);
|
||||
}
|
||||
|
||||
@@ -27,13 +27,14 @@ import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* Represents a location in the Minecraft Universe
|
||||
*/
|
||||
public class DimensionalCoord extends WorldCoord {
|
||||
|
||||
private final IWorld world;
|
||||
private final World world;
|
||||
private final DimensionType dimension;
|
||||
|
||||
public DimensionalCoord(final DimensionalCoord coordinate) {
|
||||
@@ -48,13 +49,13 @@ public class DimensionalCoord extends WorldCoord {
|
||||
this.dimension = this.world.func_230315_m_();
|
||||
}
|
||||
|
||||
public DimensionalCoord(final IWorld world, final int x, final int y, final int z) {
|
||||
public DimensionalCoord(final World world, final int x, final int y, final int z) {
|
||||
super(x, y, z);
|
||||
this.world = world;
|
||||
this.dimension = world.func_230315_m_();
|
||||
}
|
||||
|
||||
public DimensionalCoord(final IWorld world, final BlockPos pos) {
|
||||
public DimensionalCoord(final World world, final BlockPos pos) {
|
||||
super(pos);
|
||||
this.world = world;
|
||||
this.dimension = world.func_230315_m_();
|
||||
@@ -84,7 +85,7 @@ public class DimensionalCoord extends WorldCoord {
|
||||
return this.world == world;
|
||||
}
|
||||
|
||||
public IWorld getWorld() {
|
||||
public World getWorld() {
|
||||
return this.world;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,11 +111,6 @@ public abstract class AEBaseTileBlock<T extends AEBaseTileEntity> extends AEBase
|
||||
return this.tileEntityFactory.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropXpOnBlockBreak(World worldIn, BlockPos pos, int amount) {
|
||||
super.dropXpOnBlockBreak(worldIn, pos, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReplaced(BlockState state, World w, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
if (newState.getBlock() == state.getBlock()) {
|
||||
|
||||
@@ -79,10 +79,10 @@ class PaintSplotchesBakedModel implements IDynamicBakedModel {
|
||||
|
||||
if (s.isLumen()) {
|
||||
builder.setColorRGB(s.getColor().whiteVariant);
|
||||
builder.setRenderFullBright(true);
|
||||
builder.setEmissiveMaterial(true);
|
||||
} else {
|
||||
builder.setColorRGB(s.getColor().mediumVariant);
|
||||
builder.setRenderFullBright(false);
|
||||
builder.setEmissiveMaterial(false);
|
||||
}
|
||||
|
||||
float offset = offsetConstant;
|
||||
|
||||
@@ -117,7 +117,7 @@ class QnbFormedBakedModel implements IDynamicBakedModel {
|
||||
|
||||
if (formedState.isPowered()) {
|
||||
builder.setTexture(this.lightCornerTexture);
|
||||
builder.setRenderFullBright(true);
|
||||
builder.setEmissiveMaterial(true);
|
||||
for (Direction facing : Direction.values()) {
|
||||
// Offset the face by a slight amount so that it is drawn over the already drawn
|
||||
// ring texture
|
||||
@@ -131,6 +131,7 @@ class QnbFormedBakedModel implements IDynamicBakedModel {
|
||||
DEFAULT_RENDER_MIN - zOffset, DEFAULT_RENDER_MAX + xOffset,
|
||||
DEFAULT_RENDER_MAX + yOffset, DEFAULT_RENDER_MAX + zOffset);
|
||||
}
|
||||
builder.setEmissiveMaterial(false);
|
||||
}
|
||||
} else {
|
||||
builder.setTexture(this.ringTexture);
|
||||
@@ -143,7 +144,7 @@ class QnbFormedBakedModel implements IDynamicBakedModel {
|
||||
|
||||
if (formedState.isPowered()) {
|
||||
builder.setTexture(this.lightTexture);
|
||||
builder.setRenderFullBright(true);
|
||||
builder.setEmissiveMaterial(true);
|
||||
for (Direction facing : Direction.values()) {
|
||||
// Offset the face by a slight amount so that it is drawn over the already drawn
|
||||
// ring texture
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.text.NumberFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
@@ -72,14 +73,16 @@ public abstract class AEBaseMEScreen<T extends AEBaseContainer> extends AEBaseSc
|
||||
currentToolTip.add(ButtonToolTips.ItemsRequestable.text(formattedAmount));
|
||||
}
|
||||
|
||||
this.renderToolTip(matrixStack, currentToolTip, x, y, this.font);
|
||||
this.renderToolTip(matrixStack, Lists.transform(currentToolTip, ITextComponent::func_241878_f), x, y,
|
||||
this.font);
|
||||
|
||||
return;
|
||||
} else if (stack.getCount() > bigNumber) {
|
||||
final String formattedAmount = NumberFormat.getNumberInstance(Locale.US).format(stack.getCount());
|
||||
currentToolTip.add(ButtonToolTips.ItemsStored.text(formattedAmount).mergeStyle(TextFormatting.GRAY));
|
||||
|
||||
this.renderToolTip(matrixStack, currentToolTip, x, y, this.font);
|
||||
this.renderToolTip(matrixStack, Lists.transform(currentToolTip, ITextComponent::func_241878_f), x, y,
|
||||
this.font);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ public abstract class AEBaseScreen<T extends AEBaseContainer> extends ContainerS
|
||||
styledLines.add(lines.get(i).deepCopy().modifyStyle(s -> style));
|
||||
}
|
||||
|
||||
this.renderTooltip(matrices, styledLines, x, y);
|
||||
this.func_243308_b(matrices, styledLines, x, y);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,19 +8,18 @@ import net.minecraft.inventory.container.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
|
||||
/**
|
||||
* A proxy for a slot that will always return an itemstack with size 1, if there
|
||||
* is an item in the slot. Used to prevent the default item count from
|
||||
* rendering.
|
||||
*/
|
||||
class Size1Slot extends SlotItemHandler {
|
||||
class Size1Slot extends Slot {
|
||||
|
||||
private final SlotItemHandler delegate;
|
||||
private final Slot delegate;
|
||||
|
||||
public Size1Slot(SlotItemHandler delegate) {
|
||||
super(delegate.getItemHandler(), delegate.getSlotIndex(), delegate.xPos, delegate.yPos);
|
||||
public Size1Slot(Slot delegate) {
|
||||
super(delegate.inventory, delegate.getSlotIndex(), delegate.xPos, delegate.yPos);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,9 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
|
||||
this.searchField.setMaxStringLength(25);
|
||||
this.searchField.setTextColor(0xFFFFFF);
|
||||
this.searchField.setVisible(true);
|
||||
this.searchField.setFocused2(true);
|
||||
this.searchField.setResponder(str -> this.refreshList());
|
||||
this.addListener(this.searchField);
|
||||
this.changeFocus(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,11 +133,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;
|
||||
}
|
||||
|
||||
@@ -173,11 +172,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
|
||||
@@ -245,7 +240,7 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
|
||||
|
||||
/**
|
||||
* Rebuilds the list of interfaces.
|
||||
*
|
||||
* <p>
|
||||
* Respects a search term if present (ignores case) and adding only matching
|
||||
* patterns.
|
||||
*/
|
||||
@@ -338,12 +333,11 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
|
||||
|
||||
/**
|
||||
* Tries to retrieve a cache for a with search term as keyword.
|
||||
*
|
||||
* <p>
|
||||
* If this cache should be empty, it will populate it with an earlier cache if
|
||||
* available or at least the cache for the empty string.
|
||||
*
|
||||
* @param searchTerm the corresponding search
|
||||
*
|
||||
* @return a Set matching a superset of the search term
|
||||
*/
|
||||
private Set<Object> getCacheForSearchTerm(final String searchTerm) {
|
||||
|
||||
@@ -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.IInventory;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.container.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
|
||||
import appeng.api.storage.data.IAEFluidStack;
|
||||
import appeng.fluids.container.slots.IMEFluidSlot;
|
||||
|
||||
/**
|
||||
* @author BrockWS
|
||||
* @version rv6 - 22/05/2018
|
||||
* @since rv6 22/05/2018
|
||||
*/
|
||||
public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
|
||||
public class SlotFluidME extends Slot implements IMEFluidSlot {
|
||||
|
||||
private InternalFluidSlotME slot;
|
||||
private static final IInventory EMPTY_INVENTORY = new Inventory(0);
|
||||
|
||||
private final InternalFluidSlotME slot;
|
||||
|
||||
public SlotFluidME(InternalFluidSlotME slot) {
|
||||
super(null, 0, slot.getxPosition(), slot.getyPosition());
|
||||
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
@@ -50,7 +49,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(final ItemStack par1ItemStack) {
|
||||
public boolean isItemValid(final ItemStack stack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -69,7 +68,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putStack(final ItemStack par1ItemStack) {
|
||||
public void putStack(final ItemStack stack) {
|
||||
|
||||
}
|
||||
|
||||
@@ -85,7 +84,7 @@ public class SlotFluidME extends SlotItemHandler implements IMEFluidSlot {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTakeStack(final PlayerEntity par1PlayerEntity) {
|
||||
public boolean canTakeStack(final PlayerEntity player) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,23 +19,27 @@
|
||||
package appeng.client.me;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.container.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
|
||||
import appeng.api.storage.data.IAEItemStack;
|
||||
|
||||
public class SlotME extends SlotItemHandler {
|
||||
public class SlotME extends Slot {
|
||||
|
||||
private final InternalSlotME mySlot;
|
||||
private static final IInventory EMPTY_INVENTORY = new Inventory(0);
|
||||
|
||||
public SlotME(final InternalSlotME me) {
|
||||
super(null, 0, me.getxPosition(), me.getyPosition());
|
||||
this.mySlot = me;
|
||||
private final InternalSlotME slot;
|
||||
|
||||
public SlotME(final InternalSlotME slot) {
|
||||
super(EMPTY_INVENTORY, 0, slot.getxPosition(), slot.getyPosition());
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
public IAEItemStack getAEStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
return this.mySlot.getAEStack();
|
||||
if (this.slot.hasPower()) {
|
||||
return this.slot.getAEStack();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -47,15 +51,15 @@ public class SlotME extends SlotItemHandler {
|
||||
|
||||
@Override
|
||||
public ItemStack getStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
return this.mySlot.getStack();
|
||||
if (this.slot.hasPower()) {
|
||||
return this.slot.getStack();
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getHasStack() {
|
||||
if (this.mySlot.hasPower()) {
|
||||
if (this.slot.hasPower()) {
|
||||
return !this.getStack().isEmpty();
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -342,7 +342,7 @@ class CableBuilder {
|
||||
this.addBigCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
cubeBuilder.setEmissiveMaterial(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
@@ -353,14 +353,14 @@ class CableBuilder {
|
||||
this.addBigCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to normal rendering for the rest
|
||||
cubeBuilder.setRenderFullBright(false);
|
||||
cubeBuilder.setEmissiveMaterial(false);
|
||||
cubeBuilder.setTexture(texture);
|
||||
}
|
||||
|
||||
addCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
cubeBuilder.setEmissiveMaterial(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
@@ -369,6 +369,9 @@ class CableBuilder {
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to default
|
||||
cubeBuilder.setEmissiveMaterial(false);
|
||||
}
|
||||
|
||||
public void addStraightSmartConnection(Direction facing, AEColor cableColor, int channels,
|
||||
@@ -386,7 +389,7 @@ class CableBuilder {
|
||||
TextureAtlasSprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
cubeBuilder.setEmissiveMaterial(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
@@ -395,6 +398,9 @@ class CableBuilder {
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addStraightCoveredCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to default
|
||||
cubeBuilder.setEmissiveMaterial(false);
|
||||
}
|
||||
|
||||
public void addConstrainedSmartConnection(Direction facing, AEColor cableColor, int distanceFromEdge, int channels,
|
||||
@@ -417,7 +423,7 @@ class CableBuilder {
|
||||
TextureAtlasSprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
cubeBuilder.setEmissiveMaterial(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
@@ -426,6 +432,9 @@ class CableBuilder {
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addCoveredCableSizedCube(facing, distanceFromEdge, cubeBuilder);
|
||||
|
||||
// Reset back to default
|
||||
cubeBuilder.setEmissiveMaterial(false);
|
||||
}
|
||||
|
||||
public void addDenseCoveredConnection(Direction facing, AEColor cableColor, AECableType connectionType,
|
||||
@@ -449,7 +458,7 @@ class CableBuilder {
|
||||
addDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to normal rendering for the rest
|
||||
cubeBuilder.setRenderFullBright(false);
|
||||
cubeBuilder.setEmissiveMaterial(false);
|
||||
cubeBuilder.setTexture(texture);
|
||||
}
|
||||
|
||||
@@ -485,7 +494,7 @@ class CableBuilder {
|
||||
TextureAtlasSprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
cubeBuilder.setEmissiveMaterial(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
@@ -496,7 +505,7 @@ class CableBuilder {
|
||||
addDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to normal rendering for the rest
|
||||
cubeBuilder.setRenderFullBright(false);
|
||||
cubeBuilder.setEmissiveMaterial(false);
|
||||
cubeBuilder.setTexture(texture);
|
||||
}
|
||||
|
||||
@@ -529,7 +538,7 @@ class CableBuilder {
|
||||
TextureAtlasSprite evenChannel = this.smartCableTextures.getEvenTextureForChannels(channels);
|
||||
|
||||
// Render the channel indicators brightly lit at night
|
||||
cubeBuilder.setRenderFullBright(true);
|
||||
cubeBuilder.setEmissiveMaterial(true);
|
||||
|
||||
cubeBuilder.setTexture(oddChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.blackVariant);
|
||||
@@ -538,6 +547,9 @@ class CableBuilder {
|
||||
cubeBuilder.setTexture(evenChannel);
|
||||
cubeBuilder.setColorRGB(cableColor.whiteVariant);
|
||||
addStraightDenseCableSizedCube(facing, cubeBuilder);
|
||||
|
||||
// Reset back to default
|
||||
cubeBuilder.setEmissiveMaterial(false);
|
||||
}
|
||||
|
||||
private static void addDenseCableSizedCube(Direction facing, CubeBuilder cubeBuilder) {
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
|
||||
package appeng.client.render.cablebus;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -30,6 +30,11 @@ import java.util.Random;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.cache.Weigher;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
@@ -47,10 +52,22 @@ import net.minecraftforge.client.model.data.IModelData;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.api.util.AECableType;
|
||||
import appeng.api.util.AEColor;
|
||||
import appeng.metrics.Metrics;
|
||||
|
||||
public class CableBusBakedModel implements IBakedModel {
|
||||
|
||||
private static final Map<CableBusRenderState, List<BakedQuad>> CABLE_MODEL_CACHE = new HashMap<>();
|
||||
// The number of quads overall that will be cached
|
||||
private static final int CACHE_QUAD_COUNT = 5000;
|
||||
|
||||
// Keep a weak-ref to the last created cache for reporting metrics
|
||||
private static WeakReference<LoadingCache<CableBusRenderState, List<BakedQuad>>> cacheForMetrics = new WeakReference<>(
|
||||
null);
|
||||
|
||||
static {
|
||||
Metrics.cache("cable_bus_model_cache", () -> cacheForMetrics.get());
|
||||
}
|
||||
|
||||
private final LoadingCache<CableBusRenderState, List<BakedQuad>> cableModelCache;
|
||||
|
||||
private final CableBuilder cableBuilder;
|
||||
|
||||
@@ -66,6 +83,19 @@ public class CableBusBakedModel implements IBakedModel {
|
||||
this.facadeBuilder = facadeBuilder;
|
||||
this.partModels = partModels;
|
||||
this.particleTexture = particleTexture;
|
||||
this.cableModelCache = CacheBuilder.newBuilder()//
|
||||
.recordStats()//
|
||||
.maximumWeight(CACHE_QUAD_COUNT)//
|
||||
.weigher((Weigher<CableBusRenderState, List<BakedQuad>>) (key, value) -> value.size())//
|
||||
.build(new CacheLoader<CableBusRenderState, List<BakedQuad>>() {
|
||||
@Override
|
||||
public List<BakedQuad> load(CableBusRenderState renderState) {
|
||||
final List<BakedQuad> model = new ArrayList<>();
|
||||
addCableQuads(renderState, model);
|
||||
return model;
|
||||
}
|
||||
});
|
||||
cacheForMetrics = new WeakReference<>(cableModelCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,11 +122,7 @@ public class CableBusBakedModel implements IBakedModel {
|
||||
if (layer == RenderType.getCutout()) {
|
||||
|
||||
// First, handle the cable at the center of the cable bus
|
||||
final List<BakedQuad> cableModel = CABLE_MODEL_CACHE.computeIfAbsent(renderState, k -> {
|
||||
final List<BakedQuad> model = new ArrayList<>();
|
||||
this.addCableQuads(renderState, model);
|
||||
return model;
|
||||
});
|
||||
final List<BakedQuad> cableModel = cableModelCache.getUnchecked(renderState);
|
||||
quads.addAll(cableModel);
|
||||
|
||||
// Then handle attachments
|
||||
@@ -341,8 +367,4 @@ public class CableBusBakedModel implements IBakedModel {
|
||||
return ItemOverrideList.EMPTY;
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
CABLE_MODEL_CACHE.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ public class CableBusModelLoader implements IModelLoader<CableBusModel> {
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager) {
|
||||
CableBusBakedModel.clearCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -52,7 +52,7 @@ public class CubeBuilder {
|
||||
|
||||
private boolean useStandardUV = false;
|
||||
|
||||
private boolean renderFullBright;
|
||||
private boolean emissiveMaterial;
|
||||
|
||||
public CubeBuilder(List<BakedQuad> output) {
|
||||
this.output = output;
|
||||
@@ -379,7 +379,7 @@ public class CubeBuilder {
|
||||
if (e.getIndex() == 0) {
|
||||
builder.put(i, u, v);
|
||||
break;
|
||||
} else if (e.getIndex() == 2 && renderFullBright) {
|
||||
} else if (e.getIndex() == 2 && emissiveMaterial) {
|
||||
// Force Brightness to 15, this is for full bright mode
|
||||
// this vertex element will only be present in that case
|
||||
final float lightMapU = (float) (15 * 0x20) / 0xFFFF;
|
||||
@@ -434,8 +434,8 @@ public class CubeBuilder {
|
||||
this.setColorRGB((int) (r * 255) << 16 | (int) (g * 255) << 8 | (int) (b * 255));
|
||||
}
|
||||
|
||||
public void setRenderFullBright(boolean renderFullBright) {
|
||||
this.renderFullBright = renderFullBright;
|
||||
public void setEmissiveMaterial(boolean renderFullBright) {
|
||||
this.emissiveMaterial = renderFullBright;
|
||||
}
|
||||
|
||||
public void setCustomUv(Direction facing, float u1, float v1, float u2, float v2) {
|
||||
|
||||
@@ -49,7 +49,7 @@ public class P2PTunnelFrequencyBakedModel implements IDynamicBakedModel {
|
||||
|
||||
cb.setTexture(this.texture);
|
||||
cb.useStandardUV();
|
||||
cb.setRenderFullBright(active);
|
||||
cb.setEmissiveMaterial(active);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
final int[] offs = QUAD_OFFSETS[i];
|
||||
@@ -70,6 +70,10 @@ public class P2PTunnelFrequencyBakedModel implements IDynamicBakedModel {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Reset back to default
|
||||
cb.setEmissiveMaterial(false);
|
||||
|
||||
return cb.getOutput();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,10 @@ class LightBakedModel extends CraftingCubeBakedModel {
|
||||
builder.addCube(x1, y1, z1, x2, y2, z2);
|
||||
|
||||
boolean powered = state.get(AbstractCraftingUnitBlock.POWERED);
|
||||
builder.setRenderFullBright(powered);
|
||||
builder.setEmissiveMaterial(powered);
|
||||
builder.setTexture(this.lightTexture);
|
||||
builder.addCube(x1, y1, z1, x2, y2, z2);
|
||||
// Reset back to default
|
||||
builder.setEmissiveMaterial(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class MonitorBakedModel extends CraftingCubeBakedModel {
|
||||
AEColor color = getColor(modelData);
|
||||
boolean powered = state.get(CraftingMonitorBlock.POWERED);
|
||||
|
||||
builder.setRenderFullBright(powered);
|
||||
builder.setEmissiveMaterial(powered);
|
||||
|
||||
builder.setColorRGB(color.whiteVariant);
|
||||
builder.setTexture(this.lightBrightTexture);
|
||||
@@ -92,6 +92,8 @@ public class MonitorBakedModel extends CraftingCubeBakedModel {
|
||||
builder.setTexture(this.lightDarkTexture);
|
||||
builder.addCube(x1, y1, z1, x2, y2, z2);
|
||||
|
||||
// Reset back to default
|
||||
builder.setEmissiveMaterial(false);
|
||||
}
|
||||
|
||||
private static AEColor getColor(IModelData modelData) {
|
||||
|
||||
@@ -117,7 +117,7 @@ class SpatialPylonBakedModel implements IDynamicBakedModel {
|
||||
|
||||
if ((flags
|
||||
& SpatialPylonTileEntity.DISPLAY_POWERED_ENABLED) == SpatialPylonTileEntity.DISPLAY_POWERED_ENABLED) {
|
||||
builder.setRenderFullBright(true);
|
||||
builder.setEmissiveMaterial(true);
|
||||
}
|
||||
|
||||
builder.setTextures(this.textures.get(getTextureTypeFromSideInside(flags, ori, Direction.UP)),
|
||||
@@ -135,6 +135,9 @@ class SpatialPylonBakedModel implements IDynamicBakedModel {
|
||||
builder.addCube(0, 0, 0, 16, 16, 16);
|
||||
}
|
||||
|
||||
// Reset back to default
|
||||
builder.setEmissiveMaterial(false);
|
||||
|
||||
return builder.getOutput();
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ public class ChestTileEntityRenderer extends TileEntityRenderer<ChestTileEntity>
|
||||
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand,
|
||||
@Nonnull IModelData extraData) {
|
||||
if (side != null) {
|
||||
side = r.rotate(side); // This fixes the incorrect lightmap position
|
||||
side = r.resultingRotate(side); // This fixes the incorrect lightmap position
|
||||
}
|
||||
List<BakedQuad> quads = new ArrayList<>(super.getQuads(state, side, rand, extraData));
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ public final class ContainerLocator {
|
||||
public static ContainerLocator forPart(AEBasePart part) {
|
||||
IPartHost host = part.getHost();
|
||||
DimensionalCoord pos = host.getLocation();
|
||||
return new ContainerLocator(Type.PART, -1, pos.getWorld().getWorld(), pos.getBlockPos(), part.getSide());
|
||||
return new ContainerLocator(Type.PART, -1, pos.getWorld(), pos.getBlockPos(), part.getSide());
|
||||
}
|
||||
|
||||
public boolean hasItemIndex() {
|
||||
|
||||
@@ -42,7 +42,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;
|
||||
@@ -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
|
||||
|
||||
@@ -261,13 +261,19 @@ public class PatternTermContainer extends MEMonitorableContainer
|
||||
return new ItemStack[] { out };
|
||||
}
|
||||
} else {
|
||||
boolean hasValue = false;
|
||||
final ItemStack[] list = new ItemStack[3];
|
||||
|
||||
for (int i = 0; i < this.outputSlots.length; i++) {
|
||||
final ItemStack out = this.outputSlots[i].getStack();
|
||||
list[i] = out;
|
||||
if (!out.isEmpty()) {
|
||||
hasValue = true;
|
||||
}
|
||||
}
|
||||
if (hasValue) {
|
||||
return list;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.util.Set;
|
||||
import java.util.function.DoubleSupplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
@@ -393,6 +395,19 @@ public final class AEConfig {
|
||||
return this.meteoriteDimensionWhitelist;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getImprovedFluidTag() {
|
||||
return Strings.emptyToNull(COMMON.improvedFluidTag.get());
|
||||
}
|
||||
|
||||
public float getImprovedFluidMultiplier() {
|
||||
return COMMON.improvedFluidMultiplier.get().floatValue();
|
||||
}
|
||||
|
||||
public int getPrometheusMetricsServerPort() {
|
||||
return COMMON.prometheusMetricsServer.get();
|
||||
}
|
||||
|
||||
// Setters keep visibility as low as possible.
|
||||
|
||||
private static class ClientConfig {
|
||||
@@ -463,6 +478,7 @@ public final class AEConfig {
|
||||
public final BooleanValue removeCrashingItemsOnLoad;
|
||||
public final ConfigValue<Integer> formationPlaneEntityLimit;
|
||||
public final ConfigValue<Integer> craftingCalculationTimePerTick;
|
||||
public final ConfigValue<Integer> prometheusMetricsServer;
|
||||
|
||||
// Spatial IO/Dimension
|
||||
public final ConfigValue<Double> spatialPowerExponent;
|
||||
@@ -507,6 +523,11 @@ public final class AEConfig {
|
||||
public final ConfigValue<Integer> condenserMatterBallsPower;
|
||||
public final ConfigValue<Integer> condenserSingularityPower;
|
||||
|
||||
// In-World Purification
|
||||
// Settings for improved speed depending on fluid the crystal is in
|
||||
public final ConfigValue<String> improvedFluidTag;
|
||||
public final ConfigValue<Double> improvedFluidMultiplier;
|
||||
|
||||
public final Map<TickRates, ConfigValue<Integer>> tickRateMin = new HashMap<>();
|
||||
public final Map<TickRates, ConfigValue<Integer>> tickRateMax = new HashMap<>();
|
||||
|
||||
@@ -542,6 +563,12 @@ public final class AEConfig {
|
||||
.define("removeCrashingItemsOnLoad", false);
|
||||
builder.pop();
|
||||
|
||||
builder.push("metrics");
|
||||
prometheusMetricsServer = builder.comment(
|
||||
"Enables the Prometheus Metrics exporting endpoint on 127.0.0.1 on this port number. 0 to disable.")
|
||||
.define("prometheusMetricsServer", 0);
|
||||
builder.pop();
|
||||
|
||||
builder.push("automation");
|
||||
formationPlaneEntityLimit = builder.comment("TODO").define("formationPlaneEntityLimit", 128);
|
||||
builder.pop();
|
||||
@@ -617,6 +644,17 @@ public final class AEConfig {
|
||||
tickRateMax.put(tickRate, builder.define(tickRate.name() + "Max", tickRate.getDefaultMax()));
|
||||
}
|
||||
builder.pop();
|
||||
|
||||
builder.comment("Settings for in-world purification of crystals.").push("inWorldPurification");
|
||||
|
||||
improvedFluidTag = builder.comment(
|
||||
"A fluid tag that identifies fluids that improve crystal purification speed. Does not affect purification with water/lava.")
|
||||
.define("improvedFluidTag", "");
|
||||
improvedFluidMultiplier = builder
|
||||
.comment("The speed multiplier to use when the crystals are submerged in the improved fluid.")
|
||||
.defineInRange("improvedFluidMultiplier", 2.0, 1.0, 10.0);
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,13 +34,12 @@ import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
import net.minecraft.particles.ParticleType;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.gen.feature.Feature;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.fml.DeferredWorkQueue;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.fml.ModLoadingContext;
|
||||
import net.minecraftforge.fml.client.registry.RenderingRegistry;
|
||||
@@ -67,6 +66,7 @@ import appeng.entity.TinyTNTPrimedEntity;
|
||||
import appeng.entity.TinyTNTPrimedRenderer;
|
||||
import appeng.hooks.TickHandler;
|
||||
import appeng.integration.Integrations;
|
||||
import appeng.metrics.endpoint.PrometheusEndpoint;
|
||||
import appeng.parts.PartPlacement;
|
||||
import appeng.server.ServerHelper;
|
||||
|
||||
@@ -91,6 +91,8 @@ public final class AppEng {
|
||||
}
|
||||
INSTANCE = this;
|
||||
|
||||
startMetricsServer();
|
||||
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, AEConfig.CLIENT_SPEC);
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, AEConfig.COMMON_SPEC);
|
||||
|
||||
@@ -101,6 +103,7 @@ public final class AppEng {
|
||||
|
||||
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
registration = new Registration();
|
||||
modEventBus.addListener(this::bootstrap);
|
||||
modEventBus.addGenericListener(Block.class, registration::registerBlocks);
|
||||
modEventBus.addGenericListener(Item.class, registration::registerItems);
|
||||
modEventBus.addGenericListener(EntityType.class, registration::registerEntities);
|
||||
@@ -108,9 +111,6 @@ public final class AppEng {
|
||||
modEventBus.addGenericListener(TileEntityType.class, registration::registerTileEntities);
|
||||
modEventBus.addGenericListener(ContainerType.class, registration::registerContainerTypes);
|
||||
modEventBus.addGenericListener(IRecipeSerializer.class, registration::registerRecipeSerializers);
|
||||
modEventBus.addGenericListener(Feature.class, registration::registerFeatures);
|
||||
modEventBus.addGenericListener(Structure.class, registration::registerStructures);
|
||||
modEventBus.addGenericListener(Biome.class, registration::registerBiomes);
|
||||
|
||||
modEventBus.addListener(Integrations::enqueueIMC);
|
||||
modEventBus.addListener(this::commonSetup);
|
||||
@@ -129,7 +129,15 @@ public final class AppEng {
|
||||
MinecraftForge.EVENT_BUS.register(new PartPlacement());
|
||||
}
|
||||
|
||||
private void bootstrap(RegistryEvent.NewRegistry e) {
|
||||
// This has to be here so it's not run in parallel with other registrations
|
||||
AppEngBootstrap.initialize();
|
||||
}
|
||||
|
||||
private void commonSetup(FMLCommonSetupEvent event) {
|
||||
// This must run here because the config is not available earlier
|
||||
DeferredWorkQueue.runLater(AppEngBootstrap::enhanceBiomes);
|
||||
|
||||
ApiDefinitions definitions = Api.INSTANCE.definitions();
|
||||
definitions.getRegistry().getBootstrapComponents(IInitComponent.class)
|
||||
.forEachRemaining(IInitComponent::initialize);
|
||||
@@ -143,6 +151,20 @@ public final class AppEng {
|
||||
registerNetworkHandler();
|
||||
|
||||
AddonLoader.loadAddons(Api.INSTANCE);
|
||||
|
||||
startMetricsServer();
|
||||
}
|
||||
|
||||
private void startMetricsServer() {
|
||||
int prometheusPort = AEConfig.instance().getPrometheusMetricsServerPort();
|
||||
if (prometheusPort != 0) {
|
||||
try {
|
||||
AELog.info("Starting Prometheus Metrics Server on Port %s", prometheusPort);
|
||||
new PrometheusEndpoint("localhost", prometheusPort);
|
||||
} catch (Exception e) {
|
||||
AELog.warn("Failed to start Prometheus Metrics-Server: %s", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package appeng.core;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.WorldGenRegistries;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.gen.GenerationStage;
|
||||
import net.minecraft.world.gen.feature.ConfiguredFeature;
|
||||
import net.minecraft.world.gen.feature.Feature;
|
||||
import net.minecraft.world.gen.feature.OreFeatureConfig;
|
||||
import net.minecraft.world.gen.placement.NoPlacementConfig;
|
||||
import net.minecraft.world.gen.placement.Placement;
|
||||
import net.minecraft.world.gen.placement.TopSolidRangeConfig;
|
||||
|
||||
import appeng.api.features.AEFeature;
|
||||
import appeng.mixins.feature.ConfiguredFeaturesAccessor;
|
||||
import appeng.mixins.structure.ConfiguredStructureFeaturesAccessor;
|
||||
import appeng.mixins.structure.StructureFeatureAccessor;
|
||||
import appeng.spatial.SpatialStorageChunkGenerator;
|
||||
import appeng.spatial.SpatialStorageDimensionIds;
|
||||
import appeng.worldgen.BiomeModifier;
|
||||
import appeng.worldgen.ChargedQuartzOreConfig;
|
||||
import appeng.worldgen.ChargedQuartzOreFeature;
|
||||
import appeng.worldgen.meteorite.MeteoriteStructure;
|
||||
import appeng.worldgen.meteorite.MeteoriteStructurePiece;
|
||||
|
||||
/**
|
||||
* Hooks into the very early bootstrapping phase to register things before the
|
||||
* first dynamic registry manager is created.
|
||||
*/
|
||||
public final class AppEngBootstrap {
|
||||
|
||||
private static boolean initialized;
|
||||
private static ConfiguredFeature<?, ?> quartzOreFeature;
|
||||
private static ConfiguredFeature<?, ?> chargedQuartzOreFeature;
|
||||
|
||||
private AppEngBootstrap() {
|
||||
}
|
||||
|
||||
public synchronized static void initialize() {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
registerStructures();
|
||||
|
||||
quartzOreFeature = registerQuartzOreFeature();
|
||||
chargedQuartzOreFeature = registerChargedQuartzOreFeature();
|
||||
|
||||
registerDimension();
|
||||
}
|
||||
|
||||
public synchronized static void enhanceBiomes() {
|
||||
// add to all standard biomes
|
||||
// TODO: This means we'll not add these things to newly created biomes
|
||||
WorldGenRegistries.field_243657_i.forEach(b -> {
|
||||
addMeteoriteWorldGen(b);
|
||||
addQuartzWorldGen(b, quartzOreFeature, chargedQuartzOreFeature);
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerStructures() {
|
||||
|
||||
MeteoriteStructurePiece.register();
|
||||
|
||||
// Registering into the registry alone is INSUFFICIENT!
|
||||
// There's a bidirectional map in the Structure class itself primarily for the
|
||||
// purposes of NBT serialization
|
||||
StructureFeatureAccessor.register(MeteoriteStructure.ID.toString(), MeteoriteStructure.INSTANCE,
|
||||
GenerationStage.Decoration.TOP_LAYER_MODIFICATION);
|
||||
|
||||
ConfiguredStructureFeaturesAccessor.register(MeteoriteStructure.ID.toString(),
|
||||
MeteoriteStructure.CONFIGURED_INSTANCE);
|
||||
}
|
||||
|
||||
private static void addMeteoriteWorldGen(Biome b) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.METEORITE_WORLD_GEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (b.getCategory() == Biome.Category.THEEND || b.getCategory() == Biome.Category.NETHER) {
|
||||
return;
|
||||
}
|
||||
|
||||
BiomeModifier modifier = new BiomeModifier(b);
|
||||
modifier.addStructureFeature(MeteoriteStructure.CONFIGURED_INSTANCE);
|
||||
}
|
||||
|
||||
private static void addQuartzWorldGen(Biome b, ConfiguredFeature<?, ?> quartzOre,
|
||||
ConfiguredFeature<?, ?> chargedQuartz) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.CERTUS_QUARTZ_WORLD_GEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BiomeModifier modifier = new BiomeModifier(b);
|
||||
|
||||
modifier.addFeature(GenerationStage.Decoration.UNDERGROUND_ORES, quartzOre);
|
||||
|
||||
if (AEConfig.instance().isFeatureEnabled(AEFeature.CHARGED_CERTUS_ORE)) {
|
||||
modifier.addFeature(GenerationStage.Decoration.UNDERGROUND_DECORATION, chargedQuartz);
|
||||
}
|
||||
}
|
||||
|
||||
private static ConfiguredFeature<?, ?> registerQuartzOreFeature() {
|
||||
// Tell Minecraft about our configured quartz ore feature
|
||||
BlockState quartzOreState = Api.instance().definitions().blocks().quartzOre().block().getDefaultState();
|
||||
return ConfiguredFeaturesAccessor.register(AppEng.makeId("quartz_ore").toString(), Feature.ORE
|
||||
.withConfiguration(new OreFeatureConfig(OreFeatureConfig.FillerBlockType.field_241882_a, quartzOreState,
|
||||
AEConfig.instance().getQuartzOresPerCluster()))
|
||||
.withPlacement(Placement.field_242907_l/* RANGE */.configure(new TopSolidRangeConfig(12, 12, 72)))
|
||||
.func_242728_a/* spreadHorizontally */()
|
||||
.func_242731_b/* repeat */(AEConfig.instance().getQuartzOresClusterAmount()));
|
||||
}
|
||||
|
||||
private static ConfiguredFeature<?, ?> registerChargedQuartzOreFeature() {
|
||||
// Tell Minecraft about our configured charged quartz ore feature
|
||||
Registry.register(Registry.FEATURE, AppEng.makeId("charged_quartz_ore"), ChargedQuartzOreFeature.INSTANCE);
|
||||
|
||||
BlockState quartzOreState = Api.instance().definitions().blocks().quartzOre().block().getDefaultState();
|
||||
BlockState chargedQuartzOreState = Api.instance().definitions().blocks().quartzOreCharged().block()
|
||||
.getDefaultState();
|
||||
return ConfiguredFeaturesAccessor.register(AppEng.makeId("charged_quartz_ore").toString(),
|
||||
ChargedQuartzOreFeature.INSTANCE
|
||||
.withConfiguration(new ChargedQuartzOreConfig(quartzOreState, chargedQuartzOreState,
|
||||
AEConfig.instance().getSpawnChargedChance()))
|
||||
.withPlacement(Placement.NOPE.configure(NoPlacementConfig.field_236556_b_)));
|
||||
}
|
||||
|
||||
private static void registerDimension() {
|
||||
Registry.register(Registry.CHUNK_GENERATOR_CODEC, SpatialStorageDimensionIds.CHUNK_GENERATOR_ID,
|
||||
SpatialStorageChunkGenerator.CODEC);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,6 @@ import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.advancements.CriteriaTriggers;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.ScreenManager;
|
||||
import net.minecraft.client.particle.ParticleManager;
|
||||
@@ -33,17 +32,7 @@ import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
import net.minecraft.particles.ParticleType;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.gen.GenerationStage;
|
||||
import net.minecraft.world.gen.feature.Feature;
|
||||
import net.minecraft.world.gen.feature.IFeatureConfig;
|
||||
import net.minecraft.world.gen.feature.OreFeatureConfig;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
import net.minecraft.world.gen.placement.CountRangeConfig;
|
||||
import net.minecraft.world.gen.placement.IPlacementConfig;
|
||||
import net.minecraft.world.gen.placement.Placement;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.client.event.ColorHandlerEvent;
|
||||
@@ -62,14 +51,12 @@ import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||
import net.minecraftforge.fml.network.IContainerFactory;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.IForgeRegistry;
|
||||
|
||||
import appeng.api.config.Upgrades;
|
||||
import appeng.api.definitions.IBlocks;
|
||||
import appeng.api.definitions.IItems;
|
||||
import appeng.api.definitions.IParts;
|
||||
import appeng.api.features.AEFeature;
|
||||
import appeng.api.features.IRegistryContainer;
|
||||
import appeng.api.features.IWirelessTermHandler;
|
||||
import appeng.api.features.IWorldGen;
|
||||
@@ -213,22 +200,14 @@ import appeng.me.cache.PathGridCache;
|
||||
import appeng.me.cache.SecurityCache;
|
||||
import appeng.me.cache.SpatialPylonCache;
|
||||
import appeng.me.cache.TickManagerCache;
|
||||
import appeng.mixins.StructureAccessor;
|
||||
import appeng.parts.automation.PlaneModelLoader;
|
||||
import appeng.recipes.game.DisassembleRecipe;
|
||||
import appeng.recipes.game.FacadeRecipe;
|
||||
import appeng.recipes.handlers.GrinderRecipeSerializer;
|
||||
import appeng.recipes.handlers.InscriberRecipeSerializer;
|
||||
import appeng.server.AECommand;
|
||||
import appeng.spatial.SpatialStorageBiome;
|
||||
import appeng.spatial.SpatialStorageChunkGenerator;
|
||||
import appeng.spatial.SpatialStorageDimensionIds;
|
||||
import appeng.tile.AEBaseTileEntity;
|
||||
import appeng.tile.crafting.MolecularAssemblerRenderer;
|
||||
import appeng.worldgen.ChargedQuartzOreConfig;
|
||||
import appeng.worldgen.ChargedQuartzOreFeature;
|
||||
import appeng.worldgen.meteorite.MeteoriteStructure;
|
||||
import appeng.worldgen.meteorite.MeteoriteStructurePiece;
|
||||
|
||||
final class Registration {
|
||||
|
||||
@@ -682,73 +661,6 @@ final class Registration {
|
||||
new ResourceLocation(dimension));
|
||||
}
|
||||
|
||||
MeteoriteStructurePiece.register();
|
||||
|
||||
ForgeRegistries.BIOMES.forEach(b -> {
|
||||
addMeteoriteWorldGen(b);
|
||||
addQuartzWorldGen(b);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static void addMeteoriteWorldGen(Biome b) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.METEORITE_WORLD_GEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (b.getCategory() == Biome.Category.THEEND || b.getCategory() == Biome.Category.NETHER) {
|
||||
return;
|
||||
}
|
||||
|
||||
b.func_235063_a_(MeteoriteStructure.INSTANCE.func_236391_a_(IFeatureConfig.NO_FEATURE_CONFIG));
|
||||
}
|
||||
|
||||
private static void addQuartzWorldGen(Biome b) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.CERTUS_QUARTZ_WORLD_GEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlockState quartzOre = Api.instance().definitions().blocks().quartzOre().block().getDefaultState();
|
||||
b.addFeature(GenerationStage.Decoration.UNDERGROUND_ORES,
|
||||
Feature.ORE
|
||||
.withConfiguration(new OreFeatureConfig(OreFeatureConfig.FillerBlockType.NATURAL_STONE,
|
||||
quartzOre, AEConfig.instance().getQuartzOresPerCluster()))
|
||||
.withPlacement(Placement.COUNT_RANGE.configure(
|
||||
new CountRangeConfig(AEConfig.instance().getQuartzOresClusterAmount(), 12, 12, 72))));
|
||||
|
||||
if (AEConfig.instance().isFeatureEnabled(AEFeature.CHARGED_CERTUS_ORE)) {
|
||||
|
||||
BlockState chargedQuartzOre = Api.instance().definitions().blocks().quartzOreCharged().block()
|
||||
.getDefaultState();
|
||||
b.addFeature(GenerationStage.Decoration.UNDERGROUND_DECORATION,
|
||||
ChargedQuartzOreFeature.INSTANCE
|
||||
.withConfiguration(new ChargedQuartzOreConfig(quartzOre, chargedQuartzOre,
|
||||
AEConfig.instance().getSpawnChargedChance()))
|
||||
.withPlacement(Placement.NOPE.configure(IPlacementConfig.NO_PLACEMENT_CONFIG)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void registerFeatures(RegistryEvent.Register<Feature<?>> evt) {
|
||||
IForgeRegistry<Feature<?>> r = evt.getRegistry();
|
||||
|
||||
r.register(ChargedQuartzOreFeature.INSTANCE.setRegistryName(AppEng.makeId("charged_quartz_ore")));
|
||||
}
|
||||
|
||||
public void registerStructures(RegistryEvent.Register<Structure<?>> evt) {
|
||||
// Registering into the Forge registry is INSUFFICIENT!
|
||||
// There's a bidirectional map in the Structure class itself primarily for the
|
||||
// purposes of NBT serialization
|
||||
StructureAccessor.register(MeteoriteStructure.ID.toString(),
|
||||
MeteoriteStructure.INSTANCE.setRegistryName(MeteoriteStructure.ID),
|
||||
GenerationStage.Decoration.TOP_LAYER_MODIFICATION);
|
||||
|
||||
Registry.register(Registry.CHUNK_GENERATOR_CODEC, SpatialStorageDimensionIds.CHUNK_GENERATOR_ID,
|
||||
SpatialStorageChunkGenerator.CODEC);
|
||||
}
|
||||
|
||||
public void registerBiomes(RegistryEvent.Register<Biome> evt) {
|
||||
evt.getRegistry().register(SpatialStorageBiome.INSTANCE.setRegistryName(SpatialStorageDimensionIds.BIOME_ID));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
|
||||
@@ -115,7 +115,12 @@ public class ApiCrafting implements ICraftingHelper {
|
||||
// We use the shared itemstack for an identity lookup.
|
||||
IAEItemStack ais = Api.instance().storage().getStorageChannel(IItemStorageChannel.class).createStack(is);
|
||||
|
||||
return new CraftingPatternDetails(ais, world);
|
||||
try {
|
||||
return new CraftingPatternDetails(ais, world);
|
||||
} catch (IllegalStateException e) {
|
||||
AELog.warn("Could not decode an invalid pattern %s: %s", is, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean attemptRecovery(EncodedPatternItem patternItem, ItemStack itemStack, World world) {
|
||||
|
||||
@@ -20,7 +20,9 @@ package appeng.core.api.definitions;
|
||||
|
||||
import static appeng.block.AEBaseBlock.defaultProps;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.DispenserBlock;
|
||||
import net.minecraft.block.SlabBlock;
|
||||
import net.minecraft.block.SoundType;
|
||||
@@ -28,6 +30,7 @@ import net.minecraft.block.StairsBlock;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.entity.EntityClassification;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
@@ -262,18 +265,20 @@ 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(defaultProps(Material.GLASS).notSolid()))
|
||||
.rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
|
||||
rendering.renderType(RenderType.getCutout());
|
||||
}
|
||||
}).build();
|
||||
AbstractBlock.IExtendedPositionPredicate<EntityType<?>> neverAllowSpawn = (p1, p2, p3, p4) -> false;
|
||||
this.quartzGlass = registry.features(AEFeature.QUARTZ_GLASS).block("quartz_glass", () -> {
|
||||
return new QuartzGlassBlock(defaultProps(Material.GLASS).notSolid().setAllowsSpawn(neverAllowSpawn));
|
||||
}).rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void customize(IBlockRendering rendering, IItemRendering itemRendering) {
|
||||
rendering.renderType(RenderType.getCutout());
|
||||
}
|
||||
}).build();
|
||||
this.quartzVibrantGlass = deco
|
||||
.block("quartz_vibrant_glass",
|
||||
() -> new QuartzLampBlock(defaultProps(Material.GLASS).setLightLevel(b -> 15).notSolid()))
|
||||
() -> new QuartzLampBlock(defaultProps(Material.GLASS).setLightLevel(b -> 15).notSolid()
|
||||
.setAllowsSpawn(neverAllowSpawn)))
|
||||
.addFeatures(AEFeature.DECORATIVE_LIGHTS, AEFeature.QUARTZ_GLASS)
|
||||
.rendering(new BlockRenderingCustomizer() {
|
||||
@Override
|
||||
|
||||
@@ -56,6 +56,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;
|
||||
@@ -299,28 +300,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
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void setup() {
|
||||
// Expose the growth of the seed to the model system
|
||||
ItemModelsProperties.func_239418_a_(item, new ResourceLocation("appliedenergistics2: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, EntityClassification.MISC)
|
||||
.customize(builder -> builder.size(0.25F, 0.25F)).build();
|
||||
.customize(builder -> builder.size(0.25F, 0.4F)).build();
|
||||
|
||||
// rv1
|
||||
this.encodedPattern = registry.item("encoded_pattern", EncodedPatternItem::new)
|
||||
|
||||
@@ -22,12 +22,12 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
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 {
|
||||
@@ -35,18 +35,19 @@ public final class LocatableRegistry implements ILocatableRegistry {
|
||||
|
||||
public LocatableRegistry() {
|
||||
this.set = new HashMap<>();
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
MinecraftForge.EVENT_BUS.addListener(this::updateLocatable);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void updateLocatable(final LocatableEventAnnounce e) {
|
||||
private void updateLocatable(final LocatableEventAnnounce e) {
|
||||
if (Platform.isClient()) {
|
||||
return; // IGNORE!
|
||||
}
|
||||
|
||||
if (e.change == LocatableEvent.REGISTER) {
|
||||
AELog.debug("Registering locatable %s: %s", e.target.getLocatableSerial(), e.target);
|
||||
this.set.put(e.target.getLocatableSerial(), e.target);
|
||||
} else if (e.change == LocatableEvent.UNREGISTER) {
|
||||
AELog.debug("Unregistering locatable %s: %s", e.target.getLocatableSerial(), e.target);
|
||||
this.set.remove(e.target.getLocatableSerial());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,12 +51,12 @@ public class MovableTileRegistry implements IMovableRegistry {
|
||||
private final List<IMovableHandler> handlers = new ArrayList<>();
|
||||
private final DefaultSpatialHandler dsh = new DefaultSpatialHandler();
|
||||
private final IMovableHandler nullHandler = new DefaultSpatialHandler();
|
||||
private final ITag<Block> blockTagWhiteList;
|
||||
private final ITag<Block> blockTagBlackList;
|
||||
private final ITag.INamedTag<Block> blockTagWhiteList;
|
||||
private final ITag.INamedTag<Block> blockTagBlackList;
|
||||
|
||||
public MovableTileRegistry() {
|
||||
this.blockTagWhiteList = BlockTags.getCollection().getOrCreate(TAG_WHITELIST);
|
||||
this.blockTagBlackList = BlockTags.getCollection().getOrCreate(TAG_BLACKLIST);
|
||||
this.blockTagWhiteList = BlockTags.makeWrapperTag(TAG_WHITELIST.toString());
|
||||
this.blockTagBlackList = BlockTags.makeWrapperTag(TAG_BLACKLIST.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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.MockExplosionPacket;
|
||||
@@ -101,7 +101,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),
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public class BlockTransitionEffectPacket extends BasePacket {
|
||||
|
||||
data.writeInt(this.getPacketID());
|
||||
data.writeBlockPos(pos);
|
||||
int blockStateId = GameData.getBlockStateIDMap().get(blockState);
|
||||
int blockStateId = GameData.getBlockStateIDMap().getId(blockState);
|
||||
if (blockStateId == -1) {
|
||||
AELog.warn("Failed to find numeric id for block state %s", blockState);
|
||||
}
|
||||
|
||||
@@ -18,15 +18,27 @@
|
||||
|
||||
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.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.inventory.container.Container;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.IRecipeSerializer;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.item.crafting.ShapedRecipe;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.common.crafting.IShapedRecipe;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
@@ -40,8 +52,10 @@ 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;
|
||||
@@ -54,152 +68,289 @@ 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 ResourceLocation recipeId;
|
||||
/**
|
||||
* This is optional, in case the client already knows it could not resolve the
|
||||
* recipe id.
|
||||
*/
|
||||
@Nullable
|
||||
private IRecipe<?> recipe;
|
||||
private boolean crafting;
|
||||
|
||||
public JEIRecipePacket(final PacketBuffer stream) {
|
||||
final CompoundNBT comp = stream.readCompoundTag();
|
||||
if (comp != null) {
|
||||
this.recipe = new ItemStack[9][];
|
||||
for (int x = 0; x < this.recipe.length; x++) {
|
||||
final ListNBT 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.read(list.getCompound(y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.crafting = stream.readBoolean();
|
||||
final String id = stream.readString(Short.MAX_VALUE);
|
||||
this.recipeId = new ResourceLocation(id);
|
||||
|
||||
// api
|
||||
public JEIRecipePacket(final CompoundNBT recipe) {
|
||||
final PacketBuffer data = new PacketBuffer(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 Container con = pmp.openContainer;
|
||||
|
||||
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 IItemHandler craftMatrix = cct.getInventoryByName("crafting");
|
||||
final IItemHandler 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.getSlots(); x++) {
|
||||
ItemStack currentItem = craftMatrix.getStackInSlot(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()) {
|
||||
AdaptorItemHandler ad = new AdaptorItemHandler(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.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix));
|
||||
int inlineRecipeType = stream.readVarInt();
|
||||
switch (inlineRecipeType) {
|
||||
case INLINE_RECIPE_NONE:
|
||||
break;
|
||||
case INLINE_RECIPE_SHAPED:
|
||||
recipe = IRecipeSerializer.CRAFTING_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 ResourceLocation recipeId, final boolean crafting) {
|
||||
PacketBuffer 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) {
|
||||
PacketBuffer data = createCommonHeader(recipe.getId(), crafting, INLINE_RECIPE_SHAPED);
|
||||
IRecipeSerializer.CRAFTING_SHAPED.write(data, recipe);
|
||||
this.configureWrite(data);
|
||||
}
|
||||
|
||||
private PacketBuffer createCommonHeader(ResourceLocation recipeId, boolean crafting, int inlineRecipeType) {
|
||||
final PacketBuffer data = new PacketBuffer(Unpooled.buffer());
|
||||
|
||||
data.writeInt(this.getPacketID());
|
||||
data.writeBoolean(crafting);
|
||||
data.writeResourceLocation(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 Container con = pmp.openContainer;
|
||||
Preconditions.checkArgument(con instanceof IContainerCraftingPacket);
|
||||
|
||||
IRecipe<?> recipe = player.getEntityWorld().getRecipeManager().getRecipe(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 IItemHandler craftMatrix = cct.getInventoryByName("crafting");
|
||||
final IItemHandler 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 NonNullList<Ingredient> ingredients = this.ensure3by3CraftingMatrix(recipe);
|
||||
|
||||
// Handle each slot
|
||||
for (int x = 0; x < craftMatrix.getSlots(); x++) {
|
||||
ItemStack currentItem = craftMatrix.getStackInSlot(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 && ingredient.getMatchingStacks().length > 0) {
|
||||
out = AEItemStack.fromItemStack(ingredient.getMatchingStacks()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (out != null) {
|
||||
currentItem = out.createItemStack();
|
||||
}
|
||||
}
|
||||
|
||||
// If still nothing, search the player inventory.
|
||||
if (currentItem.isEmpty()) {
|
||||
ItemStack[] matchingStacks = ingredient.getMatchingStacks();
|
||||
for (ItemStack matchingStack : matchingStacks) {
|
||||
if (currentItem.isEmpty()) {
|
||||
AdaptorItemHandler ad = new AdaptorItemHandler(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.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 NonNullList<Ingredient> ensure3by3CraftingMatrix(IRecipe<?> recipe) {
|
||||
NonNullList<Ingredient> ingredients = recipe.getIngredients();
|
||||
NonNullList<Ingredient> expandedIngredients = NonNullList.withSize(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 IShapedRecipe) {
|
||||
IShapedRecipe<?> shapedRecipe = (IShapedRecipe<?>) recipe;
|
||||
int width = shapedRecipe.getRecipeWidth();
|
||||
int height = shapedRecipe.getRecipeHeight();
|
||||
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(ingredient.getMatchingStacks()).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(ingredients.getMatchingStacks()).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(ingredients.getMatchingStacks()).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(Container con, IContainerCraftingPacket cct, IRecipe<?> recipe) {
|
||||
if (con instanceof PatternTermContainer) {
|
||||
PatternTermContainer patternTerm = (PatternTermContainer) con;
|
||||
if (!patternTerm.craftingMode) {
|
||||
final IItemHandler output = cct.getInventoryByName("output");
|
||||
ItemHandlerUtil.setStackInSlot(output, 0, recipe.getRecipeOutput());
|
||||
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.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.fml.network.NetworkDirection;
|
||||
|
||||
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 PacketBuffer data;
|
||||
@Nullable
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
private int writtenBytes = 0;
|
||||
private boolean empty = true;
|
||||
|
||||
public MEFluidInventoryUpdatePacket(final PacketBuffer 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 PacketBuffer uncompressed = new PacketBuffer(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 PacketBuffer(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 IPacket<?> toPacket(NetworkDirection 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 PacketBuffer tmp = new PacketBuffer(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;
|
||||
|
||||
@@ -32,7 +26,6 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.CompressedStreamTools;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
@@ -41,55 +34,24 @@ 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 CompoundNBT in;
|
||||
// output...
|
||||
private final PacketBuffer data;
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
public CompressedNBTPacket(final PacketBuffer stream) {
|
||||
public MEInterfaceUpdatePacket(final PacketBuffer 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 = CompressedStreamTools.read(inStream);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to decompress packet.", e);
|
||||
}
|
||||
this.in = stream.readCompoundTag();
|
||||
}
|
||||
|
||||
// api
|
||||
public CompressedNBTPacket(final CompoundNBT din) throws IOException {
|
||||
|
||||
public MEInterfaceUpdatePacket(final CompoundNBT din) throws IOException {
|
||||
this.in = null;
|
||||
this.data = new PacketBuffer(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);
|
||||
}
|
||||
});
|
||||
|
||||
CompressedStreamTools.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 PacketBuffer data;
|
||||
@Nullable
|
||||
private final GZIPOutputStream compressFrame;
|
||||
|
||||
private int writtenBytes = 0;
|
||||
private boolean empty = true;
|
||||
|
||||
public MEInventoryUpdatePacket(final PacketBuffer 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 PacketBuffer uncompressed = new PacketBuffer(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 PacketBuffer(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 IPacket<?> toPacket(NetworkDirection 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 PacketBuffer tmp = new PacketBuffer(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,4 +157,8 @@ final class StorageData extends WorldSavedData implements IWorldGridStorageData
|
||||
return tag;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return storage.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,12 +28,13 @@ import com.google.common.base.Preconditions;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import appeng.metrics.Metrics;
|
||||
import appeng.services.CompassService;
|
||||
import appeng.services.compass.CompassThreadFactory;
|
||||
|
||||
/**
|
||||
* Singleton access to anything related to world-based data.
|
||||
*
|
||||
* <p>
|
||||
* Data will change depending which world is loaded. Will probably not affect
|
||||
* SMP at all since only one world is loaded, but SSP more, cause they play on
|
||||
* different worlds.
|
||||
@@ -53,8 +54,15 @@ public final class WorldData implements IWorldData {
|
||||
@Nullable
|
||||
private static MinecraftServer server;
|
||||
|
||||
static {
|
||||
Metrics.gauge("grid_storage_count", () -> {
|
||||
WorldData worldData = (WorldData) instance;
|
||||
return worldData != null ? worldData.storageData.size() : 0;
|
||||
});
|
||||
}
|
||||
|
||||
private final IWorldPlayerData playerData;
|
||||
private final IWorldGridStorageData storageData;
|
||||
private final StorageData storageData;
|
||||
private final IWorldCompassData compassData;
|
||||
|
||||
private WorldData(@Nonnull final ServerWorld overworld) {
|
||||
@@ -80,7 +88,6 @@ public final class WorldData implements IWorldData {
|
||||
|
||||
/**
|
||||
* @return ae2 data related to a specific world
|
||||
*
|
||||
* @deprecated do not use singletons which are dependent on specific world state
|
||||
*/
|
||||
@Deprecated
|
||||
@@ -102,7 +109,7 @@ public final class WorldData implements IWorldData {
|
||||
|
||||
/**
|
||||
* Requires to start up from external from here
|
||||
*
|
||||
* <p>
|
||||
* drawback of the singleton build style
|
||||
*/
|
||||
public static void onServerStarting(MinecraftServer server) {
|
||||
|
||||
@@ -28,6 +28,7 @@ import net.minecraft.loot.RandomValueRange;
|
||||
import net.minecraft.loot.conditions.SurvivesExplosion;
|
||||
import net.minecraft.loot.functions.ApplyBonus;
|
||||
import net.minecraft.loot.functions.SetCount;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
@@ -62,12 +63,13 @@ public class BlockDropProvider extends BlockLootTables implements IAE2DataProvid
|
||||
|
||||
@Override
|
||||
public void act(@Nonnull DirectoryCache cache) throws IOException {
|
||||
for (Map.Entry<ResourceLocation, Block> entry : ForgeRegistries.BLOCKS.getEntries()) {
|
||||
for (Map.Entry<RegistryKey<Block>, Block> entry : ForgeRegistries.BLOCKS.getEntries()) {
|
||||
LootTable.Builder builder;
|
||||
if (entry.getKey().getNamespace().equals(AppEng.MOD_ID)) {
|
||||
if (entry.getKey().func_240901_a_().getNamespace().equals(AppEng.MOD_ID)) {
|
||||
builder = overrides.getOrDefault(entry.getValue(), this::defaultBuilder).apply(entry.getValue());
|
||||
|
||||
IDataProvider.save(GSON, cache, toJson(builder), getPath(outputFolder, entry.getKey()));
|
||||
IDataProvider.save(GSON, cache, toJson(builder),
|
||||
getPath(outputFolder, entry.getKey().func_240901_a_()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class MeteoritePlacerItem extends AEBaseItem {
|
||||
// is a debug tool, we'll not care about being terribly efficient here
|
||||
ChunkPos.getAllInBox(new ChunkPos(spawned.getPos()), 1).forEach(cp -> {
|
||||
Chunk c = world.getChunk(cp.x, cp.z);
|
||||
player.connection.sendPacket(new SChunkDataPacket(c, 65535, false)); // 65535 == full chunk
|
||||
player.connection.sendPacket(new SChunkDataPacket(c, 65535)); // 65535 == full chunk
|
||||
});
|
||||
|
||||
return ActionResultType.SUCCESS;
|
||||
|
||||
@@ -20,11 +20,8 @@ package appeng.decorative.solid;
|
||||
|
||||
import net.minecraft.block.AbstractGlassBlock;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.util.Direction;
|
||||
|
||||
import appeng.helpers.AEMaterials;
|
||||
|
||||
public class QuartzGlassBlock extends AbstractGlassBlock {
|
||||
|
||||
public QuartzGlassBlock(Properties props) {
|
||||
@@ -33,8 +30,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;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.ToolType;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
|
||||
import appeng.block.AEBaseBlock;
|
||||
import appeng.core.worlddata.WorldData;
|
||||
@@ -43,11 +42,10 @@ public class SkyStoneBlock extends AEBaseBlock {
|
||||
super(props);
|
||||
this.type = type;
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
MinecraftForge.EVENT_BUS.addListener(this::breakFaster);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void breakFaster(final PlayerEvent.BreakSpeed event) {
|
||||
private void breakFaster(final PlayerEvent.BreakSpeed event) {
|
||||
if (event.getState().getBlock() == this && event.getPlayer() != null) {
|
||||
final ItemStack is = event.getPlayer().getItemStackFromSlot(EquipmentSlotType.MAINHAND);
|
||||
int level = -1;
|
||||
|
||||
@@ -19,13 +19,14 @@
|
||||
package appeng.entity;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import appeng.api.features.AEFeature;
|
||||
@@ -35,12 +36,27 @@ import appeng.client.EffectType;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.items.misc.CrystalSeedItem;
|
||||
import appeng.util.Platform;
|
||||
|
||||
public final 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) {
|
||||
@@ -56,126 +72,140 @@ public final class GrowingCrystalEntity extends AEBaseItemEntity {
|
||||
public void tick() {
|
||||
super.tick();
|
||||
|
||||
final ItemStack is = this.getItem();
|
||||
final Item gc = is.getItem();
|
||||
|
||||
if (!(gc instanceof IGrowableCrystal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyGrowthTick((IGrowableCrystal) gc, is);
|
||||
}
|
||||
|
||||
private void applyGrowthTick(IGrowableCrystal cry, ItemStack is) {
|
||||
if (!AEConfig.instance().isFeatureEnabled(AEFeature.IN_WORLD_PURIFICATION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ItemStack is = this.getItem();
|
||||
final Item gc = is.getItem();
|
||||
final int x = MathHelper.floor(this.getPosX());
|
||||
final int y = MathHelper.floor((this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0D);
|
||||
final int z = MathHelper.floor(this.getPosZ());
|
||||
|
||||
if (gc instanceof IGrowableCrystal) // if it changes this just stops being an issue...
|
||||
{
|
||||
final int j = MathHelper.floor(this.getPosX());
|
||||
final int i = MathHelper.floor((this.getBoundingBox().minY + this.getBoundingBox().maxY) / 2.0D);
|
||||
final int k = MathHelper.floor(this.getPosZ());
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
final BlockState state = this.world.getBlockState(pos);
|
||||
|
||||
final BlockState state = this.world.getBlockState(new BlockPos(j, i, k));
|
||||
final Material mat = state.getMaterial();
|
||||
final IGrowableCrystal cry = (IGrowableCrystal) is.getItem();
|
||||
final float multiplier = cry.getMultiplier(state, world, pos);
|
||||
|
||||
final float multiplier = cry.getMultiplier(state.getBlock(), mat);
|
||||
final int speed = (int) Math.max(1, this.getSpeed(j, i, k) * multiplier);
|
||||
if (multiplier <= 0) {
|
||||
// Crystal is in unsuitable material, reset progress and quit
|
||||
this.progress_1000 = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isClient = Platform.isClient();
|
||||
final int progressPerTick = (int) Math.max(1, this.getSpeed(pos) * multiplier);
|
||||
|
||||
if (mat.isLiquid()) {
|
||||
if (isClient) {
|
||||
this.progress_1000++;
|
||||
} else {
|
||||
this.progress_1000 += speed;
|
||||
}
|
||||
} else {
|
||||
if (world.isRemote()) {
|
||||
// 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.proxy.spawnEffect(EffectType.Vibrant, this.world, this.getPosX(), this.getPosY() + 0.2,
|
||||
this.getPosZ(), 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.proxy.spawnEffect(EffectType.Vibrant, this.world, this.getPosX(), this.getPosY() + 0.2,
|
||||
this.getPosZ(), 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.setItem(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.setItem(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 TileEntity te = this.world.getTileEntity(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.func_239622_a_(pos, direction))) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private boolean isPoweredAccelerator(BlockPos pos) {
|
||||
final TileEntity te = this.world.getTileEntity(pos);
|
||||
|
||||
return te instanceof ICrystalGrowthAccelerator && ((ICrystalGrowthAccelerator) te).isPowered();
|
||||
}
|
||||
|
||||
// Don't let seeds "float" on water surface
|
||||
@Override
|
||||
protected void applyFloatMotion() {
|
||||
ItemStack item = getItem();
|
||||
|
||||
// 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) {
|
||||
Vector3d v = this.getMotion();
|
||||
|
||||
// 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.setMotion(v.x * 0.99, v.y + yAccel, v.z * 0.99);
|
||||
|
||||
return;
|
||||
}
|
||||
super.applyFloatMotion();
|
||||
|
||||
@@ -40,7 +40,6 @@ import net.minecraft.util.SoundEvents;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.Explosion;
|
||||
import net.minecraft.world.Explosion.Mode;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
||||
import net.minecraftforge.fml.network.NetworkHooks;
|
||||
@@ -140,8 +139,8 @@ public final class TinyTNTPrimedEntity extends TNTEntity implements IEntityAddit
|
||||
return;
|
||||
}
|
||||
|
||||
final Explosion ex = new Explosion(this.world, this, this.getPosX(), this.getPosY(), this.getPosZ(), 0.2f,
|
||||
false, Mode.BREAK);
|
||||
final Explosion ex = new Explosion(this.world, this, null, null, this.getPosX(), this.getPosY(), this.getPosZ(),
|
||||
0.2f, false, Explosion.Mode.BREAK);
|
||||
final AxisAlignedBB area = new AxisAlignedBB(this.getPosX() - 1.5, this.getPosY() - 1.5f, this.getPosZ() - 1.5,
|
||||
this.getPosX() + 1.5, this.getPosY() + 1.5, this.getPosZ() + 1.5);
|
||||
final List<Entity> list = this.world.getEntitiesWithinAABBExcludingEntity(this, area);
|
||||
|
||||
@@ -37,15 +37,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;
|
||||
@@ -56,6 +59,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();
|
||||
}
|
||||
@@ -84,6 +88,7 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
for (int x = 0; x < this.facades; x++) {
|
||||
this.storage.setFacade(x, newFacades[x]);
|
||||
}
|
||||
this.notifyChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,4 +180,9 @@ public class FacadeContainer implements IFacadeContainer {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void notifyChange() {
|
||||
this.changeCallback.run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ public class FluidTerminalScreen extends AEBaseMEScreen<FluidTerminalContainer>
|
||||
list.add(new StringTextComponent(formattedAmount));
|
||||
list.add(new StringTextComponent(modName));
|
||||
|
||||
this.renderTooltip(matrixStack, list, mouseX, mouseY);
|
||||
this.func_243308_b(matrixStack, list, mouseX, mouseY);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package appeng.fluids.client.gui.widgets;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
@@ -14,7 +15,6 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
import net.minecraft.util.text.TranslationTextComponent;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidAttributes;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.FluidUtil;
|
||||
@@ -73,7 +73,7 @@ public class FluidSlotWidget extends CustomSlotWidget {
|
||||
if (clickStack.isEmpty() || mouseButton == 1) {
|
||||
this.setFluidStack(null);
|
||||
} else if (mouseButton == 0) {
|
||||
final LazyOptional<FluidStack> fluidOpt = FluidUtil.getFluidContained(clickStack);
|
||||
final Optional<FluidStack> fluidOpt = FluidUtil.getFluidContained(clickStack);
|
||||
fluidOpt.ifPresent(fluid -> {
|
||||
this.setFluidStack(AEFluidStack.fromFluidStack(fluid));
|
||||
});
|
||||
|
||||
@@ -3,12 +3,12 @@ package appeng.fluids.container;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.inventory.container.ContainerType;
|
||||
import net.minecraft.inventory.container.IContainerListener;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.FluidUtil;
|
||||
|
||||
@@ -39,7 +39,7 @@ public abstract class FluidConfigurableContainer extends UpgradeableContainer im
|
||||
|
||||
@Override
|
||||
protected ItemStack transferStackToContainer(ItemStack input) {
|
||||
LazyOptional<FluidStack> fsOpt = FluidUtil.getFluidContained(input);
|
||||
Optional<FluidStack> fsOpt = FluidUtil.getFluidContained(input);
|
||||
if (fsOpt.isPresent()) {
|
||||
final IAEFluidTank t = this.getFluidConfigInventory();
|
||||
final IAEFluidStack stack = AEFluidStack.fromFluidStack(fsOpt.orElse(null));
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
|
||||
package appeng.fluids.helper;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidAttributes;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.FluidUtil;
|
||||
@@ -46,7 +47,7 @@ public class FluidCellConfig extends CellConfig {
|
||||
if (stack.isEmpty() || stack.getItem() instanceof FluidDummyItem) {
|
||||
super.insertItem(slot, stack, simulate);
|
||||
}
|
||||
LazyOptional<FluidStack> fluidOpt = FluidUtil.getFluidContained(stack);
|
||||
Optional<FluidStack> fluidOpt = FluidUtil.getFluidContained(stack);
|
||||
if (!fluidOpt.isPresent() || !Api.instance().definitions().items().dummyFluidItem().maybeStack(1).isPresent()) {
|
||||
return stack;
|
||||
}
|
||||
@@ -64,7 +65,7 @@ public class FluidCellConfig extends CellConfig {
|
||||
if (stack.isEmpty() || stack.getItem() instanceof FluidDummyItem) {
|
||||
super.setStackInSlot(slot, stack);
|
||||
}
|
||||
LazyOptional<FluidStack> fluidOpt = FluidUtil.getFluidContained(stack);
|
||||
Optional<FluidStack> fluidOpt = FluidUtil.getFluidContained(stack);
|
||||
if (!fluidOpt.isPresent() || !Api.instance().definitions().items().dummyFluidItem().maybeStack(1).isPresent()) {
|
||||
return;
|
||||
}
|
||||
@@ -82,7 +83,7 @@ public class FluidCellConfig extends CellConfig {
|
||||
if (stack.isEmpty() || stack.getItem() instanceof FluidDummyItem) {
|
||||
super.isItemValid(slot, stack);
|
||||
}
|
||||
LazyOptional<FluidStack> fluidOpt = FluidUtil.getFluidContained(stack);
|
||||
Optional<FluidStack> fluidOpt = FluidUtil.getFluidContained(stack);
|
||||
if (!fluidOpt.isPresent() || !Api.instance().definitions().items().dummyFluidItem().maybeStack(1).isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.tags.ITag;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
@@ -57,8 +56,8 @@ import appeng.util.Platform;
|
||||
|
||||
public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridTickable {
|
||||
|
||||
public static final ResourceLocation TAG_BLACKLIST = new ResourceLocation(AppEng.MOD_ID,
|
||||
"blacklisted/fluid_annihilation_plane");
|
||||
public static final ITag.INamedTag<Fluid> TAG_BLACKLIST = FluidTags
|
||||
.makeWrapperTag(AppEng.makeId("blacklisted/fluid_annihilation_plane").toString());
|
||||
|
||||
private static final PlaneModels MODELS = new PlaneModels("part/fluid_annihilation_plane",
|
||||
"part/fluid_annihilation_plane_on");
|
||||
@@ -214,8 +213,7 @@ public class FluidAnnihilationPlanePart extends BasicStatePart implements IGridT
|
||||
}
|
||||
|
||||
private boolean isFluidBlacklisted(Fluid fluid) {
|
||||
ITag<Fluid> tag = FluidTags.getCollection().getOrCreate(TAG_BLACKLIST);
|
||||
return fluid.isIn(tag);
|
||||
return TAG_BLACKLIST.contains(fluid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -96,16 +96,15 @@ public class FluidImportBusPart extends SharedFluidBusPart {
|
||||
}
|
||||
|
||||
final TileEntity te = this.getConnectedTE();
|
||||
LazyOptional<IFluidHandler> fhOpt = LazyOptional.empty();
|
||||
if (te != null) {
|
||||
te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, this.getSide().getFacing().getOpposite());
|
||||
}
|
||||
if (fhOpt.isPresent()) {
|
||||
try {
|
||||
final IFluidHandler fh = fhOpt.orElse(null);
|
||||
final IMEMonitor<IAEFluidStack> inv = this.getProxy().getStorage().getInventory(this.getChannel());
|
||||
LazyOptional<IFluidHandler> fhOpt = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
|
||||
this.getSide().getFacing().getOpposite());
|
||||
|
||||
if (fhOpt.isPresent()) {
|
||||
try {
|
||||
final IFluidHandler fh = fhOpt.orElseThrow(() -> new IllegalStateException());
|
||||
final IMEMonitor<IAEFluidStack> inv = this.getProxy().getStorage().getInventory(this.getChannel());
|
||||
|
||||
if (fh != null) {
|
||||
final FluidStack fluidStack = fh.drain(this.calculateAmountToSend(), FluidAction.SIMULATE);
|
||||
|
||||
if (this.filterEnabled() && !this.isInFilter(fluidStack)) {
|
||||
@@ -128,12 +127,11 @@ public class FluidImportBusPart extends SharedFluidBusPart {
|
||||
}
|
||||
|
||||
return TickRateModulation.IDLE;
|
||||
} catch (GridAccessException e) {
|
||||
// skip
|
||||
}
|
||||
} catch (GridAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return TickRateModulation.SLEEP;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ import appeng.core.AppEng;
|
||||
import appeng.core.sync.packets.PaintedEntityPacket;
|
||||
import appeng.crafting.CraftingJob;
|
||||
import appeng.me.Grid;
|
||||
import appeng.metrics.Metrics;
|
||||
import appeng.tile.AEBaseTileEntity;
|
||||
import appeng.util.IWorldCallable;
|
||||
import appeng.util.Platform;
|
||||
@@ -77,6 +78,11 @@ public class TickHandler {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
static {
|
||||
Metrics.gauge("ticking_network_count", () -> INSTANCE.server.networks.size());
|
||||
Metrics.gauge("crafting_job_count", INSTANCE.craftingJobs::size);
|
||||
}
|
||||
|
||||
public static void setup(IEventBus eventBus) {
|
||||
eventBus.addListener(INSTANCE::onServerTick);
|
||||
eventBus.addListener(INSTANCE::onWorldTick);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
package appeng.integration.abstraction;
|
||||
|
||||
import mezz.jei.api.runtime.IJeiRuntime;
|
||||
|
||||
import appeng.integration.IIntegrationModule;
|
||||
|
||||
/**
|
||||
@@ -25,6 +27,10 @@ import appeng.integration.IIntegrationModule;
|
||||
*/
|
||||
public interface IJEI extends IIntegrationModule {
|
||||
|
||||
default IJeiRuntime getRuntime() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getSearchText() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper;
|
||||
|
||||
import appeng.container.implementations.CraftingTermContainer;
|
||||
|
||||
public class CraftingRecipeTransferHandler extends RecipeTransferHandler<CraftingTermContainer> {
|
||||
|
||||
CraftingRecipeTransferHandler(Class<CraftingTermContainer> containerClass, IRecipeTransferHandlerHelper helper) {
|
||||
super(containerClass, helper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IRecipeTransferError doTransferRecipe(CraftingTermContainer container, IRecipe<?> recipe,
|
||||
IRecipeLayout recipeLayout, PlayerEntity player, boolean maxTransfer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCrafting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -111,6 +111,8 @@ class FacadeRegistryPlugin implements IRecipeManagerPlugin {
|
||||
ingredients.set(7, Ingredient.fromStacks(cableAnchor));
|
||||
ingredients.set(4, Ingredient.fromStacks(textureItem));
|
||||
|
||||
result.setCount(4);
|
||||
|
||||
return new ShapedRecipe(id, "", 3, 3, ingredients, result);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,11 +82,15 @@ public class JEIPlugin implements IModPlugin {
|
||||
|
||||
@Override
|
||||
public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) {
|
||||
// Allow recipe transfer from JEI to crafting and pattern terminal
|
||||
registration.addRecipeTransferHandler(new RecipeTransferHandler<>(CraftingTermContainer.class),
|
||||
VanillaRecipeCategoryUid.CRAFTING);
|
||||
registration.addRecipeTransferHandler(new RecipeTransferHandler<>(PatternTermContainer.class),
|
||||
|
||||
// Allow vanilla crafting recipe transfer from JEI to crafting terminal
|
||||
registration.addRecipeTransferHandler(
|
||||
new CraftingRecipeTransferHandler(CraftingTermContainer.class, registration.getTransferHelper()),
|
||||
VanillaRecipeCategoryUid.CRAFTING);
|
||||
|
||||
// Universal handler for processing to try and handle all IRecipe
|
||||
registration.addUniversalRecipeTransferHandler(
|
||||
new PatternRecipeTransferHandler(PatternTermContainer.class, registration.getTransferHelper()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,6 +37,10 @@ class JeiRuntimeAdapter implements IJEI {
|
||||
return true;
|
||||
}
|
||||
|
||||
public IJeiRuntime getRuntime() {
|
||||
return runtime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSearchText() {
|
||||
return Strings.nullToEmpty(this.runtime.getIngredientFilter().getFilterText());
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
|
||||
import mezz.jei.api.constants.VanillaRecipeCategoryUid;
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper;
|
||||
|
||||
import appeng.container.implementations.PatternTermContainer;
|
||||
|
||||
public class PatternRecipeTransferHandler extends RecipeTransferHandler<PatternTermContainer> {
|
||||
|
||||
PatternRecipeTransferHandler(Class<PatternTermContainer> containerClass, IRecipeTransferHandlerHelper helper) {
|
||||
super(containerClass, helper);
|
||||
}
|
||||
|
||||
protected IRecipeTransferError doTransferRecipe(PatternTermContainer container, IRecipe<?> recipe,
|
||||
IRecipeLayout recipeLayout, PlayerEntity player, boolean maxTransfer) {
|
||||
if (container.isCraftingMode()
|
||||
&& recipeLayout.getRecipeCategory().getUid() != VanillaRecipeCategoryUid.CRAFTING) {
|
||||
return this.helper
|
||||
.createUserErrorWithTooltip(I18n.format("jei.appliedenergistics2.requires_processing_mode"));
|
||||
}
|
||||
|
||||
if (recipe.getRecipeOutput().isEmpty()) {
|
||||
return this.helper.createUserErrorWithTooltip(I18n.format("jei.appliedenergistics2.no_output"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCrafting() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,101 +18,128 @@
|
||||
|
||||
package appeng.integration.modules.jei;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.container.Container;
|
||||
import net.minecraft.inventory.container.Slot;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.item.crafting.IRecipe;
|
||||
import net.minecraft.item.crafting.Ingredient;
|
||||
import net.minecraft.item.crafting.ShapedRecipe;
|
||||
import net.minecraft.item.crafting.ShapelessRecipe;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import mezz.jei.api.gui.IRecipeLayout;
|
||||
import mezz.jei.api.gui.ingredient.IGuiIngredient;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferError;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferHandler;
|
||||
import mezz.jei.api.recipe.transfer.IRecipeTransferHandlerHelper;
|
||||
|
||||
import appeng.container.slot.CraftingMatrixSlot;
|
||||
import appeng.container.slot.FakeCraftingMatrixSlot;
|
||||
import appeng.core.sync.network.NetworkHandler;
|
||||
import appeng.core.sync.packets.JEIRecipePacket;
|
||||
import appeng.util.Platform;
|
||||
import appeng.helpers.IContainerCraftingPacket;
|
||||
|
||||
class RecipeTransferHandler<T extends Container> implements IRecipeTransferHandler<T> {
|
||||
abstract class RecipeTransferHandler<T extends Container & IContainerCraftingPacket>
|
||||
implements IRecipeTransferHandler<T> {
|
||||
|
||||
private final Class<T> containerClass;
|
||||
protected final IRecipeTransferHandlerHelper helper;
|
||||
|
||||
RecipeTransferHandler(Class<T> containerClass) {
|
||||
RecipeTransferHandler(Class<T> containerClass, IRecipeTransferHandlerHelper helper) {
|
||||
this.containerClass = containerClass;
|
||||
this.helper = helper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getContainerClass() {
|
||||
public final Class<T> getContainerClass() {
|
||||
return this.containerClass;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IRecipeTransferError transferRecipe(T container, IRecipeLayout recipeLayout, PlayerEntity player,
|
||||
boolean maxTransfer, boolean doTransfer) {
|
||||
if (!doTransfer) {
|
||||
return null;
|
||||
public final IRecipeTransferError transferRecipe(T container, Object recipe, IRecipeLayout recipeLayout,
|
||||
PlayerEntity player, boolean maxTransfer, boolean doTransfer) {
|
||||
if (!(recipe instanceof IRecipe)) {
|
||||
return this.helper.createInternalError();
|
||||
}
|
||||
final IRecipe<?> irecipe = (IRecipe<?>) recipe;
|
||||
final ResourceLocation recipeId = irecipe.getId();
|
||||
|
||||
if (recipeId == null) {
|
||||
return this.helper.createUserErrorWithTooltip(I18n.format("jei.appliedenergistics2.missing_id"));
|
||||
}
|
||||
|
||||
Map<Integer, ? extends IGuiIngredient<ItemStack>> ingredients = recipeLayout.getItemStacks()
|
||||
.getGuiIngredients();
|
||||
|
||||
final CompoundNBT recipe = new CompoundNBT();
|
||||
|
||||
int slotIndex = 0;
|
||||
for (Map.Entry<Integer, ? extends IGuiIngredient<ItemStack>> ingredientEntry : ingredients.entrySet()) {
|
||||
IGuiIngredient<ItemStack> ingredient = ingredientEntry.getValue();
|
||||
if (!ingredient.isInput()) {
|
||||
continue;
|
||||
// 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 (!player.getEntityWorld().getRecipeManager().getRecipe(recipeId).isPresent()) {
|
||||
// Validate that the recipe is a shapeless or shapedrecipe, since we can
|
||||
// serialize those
|
||||
if (!(recipe instanceof ShapedRecipe) && !(recipe instanceof ShapelessRecipe)) {
|
||||
return this.helper.createUserErrorWithTooltip(I18n.format("jei.appliedenergistics2.missing_id"));
|
||||
}
|
||||
canSendReference = false;
|
||||
}
|
||||
|
||||
for (final Slot slot : container.inventorySlots) {
|
||||
if (slot instanceof CraftingMatrixSlot || slot instanceof FakeCraftingMatrixSlot) {
|
||||
if (slot.getSlotIndex() == slotIndex) {
|
||||
final ListNBT tags = new ListNBT();
|
||||
final List<ItemStack> list = new ArrayList<>();
|
||||
final ItemStack displayed = ingredient.getDisplayedIngredient();
|
||||
if (!irecipe.canFit(3, 3)) {
|
||||
return this.helper.createUserErrorWithTooltip(I18n.format("jei.appliedenergistics2.recipe_too_large"));
|
||||
}
|
||||
|
||||
// prefer currently displayed item
|
||||
if (displayed != null && !displayed.isEmpty()) {
|
||||
list.add(displayed);
|
||||
final IRecipeTransferError error = doTransferRecipe(container, irecipe, recipeLayout, player, maxTransfer);
|
||||
|
||||
if (error != null) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (doTransfer) {
|
||||
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.
|
||||
NonNullList<Ingredient> flatIngredients = NonNullList.withSize(9, Ingredient.EMPTY);
|
||||
ItemStack output = ItemStack.EMPTY;
|
||||
|
||||
// Determine the first JEI slot that has an actual input, we'll use this to
|
||||
// offset the
|
||||
// crafting grid target slot
|
||||
int firstInputSlot = recipeLayout.getItemStacks().getGuiIngredients().entrySet().stream()
|
||||
.filter(e -> e.getValue().isInput()).mapToInt(Map.Entry::getKey).min().orElse(0);
|
||||
|
||||
// Now map the actual ingredients into the output/input
|
||||
for (Map.Entry<Integer, ? extends IGuiIngredient<ItemStack>> entry : recipeLayout.getItemStacks()
|
||||
.getGuiIngredients().entrySet()) {
|
||||
IGuiIngredient<ItemStack> item = entry.getValue();
|
||||
if (item.getDisplayedIngredient() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int inputIndex = entry.getKey() - firstInputSlot;
|
||||
if (item.isInput() && inputIndex < flatIngredients.size()) {
|
||||
ItemStack displayedIngredient = item.getDisplayedIngredient();
|
||||
if (displayedIngredient != null) {
|
||||
flatIngredients.set(inputIndex, Ingredient.fromStacks(displayedIngredient));
|
||||
}
|
||||
|
||||
// prefer pure crystals.
|
||||
for (ItemStack stack : ingredient.getAllIngredients()) {
|
||||
if (Platform.isRecipePrioritized(stack)) {
|
||||
list.add(0, stack);
|
||||
} else {
|
||||
list.add(stack);
|
||||
}
|
||||
}
|
||||
|
||||
for (final ItemStack is : list) {
|
||||
final CompoundNBT tag = new CompoundNBT();
|
||||
is.write(tag);
|
||||
tags.add(tag);
|
||||
}
|
||||
|
||||
recipe.put("#" + slot.getSlotIndex(), tags);
|
||||
break;
|
||||
} else if (!item.isInput() && output.isEmpty()) {
|
||||
output = item.getDisplayedIngredient();
|
||||
}
|
||||
}
|
||||
|
||||
ShapedRecipe fallbackRecipe = new ShapedRecipe(recipeId, "", 3, 3, flatIngredients, output);
|
||||
NetworkHandler.instance().sendToServer(new JEIRecipePacket(fallbackRecipe, isCrafting()));
|
||||
}
|
||||
|
||||
slotIndex++;
|
||||
}
|
||||
|
||||
NetworkHandler.instance().sendToServer(new JEIRecipePacket(recipe));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract IRecipeTransferError doTransferRecipe(T container, IRecipe<?> recipe, IRecipeLayout recipeLayout,
|
||||
PlayerEntity player, boolean maxTransfer);
|
||||
|
||||
protected abstract boolean isCrafting();
|
||||
}
|
||||
|
||||
@@ -24,15 +24,19 @@ import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.util.ITooltipFlag;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.tags.ITag;
|
||||
import net.minecraft.util.IItemProvider;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.StringTextComponent;
|
||||
@@ -41,6 +45,7 @@ import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import appeng.api.implementations.items.IGrowableCrystal;
|
||||
import appeng.core.AEConfig;
|
||||
import appeng.core.localization.ButtonToolTips;
|
||||
import appeng.entity.GrowingCrystalEntity;
|
||||
import appeng.items.AEBaseItem;
|
||||
@@ -94,8 +99,24 @@ public class CrystalSeedItem extends AEBaseItem implements IGrowableCrystal {
|
||||
}
|
||||
|
||||
@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
|
||||
String improvedFluidTagName = AEConfig.instance().getImprovedFluidTag();
|
||||
if (improvedFluidTagName != null) {
|
||||
ITag<Fluid> tag = FluidTags.getCollection().get(new ResourceLocation(improvedFluidTagName));
|
||||
if (tag != null && state.getFluidState().isTagged(tag)) {
|
||||
return AEConfig.instance().getImprovedFluidMultiplier();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for the normal supported fluid
|
||||
if (world != null && world.func_234923_W_() == World.field_234919_h_) {
|
||||
// In the nether, use Lava as the "normal" fluid
|
||||
return state.getFluidState().isTagged(FluidTags.LAVA) ? 1 : 0;
|
||||
} else {
|
||||
return state.getFluidState().isTagged(FluidTags.WATER) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package appeng.items.misc;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemModelsProperties;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import appeng.bootstrap.components.IClientSetupComponent;
|
||||
|
||||
/**
|
||||
* 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
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public void setup() {
|
||||
// Expose the growth of the seed to the model system
|
||||
ItemModelsProperties.func_239418_a_(item, new ResourceLocation("appliedenergistics2:growth"),
|
||||
(is, w, p) -> CrystalSeedItem.getGrowthTicks(is) / (float) CrystalSeedItem.GROWTH_TICKS_REQUIRED);
|
||||
}
|
||||
}
|
||||
@@ -307,14 +307,27 @@ public class EncodedPatternItem extends AEBaseItem {
|
||||
final ListNBT tagIn = new ListNBT();
|
||||
final ListNBT tagOut = new ListNBT();
|
||||
|
||||
boolean hasInput = false;
|
||||
for (final ItemStack i : in) {
|
||||
tagIn.add(createItemTag(i));
|
||||
if (!i.isEmpty()) {
|
||||
hasInput = true;
|
||||
}
|
||||
}
|
||||
|
||||
Preconditions.checkArgument(hasInput, "cannot encode a pattern that has no inputs.");
|
||||
|
||||
boolean hasNonEmptyOutput = false;
|
||||
for (final ItemStack i : out) {
|
||||
tagOut.add(createItemTag(i));
|
||||
if (!i.isEmpty()) {
|
||||
hasNonEmptyOutput = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Patterns without any outputs are corrupt! Never encode such a pattern.
|
||||
Preconditions.checkArgument(hasNonEmptyOutput, "cannot encode a pattern that has no output.");
|
||||
|
||||
encodedValue.put(EncodedPatternItem.NBT_INGREDIENTS, tagIn);
|
||||
encodedValue.put(EncodedPatternItem.NBT_PRODUCTS, tagOut);
|
||||
return encodedValue;
|
||||
|
||||
@@ -58,7 +58,8 @@ public class FacadeItem extends AEBaseItem implements IFacadeItem, IAlphaPassIte
|
||||
/**
|
||||
* Block tag used to explicitly whitelist blocks for use in facades.
|
||||
*/
|
||||
private static final ResourceLocation TAG_WHITELISTED = new ResourceLocation(AppEng.MOD_ID, "whitelisted/facades");
|
||||
private static final ITag.INamedTag<Block> BLOCK_WHITELIST = BlockTags
|
||||
.makeWrapperTag(AppEng.makeId("whitelisted/facades").toString());
|
||||
|
||||
private static final String NBT_ITEM_ID = "item";
|
||||
|
||||
@@ -105,8 +106,7 @@ public class FacadeItem extends AEBaseItem implements IFacadeItem, IAlphaPassIte
|
||||
BlockState blockState = block.getDefaultState();
|
||||
|
||||
final boolean areTileEntitiesEnabled = AEConfig.instance().isFeatureEnabled(AEFeature.TILE_ENTITY_FACADES);
|
||||
ITag<Block> whitelistTag = BlockTags.getCollection().getOrCreate(TAG_WHITELISTED);
|
||||
final boolean isWhiteListed = block.isIn(whitelistTag);
|
||||
final boolean isWhiteListed = BLOCK_WHITELIST.contains(block);
|
||||
final boolean isModel = blockState.getRenderType() == BlockRenderType.MODEL;
|
||||
|
||||
final BlockState defaultState = block.getDefaultState();
|
||||
|
||||
@@ -324,21 +324,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);
|
||||
}
|
||||
|
||||
TileEntity be = w.getTileEntity(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.WorldEvent;
|
||||
@@ -159,12 +158,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.getChunkProvider().isChunkLoaded(cPos)) {
|
||||
// In future versions, we might actually want to delay the entire registration
|
||||
// until the center
|
||||
// tile begins ticking normally.
|
||||
if (theWorld.isBlockLoaded(qc.center.getPos())) {
|
||||
final World cur = theWorld.getServer().getWorld(theWorld.func_234923_W_());
|
||||
|
||||
final TileEntity te = theWorld.getTileEntity(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 QuantumBridgeTileEntity[] 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,54 @@
|
||||
package appeng.metrics;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheStats;
|
||||
|
||||
/**
|
||||
* Cache Metrics simplify reporting of metrics for a Guava {@link Cache}.
|
||||
*/
|
||||
public class CacheMetrics extends Metric {
|
||||
|
||||
private final Supplier<Cache<?, ?>> cacheSupplier;
|
||||
|
||||
// Pre-allocate these to avoid repeated concatenation during reporting
|
||||
private final String sizeId;
|
||||
private final String hitCountId;
|
||||
private final String missCountId;
|
||||
private final String loadSuccessCountId;
|
||||
private final String loadExceptionCountId;
|
||||
private final String totalLoadTimeId;
|
||||
private final String evictionCountId;
|
||||
|
||||
public CacheMetrics(String id, Supplier<Cache<?, ?>> cacheSupplier) {
|
||||
super(id);
|
||||
this.cacheSupplier = cacheSupplier;
|
||||
|
||||
this.sizeId = id + ".size";
|
||||
this.hitCountId = id + ".hit-count";
|
||||
this.missCountId = id + ".miss-count";
|
||||
this.loadSuccessCountId = id + ".load-success-count";
|
||||
this.loadExceptionCountId = id + ".load-exception-count";
|
||||
this.totalLoadTimeId = id + ".total-load-time";
|
||||
this.evictionCountId = id + ".eviction-count";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MetricVisitor visitor) {
|
||||
Cache<?, ?> cache = this.cacheSupplier.get();
|
||||
|
||||
if (cache != null) {
|
||||
visitor.visitGauge(sizeId, cache.size()); // Thread-safe
|
||||
|
||||
CacheStats stats = cache.stats(); // Thread-safe
|
||||
visitor.visitGauge(hitCountId, stats.hitCount());
|
||||
visitor.visitGauge(missCountId, stats.missCount());
|
||||
visitor.visitGauge(loadSuccessCountId, stats.loadSuccessCount());
|
||||
visitor.visitGauge(loadExceptionCountId, stats.loadExceptionCount());
|
||||
visitor.visitGauge(totalLoadTimeId, stats.totalLoadTime());
|
||||
visitor.visitGauge(evictionCountId, stats.evictionCount());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package appeng.metrics;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A Gauge is a Metric that will simply read the current value of something when
|
||||
* the metrics are being reported.
|
||||
*/
|
||||
class Gauge extends Metric {
|
||||
|
||||
private final Supplier<Number> valueSupplier;
|
||||
|
||||
public Gauge(String id, Supplier<Number> valueSupplier) {
|
||||
super(id);
|
||||
this.valueSupplier = valueSupplier;
|
||||
}
|
||||
|
||||
public Supplier<Number> getValueSupplier() {
|
||||
return valueSupplier;
|
||||
}
|
||||
|
||||
public Number getValue() {
|
||||
return valueSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MetricVisitor visitor) {
|
||||
visitor.visitGauge(getId(), getValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package appeng.metrics;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
abstract class Metric {
|
||||
|
||||
private final String id;
|
||||
|
||||
public Metric(String id) {
|
||||
this.id = Objects.requireNonNull(id);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
Metric metric = (Metric) o;
|
||||
return id.equals(metric.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
public abstract void accept(MetricVisitor visitor);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package appeng.metrics;
|
||||
|
||||
public interface MetricVisitor {
|
||||
|
||||
void visitGauge(String id, Number value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package appeng.metrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.LongSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheStats;
|
||||
|
||||
/**
|
||||
* Registry to register Metrics.
|
||||
*/
|
||||
public final class Metrics {
|
||||
|
||||
private static final List<Metric> metrics = new ArrayList<>();
|
||||
|
||||
private Metrics() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a Gauge, which is a simple metric with no state that will be
|
||||
* queried for its current value whenever metrics are being reported.
|
||||
*/
|
||||
public static synchronized void gauge(String id, Supplier<Number> valueSupplier) {
|
||||
metrics.add(new Gauge(id, valueSupplier));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register several standard metrics for a Guava {@link Cache}.
|
||||
*/
|
||||
public static synchronized void cache(String name, Cache<?, ?> cache) {
|
||||
metrics.add(new CacheMetrics(name, () -> cache));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register several standard metrics for a Guava {@link Cache} based on a
|
||||
* supplier to support an underlying changing cache.
|
||||
*/
|
||||
public static synchronized void cache(String name, Supplier<Cache<?, ?>> cacheSupplier) {
|
||||
metrics.add(new CacheMetrics(name, cacheSupplier));
|
||||
}
|
||||
|
||||
public static synchronized void visit(MetricVisitor visitor) {
|
||||
for (Metric metric : metrics) {
|
||||
metric.accept(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package appeng.metrics.endpoint;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
|
||||
import appeng.metrics.Metrics;
|
||||
import appeng.metrics.reporter.PrometheusReporter;
|
||||
|
||||
/**
|
||||
* Starts an embedded HTTP-Server that will expose the Metrics in a format
|
||||
* compatible with Prometheus.
|
||||
*/
|
||||
public class PrometheusEndpoint implements AutoCloseable {
|
||||
|
||||
private final HttpServer server;
|
||||
|
||||
private final PrometheusReporter reporter = new PrometheusReporter();
|
||||
|
||||
public PrometheusEndpoint(String hostname, int port) {
|
||||
try {
|
||||
this.server = HttpServer.create();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to create metrics HTTP-server", e);
|
||||
}
|
||||
|
||||
InetSocketAddress address;
|
||||
if (hostname.isEmpty()) {
|
||||
address = new InetSocketAddress((InetAddress) null, port);
|
||||
} else {
|
||||
address = new InetSocketAddress(hostname, port);
|
||||
}
|
||||
|
||||
// Default endpoint is /metrics in Prometheus
|
||||
this.server.createContext("/metrics", this::handler);
|
||||
|
||||
try {
|
||||
this.server.bind(address, 0);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to bind metrics HTTP server to " + address, e);
|
||||
}
|
||||
|
||||
this.server.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.server.stop(0);
|
||||
}
|
||||
|
||||
private synchronized void handler(HttpExchange exchange) throws IOException {
|
||||
// Update metrics
|
||||
reporter.reset();
|
||||
Metrics.visit(reporter);
|
||||
|
||||
CharSequence report = getReport();
|
||||
|
||||
exchange.getResponseHeaders().add("Content-Type", "text/plain; version=0.0.4");
|
||||
exchange.sendResponseHeaders(200, report.length());
|
||||
|
||||
try (Writer writer = new OutputStreamWriter(exchange.getResponseBody(), StandardCharsets.US_ASCII)) {
|
||||
writer.append(report);
|
||||
}
|
||||
exchange.close();
|
||||
}
|
||||
|
||||
private CharSequence getReport() {
|
||||
return reporter.getReport();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package appeng.metrics.reporter;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import appeng.metrics.MetricVisitor;
|
||||
|
||||
/**
|
||||
* Reports Metrics as simple key-value pairs to a {@link PrintStream} (i.e.
|
||||
* {@link System#out}).
|
||||
*/
|
||||
public class PrintStreamReporter implements MetricVisitor {
|
||||
|
||||
private final PrintStream out;
|
||||
|
||||
public PrintStreamReporter(PrintStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitGauge(String id, Number value) {
|
||||
out.println(id + '=' + value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package appeng.metrics.reporter;
|
||||
|
||||
import appeng.metrics.MetricVisitor;
|
||||
|
||||
/**
|
||||
* Reports the metrics in a format compatible with Prometheus.
|
||||
* <p>
|
||||
* See <a href=
|
||||
* "https://prometheus.io/docs/instrumenting/exposition_formats/">Prometheus
|
||||
* Docs</a>
|
||||
*/
|
||||
public class PrometheusReporter implements MetricVisitor {
|
||||
|
||||
private final StringBuilder response = new StringBuilder();
|
||||
|
||||
@Override
|
||||
public void visitGauge(String id, Number value) {
|
||||
printType(id, "gauge");
|
||||
appendId(id);
|
||||
response.append(' ').append(value.toString()).append('\n');
|
||||
}
|
||||
|
||||
private void printType(String id, String type) {
|
||||
response.append("# TYPE ");
|
||||
appendId(id);
|
||||
response.append(' ').append(type).append('\n');
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
response.setLength(0);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return response.length();
|
||||
}
|
||||
|
||||
public CharSequence getReport() {
|
||||
return response;
|
||||
}
|
||||
|
||||
private void appendId(String id) {
|
||||
response.append("appeng_");
|
||||
// Sanitize to [a-zA-Z0-9:_]
|
||||
for (int i = 0; i < id.length(); i++) {
|
||||
char ch = id.charAt(i);
|
||||
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == ':' || ch == '_') {
|
||||
response.append(ch);
|
||||
} else {
|
||||
response.append('_');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package appeng.mixins;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.world.chunk.listener.IChunkStatusListener;
|
||||
import net.minecraft.world.server.ChunkManager;
|
||||
|
||||
@Mixin(ChunkManager.class)
|
||||
public interface ThreadedAnvilChunkStorageAccessor {
|
||||
|
||||
@Accessor("field_219266_t")
|
||||
IChunkStatusListener getWorldGenerationProgressListener();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package appeng.mixins.feature;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.world.gen.feature.ConfiguredFeature;
|
||||
import net.minecraft.world.gen.feature.Features;
|
||||
import net.minecraft.world.gen.feature.IFeatureConfig;
|
||||
|
||||
@Mixin(Features.class)
|
||||
public interface ConfiguredFeaturesAccessor {
|
||||
|
||||
@Invoker("func_243968_a")
|
||||
static <FC extends IFeatureConfig> ConfiguredFeature<FC, ?> register(String id,
|
||||
ConfiguredFeature<FC, ?> configuredFeature) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package appeng.mixins.spatial;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.WorldGenRegistries;
|
||||
import net.minecraft.world.biome.BiomeRegistry;
|
||||
|
||||
import appeng.spatial.SpatialStorageBiome;
|
||||
import appeng.spatial.SpatialStorageDimensionIds;
|
||||
|
||||
/**
|
||||
* This only needs to be here because the server-side will create a dynamic
|
||||
* registry manager long before our mod is initialized.
|
||||
*/
|
||||
@Mixin(BiomeRegistry.class)
|
||||
public class BiomesMixin {
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void registerBiomes(CallbackInfo ci) {
|
||||
WorldGenRegistries.func_243664_a(WorldGenRegistries.field_243657_i,
|
||||
SpatialStorageDimensionIds.BIOME_KEY.func_240901_a_(), SpatialStorageBiome.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,4 +35,4 @@ public class DimensionOptionMixin {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,25 @@ package appeng.mixins.spatial;
|
||||
|
||||
import java.util.OptionalLong;
|
||||
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.server.IDynamicRegistries;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.registry.DynamicRegistries;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.util.registry.SimpleRegistry;
|
||||
import net.minecraft.world.Dimension;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.gen.DimensionSettings;
|
||||
|
||||
import appeng.spatial.SpatialStorageChunkGenerator;
|
||||
import appeng.spatial.SpatialStorageDimensionIds;
|
||||
|
||||
/**
|
||||
@@ -21,12 +31,37 @@ import appeng.spatial.SpatialStorageDimensionIds;
|
||||
@Mixin(value = DimensionType.class)
|
||||
public class DimensionTypeMixin {
|
||||
|
||||
@Inject(method = "func_236027_a_", at = @At("TAIL"))
|
||||
private static void addRegistryDefaults(IDynamicRegistries.Impl registryTracker, CallbackInfoReturnable<?> cir) {
|
||||
@Invoker("<init>")
|
||||
static DimensionType create(OptionalLong fixedTime, boolean hasSkylight, boolean hasCeiling, boolean ultrawarm,
|
||||
boolean natural, double coordinateScale, boolean piglinSafe, boolean bedWorks, boolean respawnAnchorWorks,
|
||||
boolean hasRaids, int logicalHeight, ResourceLocation infiniburn, ResourceLocation skyProperties,
|
||||
float ambientLight) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
registryTracker.func_239774_a_(SpatialStorageDimensionIds.DIMENSION_TYPE_ID,
|
||||
new DimensionType(OptionalLong.of(12000), false, false, false, false, false, false, true, false, false,
|
||||
256, BlockTags.INFINIBURN_OVERWORLD.getName(), 1.0f));
|
||||
@Inject(method = "func_236027_a_", at = @At("TAIL"))
|
||||
private static void addRegistryDefaults(DynamicRegistries.Impl registryTracker, CallbackInfoReturnable<?> cir) {
|
||||
DimensionType dimensionType = create(OptionalLong.of(12000), false, false, false, false, 1.0, false, false,
|
||||
false, false, 256, BlockTags.INFINIBURN_OVERWORLD.getName(),
|
||||
SpatialStorageDimensionIds.SKY_PROPERTIES_ID, 1.0f);
|
||||
|
||||
Registry.register(registryTracker.func_230520_a_(),
|
||||
SpatialStorageDimensionIds.DIMENSION_TYPE_ID.func_240901_a_(), dimensionType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert our custom dimension into the initial registry. <em>This is what will
|
||||
* ultimately lead to the creation of a new World.</em>
|
||||
*/
|
||||
@Inject(method = "func_242718_a", at = @At("RETURN"))
|
||||
private static void buildDimensionRegistry(Registry<DimensionType> dimensionTypes, Registry<Biome> biomes,
|
||||
Registry<DimensionSettings> dimensionSettings, long seed,
|
||||
CallbackInfoReturnable<SimpleRegistry<Dimension>> cir) {
|
||||
SimpleRegistry<Dimension> simpleregistry = cir.getReturnValue();
|
||||
|
||||
simpleregistry.register(SpatialStorageDimensionIds.DIMENSION_ID, new Dimension(() -> {
|
||||
return dimensionTypes.func_243576_d(SpatialStorageDimensionIds.DIMENSION_TYPE_ID);
|
||||
}, new SpatialStorageChunkGenerator(biomes)), Lifecycle.stable());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package appeng.mixins.spatial;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.block.PortalInfo;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
import appeng.spatial.SpatialStorageDimensionIds;
|
||||
import appeng.spatial.SpatialStorageHelper;
|
||||
|
||||
/**
|
||||
* This mixin sets the teleport destination, because otherwise Vanilla will not
|
||||
* move the player.
|
||||
*/
|
||||
@Mixin(Entity.class)
|
||||
public class EntityMixin {
|
||||
|
||||
@Inject(method = "func_241829_a", at = @At("HEAD"), cancellable = true, allow = 1)
|
||||
public void getTeleportTarget(ServerWorld destination, CallbackInfoReturnable<PortalInfo> cri) {
|
||||
// Check if a destination has been set for the entity currently being teleported
|
||||
if (destination.func_234923_W_() == SpatialStorageDimensionIds.WORLD_ID) {
|
||||
PortalInfo target = SpatialStorageHelper.getInstance().getTeleportTarget();
|
||||
if (target != null) {
|
||||
cri.setReturnValue(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
package appeng.mixins.spatial;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.world.DimensionRenderInfo;
|
||||
import net.minecraft.util.RegistryKey;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
|
||||
import appeng.spatial.SpatialStorageDimensionIds;
|
||||
import appeng.spatial.SpatialStorageSkyProperties;
|
||||
@@ -17,12 +17,12 @@ import appeng.spatial.SpatialStorageSkyProperties;
|
||||
@Mixin(DimensionRenderInfo.class)
|
||||
public class SkyPropertiesMixin {
|
||||
|
||||
@Inject(method = "func_239215_a_", at = @At("HEAD"), cancellable = true)
|
||||
private static void byDimensionType(Optional<RegistryKey<DimensionType>> optional,
|
||||
CallbackInfoReturnable<DimensionRenderInfo> ci) {
|
||||
if (optional.orElse(null) == SpatialStorageDimensionIds.DIMENSION_TYPE_ID) {
|
||||
ci.setReturnValue(SpatialStorageSkyProperties.INSTANCE);
|
||||
}
|
||||
@Shadow
|
||||
private static Object2ObjectMap<ResourceLocation, DimensionRenderInfo> field_239208_a_/* BY_IDENTIFIER */;
|
||||
|
||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
||||
private static void init(CallbackInfo ci) {
|
||||
field_239208_a_.put(SpatialStorageDimensionIds.SKY_PROPERTIES_ID, SpatialStorageSkyProperties.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ public class SkyRenderMixin {
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Inject(method = "renderSky(Lcom/mojang/blaze3d/matrix/MatrixStack;F)V", at = @At("HEAD"), cancellable = true)
|
||||
public void renderSky(MatrixStack matrices, float tickDelta, CallbackInfo ci) {
|
||||
if (mc.world.func_234922_V_() == SpatialStorageDimensionIds.DIMENSION_TYPE_ID) {
|
||||
if (mc.world.func_234923_W_() == SpatialStorageDimensionIds.WORLD_ID) {
|
||||
SpatialSkyRender.getInstance().render(matrices);
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package appeng.mixins.structure;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
|
||||
/**
|
||||
* Allows access to the copy of _all_ structures that is maintained within each
|
||||
* instance of {@link Biome}, in order to add our new structure to it. Note that
|
||||
* this does not mean the structure will start _generating_ in this biome, it
|
||||
* will only continue to generate if an adjacent biome has started the structure
|
||||
* and it extends into this one.
|
||||
*/
|
||||
@Mixin(Biome.class)
|
||||
public interface BiomeAccessor {
|
||||
|
||||
@Accessor
|
||||
Map<Integer, List<Structure<?>>> getField_242421_g();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package appeng.mixins.structure;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
|
||||
import net.minecraft.world.gen.feature.IFeatureConfig;
|
||||
import net.minecraft.world.gen.feature.StructureFeature;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
import net.minecraft.world.gen.feature.structure.StructureFeatures;
|
||||
|
||||
@Mixin(StructureFeatures.class)
|
||||
public interface ConfiguredStructureFeaturesAccessor {
|
||||
|
||||
@Invoker("func_244162_a")
|
||||
static <FC extends IFeatureConfig, F extends Structure<FC>> StructureFeature<FC, F> register(String id,
|
||||
StructureFeature<FC, F> configuredStructureFeature) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package appeng.mixins;
|
||||
package appeng.mixins.structure;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package appeng.mixins.structure;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.world.biome.BiomeGenerationSettings;
|
||||
import net.minecraft.world.gen.feature.ConfiguredFeature;
|
||||
import net.minecraft.world.gen.feature.StructureFeature;
|
||||
|
||||
/**
|
||||
* Allows the settings in a Biome's generation settings to be modified.
|
||||
*/
|
||||
@Mixin(BiomeGenerationSettings.class)
|
||||
public interface GenerationSettingsAccessor {
|
||||
|
||||
@Accessor("field_242484_f")
|
||||
List<List<Supplier<ConfiguredFeature<?, ?>>>> getFeatures();
|
||||
|
||||
@Accessor("field_242484_f")
|
||||
void setFeatures(List<List<Supplier<ConfiguredFeature<?, ?>>>> features);
|
||||
|
||||
@Accessor("field_242485_g")
|
||||
List<Supplier<StructureFeature<?, ?>>> getStructureFeatures();
|
||||
|
||||
@Accessor("field_242485_g")
|
||||
void setStructureFeatures(List<Supplier<StructureFeature<?, ?>>> structureFeatures);
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package appeng.mixins;
|
||||
package appeng.mixins.structure;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
@@ -7,10 +7,10 @@ import net.minecraft.world.gen.GenerationStage;
|
||||
import net.minecraft.world.gen.feature.structure.Structure;
|
||||
|
||||
@Mixin(Structure.class)
|
||||
public interface StructureAccessor {
|
||||
public interface StructureFeatureAccessor {
|
||||
|
||||
@Invoker("func_236394_a_")
|
||||
static <F extends Structure<?>> F register(String id, F feature, GenerationStage.Decoration defaultStage) {
|
||||
static <F extends Structure<?>> F register(String id, F structureFeature, GenerationStage.Decoration step) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.util.math.shapes.VoxelShapes;
|
||||
import net.minecraft.util.math.vector.Vector3d;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.World;
|
||||
@@ -82,7 +81,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 +123,7 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
|
||||
|
||||
@Override
|
||||
public IFacadeContainer getFacadeContainer() {
|
||||
return new FacadeContainer(this);
|
||||
return new FacadeContainer(this, this::invalidateShapes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1096,11 +1094,7 @@ public class CableBusContainer extends CableBusStorage implements AEMultiTile, I
|
||||
}
|
||||
}
|
||||
|
||||
VoxelShape shape = VoxelShapes.empty();
|
||||
for (final AxisAlignedBB bx : boxes) {
|
||||
shape = VoxelShapes.or(shape, VoxelShapes.create(bx));
|
||||
}
|
||||
return shape;
|
||||
return VoxelShapeCache.get(boxes);
|
||||
}
|
||||
|
||||
private void invalidateShapes() {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.shapes.IBooleanFunction;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.util.math.shapes.VoxelShapes;
|
||||
|
||||
/**
|
||||
* While creation of a {@link VoxelShape} with
|
||||
* {@link VoxelShapes#create(AxisAlignedBB)} is fast enough, combining voxel
|
||||
* shapes with {@link VoxelShapes#or(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<AxisAlignedBB>, VoxelShape> CACHE = CacheBuilder.newBuilder()//
|
||||
.maximumSize(10000L)//
|
||||
.build(new CacheLoader<List<AxisAlignedBB>, VoxelShape>() {
|
||||
@Override
|
||||
public VoxelShape load(List<AxisAlignedBB> key) {
|
||||
return create(key);
|
||||
}
|
||||
});
|
||||
|
||||
private VoxelShapeCache() {
|
||||
}
|
||||
|
||||
public static VoxelShape get(List<AxisAlignedBB> boxes) {
|
||||
return CACHE.getUnchecked(boxes);
|
||||
}
|
||||
|
||||
private static VoxelShape create(List<AxisAlignedBB> boxes) {
|
||||
if (boxes.isEmpty()) {
|
||||
return VoxelShapes.empty();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
VoxelShape shape = VoxelShapes.create(boxes.get(i));
|
||||
for (; i < boxes.size(); i++) {
|
||||
AxisAlignedBB box = boxes.get(i);
|
||||
shape = VoxelShapes.combine(shape, VoxelShapes.create(box), IBooleanFunction.OR);
|
||||
}
|
||||
return shape.simplify();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -82,6 +82,10 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
|
||||
public static final ResourceLocation TAG_BLACKLIST = new ResourceLocation(AppEng.MOD_ID,
|
||||
"blacklisted/annihilation_plane");
|
||||
|
||||
private static final ITag.INamedTag<Block> BLOCK_BLACKLIST = BlockTags.makeWrapperTag(TAG_BLACKLIST.toString());
|
||||
|
||||
private static final ITag.INamedTag<Item> ITEM_BLACKLIST = ItemTags.makeWrapperTag(TAG_BLACKLIST.toString());
|
||||
|
||||
private static final PlaneModels MODELS = new PlaneModels("part/annihilation_plane", "part/annihilation_plane_on");
|
||||
|
||||
@PartModels
|
||||
@@ -527,13 +531,11 @@ public class AnnihilationPlanePart extends BasicStatePart implements IGridTickab
|
||||
}
|
||||
|
||||
public static boolean isBlockBlacklisted(Block b) {
|
||||
ITag<Block> tag = BlockTags.getCollection().getOrCreate(TAG_BLACKLIST);
|
||||
return b.isIn(tag);
|
||||
return BLOCK_BLACKLIST.contains(b);
|
||||
}
|
||||
|
||||
public static boolean isItemBlacklisted(Item i) {
|
||||
ITag<Item> tag = ItemTags.getCollection().getOrCreate(TAG_BLACKLIST);
|
||||
return i.isIn(tag);
|
||||
return ITEM_BLACKLIST.contains(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user