Compare commits

...

100 Commits

Author SHA1 Message Date
Sebastian Hartte 2bca23d75d Rebuilt the recipe transfer after upstream changes. 2020-09-10 22:05:06 +02:00
Sebastian Hartte b47543d166 Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	gradle.properties
#	src/main/java/appeng/core/Registration.java
#	src/main/java/appeng/core/sync/packets/JEIRecipePacket.java
#	src/main/java/appeng/entity/TinyTNTPrimedEntity.java
#	src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java
#	src/main/java/appeng/fluids/container/FluidConfigurableContainer.java
#	src/main/java/appeng/integration/modules/jei/FacadeRegistryPlugin.java
#	src/main/java/appeng/integration/modules/jei/JEIPlugin.java
#	src/main/java/appeng/integration/modules/jei/RecipeTransferHandler.java
#	src/main/java/appeng/mixins/structure/BiomeAccessor.java
#	src/main/java/appeng/parts/automation/AnnihilationPlanePart.java
#	src/main/java/appeng/parts/automation/FormationPlanePart.java
2020-09-10 19:20:58 +02:00
Sebastian Hartte a340925d98 Fix Wireless screen translated text. 2020-09-10 19:06:00 +02:00
yueh b8e53adf40 Fixes #4719: Take the entity size into account when spawning item entities (#4720) 2020-09-10 17:54:02 +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 0be7322c2c Formatting Fixes. 2020-09-09 02:27:12 +02:00
Sebastian Hartte a521e827db Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	src/main/java/appeng/core/api/definitions/ApiItems.java
2020-09-09 02:25:15 +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 17648633fe Merge fixes. 2020-09-09 02:23:14 +02:00
Sebastian Hartte fcbebd4ffc Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	gradle.properties
#	src/api/java/appeng/api/implementations/items/IGrowableCrystal.java
#	src/main/java/appeng/core/AEConfig.java
#	src/main/java/appeng/core/api/definitions/ApiBlocks.java
#	src/main/java/appeng/core/features/registries/LocatableRegistry.java
#	src/main/java/appeng/decorative/solid/QuartzGlassBlock.java
#	src/main/java/appeng/decorative/solid/SkyStoneBlock.java
#	src/main/java/appeng/entity/GrowingCrystalEntity.java
#	src/main/java/appeng/fluids/parts/FluidImportBusPart.java
#	src/main/java/appeng/items/misc/CrystalSeedItem.java
#	src/main/java/appeng/items/tools/powered/ColorApplicatorItem.java
#	src/main/java/appeng/me/cluster/implementations/QuantumCluster.java
#	src/main/java/appeng/parts/CableBusContainer.java
#	src/main/java/appeng/tile/AEBaseBlockEntity.java
2020-09-09 01:41:49 +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 81cc0b804d Fixes #4699: AE's glass should only hide it's sides adjacent to other AE glass.
Also disables spawn on AE's glass same as Vanilla glass.
2020-09-09 00:58:14 +02:00
Sebastian Hartte e1fc9908b3 Fixes #4693: Fix color applicator not working on cable-buses. 2020-09-09 00:51:45 +02:00
shartte 9ed1535477 Fixes #4661: Do not update a tile entity when it's in an unloaded chunk (i.e. during chunk unloading) (#4708) 2020-09-08 22:28:30 +02:00
Sebastian Hartte 1ef345d4a4 Formatting fixes. 2020-09-08 22:24:27 +02:00
Sebastian Hartte ff7d1b9719 Fixes #4704: QNB is not finding a registered QNB because it believes the chunk to be unloaded.
Also adds debug logging to the locatable registry to better debug this issues in the future.
2020-09-08 22:20:33 +02:00
shartte 88c9370e4f Crystal Growth Refactor (#4702)
* Refactored crystal in-world purification:
- Removed iterative formula
- Set the default growth factor to 1 rather than 0.5 to simplify settings
- Made the growth-tick-progress-per-tick a configuration setting for 0-6 accelerators
- Unfinished seeds now slowly sink when ejected by an annihilation plane or other system (emulates a player throwing it in)
- Instead of checking for "isLiquid", we now check for a new tag (appliedenergistics2:crystal_purification_medium) to check if the crystal is submerged in an allowed fluid for growth, defaults to #minecraft:water.

* Removed configuration options for changing how accelerators work,
replaced with improved fluid tag option with a clamped multiplier [1,10].
2020-09-08 18:10:45 +02:00
Sebastian Hartte f2aae3ef0f Added a global Voxelshape cache for cable bus voxel shapes, since combining voxel shapes turns out to be an extremely expensive process (i.e. 1.7s for 10000x5 shapes). 2020-09-08 17:56:02 +02:00
Sebastian Hartte 12739f1e66 Remove unneeded cable-bus inventory-model, which caused the part models to be loaded twice leading to unnecessary memory-usage. 2020-09-08 17:53:14 +02:00
shartte 81d2170ada Implemented a cache with maximum quad-count it will cache for the cable bus, (#4670)
which also fixes concurrent access to the hashmap.

(cherry picked from commit b756d68be1)
2020-09-08 14:28:08 +02:00
Sebastian Hartte 0f469e9df6 Bumped Forge version. 2020-09-07 23:34:56 +02:00
Sebastian Hartte 0f34f09b32 Remove object-scanning subscriptions and remove unused test-file. 2020-09-06 20:59:37 +02:00
Sebastian Hartte 8e54a8fed9 Fixes a problem where tile entities would become unremovable (well, one more of these at least),
because they would reset their block state upon removal and loss of power.
2020-09-06 20:59:19 +02:00
Sebastian Hartte ca007a3737 Fix compatibility with fabric-api 0.20 2020-09-05 19:30:00 +02:00
Sebastian Hartte 92b6650022 Reformat. 2020-09-05 19:22:21 +02:00
Sebastian Hartte e1cd3bba25 Improved logging and slight refactor. 2020-09-05 19:22:05 +02:00
Sebastian Hartte 689bf6e8d9 Removed unused worldgen registry,
added biome blacklists for meteorites and quartz ore, and
also fixed adding meteorite/quartz to biomes that are
registered after AE2 initializes.
2020-09-05 19:15:45 +02:00
Sebastian Hartte c8a5049d71 Fix path to AE2 logo in mod json. 2020-09-03 23:33:48 +02:00
Sebastian Hartte 10a1a6d855 Fixes #4674: Facade quads should not keep their original cull-faces if they're moved away
from the block face.
2020-09-03 17:54:23 +02:00
Sebastian Hartte d9bb81a00f Fixes #4680: Facade advancement is showing an untextured facade. 2020-09-03 17:36:20 +02:00
yueh 39e038d916 Fixes #4683: Hopefully LazyOptional works as advertised (#4684) 2020-09-02 21:36:40 +02:00
Sebastian Hartte 575a625f75 Also update the layer-map, even though the spatial biome should never show up in any vanilla layering. 2020-09-02 19:44:37 +02:00
Sebastian Hartte 89ea923c43 Merge fixes 2020-09-02 19:41:44 +02:00
Sebastian Hartte 5d818eb03e Merge remote-tracking branch 'origin/master' into fabric/master 2020-09-02 02:55:39 +02:00
Sebastian Hartte 12ca8d109a Merge remote-tracking branch 'origin/8.0.x-1.16.1' 2020-09-02 02:55:12 +02:00
Sebastian Hartte e34126458b Merge remote-tracking branch 'origin/master' into fabric/master
# Conflicts:
#	gradle.properties
#	src/main/java/appeng/client/gui/Size1Slot.java
#	src/main/java/appeng/client/me/SlotFluidME.java
#	src/main/java/appeng/client/me/SlotME.java
#	src/main/java/appeng/client/render/cablebus/CableBusBakedModel.java
#	src/main/java/appeng/client/render/cablebus/CableBusModelLoader.java
#	src/main/java/appeng/core/sync/packets/MEFluidInventoryUpdatePacket.java
#	src/main/java/appeng/core/sync/packets/MEInterfaceUpdatePacket.java
#	src/main/java/appeng/core/sync/packets/MEInventoryUpdatePacket.java
#	src/main/java/appeng/datagen/providers/loot/BlockDropProvider.java
#	src/main/java/appeng/fluids/client/gui/widgets/FluidSlotWidget.java
#	src/main/java/appeng/fluids/container/FluidConfigurableContainer.java
#	src/main/java/appeng/fluids/helper/FluidCellConfig.java
#	src/main/resources/META-INF/mods.toml
2020-09-02 02:45:31 +02:00
Sebastian Hartte 0ac918c363 Fixed exclusion zones for many screens. 2020-09-02 02:37:47 +02:00
Sebastian Hartte b6160e40bc Fixes #4671: Use other Ingredient method which is not client-only. 2020-09-02 01:49:24 +02:00
Sebastian Hartte cf103b06c1 Fixes #4677: Stackoverflow when crafting with the quartz knife. 2020-09-02 00:12:20 +02:00
yueh f0d0595c8f Fixes #4669: Take NBT into account for comparing. (#4675)
This only covers combining different items together.
Fuzzy filtering is still a bit too fuzzy for corner cases.
2020-09-01 21:59:08 +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 7c99fca789 Fixes removal of facades not invalidating the cached server-side collision boxes. (#4663)
(cherry picked from commit 957bc4c5cc)
2020-09-01 01:07:30 +02:00
yueh ab393b0ed1 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.

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