Compare commits

...

32 Commits

Author SHA1 Message Date
Sebastian Hartte 53f7046f93 Metrics WIP 2020-09-10 18:55:22 +02:00
yueh 44544c598f Fixes #4253: Just transfer the recipe id instead of every ingredient. (#4689)
* Fixes #4253: Just transfer the recipe id instead of every ingredient.
* If possible handle any IRecipe for processing mode
* Improvements and support for AE2 facades.
* Switched to using JEI's displayed stacks (which means we can remove the shapeless variant).

Co-authored-by: Sebastian Hartte <sebastian@hartte.de>
2020-09-09 14:08:24 +02:00
Sebastian Hartte bcee2ec427 Slightly increased the height of the item hitbox for crystals to make their pickup by annihilation planes less "clippy". 2020-09-09 02:23:58 +02:00
Sebastian Hartte 9e41d543f5 Merge remote-tracking branch 'origin/8.0.x-1.16.1' 2020-09-09 00:59:58 +02:00
Sebastian Hartte 0f469e9df6 Bumped Forge version. 2020-09-07 23:34:56 +02:00
Sebastian Hartte 12ca8d109a Merge remote-tracking branch 'origin/8.0.x-1.16.1' 2020-09-02 02:55:12 +02:00
shartte b756d68be1 Implemented a cache with maximum quad-count it will cache for the cable bus, (#4670)
which also fixes concurrent access to the hashmap.
2020-09-01 18:20:51 +02:00
Sebastian Hartte 60b07e5ca5 Merge branch '8.0.x-1.16.1' 2020-09-01 01:07:47 +02:00
shartte 957bc4c5cc Fixes removal of facades not invalidating the cached server-side collision boxes. (#4663) 2020-08-31 23:10:25 +02:00
yueh e90dd2f9c6 Serialize the complete NBT data to avoid mismatches (#4665)
This might increase the network traffic a bit, but the amount of mods actually using the share tag seems to be very limited.
For now it is worth the risk as it solves the problem. In case we run into actual issues, there might still be other solutions, which will be way more complex and can potentially introduce additional problems.
2020-08-31 23:09:14 +02:00
Sebastian Hartte 9719c7ffc3 Bump to Forge 33.0.22 2020-08-29 23:13:29 +02:00
Sebastian Hartte 319d92a371 Merge branch '8.0.x-1.16.1' 2020-08-29 22:18:12 +02:00
Masakitenchi 3a0552c56e Update zh_cn.json (#4653) 2020-08-28 10:49:11 +02:00
Sebastian Hartte 8a0dd192e5 Added Modmaven repository to README.md 2020-08-26 23:19:42 +02:00
Sebastian Hartte a97b35f3d0 Merge branch '8.0.x-1.16.1' 2020-08-26 11:39:20 +02:00
Sebastian Hartte 1394ab0863 Merge branch '8.0.x-1.16.1' 2020-08-24 23:54:57 +02:00
Sebastian Hartte 159f4c7f14 Merge branch '8.0.x-1.16.1' 2020-08-24 22:33:38 +02:00
Sebastian Hartte ee7fe9f40d Merge branch '8.0.x-1.16.1' 2020-08-24 01:06:50 +02:00
Sebastian Hartte 9c9a49f9e7 Merge branch '8.0.x-1.16.1' 2020-08-23 20:48:19 +02:00
Sebastian Hartte b7949e4134 Re-Enabled JEI and TOP in dev. 2020-08-22 19:56:37 +02:00
Sebastian Hartte ea95913ec8 Merge branch '8.0.x-1.16.1' 2020-08-22 19:38:36 +02:00
shartte 33d7f02323 Fixes #4590: Crystal seeds (other than certus) don't display their growth stages. (#4619) 2020-08-19 16:43:47 +02:00
shartte b8d4f0cffa Fixes #4611: Use of client-side only method for Tiny TNT explosion. (#4612) 2020-08-18 01:35:31 +02:00
yueh 7e1bfdb5ac Added step to publish to modmaven (#4607) 2020-08-17 22:28:01 +02:00
shartte 1f9707e256 Fixes #4602: Prevent encoding invalid patterns and handle corrupted patterns a little more gracefully. (#4608) 2020-08-17 21:50:28 +02:00
shartte 954ce1442e Fixes #4598: Incorrectly rotated face for determining block lightlevel in ME Chest renderer. (#4599) 2020-08-17 21:43:16 +02:00
Sebastian Hartte ee67c5ea50 Use different naming for fullbright, and always reset it back after setting it. 2020-08-16 14:05:10 +02:00
Sebastian Hartte 73735c5cd5 Remove use of func_244388_a, which is client-only. 2020-08-15 17:29:36 +02:00
Sebastian Hartte c1713f1682 Bump to Forge 33.0.5 2020-08-15 14:32:53 +02:00
Sebastian Hartte f455fd1994 Initial port to 1.16.2 2020-08-13 23:29:55 +02:00
Sebastian Hartte 1657c88681 Initial port to 1.16.2 2020-08-13 23:15:09 +02:00
Sebastian Hartte fd67e0e5c6 Initial port to 1.16.2 2020-08-13 23:14:49 +02:00
90 changed files with 1716 additions and 649 deletions
+11 -3
View File
@@ -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'
}
}
}
+7 -6
View File
@@ -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
#########################################################
+2 -2
View File
@@ -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}")
@@ -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);
}
@@ -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,6 +18,7 @@
package appeng.client.render.cablebus;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
@@ -51,12 +52,21 @@ 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 {
// 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;
@@ -74,6 +84,7 @@ public class CableBusBakedModel implements IBakedModel {
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>>() {
@@ -84,6 +95,7 @@ public class CableBusBakedModel implements IBakedModel {
return model;
}
});
cacheForMetrics = new WeakReference<>(cableModelCache);
}
@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();
}
@@ -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() {
+11
View File
@@ -404,6 +404,10 @@ public final class AEConfig {
return COMMON.improvedFluidMultiplier.get().floatValue();
}
public int getPrometheusMetricsServerPort() {
return COMMON.prometheusMetricsServer.get();
}
// Setters keep visibility as low as possible.
private static class ClientConfig {
@@ -474,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;
@@ -558,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();
+28 -6
View File
@@ -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)
@@ -312,7 +312,7 @@ public final class ApiItems implements IItems {
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)
@@ -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
@@ -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,11 +19,9 @@
package appeng.core.sync.packets;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferOverflowException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPOutputStream;
import javax.annotation.Nullable;
@@ -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;
@@ -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;
@@ -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);
}
}
@@ -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();
}
@@ -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();
@@ -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());
}
}
}
+31
View File
@@ -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());
}
}
+34
View File
@@ -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);
}
+51
View File
@@ -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,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);
}
@@ -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();
}
@@ -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);
}
}
@@ -379,12 +379,12 @@ public class FormationPlanePart extends AbstractFormationPlanePart<IAEItemStack>
@Override
public BlockPos getPos() {
return this.rayTraceResult.getPos();
return this.func_242401_i().getPos();
}
@Override
public boolean canPlace() {
return this.world.getBlockState(this.rayTraceResult.getPos()).isReplaceable(this);
return getWorld().getBlockState(this.getPos()).isReplaceable(this);
}
@Override
+2 -1
View File
@@ -19,6 +19,7 @@
package appeng.server;
import appeng.server.subcommands.ChunkLogger;
import appeng.server.subcommands.MetricsCommand;
import appeng.server.subcommands.SpatialStorageCommand;
import appeng.server.subcommands.Supporters;
import appeng.server.subcommands.TestMeteoritesCommand;
@@ -27,7 +28,7 @@ import appeng.server.subcommands.TestOreGenCommand;
public enum Commands {
Chunklogger(4, new ChunkLogger(), false), Supporters(0, new Supporters(), false),
TestOreGen(4, new TestOreGenCommand(), true), TestMeteorites(4, new TestMeteoritesCommand(), true),
Spatial(4, new SpatialStorageCommand(), false);
Spatial(4, new SpatialStorageCommand(), false), Metrics(4, new MetricsCommand(), false);
public final int level;
public final ISubCommand command;
@@ -0,0 +1,25 @@
package appeng.server.subcommands;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.command.CommandSource;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.text.StringTextComponent;
import appeng.metrics.Metrics;
import appeng.metrics.reporter.PrintStreamReporter;
import appeng.server.ISubCommand;
/**
* A simple way of printing out AE2's metrics on the server console.
*/
public class MetricsCommand implements ISubCommand {
@Override
public void call(MinecraftServer srv, CommandContext<CommandSource> ctx, CommandSource sender) {
System.out.println("-------- AE2 Metrics:");
Metrics.visit(new PrintStreamReporter(System.out));
System.out.println("-------- END");
sender.sendFeedback(new StringTextComponent("Metrics reported to server console..."), false);
}
}
@@ -110,7 +110,7 @@ public class SpatialStorageCommand implements ISubCommand {
}
}
throw new CommandException(ITextComponent.func_241827_a_("Couldn't find a plot for the current position."));
throw new CommandException(new StringTextComponent("Couldn't find a plot for the current position."));
}
@@ -120,8 +120,7 @@ public class SpatialStorageCommand implements ISubCommand {
private void teleportBack(CommandSource source, SpatialStoragePlot plot) {
TransitionInfo lastTransition = plot.getLastTransition();
if (lastTransition == null) {
throw new CommandException(
ITextComponent.func_241827_a_("This plot doesn't have a last known transition."));
throw new CommandException(new StringTextComponent("This plot doesn't have a last known transition."));
}
String command = getTeleportCommand(lastTransition.getWorldId(), lastTransition.getMin().add(0, 1, 0));
@@ -212,7 +211,7 @@ public class SpatialStorageCommand implements ISubCommand {
if (!(cell.getItem() instanceof SpatialStorageCellItem)) {
throw new CommandException(
ITextComponent.func_241827_a_("Storage cell items don't implement the storage cell interface!"));
new StringTextComponent("Storage cell items don't implement the storage cell interface!"));
}
SpatialStorageCellItem spatialCellItem = (SpatialStorageCellItem) cell.getItem();
@@ -321,7 +320,7 @@ public class SpatialStorageCommand implements ISubCommand {
}
}
throw new CommandException(ITextComponent.func_241827_a_("Couldn't find a plot for the current position."));
throw new CommandException(new StringTextComponent("Couldn't find a plot for the current position."));
}
}
@@ -172,8 +172,9 @@ public class TestMeteoritesCommand implements ISubCommand {
msg.append(getClickablePosition(world, settings, pos)).append(restOfLine);
// Add a tooltip
String biomeId = world.func_242406_i(pos).map(bk -> bk.func_240901_a_().toString()).orElse("unknown");
ITextComponent tooltip = new StringTextComponent(settings.toString() + "\nBiome: ").deepCopy()
.append(world.getBiome(pos).getDisplayName());
.appendString(biomeId);
msg.modifyStyle(style -> style.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, tooltip)));
sender.sendFeedback(msg, true);
@@ -31,8 +31,7 @@ import net.minecraft.block.Block;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraft.world.IServerWorld;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.event.world.WorldEvent;
@@ -92,18 +91,14 @@ public final class CompassService {
}
}
public void tryUpdateArea(final IWorld w, ChunkPos chunkPos) {
public void tryUpdateArea(final IServerWorld w, ChunkPos chunkPos) {
// If this seems weird: during worldgen, WorldAccess is a specific region, but
// getWorld is
// still the server world. We do need to use the world access to get the chunk
// in question
// though, since during worldgen, it's not comitted to the actual world yet.
World world = w.getWorld();
if (!(world instanceof ServerWorld)) {
return;
}
IChunk chunk = w.getChunk(chunkPos.x, chunkPos.z);
updateArea((ServerWorld) world, chunk);
updateArea(w.getWorld(), chunk);
}
public void updateArea(final ServerWorld w, IChunk chunk) {
@@ -323,7 +323,7 @@ public class CachedPlane {
WorldData.instance().compassData().service().updateArea(this.getWorld(), c);
SChunkDataPacket cdp = new SChunkDataPacket(c, verticalBits, false);
SChunkDataPacket cdp = new SChunkDataPacket(c, verticalBits);
world.getChunkProvider().chunkManager.getTrackingPlayers(c.getPos(), false)
.forEach(spe -> spe.connection.sendPacket(cdp));
}
@@ -20,33 +20,25 @@ package appeng.spatial;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeAmbience;
import net.minecraft.world.biome.BiomeGenerationSettings;
import net.minecraft.world.biome.MobSpawnInfo;
import net.minecraft.world.gen.surfacebuilders.ConfiguredSurfaceBuilder;
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
/**
* The single biome used within the spatial storage world.
*/
public class SpatialStorageBiome extends Biome {
public class SpatialStorageBiome {
public static final SpatialStorageBiome INSTANCE = new SpatialStorageBiome();
public SpatialStorageBiome() {
super(new Biome.Builder()
.surfaceBuilder(
new ConfiguredSurfaceBuilder<>(SurfaceBuilder.NOPE, SurfaceBuilder.STONE_STONE_GRAVEL_CONFIG))
.precipitation(RainType.NONE).category(Category.NONE).depth(0).scale(1)
// Copied from the vanilla void biome
.temperature(0.5F).downfall(0.5F).func_235097_a_(new BiomeAmbience.Builder().setWaterColor(4159204)
.setWaterFogColor(329011).setFogColor(0).build())
.parent(null));
}
@Override
@OnlyIn(Dist.CLIENT)
public int getSkyColor() {
return 0x111111;
}
public static final Biome INSTANCE = new Biome.Builder()
.func_242457_a(new BiomeGenerationSettings.Builder().func_242517_a(
new ConfiguredSurfaceBuilder<>(SurfaceBuilder.NOPE, SurfaceBuilder.STONE_STONE_GRAVEL_CONFIG))
.func_242508_a())
.precipitation(Biome.RainType.NONE).category(Biome.Category.NONE).depth(0).scale(1)
// Copied from the vanilla void biome
.temperature(0.5F).downfall(0.5F)
.func_235097_a_(new BiomeAmbience.Builder().setWaterColor(4159204).setWaterFogColor(329011).setFogColor(0)
.func_242539_d(0x111111).build())
.func_242458_a(new MobSpawnInfo.Builder().func_242572_a(0).func_242577_b()).func_242455_a();
}
@@ -23,15 +23,16 @@ import java.util.Collections;
import java.util.Optional;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryLookupCodec;
import net.minecraft.world.Blockreader;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeManager;
import net.minecraft.world.biome.provider.BiomeProvider;
import net.minecraft.world.biome.provider.SingleBiomeProvider;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.gen.ChunkGenerator;
@@ -48,18 +49,28 @@ import appeng.core.Api;
*/
public class SpatialStorageChunkGenerator extends ChunkGenerator {
/**
* This codec is necessary to restore the actual instance of the Biome we use,
* since it is sources from the dynamic registries and <em>must be the same
* object as in the registry!</em>.
* <p>
* If it was not the same object, then the Object->ID lookup would fail since it
* uses an identity hashmap internally.
*/
public static final Codec<SpatialStorageChunkGenerator> CODEC = RegistryLookupCodec
.func_244331_a(Registry.BIOME_KEY)
.xmap(SpatialStorageChunkGenerator::new, SpatialStorageChunkGenerator::getBiomeRegistry).stable().codec();
private final Registry<Biome> biomeRegistry;
private final Blockreader columnSample;
public static final SpatialStorageChunkGenerator INSTANCE = new SpatialStorageChunkGenerator();
public static final Codec<SpatialStorageChunkGenerator> CODEC = RecordCodecBuilder
.create((instance) -> instance.stable(INSTANCE));
private final BlockState defaultBlockState;
private SpatialStorageChunkGenerator() {
super(createBiomeProvider(), createSettings());
public SpatialStorageChunkGenerator(Registry<Biome> biomeRegistry) {
super(createBiomeSource(biomeRegistry), createSettings());
this.defaultBlockState = Api.instance().definitions().blocks().matrixFrame().block().getDefaultState();
this.biomeRegistry = biomeRegistry;
// Vertical sample is mostly used for Feature generation, for those purposes
// we're all filled with matrix blocks
@@ -73,8 +84,13 @@ public class SpatialStorageChunkGenerator extends ChunkGenerator {
return CODEC;
}
private static BiomeProvider createBiomeProvider() {
return new SingleBiomeProvider(SpatialStorageBiome.INSTANCE);
private static SingleBiomeProvider createBiomeSource(Registry<Biome> biomeRegistry) {
return new SingleBiomeProvider(
biomeRegistry.func_243576_d/* getOrThrow */(SpatialStorageDimensionIds.BIOME_KEY));
}
public Registry<Biome> getBiomeRegistry() {
return biomeRegistry;
}
private static DimensionStructuresSettings createSettings() {
@@ -6,6 +6,7 @@ import net.minecraft.util.registry.Registry;
import net.minecraft.world.Dimension;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import appeng.core.AppEng;
import appeng.mixins.spatial.DimensionTypeMixin;
@@ -33,13 +34,13 @@ public final class SpatialStorageDimensionIds {
* ID of the {@link net.minecraft.world.biome.Biome} used for the spatial
* storage world.
*/
public static final ResourceLocation BIOME_ID = AppEng.makeId("spatial_storage");
public static final RegistryKey<Biome> BIOME_KEY = RegistryKey.func_240903_a_(Registry.BIOME_KEY,
AppEng.makeId("spatial_storage"));
/**
* ID of the {@link Dimension} used for the spatial storage dimension.
* <p>
* This is defined in
* <code>data/minecraft/dimension/appliedenergistics2/spatial_storage.json</code>
* This is defined in {@link appeng.mixins.spatial.DimensionTypeMixin}.
*/
public static final RegistryKey<Dimension> DIMENSION_ID = RegistryKey.func_240903_a_(Registry.DIMENSION_KEY,
AppEng.makeId("spatial_storage"));
@@ -51,6 +52,12 @@ public final class SpatialStorageDimensionIds {
public static final RegistryKey<World> WORLD_ID = RegistryKey.func_240903_a_(Registry.WORLD_KEY,
AppEng.makeId("spatial_storage"));
/**
* ID of the {@link net.minecraft.client.world.DimensionRenderInfo} used for the
* spatial storage world.
*/
public static ResourceLocation SKY_PROPERTIES_ID = AppEng.makeId("spatial_storage");
private SpatialStorageDimensionIds() {
}
@@ -25,11 +25,13 @@ import java.util.function.Function;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.PortalInfo;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.math.AxisAlignedBB;
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 net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.server.ServerWorld;
@@ -50,6 +52,16 @@ public class SpatialStorageHelper {
return instance;
}
private final ThreadLocal<PortalInfo> teleportTarget = new ThreadLocal<>();
/**
* If an entity is currently being teleported, this will return the target
* within the target dimension.
*/
public PortalInfo getTeleportTarget() {
return teleportTarget.get();
}
/**
* Mostly from dimensional doors.. which mostly got it form X-Comp.
*
@@ -97,12 +109,25 @@ public class SpatialStorageHelper {
newWorld.getChunkProvider().getChunk(MathHelper.floor(link.x) >> 4, MathHelper.floor(link.z) >> 4,
ChunkStatus.FULL, true);
if (entity instanceof ServerPlayerEntity
&& link.dim.func_234922_V_() == SpatialStorageDimensionIds.DIMENSION_TYPE_ID) {
if (entity instanceof ServerPlayerEntity && link.dim.func_234923_W_() == SpatialStorageDimensionIds.WORLD_ID) {
AppEng.instance().getAdvancementTriggers().getSpatialExplorer().trigger((ServerPlayerEntity) entity);
}
entity.changeDimension(link.dim, new METeleporter(link));
// Store in a threadlocal so that EntityMixin can return it for the Vanilla
// logic to use
teleportTarget.set(new PortalInfo(new Vector3d(link.x, link.y, link.z), Vector3d.ZERO, entity.rotationYaw,
entity.rotationPitch));
try {
entity = entity.changeDimension(link.dim, new ITeleporter() {
@Override
public Entity placeEntity(Entity entity, ServerWorld currentWorld, ServerWorld destWorld, float yaw,
Function<Boolean, Entity> repositionEntity) {
return repositionEntity.apply(false);
}
});
} finally {
teleportTarget.remove();
}
if (!passengersOnOtherSide.isEmpty()) {
for (Entity passanger : passengersOnOtherSide) {
@@ -238,22 +263,4 @@ public class SpatialStorageHelper {
}
}
private static class METeleporter implements ITeleporter {
private final TelDestination destination;
METeleporter(final TelDestination d) {
this.destination = d;
}
@Override
public Entity placeEntity(Entity entity, ServerWorld currentWorld, ServerWorld destWorld, float yaw,
Function<Boolean, Entity> repositionEntity) {
Entity newEntity = repositionEntity.apply(false);
newEntity.rotationYaw = yaw;
newEntity.setPositionAndUpdate(this.destination.x, this.destination.y, this.destination.z);
newEntity.setMotion(0, 0, 0);
return newEntity;
}
}
}
@@ -0,0 +1,66 @@
package appeng.worldgen;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import com.google.common.collect.Lists;
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.StructureFeature;
import net.minecraft.world.gen.feature.structure.Structure;
import appeng.mixins.structure.BiomeAccessor;
import appeng.mixins.structure.GenerationSettingsAccessor;
public final class BiomeModifier {
private final BiomeAccessor biomeAccessor;
private final GenerationSettingsAccessor generationSettingsAccessor;
@SuppressWarnings("ConstantConditions")
public BiomeModifier(Biome biome) {
this.biomeAccessor = (BiomeAccessor) (Object) biome;
this.generationSettingsAccessor = (GenerationSettingsAccessor) biome.func_242440_e();
}
public void addFeature(GenerationStage.Decoration step, ConfiguredFeature<?, ?> feature) {
int stepIndex = step.ordinal();
List<List<Supplier<ConfiguredFeature<?, ?>>>> featuresByStep = new ArrayList<>(
generationSettingsAccessor.getFeatures());
while (featuresByStep.size() <= stepIndex) {
featuresByStep.add(Lists.newArrayList());
}
List<Supplier<ConfiguredFeature<?, ?>>> features = new ArrayList<>(featuresByStep.get(stepIndex));
features.add(() -> feature);
featuresByStep.set(stepIndex, features);
generationSettingsAccessor.setFeatures(featuresByStep);
}
public void addStructureFeature(StructureFeature<?, ?> structure) {
List<Supplier<StructureFeature<?, ?>>> features = new ArrayList<>(
generationSettingsAccessor.getStructureFeatures());
features.add(() -> structure);
generationSettingsAccessor.setStructureFeatures(features);
// Add it to the structures that will generate pieces within this biome,
// this is only half-correct since a structure can start in an adjacent biome
// and extend into biomes that would usually not start the structure
Map<Integer, List<Structure<?>>> structuresByStage = biomeAccessor.getField_242421_g();
int step = structure.field_236268_b_.func_236396_f_().ordinal();
if (!structuresByStage.containsKey(step)) {
structuresByStage.put(step, new ArrayList<>());
}
structuresByStage.get(step).add(structure.field_236268_b_);
}
}
@@ -15,7 +15,7 @@ public class ChargedQuartzOreConfig implements IFeatureConfig {
public static final Codec<ChargedQuartzOreConfig> CODEC = RecordCodecBuilder.create((instance) -> instance
.group(BlockState.BLOCKSTATE_CODEC.fieldOf("target").forGetter((config) -> config.target),
BlockState.BLOCKSTATE_CODEC.fieldOf("state").forGetter((config) -> config.state),
Codec.FLOAT.fieldOf("chance").withDefault(0f).forGetter((config) -> config.chance))
Codec.FLOAT.fieldOf("chance").orElse(0f).forGetter((config) -> config.chance))
.apply(instance, ChargedQuartzOreConfig::new));
public final BlockState target;
@@ -11,7 +11,6 @@ import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.Heightmap;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.structure.StructureManager;
/**
* Extends {@link net.minecraft.world.gen.feature.OreFeature} by also allowing
@@ -27,8 +26,8 @@ public class ChargedQuartzOreFeature extends Feature<ChargedQuartzOreConfig> {
}
@Override
public boolean func_230362_a_(ISeedReader worldIn, StructureManager structureAccessor, ChunkGenerator generator,
Random rand, BlockPos pos, ChargedQuartzOreConfig config) {
public boolean func_241855_a(ISeedReader worldIn, ChunkGenerator generator, Random rand, BlockPos pos,
ChargedQuartzOreConfig config) {
ChunkPos chunkPos = new ChunkPos(pos);
BlockPos.Mutable bpos = new BlockPos.Mutable();
@@ -9,6 +9,7 @@ import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.provider.BiomeProvider;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.feature.NoFeatureConfig;
import net.minecraft.world.gen.feature.StructureFeature;
import net.minecraft.world.gen.feature.structure.Structure;
import appeng.core.AppEng;
@@ -19,6 +20,9 @@ public class MeteoriteStructure extends Structure<NoFeatureConfig> {
public static final Structure<NoFeatureConfig> INSTANCE = new MeteoriteStructure(NoFeatureConfig.field_236558_a_);
public static final StructureFeature<NoFeatureConfig, ? extends Structure<NoFeatureConfig>> CONFIGURED_INSTANCE = INSTANCE
.func_236391_a_(NoFeatureConfig.field_236559_b_);
public MeteoriteStructure(Codec<NoFeatureConfig> configCodec) {
super(configCodec);
}
@@ -36,7 +36,7 @@ import appeng.worldgen.meteorite.fallout.FalloutMode;
public class MeteoriteStructurePiece extends StructurePiece {
public static final IStructurePieceType TYPE = IStructurePieceType.register(MeteoriteStructurePiece::new,
"AE2MTRT");
"ae2mtrt");
public static void register() {
// THIS MUST BE CALLED otherwise the static initializer above will not run,
@@ -12,9 +12,9 @@ import net.minecraft.tags.ITag;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MutableBoundingBox;
import net.minecraft.util.registry.DynamicRegistries;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biome.Category;
import net.minecraft.world.biome.Biome.TempCategory;
import net.minecraft.world.gen.ChunkGenerator;
import net.minecraft.world.gen.Heightmap;
import net.minecraft.world.gen.Heightmap.Type;
@@ -27,17 +27,18 @@ import appeng.worldgen.meteorite.fallout.FalloutMode;
public class MeteoriteStructureStart extends StructureStart<NoFeatureConfig> {
private final ITag<Block> sandTag = BlockTags.getCollection().getOrCreate(new ResourceLocation("minecraft:sand"));
private final ITag<Block> sandTag = BlockTags.getCollection().func_241834_b(new ResourceLocation("minecraft:sand"));
private final ITag<Block> terracottaTag = BlockTags.getCollection()
.getOrCreate(new ResourceLocation("forge:terracotta"));
.func_241834_b(new ResourceLocation("forge:terracotta"));
public MeteoriteStructureStart(Structure<NoFeatureConfig> p_i225815_1_, int p_i225815_2_, int p_i225815_3_,
MutableBoundingBox p_i225815_4_, int p_i225815_5_, long p_i225815_6_) {
super(p_i225815_1_, p_i225815_2_, p_i225815_3_, p_i225815_4_, p_i225815_5_, p_i225815_6_);
}
public void func_230364_a_(ChunkGenerator generator, TemplateManager templateManagerIn, int chunkX, int chunkZ,
Biome biome, NoFeatureConfig config) {
@Override
public void func_230364_a_(DynamicRegistries dynamicRegistryManager, ChunkGenerator generator,
TemplateManager templateManager, int chunkX, int chunkZ, Biome biome, NoFeatureConfig config) {
final int centerX = chunkX * 16 + this.rand.nextInt(16);
final int centerZ = chunkZ * 16 + this.rand.nextInt(16);
final float meteoriteRadius = (this.rand.nextFloat() * 6.0f) + 2;
@@ -75,7 +76,7 @@ public class MeteoriteStructureStart extends StructureStart<NoFeatureConfig> {
boolean craterLake = this.locateWaterAroundTheCrater(generator, actualPos, meteoriteRadius);
CraterType craterType = this.determineCraterType(spawnBiome);
boolean pureCrater = this.rand.nextFloat() > .9f;
FalloutMode fallout = getFalloutFromBaseBlock(spawnBiome.getSurfaceBuilderConfig().getTop());
FalloutMode fallout = getFalloutFromBaseBlock(spawnBiome.func_242440_e().func_242502_e().getTop());
components.add(
new MeteoriteStructurePiece(actualPos, meteoriteRadius, craterType, fallout, pureCrater, craterLake));
@@ -118,7 +119,9 @@ public class MeteoriteStructureStart extends StructureStart<NoFeatureConfig> {
}
private CraterType determineCraterType(Biome biome) {
final TempCategory temp = biome.getTempCategory();
// The temperature thresholds below are taken from older Vanilla code
// (temperature categories)
final float temp = biome.func_242445_k();
final Category category = biome.getCategory();
// No craters in oceans
@@ -135,7 +138,7 @@ public class MeteoriteStructureStart extends StructureStart<NoFeatureConfig> {
}
// Warm biomes, higher chance for lava
if (temp == TempCategory.WARM) {
if (temp >= 1) {
// 50% chance to actually spawn as lava
final boolean lava = rand.nextFloat() > .5f;
@@ -158,7 +161,7 @@ public class MeteoriteStructureStart extends StructureStart<NoFeatureConfig> {
}
// Temperate biomes. Water or maybe lava
if (temp == TempCategory.MEDIUM) {
if (temp < 1 && temp >= 0.2) {
// 75% chance to actually spawn with a crater lake
final boolean lake = rand.nextFloat() > .25f;
// 20% to spawn with lava
@@ -184,7 +187,7 @@ public class MeteoriteStructureStart extends StructureStart<NoFeatureConfig> {
}
// Cold biomes, Snow or Ice, maybe water and very rarely lava.
if (temp == TempCategory.COLD) {
if (temp < 0.2) {
// 75% chance to actually spawn with a crater lake
final boolean lake = rand.nextFloat() > .25f;
// 5% to spawn with lava
@@ -36,7 +36,7 @@ public class FalloutCopy extends Fallout {
public FalloutCopy(final IWorld w, BlockPos pos, final MeteoriteBlockPutter putter, final BlockState skyStone) {
super(putter, skyStone);
this.putter = putter;
this.block = w.getBiome(pos).getSurfaceBuilderConfig().getTop();
this.block = w.getBiome(pos).func_242440_e().func_242502_e().getTop();
}
@Override
+3 -2
View File
@@ -6,6 +6,7 @@ displayURL="https://github.com/AppliedEnergistics/Applied-Energistics-2"
logoFile="logo.png"
#credits="Thanks for this example mod goes to Java"
authors="TeamAppliedEnergistics"
license="See GitHub repository for details"
[[mods]]
modId="appliedenergistics2"
@@ -16,13 +17,13 @@ description="A Mod about Matter, Energy and using them to conquer the world.."
[[dependencies.appliedenergistics2]]
modId="forge"
mandatory=true
versionRange="[32.0.108,33.0.0)"
versionRange="[33.0.22,34.0.0)"
ordering="NONE"
side="BOTH"
[[dependencies.appliedenergistics2]]
modId="minecraft"
mandatory=true
versionRange="[1.16.1]"
versionRange="[1.16.2]"
ordering="NONE"
side="BOTH"
@@ -7,9 +7,14 @@
"mixins": [
"spatial.DimensionTypeMixin",
"spatial.DimensionOptionMixin",
"ThreadedAnvilChunkStorageAccessor",
"DimensionStructuresSettingsMixin",
"StructureAccessor"
"spatial.EntityMixin",
"spatial.BiomesMixin",
"structure.DimensionStructuresSettingsMixin",
"structure.ConfiguredStructureFeaturesAccessor",
"structure.StructureFeatureAccessor",
"structure.GenerationSettingsAccessor",
"structure.BiomeAccessor",
"feature.ConfiguredFeaturesAccessor"
],
"client": [
"spatial.SkyRenderMixin",
@@ -705,5 +705,9 @@
"waila.appliedenergistics2.P2POutput": "Linked (Output Side)",
"waila.appliedenergistics2.P2PUnlinked": "Unlinked",
"waila.appliedenergistics2.Showing": "Showing",
"waila.appliedenergistics2.Unlocked": "Unlocked"
"waila.appliedenergistics2.Unlocked": "Unlocked",
"jei.appliedenergistics2.missing_id": "Cannot identify recipe",
"jei.appliedenergistics2.recipe_too_large": "Recipe larger than 3x3",
"jei.appliedenergistics2.requires_processing_mode": "Requires processing mode",
"jei.appliedenergistics2.no_output": "Recipe has no output"
}
@@ -58,7 +58,7 @@
"block.appliedenergistics2.chest": "ME箱子",
"block.appliedenergistics2.chiseled_quartz_block": "錾制赛特斯石英块",
"block.appliedenergistics2.chiseled_quartz_slab": "錾制赛特斯石英台阶",
"block.appliedenergistics2.chiseled_quartz_stairs": "竖纹赛特斯石英楼梯",
"block.appliedenergistics2.chiseled_quartz_stairs": "錾制赛特斯石英楼梯",
"block.appliedenergistics2.condenser": "物质聚合器",
"block.appliedenergistics2.controller": "ME控制器",
"block.appliedenergistics2.crafting_accelerator": "并行处理单元",
@@ -77,7 +77,7 @@
"block.appliedenergistics2.fluid_interface": "ME流体接口",
"block.appliedenergistics2.fluix_block": "福鲁伊克斯块",
"block.appliedenergistics2.fluix_slab": "福鲁伊克斯台阶",
"block.appliedenergistics2.fluix_stairs": "錾制赛特斯石英楼梯",
"block.appliedenergistics2.fluix_stairs": "福鲁伊克斯楼梯",
"block.appliedenergistics2.grindstone": "石英磨具",
"block.appliedenergistics2.inscriber": "压印器",
"block.appliedenergistics2.interface": "ME接口",
@@ -92,11 +92,11 @@
"block.appliedenergistics2.quartz_glass": "石英玻璃",
"block.appliedenergistics2.quartz_growth_accelerator": "晶体催生器",
"block.appliedenergistics2.quartz_ore": "赛特斯石英矿石",
"block.appliedenergistics2.quartz_pillar": "赛特斯竖纹石英块",
"block.appliedenergistics2.quartz_pillar": "竖纹赛特斯石英块",
"block.appliedenergistics2.quartz_pillar_slab": "竖纹赛特斯石英台阶",
"block.appliedenergistics2.quartz_pillar_stairs": "赛特斯石英楼梯",
"block.appliedenergistics2.quartz_pillar_stairs": "竖纹赛特斯石英楼梯",
"block.appliedenergistics2.quartz_slab": "赛特斯石英台阶",
"block.appliedenergistics2.quartz_stairs": "福鲁伊克斯楼梯",
"block.appliedenergistics2.quartz_stairs": "赛特斯石英楼梯",
"block.appliedenergistics2.quartz_vibrant_glass": "聚能石英玻璃",
"block.appliedenergistics2.security_station": "ME安全终端",
"block.appliedenergistics2.sky_compass": "陨石罗盘",
@@ -408,28 +408,28 @@
"item.appliedenergistics2.annihilation_plane": "ME破坏面板",
"item.appliedenergistics2.basic_card": "基础卡",
"item.appliedenergistics2.biometric_card": "身份卡",
"item.appliedenergistics2.black_covered_cable": "黑色 ME包层线缆",
"item.appliedenergistics2.black_covered_dense_cable": "黑色 ME致密包层线缆",
"item.appliedenergistics2.black_glass_cable": "黑色 ME玻璃线缆",
"item.appliedenergistics2.black_lumen_paint_ball": "黑色 光通 染色球",
"item.appliedenergistics2.black_paint_ball": "黑色 染色球",
"item.appliedenergistics2.black_smart_cable": "黑色 ME智能线缆",
"item.appliedenergistics2.black_smart_dense_cable": "黑色 ME致密线缆",
"item.appliedenergistics2.black_covered_cable": "ME包层线缆(黑色)",
"item.appliedenergistics2.black_covered_dense_cable": "ME致密包层线缆(黑色)",
"item.appliedenergistics2.black_glass_cable": "ME玻璃线缆(黑色)",
"item.appliedenergistics2.black_lumen_paint_ball": "光通染色球(黑色)",
"item.appliedenergistics2.black_paint_ball": "染色球(黑色)",
"item.appliedenergistics2.black_smart_cable": "ME智能线缆(黑色)",
"item.appliedenergistics2.black_smart_dense_cable": "ME致密线缆(黑色)",
"item.appliedenergistics2.blank_pattern": "空白样板",
"item.appliedenergistics2.blue_covered_cable": "蓝色 ME包层线缆",
"item.appliedenergistics2.blue_covered_dense_cable": "蓝色 ME致密包层线缆",
"item.appliedenergistics2.blue_glass_cable": "蓝色 ME玻璃线缆",
"item.appliedenergistics2.blue_lumen_paint_ball": "蓝色 光通 染色球",
"item.appliedenergistics2.blue_paint_ball": "蓝色 染色球",
"item.appliedenergistics2.blue_smart_cable": "蓝色 ME智能线缆",
"item.appliedenergistics2.blue_smart_dense_cable": "蓝色 ME致密线缆",
"item.appliedenergistics2.brown_covered_cable": "棕色 ME包层线缆",
"item.appliedenergistics2.brown_covered_dense_cable": "棕色 ME致密包层线缆",
"item.appliedenergistics2.brown_glass_cable": "棕色 ME玻璃线缆",
"item.appliedenergistics2.brown_lumen_paint_ball": "棕色 光通 染色球",
"item.appliedenergistics2.brown_paint_ball": "棕色 染色球",
"item.appliedenergistics2.brown_smart_cable": "棕色 ME智能线缆",
"item.appliedenergistics2.brown_smart_dense_cable": "棕色 ME致密线缆",
"item.appliedenergistics2.blue_covered_cable": "ME包层线缆(蓝色)",
"item.appliedenergistics2.blue_covered_dense_cable": "ME致密包层线缆(蓝色)",
"item.appliedenergistics2.blue_glass_cable": "ME玻璃线缆(蓝色)",
"item.appliedenergistics2.blue_lumen_paint_ball": "光通染色球(蓝色)",
"item.appliedenergistics2.blue_paint_ball": "染色球(蓝色)",
"item.appliedenergistics2.blue_smart_cable": "ME智能线缆(蓝色)",
"item.appliedenergistics2.blue_smart_dense_cable": "ME致密线缆(蓝色)",
"item.appliedenergistics2.brown_covered_cable": "ME包层线缆(棕色)",
"item.appliedenergistics2.brown_covered_dense_cable": "棕色 ME致密包层线缆(棕色)",
"item.appliedenergistics2.brown_glass_cable": "ME玻璃线缆(棕色)",
"item.appliedenergistics2.brown_lumen_paint_ball": "光通染色球(棕色)",
"item.appliedenergistics2.brown_paint_ball": "染色球(棕色)",
"item.appliedenergistics2.brown_smart_cable": "ME智能线缆(棕色)",
"item.appliedenergistics2.brown_smart_dense_cable": "ME致密线缆(棕色)",
"item.appliedenergistics2.cable_anchor": "线缆锚",
"item.appliedenergistics2.cable_fluid_interface": "ME流体接口",
"item.appliedenergistics2.cable_interface": "ME接口",
@@ -459,13 +459,13 @@
"item.appliedenergistics2.crafting_monitor": "ME合成监控器",
"item.appliedenergistics2.crafting_terminal": "ME合成终端",
"item.appliedenergistics2.creative_storage_cell": "创造型ME存储元件",
"item.appliedenergistics2.cyan_covered_cable": "青色 ME包层线缆",
"item.appliedenergistics2.cyan_covered_dense_cable": "青色 ME致密包层线缆",
"item.appliedenergistics2.cyan_glass_cable": "青色 ME玻璃线缆",
"item.appliedenergistics2.cyan_lumen_paint_ball": "青色 光通 染色球",
"item.appliedenergistics2.cyan_paint_ball": "青色 染色球",
"item.appliedenergistics2.cyan_smart_cable": "青色 ME智能线缆",
"item.appliedenergistics2.cyan_smart_dense_cable": "青色 ME致密线缆",
"item.appliedenergistics2.cyan_covered_cable": "ME包层线缆(青色)",
"item.appliedenergistics2.cyan_covered_dense_cable": "ME致密包层线缆(青色)",
"item.appliedenergistics2.cyan_glass_cable": "ME玻璃线缆(青色)",
"item.appliedenergistics2.cyan_lumen_paint_ball": "光通染色球(青色)",
"item.appliedenergistics2.cyan_paint_ball": "染色球(青色)",
"item.appliedenergistics2.cyan_smart_cable": "ME智能线缆(青色)",
"item.appliedenergistics2.cyan_smart_dense_cable": "ME致密线缆(青色)",
"item.appliedenergistics2.dark_monitor": "暗色照明面板",
"item.appliedenergistics2.debug_card": "Dev.调试卡",
"item.appliedenergistics2.debug_replicator_card": "Dev.复制卡",
@@ -478,7 +478,7 @@
"item.appliedenergistics2.entropy_manipulator": "熵变机械臂",
"item.appliedenergistics2.export_bus": "ME输出总线",
"item.appliedenergistics2.facade": "线缆伪装板",
"item.appliedenergistics2.fe_p2p_tunnel": "FE P2P通道",
"item.appliedenergistics2.fe_p2p_tunnel": "P2P通道-FE",
"item.appliedenergistics2.flour": "面粉",
"item.appliedenergistics2.fluid_annihilation_plane": "ME流体破坏面板",
"item.appliedenergistics2.16k_fluid_cell_component": "16k-ME流体存储组件",
@@ -489,43 +489,43 @@
"item.appliedenergistics2.fluid_formation_plane": "ME流体成型面板",
"item.appliedenergistics2.fluid_import_bus": "ME流体输入总线",
"item.appliedenergistics2.fluid_level_emitter": "ME流体标准发信器",
"item.appliedenergistics2.fluid_p2p_tunnel": "流体 P2P通道",
"item.appliedenergistics2.fluid_storage_bus": "ME流体存总线",
"item.appliedenergistics2.fluid_p2p_tunnel": "P2P通道-流体",
"item.appliedenergistics2.fluid_storage_bus": "ME流体存总线",
"item.appliedenergistics2.16k_fluid_storage_cell": "16k-ME流体储存元件",
"item.appliedenergistics2.1k_fluid_storage_cell": "1k-ME流体储存元件",
"item.appliedenergistics2.4k_fluid_storage_cell": "4k-ME流体储存元件",
"item.appliedenergistics2.64k_fluid_storage_cell": "64k-ME流体储存元件",
"item.appliedenergistics2.fluid_terminal": "ME流体终端",
"item.appliedenergistics2.fluix_covered_cable": "Fluix默认色 ME包层线缆",
"item.appliedenergistics2.fluix_covered_dense_cable": "Fluix默认色 ME致密包层线缆",
"item.appliedenergistics2.fluix_covered_cable": "ME包层线缆(Fluix默认色)",
"item.appliedenergistics2.fluix_covered_dense_cable": "ME致密包层线缆(Fluix默认色)",
"item.appliedenergistics2.fluix_crystal": "福鲁伊克斯水晶",
"item.appliedenergistics2.fluix_crystal_seed": "福鲁伊克斯种子",
"item.appliedenergistics2.fluix_dust": "福鲁伊克斯粉",
"item.appliedenergistics2.fluix_glass_cable": "Fluix默认色 ME玻璃线缆",
"item.appliedenergistics2.fluix_lumen_paint_ball": "Fluix默认色 光通 染色球",
"item.appliedenergistics2.fluix_paint_ball": "Fluix默认色 染色球",
"item.appliedenergistics2.fluix_glass_cable": "ME玻璃线缆(Fluix默认色)",
"item.appliedenergistics2.fluix_lumen_paint_ball": "光通染色球(Fluix默认色)",
"item.appliedenergistics2.fluix_paint_ball": "色球(Fluix默认色)",
"item.appliedenergistics2.fluix_pearl": "福鲁伊克斯珍珠",
"item.appliedenergistics2.fluix_smart_cable": "Fluix默认色 ME智能线缆",
"item.appliedenergistics2.fluix_smart_dense_cable": "Fluix默认色 ME致密线缆",
"item.appliedenergistics2.fluix_smart_cable": "ME智能线缆(Fluix默认色)",
"item.appliedenergistics2.fluix_smart_dense_cable": "ME致密线缆(Fluix默认色)",
"item.appliedenergistics2.formation_core": "成型核心",
"item.appliedenergistics2.formation_plane": "ME成型面板",
"item.appliedenergistics2.fuzzy_card": "模糊卡",
"item.appliedenergistics2.gold_dust": "金粉",
"item.appliedenergistics2.gray_covered_cable": "灰色 ME包层线缆",
"item.appliedenergistics2.gray_covered_dense_cable": "灰色 ME致密包层线缆",
"item.appliedenergistics2.gray_glass_cable": "灰色 ME玻璃线缆",
"item.appliedenergistics2.gray_lumen_paint_ball": "灰色 光通 染色球",
"item.appliedenergistics2.gray_paint_ball": "灰色 染色球",
"item.appliedenergistics2.gray_smart_cable": "灰色 ME智能线缆",
"item.appliedenergistics2.gray_smart_dense_cable": "灰色 ME致密线缆",
"item.appliedenergistics2.green_covered_cable": "绿色 ME包层线缆",
"item.appliedenergistics2.green_covered_dense_cable": "绿色 ME致密包层线缆",
"item.appliedenergistics2.green_glass_cable": "绿色 ME玻璃线缆",
"item.appliedenergistics2.green_lumen_paint_ball": "绿色 光通 染色球",
"item.appliedenergistics2.green_paint_ball": "绿色 染色球",
"item.appliedenergistics2.green_smart_cable": "绿色 ME智能线缆",
"item.appliedenergistics2.green_smart_dense_cable": "绿色 ME致密线缆",
"item.appliedenergistics2.ic2_p2p_tunnel": "EU P2P通道",
"item.appliedenergistics2.gray_covered_cable": "ME包层线缆(灰色)",
"item.appliedenergistics2.gray_covered_dense_cable": "ME致密包层线缆(灰色)",
"item.appliedenergistics2.gray_glass_cable": "ME玻璃线缆(灰色)",
"item.appliedenergistics2.gray_lumen_paint_ball": "光通染色球(灰色)",
"item.appliedenergistics2.gray_paint_ball": "染色球(灰色)",
"item.appliedenergistics2.gray_smart_cable": "ME智能线缆(灰色)",
"item.appliedenergistics2.gray_smart_dense_cable": "ME致密线缆(灰色)",
"item.appliedenergistics2.green_covered_cable": "ME包层线缆(绿色)",
"item.appliedenergistics2.green_covered_dense_cable": "ME致密包层线缆(绿色)",
"item.appliedenergistics2.green_glass_cable": "ME玻璃线缆(绿色)",
"item.appliedenergistics2.green_lumen_paint_ball": "光通染色球(绿色)",
"item.appliedenergistics2.green_paint_ball": "染色球(绿色)",
"item.appliedenergistics2.green_smart_cable": "ME智能线缆(绿色)",
"item.appliedenergistics2.green_smart_dense_cable": "ME致密线缆(绿色)",
"item.appliedenergistics2.ic2_p2p_tunnel": "P2P通道-EU",
"item.appliedenergistics2.identity_annihilation_plane": "ME精准破坏面板",
"item.appliedenergistics2.import_bus": "ME输入总线",
"item.appliedenergistics2.interface_terminal": "ME接口终端",
@@ -533,44 +533,44 @@
"item.appliedenergistics2.inverted_toggle_bus": "ME反相触发总线",
"item.appliedenergistics2.inverter_card": "反相卡",
"item.appliedenergistics2.iron_dust": "铁粉",
"item.appliedenergistics2.item_p2p_tunnel": "物品 P2P通道",
"item.appliedenergistics2.item_p2p_tunnel": "P2P通道-物品",
"item.appliedenergistics2.level_emitter": "ME标准发信器",
"item.appliedenergistics2.light_blue_covered_cable": "浅蓝色 ME包层线缆",
"item.appliedenergistics2.light_blue_covered_dense_cable": "浅蓝色 ME致密包层线缆",
"item.appliedenergistics2.light_blue_glass_cable": "浅蓝色 ME玻璃线缆",
"item.appliedenergistics2.light_blue_lumen_paint_ball": "浅蓝色 光通 染色球",
"item.appliedenergistics2.light_blue_paint_ball": "浅蓝色 染色球",
"item.appliedenergistics2.light_blue_smart_cable": "浅蓝色 ME智能线缆",
"item.appliedenergistics2.light_blue_smart_dense_cable": "浅蓝色 ME致密线缆",
"item.appliedenergistics2.light_gray_covered_cable": "浅灰色 ME包层线缆",
"item.appliedenergistics2.light_gray_covered_dense_cable": "浅灰色 ME致密包层线缆",
"item.appliedenergistics2.light_gray_glass_cable": "浅灰色 ME玻璃线缆",
"item.appliedenergistics2.light_gray_lumen_paint_ball": "浅灰色 光通 染色球",
"item.appliedenergistics2.light_gray_paint_ball": "浅灰色 染色球",
"item.appliedenergistics2.light_gray_smart_cable": "浅灰色 ME智能线缆",
"item.appliedenergistics2.light_gray_smart_dense_cable": "浅灰色 ME致密线缆",
"item.appliedenergistics2.light_p2p_tunnel": "P2P通道",
"item.appliedenergistics2.lime_covered_cable": "柠檬色 ME包层线缆",
"item.appliedenergistics2.lime_covered_dense_cable": "柠檬色 ME致密包层线缆",
"item.appliedenergistics2.lime_glass_cable": "柠檬色 ME玻璃线缆",
"item.appliedenergistics2.lime_lumen_paint_ball": "柠檬色 光通 染色球",
"item.appliedenergistics2.lime_paint_ball": "柠檬色 染色球",
"item.appliedenergistics2.lime_smart_cable": "柠檬色 ME智能线缆",
"item.appliedenergistics2.lime_smart_dense_cable": "柠檬色 ME致密线缆",
"item.appliedenergistics2.light_blue_covered_cable": "ME包层线缆(浅蓝色)",
"item.appliedenergistics2.light_blue_covered_dense_cable": "ME致密包层线缆(浅蓝色)",
"item.appliedenergistics2.light_blue_glass_cable": "ME玻璃线缆(浅蓝色)",
"item.appliedenergistics2.light_blue_lumen_paint_ball": "光通染色球(浅蓝色)",
"item.appliedenergistics2.light_blue_paint_ball": "染色球(浅蓝色)",
"item.appliedenergistics2.light_blue_smart_cable": "ME智能线缆(浅蓝色)",
"item.appliedenergistics2.light_blue_smart_dense_cable": "ME致密线缆(浅蓝色)",
"item.appliedenergistics2.light_gray_covered_cable": "ME包层线缆(浅灰色)",
"item.appliedenergistics2.light_gray_covered_dense_cable": "ME致密包层线缆(浅灰色)",
"item.appliedenergistics2.light_gray_glass_cable": "ME玻璃线缆(浅灰色)",
"item.appliedenergistics2.light_gray_lumen_paint_ball": "光通染色球(浅灰色)",
"item.appliedenergistics2.light_gray_paint_ball": "染色球(浅灰色)",
"item.appliedenergistics2.light_gray_smart_cable": "ME智能线缆(浅灰色)",
"item.appliedenergistics2.light_gray_smart_dense_cable": "ME致密线缆(浅灰色)",
"item.appliedenergistics2.light_p2p_tunnel": "P2P通道-光",
"item.appliedenergistics2.lime_covered_cable": "ME包层线缆(柠檬色)",
"item.appliedenergistics2.lime_covered_dense_cable": "ME致密包层线缆(柠檬色)",
"item.appliedenergistics2.lime_glass_cable": "ME玻璃线缆(柠檬色)",
"item.appliedenergistics2.lime_lumen_paint_ball": "光通染色球(柠檬色)",
"item.appliedenergistics2.lime_paint_ball": "染色球(柠檬色)",
"item.appliedenergistics2.lime_smart_cable": "ME智能线缆(柠檬色)",
"item.appliedenergistics2.lime_smart_dense_cable": "ME致密线缆(柠檬色)",
"item.appliedenergistics2.logic_processor": "逻辑处理器",
"item.appliedenergistics2.logic_processor_asm": "半成品-逻辑处理器",
"item.appliedenergistics2.logic_processor_press": "逻辑压印模板",
"item.appliedenergistics2.printed_logic_processor": "逻辑电路板",
"item.appliedenergistics2.magenta_covered_cable": "品红色 ME包层线缆",
"item.appliedenergistics2.magenta_covered_dense_cable": "品红色 ME致密包层线缆",
"item.appliedenergistics2.magenta_glass_cable": "品红色 ME玻璃线缆",
"item.appliedenergistics2.magenta_lumen_paint_ball": "品红色 光通 染色球",
"item.appliedenergistics2.magenta_paint_ball": "品红色 染色球",
"item.appliedenergistics2.magenta_smart_cable": "品红色 ME智能线缆",
"item.appliedenergistics2.magenta_smart_dense_cable": "品红色 ME致密线缆",
"item.appliedenergistics2.magenta_covered_cable": "ME包层线缆(品红色)",
"item.appliedenergistics2.magenta_covered_dense_cable": "ME致密包层线缆(品红色)",
"item.appliedenergistics2.magenta_glass_cable": "ME玻璃线缆(品红色)",
"item.appliedenergistics2.magenta_lumen_paint_ball": "光通染色球(品红色)",
"item.appliedenergistics2.magenta_paint_ball": "染色球(品红色)",
"item.appliedenergistics2.magenta_smart_cable": "ME智能线缆(品红色)",
"item.appliedenergistics2.magenta_smart_dense_cable": "ME致密线缆(品红色)",
"item.appliedenergistics2.matter_ball": "物质球",
"item.appliedenergistics2.matter_cannon": "物质炮",
"item.appliedenergistics2.me_p2p_tunnel": "ME P2P通道",
"item.appliedenergistics2.me_p2p_tunnel": "P2P通道-ME",
"item.appliedenergistics2.memory_card": "内存卡",
"item.appliedenergistics2.monitor": "亮色照明面板",
"item.appliedenergistics2.name_press": "名称压印模板",
@@ -584,43 +584,43 @@
"item.appliedenergistics2.nether_quartz_sword": "下界石英剑",
"item.appliedenergistics2.nether_quartz_wrench": "下界石英扳手",
"item.appliedenergistics2.network_tool": "网络工具",
"item.appliedenergistics2.orange_covered_cable": "橙色 ME包层线缆",
"item.appliedenergistics2.orange_covered_dense_cable": "橙色 ME致密包层线缆",
"item.appliedenergistics2.orange_glass_cable": "橙色 ME玻璃线缆",
"item.appliedenergistics2.orange_lumen_paint_ball": "橙色 光通 染色球",
"item.appliedenergistics2.orange_paint_ball": "橙色 染色球",
"item.appliedenergistics2.orange_smart_cable": "橙色 ME智能线缆",
"item.appliedenergistics2.orange_smart_dense_cable": "橙色 ME致密线缆",
"item.appliedenergistics2.orange_covered_cable": "ME包层线缆(橙色)",
"item.appliedenergistics2.orange_covered_dense_cable": "ME致密包层线缆(橙色)",
"item.appliedenergistics2.orange_glass_cable": "ME玻璃线缆(橙色)",
"item.appliedenergistics2.orange_lumen_paint_ball": "光通染色球(橙色)",
"item.appliedenergistics2.orange_paint_ball": "染色球(橙色)",
"item.appliedenergistics2.orange_smart_cable": "ME智能线缆(橙色)",
"item.appliedenergistics2.orange_smart_dense_cable": "ME致密线缆(橙色)",
"item.appliedenergistics2.pattern_terminal": "ME样板终端",
"item.appliedenergistics2.pink_covered_cable": "粉色 ME包层线缆",
"item.appliedenergistics2.pink_covered_dense_cable": "粉色 ME致密包层线缆",
"item.appliedenergistics2.pink_glass_cable": "粉色 ME玻璃线缆",
"item.appliedenergistics2.pink_lumen_paint_ball": "粉色 光通 染色球",
"item.appliedenergistics2.pink_paint_ball": "粉色 染色球",
"item.appliedenergistics2.pink_smart_cable": "粉色 ME智能线缆",
"item.appliedenergistics2.pink_smart_dense_cable": "粉色 ME致密线缆",
"item.appliedenergistics2.pink_covered_cable": "ME包层线缆(粉色)",
"item.appliedenergistics2.pink_covered_dense_cable": "ME致密包层线缆(粉色)",
"item.appliedenergistics2.pink_glass_cable": "ME玻璃线缆(粉色)",
"item.appliedenergistics2.pink_lumen_paint_ball": "光通染色球(粉色)",
"item.appliedenergistics2.pink_paint_ball": "染色球(粉色)",
"item.appliedenergistics2.pink_smart_cable": "ME智能线缆(粉色)",
"item.appliedenergistics2.pink_smart_dense_cable": "ME致密线缆(粉色)",
"item.appliedenergistics2.portable_cell": "便携元件",
"item.appliedenergistics2.purified_certus_quartz_crystal": "高纯赛特斯石英水晶",
"item.appliedenergistics2.purified_fluix_crystal": "高纯福鲁伊克斯水晶",
"item.appliedenergistics2.purified_nether_quartz_crystal": "高纯下界石英水晶",
"item.appliedenergistics2.purple_covered_cable": "紫色 ME包层线缆",
"item.appliedenergistics2.purple_covered_dense_cable": "紫色 ME致密包层线缆",
"item.appliedenergistics2.purple_glass_cable": "紫色 ME玻璃线缆",
"item.appliedenergistics2.purple_lumen_paint_ball": "紫色 光通 染色球",
"item.appliedenergistics2.purple_paint_ball": "紫色 染色球",
"item.appliedenergistics2.purple_smart_cable": "紫色 ME智能线缆",
"item.appliedenergistics2.purple_smart_dense_cable": "紫色 ME致密线缆",
"item.appliedenergistics2.purple_covered_cable": "ME包层线缆(紫色)",
"item.appliedenergistics2.purple_covered_dense_cable": "ME致密包层线缆(紫色)",
"item.appliedenergistics2.purple_glass_cable": "ME玻璃线缆(紫色)",
"item.appliedenergistics2.purple_lumen_paint_ball": "光通染色球(紫色)",
"item.appliedenergistics2.purple_paint_ball": "染色球(紫色)",
"item.appliedenergistics2.purple_smart_cable": "ME智能线缆(紫色)",
"item.appliedenergistics2.purple_smart_dense_cable": "ME致密线缆(紫色)",
"item.appliedenergistics2.quantum_entangled_singularity": "量子缠绕态奇点",
"item.appliedenergistics2.quartz_fiber": "石英纤维",
"item.appliedenergistics2.red_covered_cable": "红色 ME包层线缆",
"item.appliedenergistics2.red_covered_dense_cable": "红色 ME致密包层线缆",
"item.appliedenergistics2.red_glass_cable": "红色 ME玻璃线缆",
"item.appliedenergistics2.red_lumen_paint_ball": "红色 光通 染色球",
"item.appliedenergistics2.red_paint_ball": "红色 染色球",
"item.appliedenergistics2.red_smart_cable": "红色 ME智能线缆",
"item.appliedenergistics2.red_smart_dense_cable": "红色 ME致密线缆",
"item.appliedenergistics2.red_covered_cable": "ME包层线缆(红色)",
"item.appliedenergistics2.red_covered_dense_cable": "ME致密包层线缆(红色)",
"item.appliedenergistics2.red_glass_cable": "ME玻璃线缆(红色)",
"item.appliedenergistics2.red_lumen_paint_ball": "光通染色球(红色)",
"item.appliedenergistics2.red_paint_ball": "染色球(红色)",
"item.appliedenergistics2.red_smart_cable": "ME智能线缆(红色)",
"item.appliedenergistics2.red_smart_dense_cable": "ME致密线缆(红色)",
"item.appliedenergistics2.redstone_card": "红石卡",
"item.appliedenergistics2.redstone_p2p_tunnel": "红石 P2P通道",
"item.appliedenergistics2.redstone_p2p_tunnel": "P2P通道-红石",
"item.appliedenergistics2.semi_dark_monitor": "照明面板",
"item.appliedenergistics2.silicon": "硅",
"item.appliedenergistics2.silicon_press": "硅压印模板",
@@ -643,24 +643,24 @@
"item.appliedenergistics2.terminal": "ME终端",
"item.appliedenergistics2.toggle_bus": "ME触发总线",
"item.appliedenergistics2.view_cell": "显示元件",
"item.appliedenergistics2.white_covered_cable": "白色 ME包层线缆",
"item.appliedenergistics2.white_covered_dense_cable": "白色 ME致密包层线缆",
"item.appliedenergistics2.white_glass_cable": "白色 ME玻璃线缆",
"item.appliedenergistics2.white_lumen_paint_ball": "白色 光通 染色球",
"item.appliedenergistics2.white_paint_ball": "白色 染色球",
"item.appliedenergistics2.white_smart_cable": "白色 ME智能线缆",
"item.appliedenergistics2.white_smart_dense_cable": "白色 ME致密线缆",
"item.appliedenergistics2.white_covered_cable": "ME包层线缆(白色)",
"item.appliedenergistics2.white_covered_dense_cable": "ME致密包层线缆(白色)",
"item.appliedenergistics2.white_glass_cable": "ME玻璃线缆(白色)",
"item.appliedenergistics2.white_lumen_paint_ball": "光通染色球(白色)",
"item.appliedenergistics2.white_paint_ball": "染色球(白色)",
"item.appliedenergistics2.white_smart_cable": "ME智能线缆(白色)",
"item.appliedenergistics2.white_smart_dense_cable": "ME致密线缆(白色)",
"item.appliedenergistics2.wireless_booster": "无线信号增幅器",
"item.appliedenergistics2.wireless_receiver": "无线接收器",
"item.appliedenergistics2.wireless_terminal": "无线终端",
"item.appliedenergistics2.wooden_gear": "木齿轮",
"item.appliedenergistics2.yellow_covered_cable": "黄色 ME包层线缆",
"item.appliedenergistics2.yellow_covered_dense_cable": "黄色 ME致密包层线缆",
"item.appliedenergistics2.yellow_glass_cable": "黄色 ME玻璃线缆",
"item.appliedenergistics2.yellow_lumen_paint_ball": "黄色 光通 染色球",
"item.appliedenergistics2.yellow_paint_ball": "黄色 染色球",
"item.appliedenergistics2.yellow_smart_cable": "黄色 ME智能线缆",
"item.appliedenergistics2.yellow_smart_dense_cable": "黄色 ME致密线缆",
"item.appliedenergistics2.yellow_covered_cable": "ME包层线缆(黄色)",
"item.appliedenergistics2.yellow_covered_dense_cable": "ME致密包层线缆(黄色)",
"item.appliedenergistics2.yellow_glass_cable": "ME玻璃线缆(黄色)",
"item.appliedenergistics2.yellow_lumen_paint_ball": "光通染色球(黄色)",
"item.appliedenergistics2.yellow_paint_ball": "染色球(黄色)",
"item.appliedenergistics2.yellow_smart_cable": "ME智能线缆(黄色)",
"item.appliedenergistics2.yellow_smart_dense_cable": "ME致密线缆(黄色)",
"itemGroup.appliedenergistics2": "应用能源2",
"itemGroup.appliedenergistics2.facades": "应用能源2-伪装板",
"key.appliedenergistics2.category": "Applied Energistics 2",
@@ -1,6 +0,0 @@
{
"type": "appliedenergistics2:spatial_storage",
"generator": {
"type": "appliedenergistics2:spatial_storage"
}
}