Compare commits

..

No commits in common. "1.21.1" and "1.21" have entirely different histories.
1.21.1 ... 1.21

109 changed files with 1273 additions and 3179 deletions

View File

@ -1,34 +0,0 @@
name: Release for 1.21.1
on:
push:
branches: [ '1.21.1' ]
workflow_dispatch:
jobs:
release:
name: Publish release JAR for Ex Deorum
runs-on: ubuntu-latest
if: "contains(github.event.head_commit.message, '[Release]') || github.event_name == 'workflow_dispatch'"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'microsoft'
java-version: '21'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- name: Upload to CurseForge
run: ./gradlew curseforge
env:
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
- name: Upload to Modrinth
run: ./gradlew modrinth
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}

View File

@ -1,12 +1,10 @@
plugins {
id 'java-library'
id 'idea'
id 'net.neoforged.moddev' version '2.0.107'
id("com.modrinth.minotaur") version '2.+'
id("com.matthewprenger.cursegradle") version '1.4.0'
id 'net.neoforged.moddev' version '0.1.120'
}
version = '3.10'
version = '3.2'
group = 'thedarkcolour.exdeorum'
base {
archivesName = 'exdeorum'
@ -16,8 +14,6 @@ java.toolchain.languageVersion = JavaLanguageVersion.of(21)
java.toolchain.vendor = JvmVendorSpec.JETBRAINS
java.withSourcesJar()
evaluationDependsOn(":coremod")
neoForge {
version = neo_version
@ -26,7 +22,8 @@ neoForge {
minecraftVersion = project.parchment_minecraft_version
}
accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg')
//validateAccessTransformers = true
accessTransformers.add('src/main/resources/META-INF/accesstransformer.cfg')
runs {
configureEach {
@ -48,7 +45,7 @@ neoForge {
data()
// instead of using --all, skip file check validation
programArguments.addAll('--server', '--client', '--dev', '--reports')
programArguments.addAll('--mod', 'exdeorum', '--output', file('src/generated/resources/').absolutePath, '--existing', file('src/main/resources/').absolutePath)
programArguments.addAll ('--mod', 'exdeorum', '--output', file('src/generated/resources/').absolutePath, '--existing', file('src/main/resources/').absolutePath)
}
}
@ -57,7 +54,7 @@ neoForge {
sourceSet(sourceSets.main)
}
coremod {
sourceSet project(':coremod').sourceSets.main
dependency project(':coremod')
}
}
}
@ -77,33 +74,32 @@ repositories {
url = 'https://maven.blamejared.com/'
content { includeGroup "mezz.jei" }
}
maven {
name = 'rei'
url = "https://maven.shedaniel.me"
}
maven {
name = 'Architectury API'
url = 'https://maven.architectury.dev'
content { includeGroup 'dev.architectury' }
url = "https://maven.architectury.dev"
content { includeGroup "dev.architectury" }
}
maven {
name = 'KubeJS and Rhino'
url = 'https://maven.latvian.dev/releases'
content { includeGroupAndSubgroups 'dev.latvian' }
url = "https://maven.saps.dev/minecraft"
content { includeGroup "dev.latvian.mods" }
}
maven {
name = 'ModKit'
url 'https://jitpack.io'
content {
includeGroup 'com.github.thedarkcolour'
// Required for KubeJS
includeGroup 'com.github.rtyley'
}
content { includeGroup 'com.github.thedarkcolour' }
}
maven {
name = 'EMI'
name = 'TerraformersMC'
url = 'https://maven.terraformersmc.com'
content { includeGroup 'dev.emi' }
}
maven {
name = 'Modrinth'
url = 'https://api.modrinth.com/maven'
name = "Modrinth"
url = "https://api.modrinth.com/maven"
content {
includeModule("maven.modrinth", "oculus")
includeModule("maven.modrinth", "embeddium")
@ -111,34 +107,39 @@ repositories {
}
maven {
url "https://cursemaven.com"
content { includeGroup "curse.maven" }
content {
includeGroup "curse.maven"
}
}
}
dependencies {
// TOP OPTIONAL
compileOnly("mcjty.theoneprobe:theoneprobe:1.21_neo-${top_version}") {
compileOnly("mcjty.theoneprobe:theoneprobe:${mc_version}_neo-${top_version}") {
transitive = false
}
// JADE OPTIONAL
implementation("curse.maven:jade-324717:6291517")
compileOnly("curse.maven:jade-324717:5109393")
// JEI OPTIONAL
compileOnly("mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}")
runtimeOnly("mezz.jei:jei-${mc_version}-neoforge:${jei_version}")
// REI OPTIONAL todo add
compileOnly("me.shedaniel:RoughlyEnoughItems-forge:${rei_version}")
compileOnly("me.shedaniel.cloth:cloth-config-neoforge:${cloth_config_version}")
// EMI OPTIONAL
compileOnly("dev.emi:emi-neoforge:${emi_version}+${mc_version}:api")
//runtimeOnly("dev.emi:emi-neoforge:${emi_version}+${mc_version}")
compileOnly("dev.emi:emi-neoforge:${emi_version}:api")
compileOnly("dev.emi:emi-neoforge:${emi_version}")
//implementation("curse.maven:reipc-521393:4837449")
// KubeJS OPTIONAL
implementation("dev.architectury:architectury-neoforge:${architectury_version}")
implementation("dev.latvian.mods:rhino:${rhino_version}")
implementation "curse.maven:rhino-416294:5554415"
implementation("dev.latvian.mods:kubejs-neoforge:${kubejs_version}")
// ModKit DEV ONLY
implementation('com.github.thedarkcolour:ModKit:4f83c92767')
implementation('com.github.thedarkcolour:ModKit:81a0889b26')
// Core mod
implementation(project(':coremod'))
jarJar(project(':coremod'))
implementation(jarJar(project(':coremod')))
// Oculus + Embeddium OPTIONAL
compileOnly('maven.modrinth:oculus:1.20.1-1.6.9')
@ -146,7 +147,7 @@ dependencies {
// testing
//implementation("curse.maven:allthecompressed-514045:4938351")
compileOnly("curse.maven:alltheores-405593:5500624")
implementation("curse.maven:alltheores-405593:5500624")
//implementation("curse.maven:inventorysorter-240633:4655091")
//implementation("curse.maven:cyclic-239286:4994392")
//implementation("curse.maven:flib-661261:4724762")
@ -154,9 +155,9 @@ dependencies {
tasks.withType(ProcessResources).configureEach {
var replaceProperties = [
mc_version : mc_version,
mod_version : version,
neo_version_range : neo_version_range,
mc_version: mc_version,
mod_version: version,
neo_version_range: neo_version_range,
loader_version_range: loader_version_range
]
inputs.properties replaceProperties
@ -164,6 +165,21 @@ tasks.withType(ProcessResources).configureEach {
filesMatching(['META-INF/neoforge.mods.toml']) {
expand replaceProperties
}
// Minify JSON resources
// Actual reduction in file size is just a few KB, but why not?
doLast {
fileTree(dir: outputs.files.asPath, include: "**/*.json").each {
File file ->
//noinspection UnnecessaryQualifiedReference
try {
file.text = groovy.json.JsonOutput.toJson(new groovy.json.JsonSlurper().parse(file))
} catch (Exception e) {
println "Unable to minify file ${file.name}"
throw new RuntimeException(e)
}
}
}
}
tasks.withType(JavaCompile).configureEach {
@ -176,63 +192,3 @@ idea {
downloadJavadoc = true
}
}
if (System.getenv("CURSEFORGE_TOKEN")) {
curseforge {
apiKey = System.getenv("CURSEFORGE_TOKEN")
project {
id = "901420"
changelogType = "markdown"
changelog = getChangelog(project.version)
releaseType = "release"
addGameVersion(mc_version)
addGameVersion("NeoForge")
addGameVersion("Java 21")
mainArtifact(jar.archiveFile) {
displayName = "Ex Deorum ${project.version}"
}
}
}
}
modrinth {
token = System.getenv("MODRINTH_TOKEN")
projectId = "WP0FLyzv"
versionName = "Ex Deorum ${project.version}"
gameVersions = [mc_version]
loaders = ["neoforge"]
changelog = getChangelog(project.version)
uploadFile = jar
additionalFiles.add(sourcesJar)
}
static def getChangelog(Object version) {
version = version.toString()
def file = new File('changelog.md')
if (!file.exists()) {
return "Changelog file not found"
}
// Relies on the changelog block being "##blahblahblah_VERSION" where _ is a space
def content = file.text.normalize().split("##.* ")
for (final def chunk in content) {
if (chunk.isEmpty()) continue
def lineTerminatorIndex = chunk.findIndexOf { c -> c == '\n' || c == '\r' }
def versionString = chunk.substring(0, lineTerminatorIndex)
if (versionString == version) {
return "## Ex Deorum $version\n" + chunk.substring(lineTerminatorIndex + 1)
}
}
// Fallback in case this fails
return "Ex Deorum Update ${version}"
}

View File

@ -1,41 +1,3 @@
## Ex Deorum 3.11
- Fixed End Cakes crashing fake players (#178)
- Fixed Compressed Sieves not allowing simultaneous insertion of material even when Simultaneous Compressed Sieve Usage was enabled
- Fixed Crucible bug where pending solids could be converted to another fluid while tank was empty (#180)
## Ex Deorum 3.10
- Now requires KubeJS 7.2 to fix incompatibility (#158)
## Ex Deorum 3.9
- Add `#exdeorum:hammer_fortune_blacklist` and `#exdeorum:compressed_hammer_fortune_blacklist` item tags, allowing pack makers to prevent Fortune from affecting a block's hammer or compressed hammer drops
## Ex Deorum 3.8
- Fix memory leak in VisualUpdateTracker (#153)
- Added Hungarian translation (#147)
- Added Japanese translation (#152)
## Ex Deorum 3.7
- Fix Barrel Mixing recipes with a result size greater than 1 only giving one output
- Allow changing drops for Random Armor Trim and Pottery Sherd, also add Tide to possible trims (#133)
## Ex Deorum 3.6
- Implement custom Compressed Sieve types. Works the same as with sieves, just replace `sieve_materials` with `compressed_sieve_materials`
- Fix silkworms not applying to certain modded leaves like TFC
## Ex Deorum 3.5
- Remove Yellorium Dust sieve drop (#116)
- Fixed Fluid Transformation recipes requiring byproducts
## Ex Deorum 3.4
- Fix JEI bug with sieve recipes overflowing due to JEI API changes
- Fix invisible output slots on JEI crook recipes
## Ex Deorum 3.3
- Now built against Minecraft 1.21.1
- Add native EMI support.
- Fix bug where removing all Compressed Sieve recipes would break regular Sieve recipe display in JEI.
- Hack fix for random crashes with fluid transformation recipe cache
## Ex Deorum 3.2
- Fix KubeJS plugin.
- Buff wooden crucibles to 4x like in old Ex Nihilo

View File

@ -3,14 +3,10 @@ plugins {
}
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
java.toolchain.vendor = JvmVendorSpec.JETBRAINS
jar {
manifest {
attributes([
"FMLModType": "LIBRARY",
"Automatic-Module-Name": "thedarkcolour.exdeorum.coremod"
])
attributes(["FMLModType": "LIBRARY"])
}
}

View File

@ -1,2 +0,0 @@
Automatic-Module-Name: thedarkcolour.exdeorum.coremod
FMLModType: LIBRARY

View File

@ -1,23 +1,22 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx1G
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx3G
org.gradle.parallel=true
org.gradle.caching=true
mc_version=1.21.1
neo_version=21.1.213
neo_version_range=[21.1,)
loader_version_range=[4,)
mc_version=1.21
neo_version=21.0.147
neo_version_range=[21,)
loader_version_range=[3,)
jei_version=19.25.0.323
emi_version=1.1.21
jei_version=19.5.3.67
rei_version=14.0.688
emi_version=1.1.7+1.21
cloth_config_version=15.0.127
top_version=12.0.3-5
kubejs_version=2101.7.2-build.296
rhino_version=2101.2.7-build.81
architectury_version=13.0.8
kubejs_version=2100.7.0-build.119
#rhino_version=2004.2.3-build.4
architectury_version=13.0.6
parchment_minecraft_version=1.21.1
parchment_mappings_version=2024.11.17
parchment_minecraft_version=1.20.6
parchment_mappings_version=2024.06.02

0
gradlew vendored Executable file → Normal file
View File

View File

@ -6,7 +6,7 @@ pluginManagement {
}
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0'
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
}
include('coremod')

View File

@ -1,4 +1,4 @@
// 1.21.1 2025-09-01T13:22:27.1441593 Tags for minecraft:item mod id exdeorum
// 1.21 2024-07-09T11:58:49.7850138 Tags for minecraft:item mod id exdeorum
6c72957356b1d59a27be736fa1da54a5a9795ef7 data/exdeorum/tags/item/barrels.json
6afa16b45f76c0defa1675d07586e2c6e6b0be69 data/exdeorum/tags/item/compressed/andesite.json
31b46613766e4cdc53196850495ab1019f61cb48 data/exdeorum/tags/item/compressed/blackstone.json
@ -22,15 +22,11 @@ fc279d9fa656ad00c5504b3f313586ca34fc4477 data/exdeorum/tags/item/compressed/red_
2de46f3e2e91a340f1b71ea5b600f8383a7ce875 data/exdeorum/tags/item/compressed/sands.json
874b33131f557d077ab366fc6506c41369151a40 data/exdeorum/tags/item/compressed/soul_sand.json
dad00c75d1a0b74a2f843bead336ee278e9cecba data/exdeorum/tags/item/compressed_hammers.json
35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/exdeorum/tags/item/compressed_hammer_fortune_blacklist.json
5feb54ce68fa657af5ce696f75b8c7a6d04cc7a7 data/exdeorum/tags/item/crooks.json
74eefeb986d633d26ad42202c4a6b5e71463c425 data/exdeorum/tags/item/end_cake_materials.json
be46bf2abe731d5ee5bd15ce72f222b2b9a49385 data/exdeorum/tags/item/hammers.json
35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/exdeorum/tags/item/hammer_fortune_blacklist.json
008b4a382f07b9c0f9a07c78bedb949b4400e011 data/exdeorum/tags/item/ore_chunks.json
b90bd3c642e69b9e800c58a9f8f53e369652e6ba data/exdeorum/tags/item/pebbles.json
10f2167f7a9472e5df6870bad71b95869fc64b9a data/exdeorum/tags/item/random_shard_drops.json
d6fa5886b22a121a9402c1ca9b7938dc29b19a10 data/exdeorum/tags/item/random_trim_drops.json
8e1b5ab26037123d3948e9ac9f50da1b7cd0a129 data/exdeorum/tags/item/sieve_meshes.json
0152da758e7665bf282f17f466599c7a009d9a15 data/exdeorum/tags/item/stone_barrels.json
8bde4a30abefaa373fa41813da07b6f79f32b874 data/exdeorum/tags/item/wooden_barrels.json

View File

@ -1,4 +1,4 @@
// 1.21.1 2025-01-05T13:28:28.0008751 Loot Tables
// 1.21 2024-07-07T13:35:07.1965604 Loot Tables
105d8a61ea7145d7798146d385d4aad24fd1588d data/exdeorum/loot_table/blocks/acacia_barrel.json
83d50cbd5e45dfa72bf102fd4c0103a388cff9c4 data/exdeorum/loot_table/blocks/acacia_compressed_sieve.json
1e77127a82cbba0937bb02694f65cf1893aeffcb data/exdeorum/loot_table/blocks/acacia_crucible.json

View File

@ -1,2 +1,2 @@
// 1.21.1 2025-01-05T13:28:27.9888761 Tags for minecraft:fluid mod id exdeorum
// 1.21 2024-07-07T13:35:07.1915587 Tags for minecraft:fluid mod id exdeorum
71d650702c2830e62790c9a110dd0c62eb552cf5 data/minecraft/tags/fluid/water.json

View File

@ -1,4 +1,4 @@
// 1.21.1 2025-01-05T13:28:28.0038743 Tags for minecraft:block mod id exdeorum
// 1.21 2024-07-07T13:35:07.193557 Tags for minecraft:block mod id exdeorum
c2f6fb7224bd1e2fdb87249751113c4d66dbc21f data/exdeorum/tags/block/mineable/hammer.json
77dfab311d3714c77bcac2df0397d23d4707f03b data/exdeorum/tags/block/watering_can_tickable.json
f6a9610ebae09549baf17e27200037cd17318055 data/minecraft/tags/block/leaves.json

View File

@ -1,2 +1,2 @@
// 1.21.1 2025-01-05T13:28:28.0258737 Sound Definitions
// 1.21 2024-07-07T13:35:07.2125585 Sound Definitions
33424544e6cf49e7ad5d1a6a9bc815d66be63114 assets/exdeorum/sounds.json

View File

@ -1,2 +1,2 @@
// 1.21.1 2025-01-05T13:28:28.0238748 Tags for minecraft:worldgen/world_preset mod id exdeorum
// 1.21 2024-07-07T13:35:07.2105588 Tags for minecraft:worldgen/world_preset mod id exdeorum
56085ba2e284a5043540b0ba0402f7352a4c2f16 data/minecraft/tags/worldgen/world_preset/normal.json

View File

@ -1,2 +1,2 @@
// 1.21.1 2025-01-05T13:28:27.9868734 ModKit Language: en_us for mod 'exdeorum'
849bf887027b0cab6ccc32bc76c89d838b19768c assets/exdeorum/lang/en_us.json
// 1.21 2024-07-07T13:35:07.189558 ModKit Language: en_us for mod 'exdeorum'
8584d262168fdd9da42460087fdb8a38f7659a68 assets/exdeorum/lang/en_us.json

View File

@ -1,4 +1,4 @@
// 1.21.1 2025-01-05T13:28:28.0028751 Tags for minecraft:worldgen/structure_set mod id exdeorum
// 1.21 2024-07-07T13:35:07.1915587 Tags for minecraft:worldgen/structure_set mod id exdeorum
35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/exdeorum/tags/worldgen/structure_set/overworld_void_structure_sets.json
56ffeb3beb8ca3df4a20420bc56f6139ebf57ada data/exdeorum/tags/worldgen/structure_set/the_end_void_structure_sets.json
14abefb27112e5ad3ebce0cb9618fb51c54e2f9d data/exdeorum/tags/worldgen/structure_set/the_nether_void_structure_sets.json

View File

@ -1,4 +1,4 @@
// 1.21.1 2025-01-05T13:28:28.0038743 Recipes
// 1.21 2024-07-07T19:09:34.6313104 Recipes
0060d0e16dba2df44cc115f8ed68ef5dc52c74f1 data/exdeorum/advancement/recipes/building_blocks/andesite.json
b9c5d12771d724cd646e637641da7a4d6b0a6bbf data/exdeorum/advancement/recipes/building_blocks/basalt.json
d87a237248c140367dbfb748d45f532534e5b45c data/exdeorum/advancement/recipes/building_blocks/blackstone.json
@ -685,6 +685,7 @@ c4f53b0950018297e971d6bff3a212f9cc10a171 data/exdeorum/recipe/compressed_sieve/d
7b153dc60840b8019090140884dddad7b725293f data/exdeorum/recipe/compressed_sieve/dust/diamond/gunpowder.json
8170891e21051270ba9f59d2ba5c6b10cfcdfd8e data/exdeorum/recipe/compressed_sieve/dust/diamond/redstone.json
e5e049c31533b7dbb9f9fe711e98732f7eb2bb28 data/exdeorum/recipe/compressed_sieve/dust/diamond/sky_dust.json
ab1071bf19ae85ddd0d1b35d58acdd6d01456da6 data/exdeorum/recipe/compressed_sieve/dust/diamond/yellorium_dust.json
67f88a4425147babb9830d510a34a0aae774df51 data/exdeorum/recipe/compressed_sieve/dust/flint/blaze_powder.json
342c9062834ee11eb716801a9075d656ddd49713 data/exdeorum/recipe/compressed_sieve/dust/flint/bone_meal.json
40bc84b70ebd1e8c100ad687eaccea369ba75dd7 data/exdeorum/recipe/compressed_sieve/dust/flint/certus_quartz_dust.json
@ -693,6 +694,7 @@ e5e049c31533b7dbb9f9fe711e98732f7eb2bb28 data/exdeorum/recipe/compressed_sieve/d
85b610c846feffbd894062d53a19d566c5f9c6f3 data/exdeorum/recipe/compressed_sieve/dust/flint/gunpowder.json
826aac6b13896fc809a67ce83ccba9eb8452746e data/exdeorum/recipe/compressed_sieve/dust/flint/redstone.json
c9f79e7cb132b7ca07f2b045de9c1f74122ac812 data/exdeorum/recipe/compressed_sieve/dust/flint/sky_dust.json
209bfeb221a9b3f14798787fc7a13a8752906232 data/exdeorum/recipe/compressed_sieve/dust/flint/yellorium_dust.json
cf768a949364dde6ad2927ea9c9cb827ee3da5b7 data/exdeorum/recipe/compressed_sieve/dust/golden/blaze_powder.json
faaddd326cd18f8164982103b53853d823cfdd52 data/exdeorum/recipe/compressed_sieve/dust/golden/bone_meal.json
d9a1cb5939312c4990bbf93bb57db4622af35bba data/exdeorum/recipe/compressed_sieve/dust/golden/certus_quartz_dust.json
@ -703,6 +705,7 @@ cad64d8bcc37bdb6bdf32e699d36a3e971ae40a5 data/exdeorum/recipe/compressed_sieve/d
f99c66e9344427836091d053a9b754266a24a189 data/exdeorum/recipe/compressed_sieve/dust/golden/raw_gold.json
69228d60b742d955f327ecdae3ddca3415a2c9e2 data/exdeorum/recipe/compressed_sieve/dust/golden/redstone.json
b39162edd94ace24664a3b8ff5c076133566ff7e data/exdeorum/recipe/compressed_sieve/dust/golden/sky_dust.json
b05c774cb20bed2e1d1579c6c1e69434b691b7d7 data/exdeorum/recipe/compressed_sieve/dust/golden/yellorium_dust.json
939a1bf0a86af68269cbd3b32b6be0c321737a22 data/exdeorum/recipe/compressed_sieve/dust/iron/blaze_powder.json
ebbdf8044b6c749238c2893212febc3d69dd2fb8 data/exdeorum/recipe/compressed_sieve/dust/iron/bone_meal.json
148a97f3179a6b8f1680f02c8ca340401d971daa data/exdeorum/recipe/compressed_sieve/dust/iron/certus_quartz_dust.json
@ -712,6 +715,7 @@ ebbdf8044b6c749238c2893212febc3d69dd2fb8 data/exdeorum/recipe/compressed_sieve/d
fb61bee9486ffcf601c85b7343db9b58f038e888 data/exdeorum/recipe/compressed_sieve/dust/iron/iron_nugget.json
a252d9cd18e079ce973dded40a194491c594bc04 data/exdeorum/recipe/compressed_sieve/dust/iron/redstone.json
091d070f65a0b3a40ceb607b7a7fa10aa3c246bf data/exdeorum/recipe/compressed_sieve/dust/iron/sky_dust.json
0b22d30a1e84899703d477be568ed92ac1dd1da8 data/exdeorum/recipe/compressed_sieve/dust/iron/yellorium_dust.json
f0fac3fadded5ad927c18ad97ecbeb5bd8948754 data/exdeorum/recipe/compressed_sieve/dust/netherite/blaze_powder.json
515ac2fbec2986a655315f22c54d221e39ad223d data/exdeorum/recipe/compressed_sieve/dust/netherite/bone_meal.json
13defbce749afac9071977a32a1d662f3e6db9f9 data/exdeorum/recipe/compressed_sieve/dust/netherite/certus_quartz_dust.json
@ -722,6 +726,7 @@ e93f272b8fce0b674310c2bf514faa334db4dfbc data/exdeorum/recipe/compressed_sieve/d
bcb4bd970e039451dd2aefcffd474833c247ec95 data/exdeorum/recipe/compressed_sieve/dust/netherite/iron_nugget.json
765fe14856853a542b0be356c2c9513ff69264de data/exdeorum/recipe/compressed_sieve/dust/netherite/redstone.json
105e80e761312507a0c3e8fc23c71a2099614dca data/exdeorum/recipe/compressed_sieve/dust/netherite/sky_dust.json
7af7afadd97a2eeb319995db5bbb9ec532122c03 data/exdeorum/recipe/compressed_sieve/dust/netherite/yellorium_dust.json
9327b383204e2a18e739f192831f130ddc95c14b data/exdeorum/recipe/compressed_sieve/dust/string/blaze_powder.json
88732230b6c02858fc2cfe6739eba490cae26c67 data/exdeorum/recipe/compressed_sieve/dust/string/bone_meal.json
0caa41d25ca3b8d57f19914ad5cac568234af66e data/exdeorum/recipe/compressed_sieve/dust/string/certus_quartz_dust.json
@ -730,6 +735,7 @@ bcb4bd970e039451dd2aefcffd474833c247ec95 data/exdeorum/recipe/compressed_sieve/d
066dd8fc93b212c5499fc5be501286723559e56e data/exdeorum/recipe/compressed_sieve/dust/string/gunpowder.json
901da5c01595ccf9e568c1828971dd07378949d3 data/exdeorum/recipe/compressed_sieve/dust/string/redstone.json
04864eebbf5226421056579b9fad60767c0032ab data/exdeorum/recipe/compressed_sieve/dust/string/sky_dust.json
d78bc46dac04f848209b5f018c024bca7a82baf4 data/exdeorum/recipe/compressed_sieve/dust/string/yellorium_dust.json
3b4c94350a8908ffd503a59a83fd8c49debe2eee data/exdeorum/recipe/compressed_sieve/gravel/diamond/aluminum_ore_chunk.json
054ee2484be76425ea44e465a3a0af64d53bdac1 data/exdeorum/recipe/compressed_sieve/gravel/diamond/amethyst_shard.json
a6e8512efeb47bf22bf63b13c8b3ea8d85b81aa7 data/exdeorum/recipe/compressed_sieve/gravel/diamond/boron_ore_chunk.json
@ -1713,6 +1719,7 @@ ede571a1e66a83bd98aaf8f6b69507b8802815ac data/exdeorum/recipe/sieve/dust/diamond
36c43fe35142d81b87474cbaf6076586dad93fcb data/exdeorum/recipe/sieve/dust/diamond/gunpowder.json
92c7744f049c54f24d622f812ffb70a0e3cda16b data/exdeorum/recipe/sieve/dust/diamond/redstone.json
a48919609f7242a1659c632307a86a506748b771 data/exdeorum/recipe/sieve/dust/diamond/sky_dust.json
e7ab1a04ca905af72a9f0170a516481432593d5c data/exdeorum/recipe/sieve/dust/diamond/yellorium_dust.json
303292ea85045dc645dec5010e288fe0d40860a2 data/exdeorum/recipe/sieve/dust/flint/blaze_powder.json
418c9a1a917392b9a21a17dd4169e15b342db4fa data/exdeorum/recipe/sieve/dust/flint/bone_meal.json
9aeca57c824db55d08324be332ba0f676a01af03 data/exdeorum/recipe/sieve/dust/flint/certus_quartz_dust.json
@ -1721,6 +1728,7 @@ f576674a5e441d0eaa05116bbe0284553557ba47 data/exdeorum/recipe/sieve/dust/flint/g
cc89959ddce1eba69eae648a808dca5075bb2f0b data/exdeorum/recipe/sieve/dust/flint/gunpowder.json
52465f5d5bccd60ab92bc527f0ce120d8b5de1a8 data/exdeorum/recipe/sieve/dust/flint/redstone.json
46c98e16b3418b1bf2beb403762e6fab351283be data/exdeorum/recipe/sieve/dust/flint/sky_dust.json
29259b58e844b5bef627d43f6698b0e97ec3a450 data/exdeorum/recipe/sieve/dust/flint/yellorium_dust.json
423bcbdfb3b9150f83cbdc1282a916e971634937 data/exdeorum/recipe/sieve/dust/golden/blaze_powder.json
14f80e66a0eaf72cf01fda201d7fb0d944f782b9 data/exdeorum/recipe/sieve/dust/golden/bone_meal.json
cdaf9c1f5fd3584018cc22407f15e1cd79dcdcef data/exdeorum/recipe/sieve/dust/golden/certus_quartz_dust.json
@ -1731,6 +1739,7 @@ cdaf9c1f5fd3584018cc22407f15e1cd79dcdcef data/exdeorum/recipe/sieve/dust/golden/
51faf72371ce967bafc17acdf596a9a5619dbd2b data/exdeorum/recipe/sieve/dust/golden/raw_gold.json
f12d267253e79958e9cd7ec3d83c6e41954232d3 data/exdeorum/recipe/sieve/dust/golden/redstone.json
17daed8e91c77e280cdc796ad93d0ff45db25b65 data/exdeorum/recipe/sieve/dust/golden/sky_dust.json
d9083ae741aa12ea15fc6d44d685ee0d568bbe22 data/exdeorum/recipe/sieve/dust/golden/yellorium_dust.json
8cd69d125cb24b6a3b1c39cc5bf128adfd85b06b data/exdeorum/recipe/sieve/dust/iron/blaze_powder.json
babb9a91ed76b9646ca59a71a41a86bad4b892ed data/exdeorum/recipe/sieve/dust/iron/bone_meal.json
0ef818c7dda3be46a888ca31572b80b6285f8596 data/exdeorum/recipe/sieve/dust/iron/certus_quartz_dust.json
@ -1740,6 +1749,7 @@ c98210715ca3d839693434141d9e8a904dcaa40e data/exdeorum/recipe/sieve/dust/iron/gr
2e14de48b4dee734007fe477cf25520beca3ef6e data/exdeorum/recipe/sieve/dust/iron/iron_nugget.json
90a4230141746c2412bbc1399d7aa8f16eb111a6 data/exdeorum/recipe/sieve/dust/iron/redstone.json
04e81ef9d78560e0d5a8f65d85896309f3715f41 data/exdeorum/recipe/sieve/dust/iron/sky_dust.json
9b984d09c904e78cd0e2e2f75af4b1030ffe638e data/exdeorum/recipe/sieve/dust/iron/yellorium_dust.json
71d76b6989e3eb3cd01145ca0906f632600c5bce data/exdeorum/recipe/sieve/dust/netherite/blaze_powder.json
39c75573c4a5db91d22053e78229035b8d231786 data/exdeorum/recipe/sieve/dust/netherite/bone_meal.json
5ec4c50fad6c87720a5ebb47287df3d9f4095d11 data/exdeorum/recipe/sieve/dust/netherite/certus_quartz_dust.json
@ -1750,6 +1760,7 @@ f802f1e478f16ce0c5d462d1cd402d2ee7a2bec6 data/exdeorum/recipe/sieve/dust/netheri
9c383adcf563681da09a3af19d5048fd761847ff data/exdeorum/recipe/sieve/dust/netherite/iron_nugget.json
e2dfed4ec6e2173b38ba4cf9438ecf90de7555ff data/exdeorum/recipe/sieve/dust/netherite/redstone.json
16265ab169283d98cec0967061d0ef18995189e5 data/exdeorum/recipe/sieve/dust/netherite/sky_dust.json
dc9812de337601ee6f5383e6896c37959dcdadc0 data/exdeorum/recipe/sieve/dust/netherite/yellorium_dust.json
143d40d4a0ba03c3a2eb1d5e5c14b9795626d207 data/exdeorum/recipe/sieve/dust/string/blaze_powder.json
e85f9e36c86c4743388a23347b91fe4fd89e833f data/exdeorum/recipe/sieve/dust/string/bone_meal.json
0cfb736683d24614f51babcd97bc6f810e19ca84 data/exdeorum/recipe/sieve/dust/string/certus_quartz_dust.json
@ -1758,6 +1769,7 @@ b82f4c4e8a8e8d3f81cfa12529ff9c91bd258930 data/exdeorum/recipe/sieve/dust/string/
652a04bfad520c23e8f42515e9f3f63612c2a65b data/exdeorum/recipe/sieve/dust/string/gunpowder.json
7df24c2fb65827409de280fc5e1604f313fff5b7 data/exdeorum/recipe/sieve/dust/string/redstone.json
0172633335e28c8e770ebe8e897b9f000cb9929e data/exdeorum/recipe/sieve/dust/string/sky_dust.json
bb4d21aa9f8f68dfeb6b9bd8e9f13a8c829bd8dd data/exdeorum/recipe/sieve/dust/string/yellorium_dust.json
d1e5352b7dfca55be5be84f1ea25f2d837ab7bf1 data/exdeorum/recipe/sieve/gravel/diamond/aluminum_ore_chunk.json
c2d0893f3d45a5bc10196791c0be17600c4a1149 data/exdeorum/recipe/sieve/gravel/diamond/amethyst_shard.json
36fa9dd4488b6ad206f280e93a79e86109991970 data/exdeorum/recipe/sieve/gravel/diamond/boron_ore_chunk.json

View File

@ -1,4 +1,4 @@
// 1.21.1 2025-01-05T13:28:28.0248746 Advancements
// 1.21 2024-07-07T13:35:07.2115571 Advancements
dd4ecee3e84646521f1b79795d467d69cf9fd5ec data/exdeorum/advancement/core/barrel.json
33171a87fed6c1d520a8d3addf1799451d6ee882 data/exdeorum/advancement/core/crook.json
82e6fb7ca651de853a24ce4e7b896460490872bd data/exdeorum/advancement/core/root.json

View File

@ -1,5 +1,5 @@
// 1.21.1 2025-06-03T14:16:11.5333103 Global Loot Modifiers : exdeorum
// 1.21 2024-07-09T12:06:52.712022 Global Loot Modifiers : exdeorum
539ba0e881830430ae2c03f7ac8dec6f2de478a0 data/exdeorum/loot_modifiers/compressed_hammer.json
dd0417e36e03e0f51e1f1bbcff295b54128fdf8f data/exdeorum/loot_modifiers/crook.json
57991d8346a472f12c1a4b6cb94151d2c1bfa371 data/exdeorum/loot_modifiers/hammer.json
4dbec2c1b329ffcd96f4f903f59382c75e0d538c data/neoforge/loot_modifiers/global_loot_modifiers.json
ec4635d28242c1e6ec5858fb58e43c004a34dbc1 data/neoforge/loot_modifiers/global_loot_modifiers.json

View File

@ -1,4 +1,4 @@
// 1.21.1 2025-01-05T13:28:27.9898762 ModKit Item Models for mod 'exdeorum'
// 1.21 2024-07-07T13:35:07.1915587 ModKit Item Models for mod 'exdeorum'
4ba3bb2c6174ac3728a4b85e34681f118ec8eb34 assets/exdeorum/models/item/acacia_barrel.json
8ddbf3f507fc1ee45e3aa4db98d7f7d2e53adff1 assets/exdeorum/models/item/acacia_compressed_sieve.json
c03ce41f7c071498fcbd5f5225e91dcb2f365fbb assets/exdeorum/models/item/acacia_crucible.json

View File

@ -1,4 +1,4 @@
// 1.21.1 2025-01-05T13:28:27.9948744 ModKit Block Models for mod 'exdeorum'
// 1.21 2024-07-07T13:35:07.194558 ModKit Block Models for mod 'exdeorum'
c73197f2dc770a353883c387b2b1f0b082283576 assets/exdeorum/blockstates/acacia_barrel.json
e36a3d22e00c0eae2336a39f3d0c904ef1d89119 assets/exdeorum/blockstates/acacia_compressed_sieve.json
a3ef4562a4c7833439d8d66ff9c210406d317995 assets/exdeorum/blockstates/acacia_crucible.json

View File

@ -179,17 +179,6 @@
"config.jade.plugin_exdeorum.crucible": "Crucible",
"config.jade.plugin_exdeorum.infested_leaves": "Infested Leaves",
"config.jade.plugin_exdeorum.sieve": "Sieve",
"emi.category.exdeorum.barrel_compost": "Barrel Compost",
"emi.category.exdeorum.barrel_fluid_mixing": "Barrel Fluid Mixing",
"emi.category.exdeorum.barrel_mixing": "Barrel Mixing",
"emi.category.exdeorum.compressed_hammer": "Compressed Hammer",
"emi.category.exdeorum.compressed_sieve": "Compressed Sieve",
"emi.category.exdeorum.crook": "Crook",
"emi.category.exdeorum.crucible_heat_sources": "Crucible Heat Source",
"emi.category.exdeorum.hammer": "Hammer",
"emi.category.exdeorum.lava_crucible": "Lava Crucible",
"emi.category.exdeorum.sieve": "Sieve",
"emi.category.exdeorum.water_crucible": "Water Crucible",
"exdeorum.container.mechanical_hammer": "Mechanical Hammer",
"exdeorum.container.mechanical_sieve": "Mechanical Sieve",
"fluid_type.exdeorum.witch_water": "Witch Water",

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:compressed_sieve",
"ingredient": {
"tag": "exdeorum:compressed/dust"
},
"mesh": {
"item": "exdeorum:diamond_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 7.0,
"p": 0.12
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:compressed_sieve",
"ingredient": {
"tag": "exdeorum:compressed/dust"
},
"mesh": {
"item": "exdeorum:flint_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 7.0,
"p": 0.055
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:compressed_sieve",
"ingredient": {
"tag": "exdeorum:compressed/dust"
},
"mesh": {
"item": "exdeorum:golden_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 7.0,
"p": 0.1
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:compressed_sieve",
"ingredient": {
"tag": "exdeorum:compressed/dust"
},
"mesh": {
"item": "exdeorum:iron_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 7.0,
"p": 0.08
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:compressed_sieve",
"ingredient": {
"tag": "exdeorum:compressed/dust"
},
"mesh": {
"item": "exdeorum:netherite_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 7.0,
"p": 0.14
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:compressed_sieve",
"ingredient": {
"tag": "exdeorum:compressed/dust"
},
"mesh": {
"item": "exdeorum:string_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 7.0,
"p": 0.05
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:sieve",
"ingredient": {
"item": "exdeorum:dust"
},
"mesh": {
"item": "exdeorum:diamond_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.12
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:sieve",
"ingredient": {
"item": "exdeorum:dust"
},
"mesh": {
"item": "exdeorum:flint_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.055
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:sieve",
"ingredient": {
"item": "exdeorum:dust"
},
"mesh": {
"item": "exdeorum:golden_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.1
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:sieve",
"ingredient": {
"item": "exdeorum:dust"
},
"mesh": {
"item": "exdeorum:iron_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.08
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:sieve",
"ingredient": {
"item": "exdeorum:dust"
},
"mesh": {
"item": "exdeorum:netherite_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.14
}
}

View File

@ -0,0 +1,24 @@
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "bigreactors"
}
],
"type": "exdeorum:sieve",
"ingredient": {
"item": "exdeorum:dust"
},
"mesh": {
"item": "exdeorum:string_mesh"
},
"result": {
"count": 1,
"id": "biggerreactors:yellorium_dust"
},
"result_amount": {
"type": "minecraft:binomial",
"n": 1.0,
"p": 0.05
}
}

View File

@ -1,5 +0,0 @@
{
"values": [
"#minecraft:decorated_pot_sherds"
]
}

View File

@ -1,19 +0,0 @@
{
"values": [
"minecraft:wayfinder_armor_trim_smithing_template",
"minecraft:shaper_armor_trim_smithing_template",
"minecraft:host_armor_trim_smithing_template",
"minecraft:raiser_armor_trim_smithing_template",
"minecraft:coast_armor_trim_smithing_template",
"minecraft:dune_armor_trim_smithing_template",
"minecraft:eye_armor_trim_smithing_template",
"minecraft:sentry_armor_trim_smithing_template",
"minecraft:silence_armor_trim_smithing_template",
"minecraft:vex_armor_trim_smithing_template",
"minecraft:ward_armor_trim_smithing_template",
"minecraft:wild_armor_trim_smithing_template",
"minecraft:tide_armor_trim_smithing_template",
"minecraft:flow_armor_trim_smithing_template",
"minecraft:bolt_armor_trim_smithing_template"
]
}

View File

@ -1,7 +1,7 @@
{
"entries": [
"exdeorum:hammer",
"exdeorum:compressed_hammer",
"exdeorum:hammer",
"exdeorum:crook"
],
"replace": false

View File

@ -89,9 +89,8 @@ public class EndCakeBlock extends CakeBlock {
return InteractionResult.PASS;
}
// todo test
private static boolean tryTeleport(ServerLevel level, Player player) {
if (player.isFakePlayer()) return false;
if (level.dimension() != Level.END) {
var endLevel = level.getServer().getLevel(Level.END);

View File

@ -38,6 +38,7 @@ import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.HitResult;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.loading.FMLEnvironment;
import org.jetbrains.annotations.Nullable;
@ -45,7 +46,6 @@ import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity;
import thedarkcolour.exdeorum.client.RenderUtil;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.registry.EBlockEntities;
import thedarkcolour.exdeorum.registry.EBlocks;
public class InfestedLeavesBlock extends LeavesBlock implements EntityBlock {
public static final BooleanProperty FULLY_INFESTED = BooleanProperty.create("fully_infested");
@ -55,13 +55,6 @@ public class InfestedLeavesBlock extends LeavesBlock implements EntityBlock {
registerDefaultState(defaultBlockState().setValue(FULLY_INFESTED, false));
}
public static void setBlock(Level level, BlockPos pos, BlockState fromState) {
level.setBlock(pos, EBlocks.INFESTED_LEAVES.get().defaultBlockState()
.setValue(LeavesBlock.DISTANCE, fromState.hasProperty(LeavesBlock.DISTANCE) ? fromState.getValue(LeavesBlock.DISTANCE) : 0)
.setValue(LeavesBlock.PERSISTENT, fromState.hasProperty(LeavesBlock.PERSISTENT) ? fromState.getValue(LeavesBlock.PERSISTENT) : false),
2);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);

View File

@ -208,11 +208,10 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
}
var result = recipe.getResult();
var contained = this.tank.getFluid();
var hadPendingSolids = this.solids > 0;
shrinkAction.accept(item);
this.solids = (short) Math.min(this.solids + result.getAmount(), MAX_SOLIDS);
if (contained.isEmpty() && !hadPendingSolids) {
if (contained.isEmpty()) {
this.fluid = result.getFluid();
updateLight(this.level, this.worldPosition, this.fluid);
}
@ -243,7 +242,7 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
var result = recipe.getResult();
var contained = this.tank.getFluid();
if (FluidStack.isSameFluidSameComponents(result, contained) || (contained.isEmpty() && canAddToPendingFluid(result))) {
if (FluidStack.isSameFluidSameComponents(result, contained) || contained.isEmpty()) {
return result.getAmount() + this.solids <= MAX_SOLIDS ? InsertionResult.YES : InsertionResult.FULL;
}
}
@ -251,10 +250,6 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
return InsertionResult.NO;
}
private boolean canAddToPendingFluid(FluidStack result) {
return this.solids == 0 || this.fluid == null || result.getFluid() == this.fluid;
}
public abstract int getMeltingRate();
public int getSolids() {
@ -309,7 +304,7 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
}
}
private class FluidHandler extends FluidHelper {
private static class FluidHandler extends FluidHelper {
public FluidHandler() {
super(MAX_FLUID_CAPACITY);
}
@ -318,16 +313,6 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
public boolean isFluidValid(FluidStack stack) {
return false;
}
@Override
protected void onContentsChanged() {
if (this.fluid.isEmpty() && AbstractCrucibleBlockEntity.this.solids == 0) {
AbstractCrucibleBlockEntity.this.fluid = null;
}
updateLight(AbstractCrucibleBlockEntity.this.level, AbstractCrucibleBlockEntity.this.worldPosition, this.fluid.getFluid());
AbstractCrucibleBlockEntity.this.markUpdated();
}
}
// inner class

View File

@ -26,6 +26,7 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.stats.Stats;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
@ -159,7 +160,7 @@ public abstract class AbstractSieveBlockEntity extends EBlockEntity implements S
}
if ((x | z) != 0) {
if (level.getBlockEntity(cursor) instanceof AbstractSieveBlockEntity other && other.getType() == getType()) {
if (level.getBlockEntity(cursor) instanceof SieveBlockEntity other) {
var otherLogic = other.logic;
if (otherLogic.getContents().isEmpty()) {

View File

@ -66,6 +66,7 @@ import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.registry.EBlockEntities;
import thedarkcolour.exdeorum.registry.ESounds;
import java.util.Objects;
import java.util.Optional;
public class BarrelBlockEntity extends ETankBlockEntity {
@ -266,7 +267,7 @@ public class BarrelBlockEntity extends ETankBlockEntity {
var itemFluidCap = playerItem.getCapability(Capabilities.FluidHandler.ITEM);
if (itemFluidCap != null) {
var itemFluid = itemFluidCap.drain(1000, IFluidHandler.FluidAction.SIMULATE);
BarrelFluidMixingRecipe recipe = getRecipeCaches().getFluidMixingRecipe(this.tank.getFluid(), itemFluid.getFluid());
BarrelFluidMixingRecipe recipe = RecipeUtil.getFluidMixingRecipe(this.tank.getFluid(), itemFluid.getFluid());
// If draining item fluid was possible and tank has enough fluid to mix...
if (recipe != null && this.tank.getFluidAmount() >= recipe.baseFluid().amount() && itemFluid.getAmount() == 1000) {
@ -370,12 +371,12 @@ public class BarrelBlockEntity extends ETankBlockEntity {
return false;
}
var recipe = getRecipeCaches().getBarrelMixingRecipe(this.level.getRecipeManager(), playerItem, this.tank.getFluid());
var recipe = RecipeUtil.getBarrelMixingRecipe(this.level.getRecipeManager(), playerItem, this.tank.getFluid());
if (recipe != null) {
if (!simulate) {
// Empty barrel
this.tank.drain(recipe.fluid.amount(), IFluidHandler.FluidAction.EXECUTE);
this.tank.drain(recipe.fluidAmount, IFluidHandler.FluidAction.EXECUTE);
// Replace fluid with result
setItem(recipe.result.copy());
this.level.playSound(null, this.worldPosition, ESounds.BARREL_MIXING.get(), SoundSource.BLOCKS, 0.8f, 1.0f);
@ -389,9 +390,9 @@ public class BarrelBlockEntity extends ETankBlockEntity {
private boolean tryComposting(ItemStack stack, boolean simulate) {
if (simulate) {
return getRecipeCaches().isCompostable(stack);
return RecipeUtil.isCompostable(stack);
} else {
var recipe = getRecipeCaches().getBarrelCompostRecipe(stack);
var recipe = RecipeUtil.getBarrelCompostRecipe(stack);
if (recipe != null) {
addCompost(stack, recipe.getVolume());
return true;
@ -437,7 +438,7 @@ public class BarrelBlockEntity extends ETankBlockEntity {
var aboveFluid = aboveFluidState.getType();
if (aboveFluid != Fluids.EMPTY) {
BarrelFluidMixingRecipe recipe = getRecipeCaches().getFluidMixingRecipe(this.tank.getFluid(), aboveFluid instanceof FlowingFluid flowing ? flowing.getSource() : aboveFluid);
BarrelFluidMixingRecipe recipe = RecipeUtil.getFluidMixingRecipe(this.tank.getFluid(), aboveFluid instanceof FlowingFluid flowing ? flowing.getSource() : aboveFluid);
if (recipe != null) {
// If additive is not consumed, just craft
@ -464,7 +465,7 @@ public class BarrelBlockEntity extends ETankBlockEntity {
this.currentTransformRecipe = null;
} else {
var belowState = this.level.getBlockState(this.worldPosition.below());
this.currentTransformRecipe = getRecipeCaches().getFluidTransformationRecipe(this.tank.getFluid().getFluid(), belowState);
this.currentTransformRecipe = RecipeUtil.getFluidTransformationRecipe(this.tank.getFluid().getFluid(), belowState);
if (this.currentTransformRecipe != null) {
var color = this.currentTransformRecipe.resultColor();
@ -639,7 +640,12 @@ public class BarrelBlockEntity extends ETankBlockEntity {
}
public ItemStack extract(boolean simulate) {
return extractItem(0, 64, simulate);
return extractItem(0, 1, simulate);
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
return super.extractItem(slot, amount, simulate);
}
@Override

View File

@ -34,10 +34,6 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import thedarkcolour.exdeorum.network.VisualUpdateTracker;
import thedarkcolour.exdeorum.recipe.RecipeCaches;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import java.util.Objects;
public abstract class EBlockEntity extends BlockEntity {
public EBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
@ -82,8 +78,4 @@ public abstract class EBlockEntity extends BlockEntity {
public InteractionResult useWithoutItem(Level level, Player player) {
return InteractionResult.PASS;
}
public RecipeCaches getRecipeCaches() {
return RecipeUtil.getCaches(Objects.requireNonNull(this.level));
}
}

View File

@ -28,6 +28,7 @@ import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.state.BlockState;
@ -91,7 +92,10 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
// DO NOT SPREAD TO ALREADY INFESTED LEAVES
if (state.is(BlockTags.LEAVES) && state.getBlock() != EBlocks.INFESTED_LEAVES.get()) {
// Spread and keep distance/persistent properties
InfestedLeavesBlock.setBlock(level, targetPos, state);
level.setBlock(targetPos, EBlocks.INFESTED_LEAVES.get().defaultBlockState()
.setValue(LeavesBlock.DISTANCE, state.getValue(LeavesBlock.DISTANCE))
.setValue(LeavesBlock.PERSISTENT, state.getValue(LeavesBlock.PERSISTENT)),
2);
var te = level.getBlockEntity(targetPos);
// Set mimic state of other block

View File

@ -23,6 +23,7 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe;
import thedarkcolour.exdeorum.registry.EBlockEntities;
@ -35,12 +36,12 @@ public class LavaCrucibleBlockEntity extends AbstractCrucibleBlockEntity {
@Override
public int getMeltingRate() {
return getRecipeCaches().getHeatValue(this.level.getBlockState(getBlockPos().below()));
return RecipeUtil.getHeatValue(this.level.getBlockState(getBlockPos().below()));
}
@Override
protected @Nullable CrucibleRecipe getRecipe(ItemStack item) {
return getRecipeCaches().getLavaCrucibleRecipe(item);
return RecipeUtil.getLavaCrucibleRecipe(item);
}
@Override

View File

@ -20,18 +20,20 @@ package thedarkcolour.exdeorum.blockentity;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.loot.LootContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.block.MechanicalHammerBlock;
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
@ -62,8 +64,8 @@ public class MechanicalHammerBlockEntity extends AbstractMachineBlockEntity<Mech
super(EBlockEntities.MECHANICAL_HAMMER.get(), pos, state, ItemHandler::new, EConfig.SERVER.mechanicalHammerEnergyStorage.get());
}
public static boolean isValidInput(Level level, ItemStack stack) {
return RecipeUtil.getCaches(level).getHammerRecipe(stack.getItem()) != null;
public static boolean isValidInput(ItemStack stack) {
return RecipeUtil.getHammerRecipe(stack.getItem()) != null;
}
@Override
@ -126,7 +128,7 @@ public class MechanicalHammerBlockEntity extends AbstractMachineBlockEntity<Mech
var output = this.inventory.getStackInSlot(OUTPUT_SLOT);
if (output.isEmpty() || output.getCount() < output.getMaxStackSize()) {
var recipe = getRecipeCaches().getHammerRecipe(input.getItem());
var recipe = RecipeUtil.getHammerRecipe(input.getItem());
if (recipe != null && (output.isEmpty() || ItemStack.isSameItemSameComponents(recipe.result, output))) {
return recipe;
@ -150,9 +152,7 @@ public class MechanicalHammerBlockEntity extends AbstractMachineBlockEntity<Mech
@SuppressWarnings("DataFlowIssue")
LootContext ctx = RecipeUtil.emptyLootContext((ServerLevel) this.level);
var resultCount = recipe.resultAmount.getInt(ctx);
if (!input.is(EItemTags.HAMMER_FORTUNE_BLACKLIST)) {
resultCount += HammerLootModifier.calculateFortuneBonus(this.level.registryAccess(), this.inventory.getStackInSlot(HAMMER_SLOT), ctx.getRandom(), resultCount == 0);
}
resultCount += HammerLootModifier.calculateFortuneBonus(this.level.registryAccess(), this.inventory.getStackInSlot(HAMMER_SLOT), ctx.getRandom(), resultCount == 0);
var output = this.inventory.getStackInSlot(OUTPUT_SLOT);
if (output.isEmpty()) {
this.inventory.setStackInSlot(OUTPUT_SLOT, recipe.result.copyWithCount(resultCount));
@ -227,9 +227,9 @@ public class MechanicalHammerBlockEntity extends AbstractMachineBlockEntity<Mech
}
@Override
public boolean isItemValid(int slot, ItemStack stack) {
public boolean isItemValid(int slot, @NotNull ItemStack stack) {
if (slot == INPUT_SLOT) {
return this.hammer.getRecipeCaches().getHammerRecipe(stack.getItem()) != null;
return RecipeUtil.getHammerRecipe(stack.getItem()) != null;
} else if (slot == HAMMER_SLOT) {
return stack.is(EItemTags.HAMMERS);
} else {

View File

@ -36,13 +36,10 @@ import thedarkcolour.exdeorum.blockentity.logic.SieveLogic;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.menu.MechanicalSieveMenu;
import thedarkcolour.exdeorum.recipe.RecipeCaches;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.registry.EBlockEntities;
import thedarkcolour.exdeorum.tag.EItemTags;
import java.util.Objects;
public class MechanicalSieveBlockEntity extends AbstractMachineBlockEntity<MechanicalSieveBlockEntity> implements SieveLogic.Owner {
private static final Component TITLE = Component.translatable(TranslationKeys.MECHANICAL_SIEVE_SCREEN_TITLE);
private static final int INPUT_SLOT = 0;
@ -184,7 +181,7 @@ public class MechanicalSieveBlockEntity extends AbstractMachineBlockEntity<Mecha
@Override
public boolean isItemValid(int slot, ItemStack stack) {
if (slot == INPUT_SLOT) {
return !this.sieve.getRecipeCaches().getSieveRecipes(getStackInSlot(1).getItem(), stack).isEmpty();
return !RecipeUtil.getSieveRecipes(getStackInSlot(1).getItem(), stack).isEmpty();
} else if (slot == MESH_SLOT) {
return stack.is(EItemTags.SIEVE_MESHES);
} else {
@ -205,7 +202,7 @@ public class MechanicalSieveBlockEntity extends AbstractMachineBlockEntity<Mecha
@Override
protected void onContentsChanged(int slot) {
if (slot == MESH_SLOT) {
this.sieve.logic.setMesh(Objects.requireNonNull(this.sieve.level).registryAccess(), this.sieve.inventory.getStackInSlot(MESH_SLOT));
this.sieve.logic.setMesh(this.sieve.level.registryAccess(), this.sieve.inventory.getStackInSlot(MESH_SLOT));
}
}

View File

@ -36,7 +36,7 @@ public class WaterCrucibleBlockEntity extends AbstractCrucibleBlockEntity {
@Override
protected @Nullable CrucibleRecipe getRecipe(ItemStack item) {
return getRecipeCaches().getWaterCrucibleRecipe(item);
return RecipeUtil.getWaterCrucibleRecipe(item);
}
@Override

View File

@ -1,6 +1,7 @@
package thedarkcolour.exdeorum.blockentity.logic;
import net.minecraft.world.item.ItemStack;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
import java.util.List;
@ -12,6 +13,6 @@ public class CompressedSieveLogic extends SieveLogic {
@Override
protected List<? extends SieveRecipe> getDropsFor(ItemStack contents) {
return this.owner.getRecipeCaches().getCompressedSieveRecipes(this.mesh.getItem(), contents);
return RecipeUtil.getCompressedSieveRecipes(this.mesh.getItem(), contents);
}
}

View File

@ -32,7 +32,6 @@ import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.storage.loot.LootContext;
import thedarkcolour.exdeorum.config.EConfig;
import thedarkcolour.exdeorum.recipe.RecipeCaches;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
import thedarkcolour.exdeorum.tag.EItemTags;
@ -40,7 +39,7 @@ import thedarkcolour.exdeorum.tag.EItemTags;
import java.util.List;
public class SieveLogic {
protected final Owner owner;
private final Owner owner;
private final boolean mechanical;
// block currently being sifted
@ -130,7 +129,7 @@ public class SieveLogic {
}
protected List<? extends SieveRecipe> getDropsFor(ItemStack contents) {
return this.owner.getRecipeCaches().getSieveRecipes(this.mesh.getItem(), contents);
return RecipeUtil.getSieveRecipes(this.mesh.getItem(), contents);
}
protected int getResultAmount(SieveRecipe recipe, LootContext context, RandomSource rand) {
@ -238,8 +237,6 @@ public class SieveLogic {
// implement on the owner of this sieve logic
public interface Owner {
RecipeCaches getRecipeCaches();
ServerLevel getServerLevel();
// Return whether the result item was consumed

View File

@ -31,7 +31,6 @@ import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.util.Unit;
import net.minecraft.world.level.levelgen.presets.WorldPreset;
import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.ModList;
import net.neoforged.fml.event.config.ModConfigEvent;
@ -71,10 +70,9 @@ public class ClientHandler {
fmlBus.addListener(ClientHandler::onPlayerRespawn);
fmlBus.addListener(ClientHandler::onPlayerLogout);
fmlBus.addListener(ClientHandler::onScreenOpen);
// we need to be at HIGH or HIGHEST to be called before JEI
fmlBus.addListener(EventPriority.HIGHEST, ClientHandler::onRecipesUpdated);
fmlBus.addListener(ClientHandler::onRecipesUpdated);
if (ModList.get().isLoaded(ModIds.JEI) || ModList.get().isLoaded(ModIds.EMI)) {
if (ModList.get().isLoaded(ModIds.JEI)) {
modBus.addListener(ClientHandler::registerAdditionalModels);
}
}
@ -108,7 +106,6 @@ public class ClientHandler {
private static void onPlayerLogout(ClientPlayerNetworkEvent.LoggingOut event) {
isInVoidWorld = false;
ClientsideCode.getRecipeCaches().unload();
}
private static void onConfigChanged(ModConfigEvent.Reloading event) {
@ -163,7 +160,9 @@ public class ClientHandler {
}
private static void onRecipesUpdated(RecipesUpdatedEvent event) {
ClientsideCode.getRecipeCaches().reload(event.getRecipeManager());
if (!Minecraft.getInstance().isSingleplayer()) {
RecipeUtil.reload(event.getRecipeManager());
}
}
public static void disableVoidFogRendering() {

View File

@ -1,43 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.client;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.world.item.crafting.RecipeManager;
import net.neoforged.fml.util.thread.EffectiveSide;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.RecipeCaches;
public class ClientsideCode {
private static final RecipeCaches RECIPE_CACHES = new RecipeCaches();
public static RecipeCaches getRecipeCaches() {
return RECIPE_CACHES;
}
@Nullable
public static RecipeManager getRecipeManager() {
ClientPacketListener connection = Minecraft.getInstance().getConnection();
if (connection != null) {
return connection.getRecipeManager();
}
return null;
}
}

View File

@ -1,249 +0,0 @@
package thedarkcolour.exdeorum.compat;
import com.mojang.blaze3d.platform.Lighting;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Axis;
import net.minecraft.ChatFormatting;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.neoforged.neoforge.client.RenderTypeHelper;
import net.neoforged.neoforge.client.model.data.ModelData;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Matrix4fStack;
import org.joml.Vector3f;
import thedarkcolour.exdeorum.client.ClientHandler;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.registry.EBlocks;
// client-only logic shared between JEI and EMI
public class ClientXeiUtil {
private static final ItemStack OAK_BARREL = new ItemStack(DefaultMaterials.OAK_BARREL.getItem());
private static final FluidState EMPTY = Fluids.EMPTY.defaultFluidState();
private static final BlockState AIR = Blocks.AIR.defaultBlockState();
// From https://github.com/The-Aether-Team/Nitrogen/blob/1.20.1-develop/src/main/java/com/aetherteam/nitrogen/integration/jei/BlockStateRenderer.java
private static final Vector3f L1 = new Vector3f(0.4F, 0.0F, 1.0F).normalize();
private static final Vector3f L2 = new Vector3f(-0.4F, 1.0F, -0.2F).normalize();
public static void renderItemAlternativeModel(GuiGraphics graphics, BakedModel model, ItemStack stack, int xOffset, int yOffset) {
Minecraft mc = Minecraft.getInstance();
var pose = graphics.pose();
pose.pushPose();
pose.translate(8 + xOffset, 8 + yOffset, 150);
try {
pose.mulPose(new Matrix4f().scaling(1.0F, -1.0F, 1.0F));
pose.scale(16f, 16f, 16f);
boolean flag = !model.usesBlockLight();
if (flag) {
Lighting.setupForFlatItems();
}
mc.getItemRenderer().render(stack, ItemDisplayContext.GUI, false, pose, graphics.bufferSource(), 0xf000f0, OverlayTexture.NO_OVERLAY, model);
graphics.flush();
if (flag) {
Lighting.setupFor3DItems();
}
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Rendering item");
CrashReportCategory crashreportcategory = crashreport.addCategory("Item being rendered");
crashreportcategory.setDetail("Item Type", () -> String.valueOf(stack.getItem()));
crashreportcategory.setDetail("Registry Name", () -> BuiltInRegistries.ITEM.getKey(stack.getItem()).toString());
throw new ReportedException(crashreport);
}
pose.popPose();
// From end of ItemStackRenderer
RenderSystem.disableBlend();
}
// https://github.com/way2muchnoise/JustEnoughResources/blob/89ee40ff068c8d6eb6ab103f76381445691cffc9/Common/src/main/java/jeresources/util/RenderHelper.java#L100
public static void renderBlock(GuiGraphics guiGraphics, BlockState state, float x, float y, float z, float scale) {
PoseStack poseStack = guiGraphics.pose();
poseStack.pushPose();
poseStack.translate(x, y, z);
poseStack.scale(-scale, -scale, -scale);
poseStack.translate(-0.5F, -0.5F, 0);
poseStack.mulPose(Axis.XP.rotationDegrees(-30F));
poseStack.translate(0.5F, 0, -0.5F);
poseStack.mulPose(Axis.YP.rotationDegrees(45f));
poseStack.translate(-0.5F, 0, 0.5F);
RenderSystem.setShaderColor(1F, 1F, 1F, 1F);
poseStack.translate(0, 0, -1);
FluidState fluidState = state.getFluidState();
if (fluidState.isEmpty()) {
MultiBufferSource.BufferSource buffers = Minecraft.getInstance().renderBuffers().bufferSource();
RenderSystem.setupGui3DDiffuseLighting(L1, L2);
if (state.is(EBlocks.INFESTED_LEAVES.get())) {
var blockRenderer = Minecraft.getInstance().getBlockRenderer();
var bakedmodel = blockRenderer.getBlockModel(state);
for (var renderType : bakedmodel.getRenderTypes(state, RandomSource.create(42), ModelData.EMPTY)) {
blockRenderer.getModelRenderer().renderModel(poseStack.last(), buffers.getBuffer(RenderTypeHelper.getEntityRenderType(renderType, false)), state, bakedmodel, 1f, 1f, 1f, 15728880, OverlayTexture.NO_OVERLAY, ModelData.EMPTY, renderType);
}
} else {
Minecraft.getInstance().getBlockRenderer().renderSingleBlock(state, poseStack, buffers, 15728880, OverlayTexture.NO_OVERLAY, ModelData.EMPTY, null);
}
buffers.endBatch();
} else {
RenderType renderType = ItemBlockRenderTypes.getRenderLayer(fluidState);
Matrix4fStack modelView = RenderSystem.getModelViewStack();
Tesselator tesselator = Tesselator.getInstance();
renderType.setupRenderState();
modelView.pushMatrix();
modelView.mul(poseStack.last().pose());
RenderSystem.applyModelViewMatrix();
BufferBuilder builder = tesselator.begin(renderType.mode(), renderType.format());
Dummy.tempState = state;
Dummy.tempFluid = fluidState;
Minecraft.getInstance().getBlockRenderer().renderLiquid(BlockPos.ZERO, Dummy.INSTANCE, builder, state, state.getFluidState());
Dummy.tempFluid = EMPTY;
Dummy.tempState = AIR;
MeshData build = builder.build();
if (build != null) {
BufferUploader.drawWithShader(build);
}
renderType.clearRenderState();
modelView.popMatrix();
RenderSystem.applyModelViewMatrix();
}
poseStack.popPose();
}
public static void renderItemWithAsterisk(GuiGraphics graphics, ItemStack stack) {
Minecraft mc = Minecraft.getInstance();
BakedModel model = mc.getItemRenderer().getModel(stack, mc.level, null, 0);
renderItemAlternativeModel(graphics, model, stack, 0, 0);
renderAsterisk(graphics, 0, 0);
}
public static void renderAsterisk(GuiGraphics graphics, int xOffset, int yOffset) {
graphics.pose().pushPose();
graphics.pose().translate(0f, 0f, 200f);
var font = Minecraft.getInstance().font;
// 0xff5555 is Minecraft's red text color.
graphics.drawString(font, "*", xOffset + 19 - 2 - font.width("*"), yOffset + 12, 0xff5555, true);
graphics.pose().popPose();
}
// Takes a decimal probability and returns a user-friendly percentage value
public static Component formatChance(double probability) {
var chance = XeiUtil.FORMATTER.format(probability * 100);
return Component.translatable(TranslationKeys.SIEVE_RECIPE_CHANCE, chance).withStyle(ChatFormatting.GRAY);
}
public static void renderFilledCompostBarrel(GuiGraphics guiGraphics, int xOffset, int yOffset) {
// From mezz.jei.library.render.ItemStackRenderer
RenderSystem.enableDepthTest();
Minecraft mc = Minecraft.getInstance();
var model = mc.getModelManager().getModel(ClientHandler.OAK_BARREL_COMPOSTING);
// From GuiGraphics.renderFakeItem
ClientXeiUtil.renderItemAlternativeModel(guiGraphics, model, OAK_BARREL, xOffset, yOffset);
// From end of DrawableIngredient
RenderSystem.disableDepthTest();
}
public enum Dummy implements BlockAndTintGetter {
INSTANCE;
private static BlockState tempState = AIR;
private static FluidState tempFluid = EMPTY;
@Override
public float getShade(Direction pDirection, boolean pShade) {
return 1;
}
@SuppressWarnings("DataFlowIssue")
@Override
public LevelLightEngine getLightEngine() {
return Minecraft.getInstance().level.getLightEngine();
}
@Override
public int getBlockTint(BlockPos pBlockPos, ColorResolver pColorResolver) {
return 0;
}
@Override
public int getBrightness(LightLayer pLightType, BlockPos pBlockPos) {
return 15;
}
@Override
public int getRawBrightness(BlockPos pBlockPos, int pAmount) {
return 15;
}
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pPos) {
return null;
}
@Override
public BlockState getBlockState(BlockPos pos) {
return pos.equals(BlockPos.ZERO) ? tempState : AIR;
}
@Override
public FluidState getFluidState(BlockPos pos) {
return pos.equals(BlockPos.ZERO) ? tempFluid : EMPTY;
}
@Override
public int getHeight() {
return 0;
}
@Override
public int getMinBuildHeight() {
return 0;
}
}
}

View File

@ -19,15 +19,16 @@
package thedarkcolour.exdeorum.compat;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.client.Minecraft;
import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
import net.minecraft.world.Container;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeInput;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.enchantment.ItemEnchantments;
import net.minecraft.world.level.ItemLike;
@ -39,6 +40,7 @@ import thedarkcolour.exdeorum.registry.EItems;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
@ -79,8 +81,8 @@ public class CompatUtil {
return materials;
}
public static <C extends RecipeInput, R extends Recipe<C>, T> List<T> collectAllRecipes(RecipeManager recipeManager, RecipeType<R> recipeType, Function<R, T> mapper) {
var byType = recipeManager.byType(recipeType);
public static <C extends RecipeInput, R extends Recipe<C>, T> List<T> collectAllRecipes(RecipeType<R> recipeType, Function<R, T> mapper) {
var byType = Objects.requireNonNull(Minecraft.getInstance().level).getRecipeManager().byType(recipeType);
List<T> recipes = new ObjectArrayList<>(byType.size());
for (RecipeHolder<R> value : byType) {
recipes.add(mapper.apply(value.value()));

View File

@ -29,7 +29,6 @@ import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import org.apache.commons.lang3.mutable.MutableInt;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
import thedarkcolour.exdeorum.registry.EItems;
@ -40,14 +39,13 @@ import java.util.List;
import java.util.function.Function;
// Since no JEI code is used here, this can be reused for REI
public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Result> results) {
public static final MutableInt SIEVE_ROWS = new MutableInt(0);
public static final MutableInt COMPRESSED_SIEVE_ROWS = new MutableInt(0);
public record GroupedSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Result> results) {
public static int maxSieveRows;
public static ImmutableList<XeiSieveRecipe> getAllRecipesGrouped(RecipeType<? extends SieveRecipe> recipeType, MutableInt maxRows) {
int maxSieveRows = 1;
public static ImmutableList<GroupedSieveRecipe> getAllRecipesGrouped(RecipeType<? extends SieveRecipe> recipeType) {
maxSieveRows = 1;
var recipes = CompatUtil.collectAllRecipes(RecipeUtil.getClientRecipeManager(), recipeType, Function.identity());
var recipes = CompatUtil.collectAllRecipes(recipeType, Function.identity());
Multimap<Ingredient, SieveRecipe> ingredientGrouper = ArrayListMultimap.create();
for (int i = 0; i < recipes.size(); i++) {
@ -66,11 +64,11 @@ public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Result>
}
}
ImmutableList.Builder<XeiSieveRecipe> jeiRecipes = new ImmutableList.Builder<>();
ImmutableList.Builder<GroupedSieveRecipe> jeiRecipes = new ImmutableList.Builder<>();
// Sort based on expected count of result
var resultSorter = Comparator.comparingDouble(Result::expectedCount).reversed();
// Sort based on order of sieve tier
var meshSorter = Comparator.comparingInt(XeiSieveRecipe::meshOrder);
var meshSorter = Comparator.comparingInt(GroupedSieveRecipe::meshOrder);
// ingredients with common ingredients are grouped into lists (ex. dirt)
for (var ingredient : ingredientGrouper.keySet()) {
@ -99,7 +97,7 @@ public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Result>
results.sort(resultSorter);
var jeiRecipe = new XeiSieveRecipe(ingredient, new ItemStack(mesh), results);
var jeiRecipe = new GroupedSieveRecipe(ingredient, new ItemStack(mesh), results);
jeiRecipes.add(jeiRecipe);
var rows = Mth.ceil((float) meshRecipes.size() / 9f);
@ -108,9 +106,6 @@ public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Result>
}
}
}
maxRows.setValue(maxSieveRows);
return jeiRecipes.build();
}

View File

@ -1,266 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonObject;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.ChatFormatting;
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.WallTorchBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.storage.loot.providers.number.BinomialDistributionGenerator;
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.ModList;
import net.neoforged.neoforgespi.language.IModInfo;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.loot.SummationGenerator;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
// common logic shared between JEI, EMI, and REI (boo REI sucks)
public class XeiUtil {
// One To One (Hammer, Crucible)
public static final int ONE_TO_ONE_WIDTH = 72;
public static final int ONE_TO_ONE_HEIGHT = 18;
// Barrel mixing (Fluid/Item, Fluid/Fluid)
public static final int BARREL_MIXING_WIDTH = 120;
public static final int BARREL_MIXING_HEIGHT = 18;
// Block predicate (Crucible Heat, Sieve)
public static final Component REQUIRES_CERTAIN_STATE = Component.translatable(TranslationKeys.CROOK_CATEGORY_REQUIRES_STATE).withStyle(ChatFormatting.GRAY);
// Sieve
public static final int SIEVE_WIDTH = 162;
public static final int SIEVE_ROW_START = 28;
public static final int SIEVE_ROW_HEIGHT = 18;
public static final Component BY_HAND_ONLY_LABEL = Component.translatable(TranslationKeys.SIEVE_RECIPE_BY_HAND_ONLY).withStyle(ChatFormatting.RED);
public static final DecimalFormat FORMATTER = new DecimalFormat();
static {
FORMATTER.setMinimumFractionDigits(0);
FORMATTER.setMaximumFractionDigits(3);
}
// Takes a decimal probability and returns a user-friendly percentage value
public static Component formatChance(double probability) {
var chance = FORMATTER.format(probability * 100);
return Component.translatable(TranslationKeys.SIEVE_RECIPE_CHANCE, chance).withStyle(ChatFormatting.GRAY);
}
public static List<BlockState> getStates(BlockPredicate predicate) {
if (predicate instanceof BlockPredicate.BlockStatePredicate state) {
return state.possibleStates()
.filter(blockState -> !blockState.hasProperty(BlockStateProperties.WATERLOGGED) || !blockState.getValue(BlockStateProperties.WATERLOGGED))
.toList();
} else if (predicate instanceof BlockPredicate.SingleBlockPredicate block) {
return ImmutableList.of(block.block().defaultBlockState());
} else if (predicate instanceof BlockPredicate.TagPredicate tag) {
var list = new ArrayList<BlockState>();
for (var holder : BuiltInRegistries.BLOCK.getTagOrEmpty(tag.tag())) {
if (holder.isBound()) {
list.add(holder.value().defaultBlockState());
}
}
return list;
}
throw new IllegalArgumentException("Invalid Block Predicate");
}
// Copied from mezz.jei.forge.platform.ModHelper and mezz.jei.library.ModIdHelper
public static Component getModDisplayName(String modId) {
String string = ModList.get().getModContainerById(modId)
.map(ModContainer::getModInfo)
.map(IModInfo::getDisplayName)
.orElseGet(() -> StringUtils.capitalize(modId));
String withoutFormattingCodes = ChatFormatting.stripFormatting(string);
return Component.literal((withoutFormattingCodes == null) ? "" : withoutFormattingCodes).withStyle(style -> style.withItalic(true).withColor(ChatFormatting.BLUE));
}
public static List<Component> getBlockTooltip(List<Component> extraDetails, Block block) {
var modId = BuiltInRegistries.BLOCK.getKey(block).getNamespace();
var tooltip = new ArrayList<Component>();
tooltip.add(Component.translatable(block.getDescriptionId()));
tooltip.addAll(extraDetails);
tooltip.add(getModDisplayName(modId));
return tooltip;
}
public static ImmutableList<Component> getStateRequirements(BlockPredicate.@Nullable BlockStatePredicate predicate) {
ImmutableList.Builder<Component> requirements = ImmutableList.builder();
if (predicate != null) {
var json = CodecUtil.encode(StatePropertiesPredicate.CODEC, predicate.properties());
if (json instanceof JsonObject obj) {
for (var entry : obj.entrySet()) {
requirements.add(Component.literal(" " + entry.getKey() + "=" + entry.getValue().toString()).withStyle(ChatFormatting.GRAY));
}
}
}
return requirements.build();
}
public static List<Component> getExtraDetails(BlockPredicate predicate) {
List<Component> extraDetails;
if (predicate instanceof BlockPredicate.TagPredicate tag) {
extraDetails = ImmutableList.of(Component.literal("#" + tag.tag().location()).withStyle(ChatFormatting.GRAY));
} else if (predicate instanceof BlockPredicate.BlockStatePredicate state) {
var requirements = getStateRequirements(state);
extraDetails = new ArrayList<>(requirements.size() + 1);
extraDetails.add(REQUIRES_CERTAIN_STATE);
extraDetails.addAll(requirements);
} else {
extraDetails = List.of();
}
return extraDetails;
}
public static void addSieveDropTooltip(boolean byHandOnly, NumberProvider provider, Consumer<Component> tooltipLines) {
if (byHandOnly) {
tooltipLines.accept(XeiUtil.BY_HAND_ONLY_LABEL);
}
if (provider instanceof BinomialDistributionGenerator binomial) {
if (binomial.n() instanceof ConstantValue constant && constant.value() == 1) {
var chanceLabel = XeiUtil.formatChance(RecipeUtil.getExpectedValue(binomial.p()));
tooltipLines.accept(chanceLabel);
} else {
addAvgOutput(tooltipLines, RecipeUtil.getExpectedValue(provider));
}
addMinMaxes(tooltipLines, 0, getMax(binomial.n()));
} else if (provider.getClass() != ConstantValue.class) {
var val = RecipeUtil.getExpectedValue(provider);
if (val != -1.0) {
addAvgOutput(tooltipLines, val);
if (provider instanceof UniformGenerator || provider instanceof SummationGenerator) {
addMinMaxes(tooltipLines, getMin(provider), getMax(provider));
}
}
}
}
private static double getMin(NumberProvider provider) {
if (provider instanceof ConstantValue value) {
return value.value();
} else if (provider instanceof UniformGenerator uniform) {
return getMin(uniform.min());
} else if (provider instanceof BinomialDistributionGenerator) {
return 0;
} else if (provider instanceof SummationGenerator summation) {
double sum = 0;
for (var child : summation.providers()) {
sum += getMin(child);
}
return sum;
}
return 0;
}
private static double getMax(NumberProvider provider) {
if (provider instanceof ConstantValue value) {
return value.value();
} else if (provider instanceof UniformGenerator uniform) {
return getMax(uniform.max());
} else if (provider instanceof BinomialDistributionGenerator binomial) {
return getMax(binomial.n());
} else if (provider instanceof SummationGenerator summation) {
double sum = 0;
for (var child : summation.providers()) {
sum += getMax(child);
}
return sum;
}
return 0;
}
private static void addAvgOutput(Consumer<Component> tooltipLines, double avgValue) {
String avgOutput = XeiUtil.FORMATTER.format(avgValue);
tooltipLines.accept(Component.translatable(TranslationKeys.SIEVE_RECIPE_AVERAGE_OUTPUT, avgOutput).withStyle(ChatFormatting.GRAY));
}
// when the player holds shift, they can see the min/max amounts of a drop
private static void addMinMaxes(Consumer<Component> tooltipLines, double min, double max) {
String minFormatted = XeiUtil.FORMATTER.format(min);
String maxFormatted = XeiUtil.FORMATTER.format(max);
tooltipLines.accept(Component.translatable(TranslationKeys.SIEVE_RECIPE_MIN_OUTPUT, minFormatted).withStyle(ChatFormatting.GRAY));
tooltipLines.accept(Component.translatable(TranslationKeys.SIEVE_RECIPE_MAX_OUTPUT, maxFormatted).withStyle(ChatFormatting.GRAY));
}
// public interface HeatRecipeAcceptor {
// void accept(int heat, BlockState state);
// }
//
// public static void addCrucibleHeatRecipes(HeatRecipeAcceptor acceptor) {
// var values = new Object2IntOpenHashMap<Block>();
// for (var entry : RecipeUtil.getHeatSources()) {
// var state = entry.getKey();
// var block = state.getBlock();
//
// if (block instanceof WallTorchBlock) continue;
//
// if (block != Blocks.AIR) {
// final int newValue = entry.getIntValue();
//
// values.computeInt(block, (key, value) -> {
// if (value != null) {
// return Math.max(value, newValue);
// } else {
// return newValue == 0 ? null : newValue;
// }
// });
// }
// }
//
// for (var entry : values.object2IntEntrySet()) {
// acceptor.accept(entry.getIntValue(), entry.getKey().defaultBlockState());
// }
// }
}

View File

@ -1,75 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import dev.emi.emi.api.widget.WidgetHolder;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe;
import java.util.List;
class BarrelCompostEmiRecipe extends EEmiRecipe {
private final List<EmiIngredient> inputs;
private final int volume;
public BarrelCompostEmiRecipe(BarrelCompostRecipe recipe, ResourceLocation id) {
super(id);
this.inputs = EmiUtil.inputs(recipe);
this.volume = recipe.getVolume();
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.BARREL_COMPOST;
}
@Override
public List<EmiIngredient> getInputs() {
return this.inputs;
}
@Override
public List<EmiStack> getOutputs() {
return List.of();
}
@Override
public int getDisplayWidth() {
return 120;
}
@Override
public int getDisplayHeight() {
return 18;
}
@Override
public void addWidgets(WidgetHolder widgets) {
widgets.addSlot(this.inputs.getFirst(), 0, 0);
var volumeLabel = Component.translatable(TranslationKeys.BARREL_COMPOST_RECIPE_VOLUME, this.volume);
widgets.addText(volumeLabel, 24, 5, 0xff808080, false);
}
}

View File

@ -1,100 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import dev.emi.emi.api.neoforge.NeoForgeEmiIngredient;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.render.EmiTexture;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import dev.emi.emi.api.widget.WidgetHolder;
import net.minecraft.resources.ResourceLocation;
import thedarkcolour.exdeorum.compat.XeiUtil;
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe;
import java.util.List;
abstract class BarrelMixingEmiRecipe extends EEmiRecipe {
private final EmiIngredient base;
private final EmiIngredient additive;
private final List<EmiIngredient> inputs;
private final List<EmiStack> outputs;
public BarrelMixingEmiRecipe(EmiIngredient base, EmiIngredient additive, List<EmiStack> outputs, ResourceLocation id) {
super(id);
this.base = base;
this.additive = additive;
this.inputs = List.of(base, additive);
this.outputs = outputs;
}
@Override
public List<EmiIngredient> getInputs() {
return this.inputs;
}
@Override
public List<EmiStack> getOutputs() {
return this.outputs;
}
@Override
public int getDisplayWidth() {
return XeiUtil.BARREL_MIXING_WIDTH;
}
@Override
public int getDisplayHeight() {
return XeiUtil.BARREL_MIXING_HEIGHT;
}
@Override
public void addWidgets(WidgetHolder widgets) {
widgets.addSlot(this.base, 0, 0);
widgets.addTexture(EmiTexture.PLUS, 22, 2);
widgets.addSlot(this.additive, 39, 0);
widgets.addTexture(EmiTexture.EMPTY_ARROW, 63, 1);
widgets.addSlot(this.outputs.getFirst(), 78 + 15, 0).recipeContext(this);
}
static class Items extends BarrelMixingEmiRecipe {
public Items(BarrelMixingRecipe recipe, ResourceLocation id) {
super(NeoForgeEmiIngredient.of(recipe.fluid), EmiIngredient.of(recipe.ingredient), EmiUtil.outputs(recipe.result), id);
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.BARREL_MIXING;
}
}
static class Fluids extends BarrelMixingEmiRecipe {
public Fluids(BarrelFluidMixingRecipe recipe, ResourceLocation id) {
super(NeoForgeEmiIngredient.of(recipe.baseFluid()), NeoForgeEmiIngredient.of(recipe.additiveFluid()), EmiUtil.outputs(recipe.result()), id);
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.BARREL_FLUID_MIXING;
}
}
}

View File

@ -1,111 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import dev.emi.emi.api.neoforge.NeoForgeEmiStack;
import dev.emi.emi.api.stack.EmiStack;
import dev.emi.emi.api.widget.Bounds;
import dev.emi.emi.api.widget.SlotWidget;
import dev.emi.emi.api.widget.Widget;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.fluids.FluidStack;
import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import thedarkcolour.exdeorum.compat.XeiUtil;
import java.util.List;
import java.util.function.Predicate;
public class BlockEmiWidget extends Widget {
private final List<BlockState> states;
private final List<Component> extraDetails;
private final int x;
private final int y;
private final float scale;
private final Bounds bounds;
public BlockEmiWidget(List<BlockState> states, List<Component> extraDetails, int x, int y, float scale) {
this.states = states;
this.extraDetails = extraDetails;
this.x = x;
this.y = y;
this.scale = scale;
int size = (int) (1.5f * scale);
this.bounds = new Bounds(x - size / 2, y - size / 4, size, size);
}
@Override
public Bounds getBounds() {
return this.bounds;
}
@Override
public void render(GuiGraphics draw, int mouseX, int mouseY, float delta) {
draw.pose().pushPose();
int index = (int) (System.currentTimeMillis() / 1000 % this.states.size());
BlockState current = this.states.get(index);
ClientXeiUtil.renderBlock(draw, current, this.x, this.y, 0, this.scale);
draw.pose().popPose();
}
@Override
public List<ClientTooltipComponent> getTooltip(int mouseX, int mouseY) {
int index = (int) (System.currentTimeMillis() / 1000 % this.states.size());
BlockState current = this.states.get(index);
List<Component> tooltip = XeiUtil.getBlockTooltip(this.extraDetails, current.getBlock());
return tooltip.stream()
.map(component -> ClientTooltipComponent.create(component.getVisualOrderText()))
.toList();
}
@Override
public boolean mouseClicked(int mouseX, int mouseY, int button) {
return slotCall(this.states, widget -> widget.mouseClicked(1, 1, button));
}
@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
return slotCall(this.states, widget -> widget.keyPressed(keyCode, scanCode, modifiers));
}
// Hack to use internal EMI behavior of switching to different recipe view
private static boolean slotCall(List<BlockState> states, Predicate<SlotWidget> call) {
int index = (int) (System.currentTimeMillis() / 1000 % states.size());
BlockState current = states.get(index);
EmiStack stack = EmiStack.of(current.getBlock());
if (stack.isEmpty() && !current.getFluidState().isEmpty()) {
stack = NeoForgeEmiStack.of(new FluidStack(current.getFluidState().getType(), 1000));
}
if (stack.isEmpty()) {
return false;
} else {
SlotWidget internal = new SlotWidget(stack, 0, 0);
return call.test(internal);
}
}
}

View File

@ -1,81 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import com.google.common.collect.ImmutableList;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.render.EmiTexture;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import dev.emi.emi.api.widget.WidgetHolder;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.state.BlockState;
import thedarkcolour.exdeorum.compat.XeiUtil;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import java.util.List;
class CrookEmiRecipe extends EEmiRecipe {
private final List<EmiIngredient> inputs;
private final List<EmiStack> outputs;
private final List<BlockState> states;
private final BlockPredicate predicate;
public CrookEmiRecipe(CrookRecipe recipe, ResourceLocation id) {
super(id);
this.inputs = EmiUtil.inputs(recipe.blockPredicate());
this.outputs = ImmutableList.of(EmiStack.of(recipe.result()));
this.states = XeiUtil.getStates(recipe.blockPredicate());
this.predicate = recipe.blockPredicate();
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.CROOK;
}
@Override
public List<EmiIngredient> getInputs() {
return this.inputs;
}
@Override
public List<EmiStack> getOutputs() {
return this.outputs;
}
@Override
public int getDisplayWidth() {
return 120;
}
@Override
public int getDisplayHeight() {
return 48;
}
@Override
public void addWidgets(WidgetHolder widgets) {
widgets.addTexture(EmiTexture.EMPTY_ARROW, 50, 18);
widgets.addSlot(this.outputs.getFirst(), 79, 17).recipeContext(this);
widgets.add(new BlockEmiWidget(this.states, XeiUtil.getExtraDetails(this.predicate), 28, 18, 20f));
}
}

View File

@ -1,63 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.stack.EmiStack;
import net.minecraft.resources.ResourceLocation;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe;
import java.util.List;
abstract class CrucibleEmiRecipe extends EmiOneToOneRecipe {
private final List<EmiStack> outputs;
CrucibleEmiRecipe(CrucibleRecipe recipe, ResourceLocation id) {
super(recipe, id);
this.outputs = EmiUtil.outputs(recipe.getResult());
}
@Override
public List<EmiStack> getOutputs() {
return this.outputs;
}
static class Lava extends CrucibleEmiRecipe {
Lava(CrucibleRecipe recipe, ResourceLocation id) {
super(recipe, id);
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.LAVA_CRUCIBLE;
}
}
static class Water extends CrucibleEmiRecipe {
Water(CrucibleRecipe recipe, ResourceLocation id) {
super(recipe, id);
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.WATER_CRUCIBLE;
}
}
}

View File

@ -1,82 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import dev.emi.emi.api.widget.TextWidget;
import dev.emi.emi.api.widget.WidgetHolder;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.state.BlockState;
import thedarkcolour.exdeorum.compat.XeiUtil;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleHeatRecipe;
import java.util.List;
class CrucibleHeatEmiRecipe extends EEmiRecipe {
private final List<EmiIngredient> inputs;
private final List<BlockState> states;
private final BlockPredicate predicate;
private final int heatValue;
public CrucibleHeatEmiRecipe(CrucibleHeatRecipe recipe, ResourceLocation id) {
super(id);
this.inputs = EmiUtil.inputs(recipe.blockPredicate());
this.states = XeiUtil.getStates(recipe.blockPredicate());
this.predicate = recipe.blockPredicate();
this.heatValue = recipe.heatValue();
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.CRUCIBLE_HEAT_SOURCES;
}
@Override
public List<EmiIngredient> getInputs() {
return this.inputs;
}
@Override
public List<EmiStack> getOutputs() {
return List.of();
}
@Override
public int getDisplayWidth() {
return 120;
}
@Override
public int getDisplayHeight() {
return 48;
}
@Override
public void addWidgets(WidgetHolder widgets) {
widgets.addText(Component.translatable(TranslationKeys.CRUCIBLE_HEAT_SOURCE_CATEGORY_MULTIPLIER, this.heatValue), 60, 5, 0xff808080, false)
.horizontalAlign(TextWidget.Alignment.CENTER);
widgets.add(new BlockEmiWidget(this.states, XeiUtil.getExtraDetails(this.predicate), 60, 24, 20f));
}
}

View File

@ -1,61 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import dev.emi.emi.api.render.EmiTexture;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.widget.WidgetHolder;
import net.minecraft.resources.ResourceLocation;
import thedarkcolour.exdeorum.compat.XeiUtil;
import thedarkcolour.exdeorum.recipe.SingleIngredientRecipe;
import java.util.List;
abstract class EmiOneToOneRecipe extends EEmiRecipe {
private final List<EmiIngredient> inputs;
EmiOneToOneRecipe(SingleIngredientRecipe recipe, ResourceLocation id) {
super(id);
this.inputs = EmiUtil.inputs(recipe);
}
@Override
public List<EmiIngredient> getInputs() {
return this.inputs;
}
@Override
public int getDisplayWidth() {
return XeiUtil.ONE_TO_ONE_WIDTH;
}
@Override
public int getDisplayHeight() {
return XeiUtil.ONE_TO_ONE_HEIGHT;
}
@Override
public void addWidgets(WidgetHolder widgets) {
// todo replace with first in 1.21
widgets.addSlot(this.inputs.get(0), 0, 0);
widgets.addTexture(EmiTexture.EMPTY_ARROW, 24, 1);
widgets.addSlot(getOutputs().get(0), 54, 0).recipeContext(this);
}
}

View File

@ -1,90 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import com.google.common.collect.ImmutableList;
import dev.emi.emi.api.EmiRegistry;
import dev.emi.emi.api.neoforge.NeoForgeEmiStack;
import dev.emi.emi.api.recipe.EmiRecipe;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeInput;
import net.minecraft.world.item.crafting.RecipeType;
import net.neoforged.neoforge.fluids.FluidStack;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.SingleIngredientRecipe;
import java.util.HashSet;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Supplier;
class EmiUtil {
// Returns a list with 1 element.
static List<EmiIngredient> inputs(SingleIngredientRecipe recipe) {
return ImmutableList.of(EmiIngredient.of(recipe.ingredient));
}
static List<EmiIngredient> inputs(BlockPredicate predicate) {
if (predicate instanceof BlockPredicate.SingleBlockPredicate block) {
Item item = block.block().asItem();
if (item != Items.AIR) {
return ImmutableList.of(EmiStack.of(item));
}
} else {
ImmutableList.Builder<EmiIngredient> builder = ImmutableList.builder();
var items = new HashSet<Item>();
predicate.possibleStates().forEach(state -> {
Item item = state.getBlock().asItem();
if (item != Items.AIR) {
if (items.add(item)) {
builder.add(EmiStack.of(item));
}
}
});
// Need to wrap list in an ingredient to get OR behavior instead of AND behavior
return ImmutableList.of(EmiIngredient.of(builder.build()));
}
return ImmutableList.of();
}
public static <C extends RecipeInput, R extends Recipe<C>> void addAll(EmiRegistry registry, Supplier<RecipeType<R>> type, BiFunction<R, ResourceLocation, ? extends EmiRecipe> factory) {
for (var holder : registry.getRecipeManager().byType(type.get())) {
registry.addRecipe(factory.apply(holder.value(), holder.id()));
}
}
public static List<EmiStack> outputs(ItemStack result) {
return ImmutableList.of(EmiStack.of(result));
}
public static List<EmiStack> outputs(FluidStack stack) {
return ImmutableList.of(NeoForgeEmiStack.of(new FluidStack(stack.getFluid(), stack.getAmount())));
}
}

View File

@ -22,129 +22,17 @@ import dev.emi.emi.api.EmiEntrypoint;
import dev.emi.emi.api.EmiInitRegistry;
import dev.emi.emi.api.EmiPlugin;
import dev.emi.emi.api.EmiRegistry;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.render.EmiRenderable;
import dev.emi.emi.api.stack.EmiStack;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.WallTorchBlock;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import thedarkcolour.exdeorum.compat.CompatUtil;
import thedarkcolour.exdeorum.compat.XeiSieveRecipe;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.registry.EItems;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.HashSet;
import java.util.Set;
@EmiEntrypoint
public class ExDeorumEmiPlugin implements EmiPlugin {
static final EmiRecipeCategory BARREL_COMPOST = emiCategory("barrel_compost", (graphics, x, y, partialTick) -> ClientXeiUtil.renderFilledCompostBarrel(graphics, x, y));
static final EmiRecipeCategory BARREL_MIXING = emiCategory("barrel_mixing", EmiStack.of(DefaultMaterials.OAK_BARREL));
static final EmiRecipeCategory BARREL_FLUID_MIXING = emiCategory("barrel_fluid_mixing", EmiStack.of(DefaultMaterials.STONE_BARREL));
static final EmiRecipeCategory LAVA_CRUCIBLE = emiCategory("lava_crucible", EmiStack.of(DefaultMaterials.PORCELAIN_CRUCIBLE));
static final EmiRecipeCategory WATER_CRUCIBLE = emiCategory("water_crucible", EmiStack.of(DefaultMaterials.OAK_CRUCIBLE));
static final EmiRecipeCategory CRUCIBLE_HEAT_SOURCES = emiCategory("crucible_heat_sources", EmiStack.of(DefaultMaterials.PORCELAIN_CRUCIBLE));
static final EmiRecipeCategory SIEVE = emiCategory("sieve", EmiStack.of(DefaultMaterials.OAK_SIEVE));
static final EmiRecipeCategory COMPRESSED_SIEVE = emiCategory("compressed_sieve", EmiStack.of(DefaultMaterials.OAK_COMPRESSED_SIEVE));
static final EmiRecipeCategory HAMMER = emiCategory("hammer", EmiStack.of(EItems.DIAMOND_HAMMER.get()));
static final EmiRecipeCategory COMPRESSED_HAMMER = emiCategory("compressed_hammer", EmiStack.of(EItems.COMPRESSED_DIAMOND_HAMMER.get()));
static final EmiRecipeCategory CROOK = emiCategory("crook", EmiStack.of(EItems.CROOK.get()));
private static EmiRecipeCategory emiCategory(String name, EmiRenderable icon) {
return new EmiRecipeCategory(ExDeorum.loc(name), icon);
}
@Override
public void register(EmiRegistry registry) {
addCategories(registry);
addWorkstations(registry);
addRecipes(registry);
}
private static void addCategories(EmiRegistry registry) {
registry.addCategory(BARREL_COMPOST);
registry.addCategory(BARREL_MIXING);
registry.addCategory(BARREL_FLUID_MIXING);
registry.addCategory(LAVA_CRUCIBLE);
registry.addCategory(WATER_CRUCIBLE);
registry.addCategory(CRUCIBLE_HEAT_SOURCES);
registry.addCategory(SIEVE);
registry.addCategory(COMPRESSED_SIEVE);
registry.addCategory(HAMMER);
registry.addCategory(COMPRESSED_HAMMER);
registry.addCategory(CROOK);
}
private static void addWorkstations(EmiRegistry registry) {
for (var barrel : CompatUtil.getAvailableBarrels(true)) {
var stack = EmiStack.of(barrel);
registry.addWorkstation(BARREL_COMPOST, stack);
registry.addWorkstation(BARREL_MIXING, stack);
registry.addWorkstation(BARREL_FLUID_MIXING, stack);
}
for (var lavaCrucible : CompatUtil.getAvailableLavaCrucibles(true)) {
var stack = EmiStack.of(lavaCrucible);
registry.addWorkstation(LAVA_CRUCIBLE, stack);
registry.addWorkstation(CRUCIBLE_HEAT_SOURCES, stack);
}
for (var waterCrucible : CompatUtil.getAvailableWaterCrucibles(true)) {
registry.addWorkstation(WATER_CRUCIBLE, EmiStack.of(waterCrucible));
}
for (var sieve : CompatUtil.getAvailableSieves(true, true)) {
registry.addWorkstation(SIEVE, EmiStack.of(sieve));
}
for (var compressedSieve : CompatUtil.getAvailableCompressedSieves(true)) {
registry.addWorkstation(COMPRESSED_SIEVE, EmiStack.of(compressedSieve));
}
registry.addWorkstation(HAMMER, EmiStack.of(EItems.WOODEN_HAMMER.get()));
registry.addWorkstation(HAMMER, EmiStack.of(EItems.STONE_HAMMER.get()));
registry.addWorkstation(HAMMER, EmiStack.of(EItems.GOLDEN_HAMMER.get()));
registry.addWorkstation(HAMMER, EmiStack.of(EItems.IRON_HAMMER.get()));
registry.addWorkstation(HAMMER, EmiStack.of(EItems.DIAMOND_HAMMER.get()));
registry.addWorkstation(HAMMER, EmiStack.of(EItems.NETHERITE_HAMMER.get()));
registry.addWorkstation(HAMMER, EmiStack.of(EItems.MECHANICAL_HAMMER.get()));
registry.addWorkstation(COMPRESSED_HAMMER, EmiStack.of(EItems.COMPRESSED_WOODEN_HAMMER.get()));
registry.addWorkstation(COMPRESSED_HAMMER, EmiStack.of(EItems.COMPRESSED_STONE_HAMMER.get()));
registry.addWorkstation(COMPRESSED_HAMMER, EmiStack.of(EItems.COMPRESSED_GOLDEN_HAMMER.get()));
registry.addWorkstation(COMPRESSED_HAMMER, EmiStack.of(EItems.COMPRESSED_IRON_HAMMER.get()));
registry.addWorkstation(COMPRESSED_HAMMER, EmiStack.of(EItems.COMPRESSED_DIAMOND_HAMMER.get()));
registry.addWorkstation(COMPRESSED_HAMMER, EmiStack.of(EItems.COMPRESSED_NETHERITE_HAMMER.get()));
registry.addWorkstation(CROOK, EmiStack.of(EItems.CROOK.get()));
registry.addWorkstation(CROOK, EmiStack.of(EItems.BONE_CROOK.get()));
}
private static void addRecipes(EmiRegistry registry) {
EmiUtil.addAll(registry, ERecipeTypes.BARREL_COMPOST, BarrelCompostEmiRecipe::new);
EmiUtil.addAll(registry, ERecipeTypes.BARREL_MIXING, BarrelMixingEmiRecipe.Items::new);
EmiUtil.addAll(registry, ERecipeTypes.BARREL_FLUID_MIXING, BarrelMixingEmiRecipe.Fluids::new);
EmiUtil.addAll(registry, ERecipeTypes.LAVA_CRUCIBLE, CrucibleEmiRecipe.Lava::new);
EmiUtil.addAll(registry, ERecipeTypes.WATER_CRUCIBLE, CrucibleEmiRecipe.Water::new);
for (var holder : registry.getRecipeManager().byType(ERecipeTypes.CRUCIBLE_HEAT_SOURCE.get())) {
var value = holder.value();
if (value.blockPredicate() instanceof BlockPredicate.SingleBlockPredicate block && block.block() instanceof WallTorchBlock) {
continue;
}
registry.addRecipe(new CrucibleHeatEmiRecipe(value, holder.id()));
}
for (XeiSieveRecipe recipe : XeiSieveRecipe.getAllRecipesGrouped(ERecipeTypes.SIEVE.get(), XeiSieveRecipe.SIEVE_ROWS)) {
registry.addRecipe(new SieveEmiRecipe.Sieve(recipe));
}
for (XeiSieveRecipe recipe : XeiSieveRecipe.getAllRecipesGrouped(ERecipeTypes.COMPRESSED_SIEVE.get(), XeiSieveRecipe.COMPRESSED_SIEVE_ROWS)) {
registry.addRecipe(new SieveEmiRecipe.CompressedSieve(recipe));
}
EmiUtil.addAll(registry, ERecipeTypes.HAMMER, HammerEmiRecipe.Hammer::new);
EmiUtil.addAll(registry, ERecipeTypes.COMPRESSED_HAMMER, HammerEmiRecipe.CompressedHammer::new);
EmiUtil.addAll(registry, ERecipeTypes.CROOK, CrookEmiRecipe::new);
public void register(EmiRegistry emiRegistry) {
}
@Override
@ -162,6 +50,8 @@ public class ExDeorumEmiPlugin implements EmiPlugin {
toRemoveItems.add(itemLike.asItem());
}
registry.disableStacks(stack -> toRemoveItems.contains(stack.getItemStack().getItem()));
registry.disableStacks(stack -> {
return toRemoveItems.contains(stack.getItemStack().getItem());
});
}
}

View File

@ -1,45 +0,0 @@
package thedarkcolour.exdeorum.compat.emi;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.stack.EmiStack;
import net.minecraft.resources.ResourceLocation;
import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
import java.util.List;
abstract class HammerEmiRecipe extends EmiOneToOneRecipe {
private final List<EmiStack> outputs;
HammerEmiRecipe(HammerRecipe recipe, ResourceLocation id) {
super(recipe, id);
this.outputs = EmiUtil.outputs(recipe.result);
}
@Override
public List<EmiStack> getOutputs() {
return this.outputs;
}
static class Hammer extends HammerEmiRecipe {
Hammer(HammerRecipe recipe, ResourceLocation id) {
super(recipe, id);
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.HAMMER;
}
}
static class CompressedHammer extends HammerEmiRecipe {
CompressedHammer(HammerRecipe recipe, ResourceLocation id) {
super(recipe, id);
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.COMPRESSED_HAMMER;
}
}
}

View File

@ -1,145 +0,0 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
import com.google.common.collect.ImmutableList;
import dev.emi.emi.api.recipe.EmiRecipeCategory;
import dev.emi.emi.api.stack.EmiIngredient;
import dev.emi.emi.api.stack.EmiStack;
import dev.emi.emi.api.widget.SlotWidget;
import dev.emi.emi.api.widget.WidgetHolder;
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.compat.XeiSieveRecipe;
import thedarkcolour.exdeorum.compat.XeiUtil;
import java.util.Arrays;
import java.util.List;
abstract class SieveEmiRecipe extends EEmiRecipe {
private final List<EmiIngredient> inputs;
private final int rows;
private final List<EmiStack> outputs;
private final XeiSieveRecipe recipe;
SieveEmiRecipe(XeiSieveRecipe recipe, int rows) {
super(determineId(recipe));
this.inputs = ImmutableList.of(EmiIngredient.of(recipe.ingredient()), EmiStack.of(recipe.mesh()));
this.rows = rows;
this.recipe = recipe;
ImmutableList.Builder<EmiStack> outputs = ImmutableList.builderWithExpectedSize(recipe.results().size());
for (XeiSieveRecipe.Result result : recipe.results()) {
outputs.add(EmiStack.of(result.item));
}
this.outputs = outputs.build();
}
private static ResourceLocation determineId(XeiSieveRecipe recipe) {
Item mesh = recipe.mesh().getItem();
int hashCode = Arrays.hashCode(Arrays.stream(recipe.ingredient().getItems())
.map(ItemStack::getItem)
.toArray());
return ExDeorum.loc(BuiltInRegistries.ITEM.getKey(mesh).getPath() + "_" + hashCode);
}
@Override
public List<EmiIngredient> getInputs() {
return this.inputs;
}
@Override
public List<EmiStack> getOutputs() {
return this.outputs;
}
@Override
public int getDisplayWidth() {
return XeiUtil.SIEVE_WIDTH;
}
@Override
public int getDisplayHeight() {
return XeiUtil.SIEVE_ROW_START + XeiUtil.SIEVE_ROW_HEIGHT * this.rows;
}
@Override
public void addWidgets(WidgetHolder widgets) {
widgets.addSlot(this.inputs.get(0), 58, 1);
widgets.addSlot(this.inputs.get(1), 86, 1);
for (int i = 0; i < this.rows * 9; i++) {
int x = (i % 9) * 18;
int y = XeiUtil.SIEVE_ROW_START + 18 * (i / 9);
if (i < this.outputs.size()) {
XeiSieveRecipe.Result result = this.recipe.results().get(i);
widgets.add(new SieveResultWidget(this.outputs.get(i), x, y, result.byHandOnly, result.provider)).recipeContext(this);
} else {
widgets.addSlot(x, y);
}
}
}
static class Sieve extends SieveEmiRecipe {
Sieve(XeiSieveRecipe recipe) {
super(recipe, XeiSieveRecipe.SIEVE_ROWS.intValue());
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.SIEVE;
}
}
static class CompressedSieve extends SieveEmiRecipe {
CompressedSieve(XeiSieveRecipe recipe) {
super(recipe, XeiSieveRecipe.COMPRESSED_SIEVE_ROWS.intValue());
}
@Override
public EmiRecipeCategory getCategory() {
return ExDeorumEmiPlugin.COMPRESSED_SIEVE;
}
}
private static class SieveResultWidget extends SlotWidget {
private final boolean byHandOnly;
private final NumberProvider amount;
public SieveResultWidget(EmiIngredient stack, int x, int y, boolean byHandOnly, NumberProvider amount) {
super(stack, x, y);
this.byHandOnly = byHandOnly;
this.amount = amount;
}
@Override
public List<ClientTooltipComponent> getTooltip(int mouseX, int mouseY) {
List<ClientTooltipComponent> list = super.getTooltip(mouseX, mouseY);
XeiUtil.addSieveDropTooltip(this.byHandOnly, this.amount, line -> list.add(ClientTooltipComponent.create(line.getVisualOrderText())));
return list;
}
}
}

View File

@ -18,6 +18,7 @@
package thedarkcolour.exdeorum.compat.jei;
import com.mojang.blaze3d.systems.RenderSystem;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
@ -29,8 +30,10 @@ import mezz.jei.api.recipe.category.IRecipeCategory;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component;
import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import net.minecraft.world.item.ItemStack;
import thedarkcolour.exdeorum.client.ClientHandler;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe;
class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
@ -85,6 +88,8 @@ class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
}
private static class DrawableIcon implements IDrawable {
private final ItemStack oakBarrel = new ItemStack(DefaultMaterials.OAK_BARREL.getItem());
@Override
public int getWidth() {
return 16;
@ -97,7 +102,15 @@ class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
@Override
public void draw(GuiGraphics guiGraphics, int xOffset, int yOffset) {
ClientXeiUtil.renderFilledCompostBarrel(guiGraphics, xOffset, yOffset);
// From mezz.jei.library.render.ItemStackRenderer
RenderSystem.enableDepthTest();
Minecraft mc = Minecraft.getInstance();
var model = mc.getModelManager().getModel(ClientHandler.OAK_BARREL_COMPOSTING);
// From GuiGraphics.renderFakeItem
ClientJeiUtil.renderItemAlternativeModel(guiGraphics, model, this.oakBarrel, xOffset, yOffset);
// From end of DrawableIngredient
RenderSystem.disableDepthTest();
}
}
}

View File

@ -31,7 +31,6 @@ import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
@ -128,7 +127,7 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
super.draw(recipe, recipeSlotsView, graphics, mouseX, mouseY);
if (recipe.consumesAdditive()) {
ClientXeiUtil.renderAsterisk(graphics, 18 + 3 + 3 + 8, 0);
ClientJeiUtil.renderAsterisk(graphics, 18 + 3 + 3 + 8, 0);
}
}
}

View File

@ -18,7 +18,10 @@
package thedarkcolour.exdeorum.compat.jei;
import com.mojang.blaze3d.platform.Lighting;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import com.mojang.math.Axis;
import mezz.jei.api.ingredients.IIngredientRenderer;
import mezz.jei.api.ingredients.IIngredientType;
import mezz.jei.api.ingredients.ITypedIngredient;
@ -26,21 +29,166 @@ import mezz.jei.api.recipe.IFocusFactory;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.runtime.IIngredientManager;
import mezz.jei.api.runtime.IRecipesGui;
import net.minecraft.ChatFormatting;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.lighting.LevelLightEngine;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.neoforged.fml.ModList;
import net.neoforged.neoforge.fluids.FluidStack;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import org.joml.Matrix4f;
import org.joml.Matrix4fStack;
import org.joml.Vector3f;
import thedarkcolour.exdeorum.compat.ModIds;
import thedarkcolour.exdeorum.data.TranslationKeys;
import java.text.DecimalFormat;
import java.util.List;
import java.util.function.Consumer;
class ClientJeiUtil {
private static final FluidState EMPTY = Fluids.EMPTY.defaultFluidState();
private static final BlockState AIR = Blocks.AIR.defaultBlockState();
// From https://github.com/The-Aether-Team/Nitrogen/blob/1.20.1-develop/src/main/java/com/aetherteam/nitrogen/integration/jei/BlockStateRenderer.java
private static final Vector3f L1 = new Vector3f(0.4F, 0.0F, 1.0F).normalize();
private static final Vector3f L2 = new Vector3f(-0.4F, 1.0F, -0.2F).normalize();
static final DecimalFormat FORMATTER = new DecimalFormat();
// https://github.com/way2muchnoise/JustEnoughResources/blob/89ee40ff068c8d6eb6ab103f76381445691cffc9/Common/src/main/java/jeresources/util/RenderHelper.java#L100
static void renderBlock(GuiGraphics guiGraphics, BlockState block, float x, float y, float z, float scale, RenderBlockFn renderFunction) {
PoseStack poseStack = guiGraphics.pose();
poseStack.translate(x, y, z);
poseStack.scale(-scale, -scale, -scale);
poseStack.translate(-0.5F, -0.5F, 0);
poseStack.mulPose(Axis.XP.rotationDegrees(-30F));
poseStack.translate(0.5F, 0, -0.5F);
poseStack.mulPose(Axis.YP.rotationDegrees(45f));
poseStack.translate(-0.5F, 0, 0.5F);
poseStack.pushPose();
RenderSystem.setShaderColor(1F, 1F, 1F, 1F);
poseStack.translate(0, 0, -1);
FluidState fluidState = block.getFluidState();
if (fluidState.isEmpty()) {
MultiBufferSource.BufferSource buffers = Minecraft.getInstance().renderBuffers().bufferSource();
RenderSystem.setupGui3DDiffuseLighting(L1, L2);
renderFunction.renderBlock(block, poseStack, buffers);
buffers.endBatch();
} else {
RenderType renderType = ItemBlockRenderTypes.getRenderLayer(fluidState);
Matrix4fStack modelView = RenderSystem.getModelViewStack();
Tesselator tesselator = Tesselator.getInstance();
renderType.setupRenderState();
modelView.pushMatrix();
modelView.mul(poseStack.last().pose());
RenderSystem.applyModelViewMatrix();
BufferBuilder builder = tesselator.begin(renderType.mode(), renderType.format());
Dummy.tempState = block;
Dummy.tempFluid = fluidState;
Minecraft.getInstance().getBlockRenderer().renderLiquid(BlockPos.ZERO, Dummy.INSTANCE, builder, block, block.getFluidState());
Dummy.tempFluid = EMPTY;
Dummy.tempState = AIR;
MeshData build = builder.build();
if (build != null) {
BufferUploader.drawWithShader(build);
}
renderType.clearRenderState();
modelView.popMatrix();
RenderSystem.applyModelViewMatrix();
}
poseStack.popPose();
}
static void renderItemWithAsterisk(GuiGraphics graphics, ItemStack stack) {
Minecraft mc = Minecraft.getInstance();
BakedModel model = mc.getItemRenderer().getModel(stack, mc.level, null, 0);
renderItemAlternativeModel(graphics, model, stack, 0, 0);
renderAsterisk(graphics, 0, 0);
}
static void renderAsterisk(GuiGraphics graphics, int xOffset, int yOffset) {
graphics.pose().pushPose();
graphics.pose().translate(0f, 0f, 200f);
var font = Minecraft.getInstance().font;
// 0xff5555 is Minecraft's red text color.
graphics.drawString(font, "*", xOffset + 19 - 2 - font.width("*"), yOffset + 12, 0xff5555, true);
graphics.pose().popPose();
}
static void renderItemAlternativeModel(GuiGraphics graphics, BakedModel model, ItemStack stack, int xOffset, int yOffset) {
Minecraft mc = Minecraft.getInstance();
var pose = graphics.pose();
pose.pushPose();
pose.translate(8 + xOffset, 8 + yOffset, 150);
try {
pose.mulPose(new Matrix4f().scaling(1.0F, -1.0F, 1.0F));
pose.scale(16f, 16f, 16f);
boolean flag = !model.usesBlockLight();
if (flag) {
Lighting.setupForFlatItems();
}
mc.getItemRenderer().render(stack, ItemDisplayContext.GUI, false, pose, graphics.bufferSource(), 0xf000f0, OverlayTexture.NO_OVERLAY, model);
graphics.flush();
if (flag) {
Lighting.setupFor3DItems();
}
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Rendering item");
CrashReportCategory crashreportcategory = crashreport.addCategory("Item being rendered");
crashreportcategory.setDetail("Item Type", () -> {
return String.valueOf(stack.getItem());
});
crashreportcategory.setDetail("Registry Name", () -> BuiltInRegistries.ITEM.getKey(stack.getItem()).toString());
throw new ReportedException(crashreport);
}
pose.popPose();
// From end of ItemStackRenderer
RenderSystem.disableBlend();
}
// Required due to broken JEI implementation in REI plugin compatibility
static <T> void checkTypedIngredient(IIngredientManager manager, IIngredientType<T> ingredientType, @Nullable T uncheckedIngredient, Consumer<ITypedIngredient<T>> action) {
if ((uncheckedIngredient instanceof ItemStack stack && !stack.isEmpty()) || (uncheckedIngredient instanceof FluidStack fluidStack && !fluidStack.isEmpty())) {
@ -51,6 +199,9 @@ class ClientJeiUtil {
static <T> void showRecipes(IFocusFactory focusFactory, ITypedIngredient<T> ingredient) {
if (Minecraft.getInstance().screen instanceof IRecipesGui recipesGui) {
recipesGui.show(focusFactory.createFocus(RecipeIngredientRole.OUTPUT, ingredient));
} else if (ModList.get().isLoaded(ModIds.REI_PC)) {
// todo fix when REIPC is on 1.21
//ViewSearchBuilder.builder().addRecipesFor(JEIPluginDetector.unwrapStack(ingredient)).open();
}
}
@ -58,6 +209,79 @@ class ClientJeiUtil {
if (Minecraft.getInstance().screen instanceof IRecipesGui recipesGui) {
// input + catalyst
recipesGui.show(List.of(focusFactory.createFocus(RecipeIngredientRole.INPUT, ingredient), focusFactory.createFocus(RecipeIngredientRole.CATALYST, ingredient)));
} else if (ModList.get().isLoaded(ModIds.REI_PC)) {
// todo fix when REIPC is on 1.21
//ViewSearchBuilder.builder().addUsagesFor(JEIPluginDetector.unwrapStack(ingredient)).open();
}
}
// Takes a decimal probability and returns a user-friendly percentage value
static Component formatChance(double probability) {
var chance = FORMATTER.format(probability * 100);
return Component.translatable(TranslationKeys.SIEVE_RECIPE_CHANCE, chance).withStyle(ChatFormatting.GRAY);
}
@FunctionalInterface
interface RenderBlockFn {
void renderBlock(BlockState block, PoseStack poseStack, MultiBufferSource.BufferSource buffers);
}
private enum Dummy implements BlockAndTintGetter {
INSTANCE;
private static BlockState tempState = AIR;
private static FluidState tempFluid = EMPTY;
@Override
public float getShade(Direction pDirection, boolean pShade) {
return 1;
}
@SuppressWarnings("DataFlowIssue")
@Override
public LevelLightEngine getLightEngine() {
return Minecraft.getInstance().level.getLightEngine();
}
@Override
public int getBlockTint(BlockPos pBlockPos, ColorResolver pColorResolver) {
return 0;
}
@Override
public int getBrightness(LightLayer pLightType, BlockPos pBlockPos) {
return 15;
}
@Override
public int getRawBrightness(BlockPos pBlockPos, int pAmount) {
return 15;
}
@Nullable
@Override
public BlockEntity getBlockEntity(BlockPos pPos) {
return null;
}
@Override
public BlockState getBlockState(BlockPos pos) {
return pos.equals(BlockPos.ZERO) ? tempState : AIR;
}
@Override
public FluidState getFluidState(BlockPos pos) {
return pos.equals(BlockPos.ZERO) ? tempFluid : EMPTY;
}
@Override
public int getHeight() {
return 0;
}
@Override
public int getMinBuildHeight() {
return 0;
}
}
@ -69,7 +293,7 @@ class ClientJeiUtil {
if (ingredient != null) {
// From mezz.jei.library.render.ItemStackRenderer
RenderSystem.enableDepthTest();
ClientXeiUtil.renderItemWithAsterisk(graphics, ingredient);
ClientJeiUtil.renderItemWithAsterisk(graphics, ingredient);
// From end of DrawableIngredient
RenderSystem.disableDepthTest();
}

View File

@ -3,17 +3,17 @@ package thedarkcolour.exdeorum.compat.jei;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.RecipeType;
import net.minecraft.network.chat.Component;
import thedarkcolour.exdeorum.compat.XeiSieveRecipe;
import thedarkcolour.exdeorum.compat.GroupedSieveRecipe;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
class CompressedSieveCategory extends SieveCategory {
CompressedSieveCategory(IGuiHelper helper) {
super(helper, DefaultMaterials.OAK_COMPRESSED_SIEVE, Component.translatable(TranslationKeys.COMPRESSED_SIEVE_CATEGORY_TITLE), XeiSieveRecipe.COMPRESSED_SIEVE_ROWS);
super(helper, DefaultMaterials.OAK_COMPRESSED_SIEVE, Component.translatable(TranslationKeys.COMPRESSED_SIEVE_CATEGORY_TITLE));
}
@Override
public RecipeType<XeiSieveRecipe> getRecipeType() {
public RecipeType<GroupedSieveRecipe> getRecipeType() {
return ExDeorumJeiPlugin.COMPRESSED_SIEVE;
}
}

View File

@ -21,7 +21,6 @@ package thedarkcolour.exdeorum.compat.jei;
import com.mojang.blaze3d.platform.InputConstants;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.gui.builder.ITooltipBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.helpers.IJeiHelpers;
@ -33,15 +32,23 @@ import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.api.runtime.IIngredientManager;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import net.neoforged.neoforge.client.RenderTypeHelper;
import net.neoforged.neoforge.client.model.data.ModelData;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.registry.EBlocks;
import thedarkcolour.exdeorum.registry.EItems;
import java.util.ArrayList;
import java.util.List;
public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
private static final Component REQUIRES_CERTAIN_STATE = Component.translatable(TranslationKeys.CROOK_CATEGORY_REQUIRES_STATE).withStyle(ChatFormatting.GRAY);
@ -93,8 +100,8 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
@Override
public void setRecipe(IRecipeLayoutBuilder builder, CrookJeiRecipe recipe, IFocusGroup focuses) {
recipe.addIngredients(builder);
builder.addSlot(RecipeIngredientRole.OUTPUT, 80, 18).addItemStack(recipe.result).addRichTooltipCallback((recipeSlotView, tooltip) -> {
tooltip.add(ClientXeiUtil.formatChance(recipe.chance));
builder.addSlot(RecipeIngredientRole.OUTPUT, 80, 18).addItemStack(recipe.result).addTooltipCallback((recipeSlotView, tooltip) -> {
tooltip.add(ClientJeiUtil.formatChance(recipe.chance));
});
}
@ -106,15 +113,29 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
this.slot.draw(graphics, 79, 17);
BlockState state = this.timer.getCycledItem(recipe.states);
ClientXeiUtil.renderBlock(graphics, state, 28, 18, 10, 20f);
if (state.is(EBlocks.INFESTED_LEAVES.get())) {
ClientJeiUtil.renderBlock(graphics, state, 28, 18, 10, 20f, (block, poseStack, buffers) -> {
var blockRenderer = Minecraft.getInstance().getBlockRenderer();
var bakedmodel = blockRenderer.getBlockModel(state);
for (var renderType : bakedmodel.getRenderTypes(state, RandomSource.create(42), ModelData.EMPTY)) {
blockRenderer.getModelRenderer().renderModel(poseStack.last(), buffers.getBuffer(RenderTypeHelper.getEntityRenderType(renderType, false)), state, bakedmodel, 1f, 1f, 1f, 15728880, OverlayTexture.NO_OVERLAY, ModelData.EMPTY, renderType);
}
});
} else {
ClientJeiUtil.renderBlock(graphics, state, 28, 18, 10, 20f, (block, poseStack, buffers) -> {
//noinspection DataFlowIssue
Minecraft.getInstance().getBlockRenderer().renderSingleBlock(block, poseStack, buffers, 15728880, OverlayTexture.NO_OVERLAY, ModelData.EMPTY, null);
});
}
}
@Override
public void getTooltip(ITooltipBuilder tooltip, CrookJeiRecipe recipe, IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) {
public List<Component> getTooltipStrings(CrookJeiRecipe recipe, IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) {
if (12 < mouseX && mouseX < 44 && 10 < mouseY && mouseY < 42) {
var block = this.timer.getCycledItem(recipe.states).getBlock();
var modId = BuiltInRegistries.BLOCK.getKey(block).getNamespace();
var tooltip = new ArrayList<Component>();
tooltip.add(Component.translatable(block.getDescriptionId()));
if (recipe instanceof CrookJeiRecipe.StatesRecipe statesRecipe && !statesRecipe.requirements.isEmpty()) {
tooltip.add(REQUIRES_CERTAIN_STATE);
@ -123,7 +144,10 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
tooltip.add(Component.literal("#" + tagRecipe.tag.location()).withStyle(ChatFormatting.GRAY));
}
tooltip.add(Component.literal(this.modIdHelper.getFormattedModNameForModId(modId)));
return tooltip;
}
return List.of();
}
@Override

View File

@ -19,8 +19,11 @@
package thedarkcolour.exdeorum.compat.jei;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonObject;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.recipe.RecipeIngredientRole;
import net.minecraft.ChatFormatting;
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.tags.TagKey;
@ -30,8 +33,8 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.compat.XeiUtil;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.CodecUtil;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import java.util.ArrayList;
@ -98,7 +101,16 @@ public sealed abstract class CrookJeiRecipe {
this.itemIngredients = itemIngredients.build();
this.requirements = XeiUtil.getStateRequirements(predicate);
ImmutableList.Builder<Component> requirements = ImmutableList.builder();
if (predicate != null) {
var json = CodecUtil.encode(StatePropertiesPredicate.CODEC, predicate.properties());
if (json instanceof JsonObject obj) {
for (var entry : obj.entrySet()) {
requirements.add(Component.literal(" " + entry.getKey() + "=" + entry.getValue().toString()).withStyle(ChatFormatting.GRAY));
}
}
}
this.requirements = requirements.build();
}
@Override
@ -122,7 +134,7 @@ public sealed abstract class CrookJeiRecipe {
private final ItemStack itemIngredient;
BlockRecipe(Block block, ItemStack result, float chance) {
super(ImmutableList.of(block.defaultBlockState()), result, chance);
super(List.of(block.defaultBlockState()), result, chance);
var item = block.asItem();
if (item == Items.AIR) {

View File

@ -33,11 +33,11 @@ import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.api.runtime.IIngredientManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
@ -103,7 +103,10 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceR
graphics.drawString(font, volumeLabel, 60 - font.width(volumeLabel) / 2, 5, 0xff808080, false);
ClientXeiUtil.renderBlock(graphics, recipe.blockState(), 60, 24, 10, 20F);
ClientJeiUtil.renderBlock(graphics, recipe.blockState(), 60, 24, 10, 20F, (block, poseStack, buffers) -> {
//noinspection deprecation
Minecraft.getInstance().getBlockRenderer().renderSingleBlock(block, poseStack, buffers, 15728880, OverlayTexture.NO_OVERLAY);
});
}
@Override

View File

@ -44,7 +44,7 @@ public class CycleTimer {
public void onDraw() {
if (!Screen.hasShiftDown()) {
if (this.pausedDuration > 0) {
if (pausedDuration > 0) {
this.startTime += this.pausedDuration;
this.pausedDuration = 0;
}

View File

@ -46,12 +46,11 @@ import net.neoforged.fml.ModList;
import net.neoforged.neoforge.fluids.FluidStack;
import net.neoforged.neoforge.registries.DeferredHolder;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.client.ClientsideCode;
import thedarkcolour.exdeorum.client.screen.MechanicalHammerScreen;
import thedarkcolour.exdeorum.client.screen.MechanicalSieveScreen;
import thedarkcolour.exdeorum.compat.CompatUtil;
import thedarkcolour.exdeorum.compat.GroupedSieveRecipe;
import thedarkcolour.exdeorum.compat.ModIds;
import thedarkcolour.exdeorum.compat.XeiSieveRecipe;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.item.WateringCanItem;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
@ -82,8 +81,8 @@ public class ExDeorumJeiPlugin implements IModPlugin {
static final RecipeType<CrucibleRecipe> LAVA_CRUCIBLE = recipeType("lava_crucible", CrucibleRecipe.class);
static final RecipeType<CrucibleRecipe> WATER_CRUCIBLE = recipeType("water_crucible", CrucibleRecipe.class);
static final RecipeType<CrucibleHeatSourceRecipe> CRUCIBLE_HEAT_SOURCES = recipeType("crucible_heat_sources", CrucibleHeatSourceRecipe.class);
static final RecipeType<XeiSieveRecipe> SIEVE = recipeType("sieve", XeiSieveRecipe.class);
static final RecipeType<XeiSieveRecipe> COMPRESSED_SIEVE = recipeType("compressed_sieve", XeiSieveRecipe.class);
static final RecipeType<GroupedSieveRecipe> SIEVE = recipeType("sieve", GroupedSieveRecipe.class);
static final RecipeType<GroupedSieveRecipe> COMPRESSED_SIEVE = recipeType("compressed_sieve", GroupedSieveRecipe.class);
static final RecipeType<HammerRecipe> HAMMER = recipeType("hammer", HammerRecipe.class);
static final RecipeType<HammerRecipe> COMPRESSED_HAMMER = recipeType("compressed_hammer", CompressedHammerRecipe.class);
static final RecipeType<CrookJeiRecipe> CROOK = recipeType("crook", CrookJeiRecipe.class);
@ -199,8 +198,7 @@ public class ExDeorumJeiPlugin implements IModPlugin {
if (RecipeUtil.isTagEmpty(EItemTags.ORES_ZINC)) toRemove.add(new ItemStack(EItems.ZINC_ORE_CHUNK.get()));
if (RecipeUtil.isTagEmpty(EItemTags.ORES_IRIDIUM)) toRemove.add(new ItemStack(EItems.IRIDIUM_ORE_CHUNK.get()));
if (RecipeUtil.isTagEmpty(EItemTags.ORES_THORIUM)) toRemove.add(new ItemStack(EItems.THORIUM_ORE_CHUNK.get()));
if (RecipeUtil.isTagEmpty(EItemTags.ORES_MAGNESIUM))
toRemove.add(new ItemStack(EItems.MAGNESIUM_ORE_CHUNK.get()));
if (RecipeUtil.isTagEmpty(EItemTags.ORES_MAGNESIUM)) toRemove.add(new ItemStack(EItems.MAGNESIUM_ORE_CHUNK.get()));
if (RecipeUtil.isTagEmpty(EItemTags.ORES_LITHIUM)) toRemove.add(new ItemStack(EItems.LITHIUM_ORE_CHUNK.get()));
if (RecipeUtil.isTagEmpty(EItemTags.ORES_BORON)) toRemove.add(new ItemStack(EItems.BORON_ORE_CHUNK.get()));
@ -216,16 +214,16 @@ public class ExDeorumJeiPlugin implements IModPlugin {
addRecipes(registration, HAMMER, ERecipeTypes.HAMMER);
//noinspection rawtypes,unchecked
addRecipes(registration, COMPRESSED_HAMMER, ((DeferredHolder) ERecipeTypes.COMPRESSED_HAMMER));
registration.addRecipes(CROOK, CompatUtil.collectAllRecipes(RecipeUtil.getClientRecipeManager(), ERecipeTypes.CROOK.get(), CrookJeiRecipe::create));
registration.addRecipes(SIEVE, XeiSieveRecipe.getAllRecipesGrouped(ERecipeTypes.SIEVE.get(), XeiSieveRecipe.SIEVE_ROWS));
registration.addRecipes(COMPRESSED_SIEVE, XeiSieveRecipe.getAllRecipesGrouped(ERecipeTypes.COMPRESSED_SIEVE.get(), XeiSieveRecipe.COMPRESSED_SIEVE_ROWS));
registration.addRecipes(CROOK, CompatUtil.collectAllRecipes(ERecipeTypes.CROOK.get(), CrookJeiRecipe::create));
registration.addRecipes(SIEVE, GroupedSieveRecipe.getAllRecipesGrouped(ERecipeTypes.SIEVE.get()));
registration.addRecipes(COMPRESSED_SIEVE, GroupedSieveRecipe.getAllRecipesGrouped(ERecipeTypes.COMPRESSED_SIEVE.get()));
addCrucibleHeatSources(registration);
}
private static void addCrucibleHeatSources(IRecipeRegistration registration) {
var values = new Object2IntOpenHashMap<Block>();
for (var entry : ClientsideCode.getRecipeCaches().getHeatSources()) {
for (var entry : RecipeUtil.getHeatSources()) {
var state = entry.getKey();
var block = state.getBlock();
@ -301,6 +299,6 @@ public class ExDeorumJeiPlugin implements IModPlugin {
}
private static <C extends RecipeInput, T extends Recipe<C>> void addRecipes(IRecipeRegistration registration, RecipeType<T> category, Supplier<net.minecraft.world.item.crafting.RecipeType<T>> type) {
registration.addRecipes(category, CompatUtil.collectAllRecipes(RecipeUtil.getClientRecipeManager(), type.get(), Function.identity()));
registration.addRecipes(category, CompatUtil.collectAllRecipes(type.get(), Function.identity()));
}
}

View File

@ -18,6 +18,7 @@
package thedarkcolour.exdeorum.compat.jei;
import com.google.common.collect.ImmutableList;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.gui.builder.IRecipeSlotBuilder;
@ -28,38 +29,53 @@ import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.storage.loot.providers.number.BinomialDistributionGenerator;
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
import net.minecraft.world.level.storage.loot.providers.number.NumberProvider;
import org.apache.commons.lang3.mutable.MutableInt;
import thedarkcolour.exdeorum.compat.XeiSieveRecipe;
import thedarkcolour.exdeorum.compat.XeiUtil;
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator;
import net.neoforged.neoforge.common.util.Lazy;
import thedarkcolour.exdeorum.compat.GroupedSieveRecipe;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.loot.SummationGenerator;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
class SieveCategory implements IRecipeCategory<XeiSieveRecipe> {
class SieveCategory implements IRecipeCategory<GroupedSieveRecipe> {
private static final Component BY_HAND_ONLY_LABEL = Component.translatable(TranslationKeys.SIEVE_RECIPE_BY_HAND_ONLY).withStyle(ChatFormatting.RED);
public static final int WIDTH = 162;
public static final int ROW_START = 28;
static {
ClientJeiUtil.FORMATTER.setMinimumFractionDigits(0);
ClientJeiUtil.FORMATTER.setMaximumFractionDigits(3);
}
private final Lazy<IDrawable> background;
private final IDrawable slot;
private final IDrawable row;
private final IDrawable icon;
private final Component title;
private final MutableInt rows;
SieveCategory(IGuiHelper helper, ItemLike icon, Component title, MutableInt rows) {
SieveCategory(IGuiHelper helper, ItemLike icon, Component title) {
this.background = Lazy.of(() -> helper.createBlankDrawable(WIDTH, ROW_START + 18 * GroupedSieveRecipe.maxSieveRows));
this.slot = helper.getSlotDrawable();
this.row = helper.createDrawable(ExDeorumJeiPlugin.EX_DEORUM_JEI_TEXTURE, 0, 0, 162, 18);
this.icon = helper.createDrawableItemStack(new ItemStack(icon));
this.title = title;
this.rows = rows;
}
SieveCategory(IGuiHelper helper) {
this(helper, DefaultMaterials.OAK_SIEVE, Component.translatable(TranslationKeys.SIEVE_CATEGORY_TITLE), XeiSieveRecipe.SIEVE_ROWS);
this(helper, DefaultMaterials.OAK_SIEVE, Component.translatable(TranslationKeys.SIEVE_CATEGORY_TITLE));
}
@Override
public RecipeType<XeiSieveRecipe> getRecipeType() {
public RecipeType<GroupedSieveRecipe> getRecipeType() {
return ExDeorumJeiPlugin.SIEVE;
}
@ -69,13 +85,8 @@ class SieveCategory implements IRecipeCategory<XeiSieveRecipe> {
}
@Override
public int getWidth() {
return XeiUtil.SIEVE_WIDTH;
}
@Override
public int getHeight() {
return XeiUtil.SIEVE_ROW_START + XeiUtil.SIEVE_ROW_HEIGHT * this.rows.intValue();
public IDrawable getBackground() {
return this.background.get();
}
@Override
@ -84,35 +95,111 @@ class SieveCategory implements IRecipeCategory<XeiSieveRecipe> {
}
@Override
public void setRecipe(IRecipeLayoutBuilder builder, XeiSieveRecipe recipe, IFocusGroup focuses) {
public void setRecipe(IRecipeLayoutBuilder builder, GroupedSieveRecipe recipe, IFocusGroup focuses) {
builder.addSlot(RecipeIngredientRole.INPUT, 59, 1).addIngredients(recipe.ingredient());
builder.addSlot(RecipeIngredientRole.CATALYST, 87, 1).addItemStack(recipe.mesh());
for (int i = 0; i < recipe.results().size(); i++) {
var result = recipe.results().get(i);
var slot = builder.addSlot(RecipeIngredientRole.OUTPUT, 1 + (i % 9) * 18, 1 + XeiUtil.SIEVE_ROW_START + 18 * (i / 9)).addItemStack(result.item);
var slot = builder.addSlot(RecipeIngredientRole.OUTPUT, 1 + (i % 9) * 18, 1 + ROW_START + 18 * (i / 9)).addItemStack(result.item);
addTooltips(slot, result.byHandOnly, result.provider);
}
}
public static void addTooltips(IRecipeSlotBuilder slot, boolean byHandOnly, NumberProvider provider) {
var tooltipLines = new ImmutableList.Builder<Component>();
if (byHandOnly) {
tooltipLines.add(BY_HAND_ONLY_LABEL);
slot.setCustomRenderer(VanillaTypes.ITEM_STACK, ClientJeiUtil.AsteriskItemRenderer.INSTANCE);
}
slot.addRichTooltipCallback((slotView, tooltip) -> {
XeiUtil.addSieveDropTooltip(byHandOnly, provider, tooltip::add);
if (provider instanceof BinomialDistributionGenerator binomial) {
if (binomial.n() instanceof ConstantValue constant && constant.value() == 1) {
var chanceLabel = ClientJeiUtil.formatChance(RecipeUtil.getExpectedValue(binomial.p()));
tooltipLines.add(chanceLabel);
} else {
addAvgOutput(tooltipLines, RecipeUtil.getExpectedValue(provider));
}
addMinMaxes(tooltipLines, 0, getMax(binomial.n()));
} else if (provider.getClass() != ConstantValue.class) {
var val = RecipeUtil.getExpectedValue(provider);
if (val != -1.0) {
addAvgOutput(tooltipLines, val);
if (provider instanceof UniformGenerator || provider instanceof SummationGenerator) {
addMinMaxes(tooltipLines, getMin(provider), getMax(provider));
}
}
}
var tooltipLinesList = tooltipLines.build();
slot.addTooltipCallback((slotView, tooltip) -> {
tooltip.addAll(tooltipLinesList);
});
}
private static double getMin(NumberProvider provider) {
if (provider instanceof ConstantValue value) {
return value.value();
} else if (provider instanceof UniformGenerator uniform) {
return getMin(uniform.min());
} else if (provider instanceof BinomialDistributionGenerator) {
return 0;
} else if (provider instanceof SummationGenerator summation) {
double sum = 0;
for (var child : summation.providers()) {
sum += getMin(child);
}
return sum;
}
return 0;
}
private static double getMax(NumberProvider provider) {
if (provider instanceof ConstantValue value) {
return value.value();
} else if (provider instanceof UniformGenerator uniform) {
return getMax(uniform.max());
} else if (provider instanceof BinomialDistributionGenerator binomial) {
return getMax(binomial.n());
} else if (provider instanceof SummationGenerator summation) {
double sum = 0;
for (var child : summation.providers()) {
sum += getMax(child);
}
return sum;
}
return 0;
}
private static void addAvgOutput(ImmutableList.Builder<Component> tooltipLines, double avgValue) {
String avgOutput = ClientJeiUtil.FORMATTER.format(avgValue);
tooltipLines.add(Component.translatable(TranslationKeys.SIEVE_RECIPE_AVERAGE_OUTPUT, avgOutput).withStyle(ChatFormatting.GRAY));
}
// when the player holds shift, they can see the min/max amounts of a drop
private static void addMinMaxes(ImmutableList.Builder<Component> tooltipLines, double min, double max) {
String minFormatted = ClientJeiUtil.FORMATTER.format(min);
String maxFormatted = ClientJeiUtil.FORMATTER.format(max);
tooltipLines.add(Component.translatable(TranslationKeys.SIEVE_RECIPE_MIN_OUTPUT, minFormatted).withStyle(ChatFormatting.GRAY));
tooltipLines.add(Component.translatable(TranslationKeys.SIEVE_RECIPE_MAX_OUTPUT, maxFormatted).withStyle(ChatFormatting.GRAY));
}
@Override
public void draw(XeiSieveRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
public void draw(GroupedSieveRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
this.slot.draw(graphics, 58, 0);
this.slot.draw(graphics, 86, 0);
int rows = this.rows.intValue();
for (int i = 0; i < rows; i++) {
for (int i = 0; i < GroupedSieveRecipe.maxSieveRows; i++) {
this.row.draw(graphics, 0, 28 + i * 18);
}
}

View File

@ -1,6 +1,6 @@
/*
* Ex Deorum
* Copyright (c) 2025 thedarkcolour
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -20,7 +20,7 @@ package thedarkcolour.exdeorum.compat.kubejs;
import com.google.gson.JsonObject;
import com.mojang.serialization.JsonOps;
import dev.latvian.mods.kubejs.plugin.builtin.event.ServerEvents;
import dev.latvian.mods.kubejs.bindings.event.ServerEvents;
import dev.latvian.mods.kubejs.recipe.RecipesKubeEvent;
import dev.latvian.mods.kubejs.recipe.filter.RecipeFilterParseEvent;
import dev.latvian.mods.kubejs.recipe.match.ReplacementMatchInfo;
@ -81,10 +81,7 @@ class ExDeorumKubeJsBindings {
@HideFromJS
private static void removeDefaultRecipes(RecipesKubeEvent event, DeferredHolder<? extends RecipeType<?>, ? extends RecipeType<?>> recipeType) {
event.remove(null, (ctx) -> {
var r = ctx.recipe();
return r.kjs$getType().equals(recipeType.getId()) && r.kjs$getOrCreateId().getNamespace().equals(ExDeorum.ID);
});
event.remove(null, (ctx, r) -> r.kjs$getType().equals(recipeType.getId()) && r.kjs$getOrCreateId().getNamespace().equals(ExDeorum.ID));
}
@HideFromJS

View File

@ -1,6 +1,6 @@
/*
* Ex Deorum
* Copyright (c) 2025 thedarkcolour
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -18,17 +18,17 @@
package thedarkcolour.exdeorum.compat.kubejs;
import dev.latvian.mods.kubejs.core.RecipeLikeKJS;
import dev.latvian.mods.kubejs.recipe.KubeRecipe;
import dev.latvian.mods.kubejs.recipe.filter.RecipeFilter;
import dev.latvian.mods.kubejs.recipe.filter.RecipeMatchContext;
import dev.latvian.mods.kubejs.recipe.match.ItemMatch;
import dev.latvian.mods.kubejs.recipe.match.ReplacementMatchInfo;
import dev.latvian.mods.rhino.Context;
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
public record SieveMeshFilter(ReplacementMatchInfo info) implements RecipeFilter {
@Override
public boolean test(RecipeMatchContext ctx) {
var r = ctx.recipe();
return r instanceof KubeRecipe recipeJs && recipeJs.getOriginalRecipe() instanceof SieveRecipe sieveRecipe && this.info.match() instanceof ItemMatch match && match.matches(ctx, sieveRecipe.mesh, false);
public boolean test(Context cx, RecipeLikeKJS r) {
return r instanceof KubeRecipe recipeJs && recipeJs.getOriginalRecipe() instanceof SieveRecipe sieveRecipe && this.info.match() instanceof ItemMatch match && match.matches(cx, sieveRecipe.mesh, false);
}
}

View File

@ -0,0 +1,53 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.rei;
import me.shedaniel.rei.api.client.entry.filtering.base.BasicFilteringRule;
import me.shedaniel.rei.api.client.plugins.REIClientPlugin;
import me.shedaniel.rei.api.common.entry.EntryIngredient;
import me.shedaniel.rei.api.common.entry.EntryStack;
import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
import me.shedaniel.rei.forge.REIPluginClient;
import net.minecraft.world.item.ItemStack;
import thedarkcolour.exdeorum.compat.CompatUtil;
@SuppressWarnings("UnstableApiUsage")
@REIPluginClient
public class ExDeorumReiPlugin implements REIClientPlugin {
@Override
public void registerBasicEntryFiltering(BasicFilteringRule<?> rule) {
rule.hide(() -> {
var builder = EntryIngredient.builder();
for (var barrel : CompatUtil.getAvailableBarrels(false)) {
builder.add(EntryStack.of(VanillaEntryTypes.ITEM, new ItemStack(barrel)));
}
for (var sieve : CompatUtil.getAvailableSieves(false, false)) {
builder.add(EntryStack.of(VanillaEntryTypes.ITEM, new ItemStack(sieve)));
}
for (var crucible : CompatUtil.getAvailableLavaCrucibles(false)) {
builder.add(EntryStack.of(VanillaEntryTypes.ITEM, new ItemStack(crucible)));
}
for (var crucible : CompatUtil.getAvailableWaterCrucibles(false)) {
builder.add(EntryStack.of(VanillaEntryTypes.ITEM, new ItemStack(crucible)));
}
return builder.build();
});
}
}

View File

@ -0,0 +1,21 @@
/*
* Ex Deorum
* Copyright (c) 2024 thedarkcolour
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@net.minecraft.MethodsReturnNonnullByDefault
@javax.annotation.ParametersAreNonnullByDefault
package thedarkcolour.exdeorum.compat.rei;

View File

@ -108,18 +108,6 @@ class English {
english.add(TranslationKeys.SIEVE_RECIPE_MAX_OUTPUT, "Max: %s");
english.add(TranslationKeys.SIEVE_RECIPE_BY_HAND_ONLY, "Does not drop from Mechanical Sieve");
english.add(TranslationKeys.EMI_BARREL_COMPOST_CATEGORY_TITLE, "Barrel Compost");
english.add(TranslationKeys.EMI_BARREL_MIXING_CATEGORY_TITLE, "Barrel Mixing");
english.add(TranslationKeys.EMI_BARREL_FLUID_MIXING_CATEGORY_TITLE, "Barrel Fluid Mixing");
english.add(TranslationKeys.EMI_LAVA_CRUCIBLE_CATEGORY_TITLE, "Lava Crucible");
english.add(TranslationKeys.EMI_WATER_CRUCIBLE_CATEGORY_TITLE, "Water Crucible");
english.add(TranslationKeys.EMI_CRUCIBLE_HEAT_SOURCES_CATEGORY_TITLE, "Crucible Heat Source");
english.add(TranslationKeys.EMI_SIEVE_CATEGORY_TITLE, "Sieve");
english.add(TranslationKeys.EMI_COMPRESSED_SIEVE_CATEGORY_TITLE, "Compressed Sieve");
english.add(TranslationKeys.EMI_HAMMER_CATEGORY_TITLE, "Hammer");
english.add(TranslationKeys.EMI_COMPRESSED_HAMMER_CATEGORY_TITLE, "Compressed Hammer");
english.add(TranslationKeys.EMI_CROOK_CATEGORY_TITLE, "Crook");
english.add(TranslationKeys.MECHANICAL_SIEVE_SCREEN_TITLE, "Mechanical Sieve");
english.add(TranslationKeys.REDSTONE_CONTROL_MODES[RedstoneControlWidget.REDSTONE_MODE_IGNORED], "Always");
english.add(TranslationKeys.REDSTONE_CONTROL_MODES[RedstoneControlWidget.REDSTONE_MODE_UNPOWERED], "Unpowered");

View File

@ -62,8 +62,8 @@ public class ModCompatData {
public static final DeferredItem<Item>
GRAINS_OF_INFINITY = item(ModIds.ENDERIO, "grains_of_infinity");
// Bigger reactors
//public static final DeferredItem<Item>
// YELLORIUM_DUST = item(ModIds.BIGGER_REACTORS, "yellorium_dust");
public static final DeferredItem<Item>
YELLORIUM_DUST = item(ModIds.BIGGER_REACTORS, "yellorium_dust");
// Biomes O' Plenty
public static final DeferredBlock<Block>
FIR_PLANKS = block(ModIds.BIOMES_O_PLENTY, "fir_planks"),

View File

@ -99,30 +99,6 @@ class ModTags {
tags.tag(EItemTags.STONE_BARRELS).add(DefaultMaterials.STONE_BARREL.getItem(), DefaultMaterials.CRYSTALLIZED_BARREL.getItem());
tags.tag(EItemTags.BARRELS).addTags(EItemTags.WOODEN_BARRELS, EItemTags.STONE_BARRELS);
// empty by default; pack makers can add items they don't want affected by Fortune-enchanted hammers
tags.tag(EItemTags.HAMMER_FORTUNE_BLACKLIST);
tags.tag(EItemTags.COMPRESSED_HAMMER_FORTUNE_BLACKLIST);
tags.tag(EItemTags.RANDOM_SHERD_DROPS).addTag(ItemTags.DECORATED_POT_SHERDS);
tags.tag(EItemTags.RANDOM_TRIM_DROPS).add(
Items.WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.HOST_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.RAISER_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.COAST_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.DUNE_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.EYE_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.VEX_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.WARD_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.WILD_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.TIDE_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.FLOW_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.BOLT_ARMOR_TRIM_SMITHING_TEMPLATE
);
// Cyclic adds ONE compressed block :)
tags.tag(ECompressedBlocks.COMPRESSED_COBBLESTONE.getTag()).addOptional(ResourceLocation.fromNamespaceAndPath(ModIds.CYCLIC, "compressed_cobblestone"));

View File

@ -19,7 +19,6 @@
package thedarkcolour.exdeorum.data;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.compat.ModIds;
public class TranslationKeys {
// Misc
@ -85,19 +84,6 @@ public class TranslationKeys {
public static final String SIEVE_RECIPE_MAX_OUTPUT = "gui." + ExDeorum.ID + ".category.sieve.max_output";
public static final String SIEVE_RECIPE_BY_HAND_ONLY = "gui." + ExDeorum.ID + ".category.sieve.by_hand_only";
// EMI recipe categories
public static final String EMI_BARREL_COMPOST_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".barrel_compost";
public static final String EMI_BARREL_MIXING_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".barrel_mixing";
public static final String EMI_BARREL_FLUID_MIXING_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".barrel_fluid_mixing";
public static final String EMI_LAVA_CRUCIBLE_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".lava_crucible";
public static final String EMI_WATER_CRUCIBLE_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".water_crucible";
public static final String EMI_CRUCIBLE_HEAT_SOURCES_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".crucible_heat_sources";
public static final String EMI_SIEVE_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".sieve";
public static final String EMI_COMPRESSED_SIEVE_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".compressed_sieve";
public static final String EMI_HAMMER_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".hammer";
public static final String EMI_COMPRESSED_HAMMER_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".compressed_hammer";
public static final String EMI_CROOK_CATEGORY_TITLE = ModIds.EMI + ".category." + ExDeorum.ID + ".crook";
// Screens
public static final String MECHANICAL_SIEVE_SCREEN_TITLE = ExDeorum.ID + ".container.mechanical_sieve";
public static final String[] REDSTONE_CONTROL_MODES = new String[] {

View File

@ -467,6 +467,7 @@ class SieveRecipes {
drops.add(Items.BLAZE_POWDER, chance(0.03f));
drops.addConditional(ModCompatData.GRAINS_OF_INFINITY.get(), chance(0.06f), Recipes.ENDERIO);
drops.addConditional(ModCompatData.YELLORIUM_DUST.get(), chance(0.05f), Recipes.EXTREME_REACTORS);
drops.addConditional(ModCompatData.SKY_STONE_DUST.get(), chance(0.06f), Recipes.AE2);
drops.addConditional(ModCompatData.CERTUS_QUARTZ_DUST.get(), chance(0.06f), Recipes.AE2);
});
@ -478,6 +479,7 @@ class SieveRecipes {
drops.add(Items.BLAZE_POWDER, chance(0.04f));
drops.addConditional(ModCompatData.GRAINS_OF_INFINITY.get(), chance(0.07f), Recipes.ENDERIO);
drops.addConditional(ModCompatData.YELLORIUM_DUST.get(), chance(0.055f), Recipes.EXTREME_REACTORS);
drops.addConditional(ModCompatData.SKY_STONE_DUST.get(), chance(0.07f), Recipes.AE2);
drops.addConditional(ModCompatData.CERTUS_QUARTZ_DUST.get(), chance(0.07f), Recipes.AE2);
});
@ -490,6 +492,7 @@ class SieveRecipes {
drops.add(Items.IRON_NUGGET, chance(0.06f));
drops.addConditional(ModCompatData.GRAINS_OF_INFINITY.get(), chance(0.09f), Recipes.ENDERIO);
drops.addConditional(ModCompatData.YELLORIUM_DUST.get(), chance(0.08f), Recipes.EXTREME_REACTORS);
drops.addConditional(ModCompatData.SKY_STONE_DUST.get(), chance(0.075f), Recipes.AE2);
drops.addConditional(ModCompatData.CERTUS_QUARTZ_DUST.get(), chance(0.075f), Recipes.AE2);
});
@ -503,6 +506,7 @@ class SieveRecipes {
drops.add(Items.RAW_GOLD, chance(0.02f));
drops.addConditional(ModCompatData.GRAINS_OF_INFINITY.get(), chance(0.11f), Recipes.ENDERIO);
drops.addConditional(ModCompatData.YELLORIUM_DUST.get(), chance(0.10f), Recipes.EXTREME_REACTORS);
drops.addConditional(ModCompatData.SKY_STONE_DUST.get(), chance(0.08f), Recipes.AE2);
drops.addConditional(ModCompatData.CERTUS_QUARTZ_DUST.get(), chance(0.08f), Recipes.AE2);
});
@ -515,6 +519,7 @@ class SieveRecipes {
drops.add(Items.GOLD_NUGGET, chance(0.08f));
drops.addConditional(ModCompatData.GRAINS_OF_INFINITY.get(), chance(0.12f), Recipes.ENDERIO);
drops.addConditional(ModCompatData.YELLORIUM_DUST.get(), chance(0.12f), Recipes.EXTREME_REACTORS);
drops.addConditional(ModCompatData.SKY_STONE_DUST.get(), chance(0.10f), Recipes.AE2);
drops.addConditional(ModCompatData.CERTUS_QUARTZ_DUST.get(), chance(0.10f), Recipes.AE2);
});
@ -528,6 +533,7 @@ class SieveRecipes {
drops.add(Items.IRON_NUGGET, chance(0.08f));
drops.addConditional(ModCompatData.GRAINS_OF_INFINITY.get(), chance(0.135f), Recipes.ENDERIO);
drops.addConditional(ModCompatData.YELLORIUM_DUST.get(), chance(0.14f), Recipes.EXTREME_REACTORS);
drops.addConditional(ModCompatData.SKY_STONE_DUST.get(), chance(0.11f), Recipes.AE2);
drops.addConditional(ModCompatData.CERTUS_QUARTZ_DUST.get(), chance(0.11f), Recipes.AE2);
});

View File

@ -16,21 +16,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package thedarkcolour.exdeorum.compat.emi;
package thedarkcolour.exdeorum.event;
import dev.emi.emi.api.recipe.EmiRecipe;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;
abstract class EEmiRecipe implements EmiRecipe {
protected final ResourceLocation id;
EEmiRecipe(ResourceLocation id) {
this.id = id;
}
@Override
public @Nullable ResourceLocation getId() {
return this.id;
// necessary to avoid EventBus loading LocalPlayer through its ASM transformations
class ClientsideCode {
@Nullable
static Player getLocalPlayer() {
return Minecraft.getInstance().player;
}
}

View File

@ -58,7 +58,6 @@ import net.neoforged.neoforge.fluids.FluidInteractionRegistry;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
import thedarkcolour.exdeorum.client.ClientsideCode;
import thedarkcolour.exdeorum.client.CompostColors;
import thedarkcolour.exdeorum.compat.ModIds;
import thedarkcolour.exdeorum.config.EConfig;
@ -67,7 +66,6 @@ import thedarkcolour.exdeorum.item.WateringCanItem;
import thedarkcolour.exdeorum.material.BarrelMaterial;
import thedarkcolour.exdeorum.network.NetworkHandler;
import thedarkcolour.exdeorum.network.VisualUpdateTracker;
import thedarkcolour.exdeorum.recipe.RecipeCaches;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.registry.EBlockEntities;
import thedarkcolour.exdeorum.registry.EFluids;
@ -97,7 +95,7 @@ public final class EventHandler {
}
private static void serverShutdown(ServerStoppingEvent event) {
RecipeUtil.getServerRecipeCaches().unload();
RecipeUtil.unload();
}
private static void handleDebugCommands(ClientChatEvent event) {
@ -211,6 +209,10 @@ public final class EventHandler {
ExDeorum.LOGGER.error("Unable to grant player the Void World advancement. Ex Deorum advancements will not show");
}
}
} else {
if (Minecraft.getInstance().getConnection() != null) {
RecipeUtil.reload(Minecraft.getInstance().getConnection().getRecipeManager());
}
}
}
@ -229,8 +231,7 @@ public final class EventHandler {
var recipes = event.getServerResources().getRecipeManager();
event.addListener((prepBarrier, resourceManager, prepProfiler, reloadProfiler, backgroundExecutor, gameExecutor) -> {
return prepBarrier.wait(Unit.INSTANCE).thenRunAsync(() -> {
// This is called on render thread when joining a singleplayer world, so we skip assertions
RecipeUtil.getServerRecipeCaches(true).reload(recipes);
RecipeUtil.reload(recipes);
}, gameExecutor);
});
}

View File

@ -18,31 +18,29 @@
package thedarkcolour.exdeorum.item;
import com.google.common.collect.Lists;
import net.minecraft.ChatFormatting;
import net.minecraft.Util;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.tags.TagKey;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.registry.EItems;
import java.util.ArrayList;
import java.util.List;
public class RandomResultItem extends Item {
private final TagKey<Item> possibilities;
public RandomResultItem(Properties properties, TagKey<Item> possibilities) {
public abstract class RandomResultItem extends Item {
public RandomResultItem(Properties properties) {
super(properties);
this.possibilities = possibilities;
}
@Override
@ -50,15 +48,12 @@ public class RandomResultItem extends Item {
var stack = player.getItemInHand(hand);
if (!level.isClientSide) {
var possibleResults = new ArrayList<Item>();
for (var holder : BuiltInRegistries.ITEM.getTagOrEmpty(this.possibilities)) {
possibleResults.add(holder.value());
}
var possibilities = getPossibilities();
if (!player.getAbilities().instabuild) {
stack.shrink(1);
}
var newItem = new ItemStack(Util.getRandom(possibleResults, level.random));
var newItem = new ItemStack(Util.getRandom(possibilities, level.random));
player.getInventory().placeItemBackInInventory(newItem);
return InteractionResultHolder.consume(stack.isEmpty() ? player.getItemInHand(hand) : stack);
@ -66,9 +61,50 @@ public class RandomResultItem extends Item {
return InteractionResultHolder.success(stack);
}
@Override
public void appendHoverText(ItemStack pStack, TooltipContext pLevel, List<Component> tooltip, TooltipFlag pIsAdvanced) {
if (this == EItems.RANDOM_ARMOR_TRIM.value()) {
protected abstract List<Item> getPossibilities();
public static class RandomSherd extends RandomResultItem {
public RandomSherd(Properties properties) {
super(properties);
}
@Override
protected List<Item> getPossibilities() {
var list = new ArrayList<Item>();
for (var holder : BuiltInRegistries.ITEM.getTagOrEmpty(ItemTags.DECORATED_POT_SHERDS)) {
list.add(holder.value());
}
return list;
}
}
public static class RandomArmorTrim extends RandomResultItem {
public static final List<Item> POSSIBLE_TRIMS = Lists.newArrayList(
Items.WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.SHAPER_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.HOST_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.RAISER_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.COAST_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.DUNE_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.EYE_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.VEX_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.WARD_ARMOR_TRIM_SMITHING_TEMPLATE,
Items.WILD_ARMOR_TRIM_SMITHING_TEMPLATE
);
public RandomArmorTrim(Properties properties) {
super(properties);
}
@Override
protected List<Item> getPossibilities() {
return POSSIBLE_TRIMS;
}
@Override
public void appendHoverText(ItemStack pStack, TooltipContext pLevel, List<Component> tooltip, TooltipFlag pIsAdvanced) {
tooltip.add(Component.translatable(TranslationKeys.RANDOM_TRIM_DOES_NOT_CONTAIN_UPGRADE).withStyle(ChatFormatting.DARK_GRAY));
}
}

View File

@ -25,7 +25,7 @@ import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import thedarkcolour.exdeorum.block.InfestedLeavesBlock;
import net.minecraft.world.level.block.LeavesBlock;
import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity;
import thedarkcolour.exdeorum.registry.EBlocks;
import thedarkcolour.exdeorum.registry.ESounds;
@ -45,7 +45,9 @@ public class SilkwormItem extends Item {
if (state.is(BlockTags.LEAVES) && state.getBlock() != EBlocks.INFESTED_LEAVES.get()) {
if (!level.isClientSide) {
// Replace with infested block
InfestedLeavesBlock.setBlock(level, pos, state);
level.setBlock(pos, EBlocks.INFESTED_LEAVES.get().defaultBlockState()
.setValue(LeavesBlock.DISTANCE, state.getValue(LeavesBlock.DISTANCE))
.setValue(LeavesBlock.PERSISTENT, state.getValue(LeavesBlock.PERSISTENT)), 2);
level.playSound(null, pos, ESounds.SILK_WORM_INFEST.get(), SoundSource.BLOCKS);

View File

@ -3,20 +3,18 @@ package thedarkcolour.exdeorum.loot;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.neoforged.neoforge.common.loot.IGlobalLootModifier;
import net.neoforged.neoforge.common.loot.LootModifier;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
import thedarkcolour.exdeorum.tag.EItemTags;
public class CompressedHammerLootModifier extends HammerLootModifier {
public static final MapCodec<CompressedHammerLootModifier> CODEC = RecordCodecBuilder.mapCodec(inst -> LootModifier.codecStart(inst).apply(inst, CompressedHammerLootModifier::new));
public CompressedHammerLootModifier(LootItemCondition[] conditionsIn) {
super(conditionsIn, EItemTags.COMPRESSED_HAMMER_FORTUNE_BLACKLIST);
super(conditionsIn);
}
@Override
@ -25,7 +23,7 @@ public class CompressedHammerLootModifier extends HammerLootModifier {
}
@Override
protected @Nullable HammerRecipe getRecipe(Item itemForm, LootContext context) {
return RecipeUtil.getCaches(context.getLevel()).getCompressedHammerRecipe(itemForm);
protected @Nullable HammerRecipe getRecipe(Item itemForm) {
return RecipeUtil.getCompressedHammerRecipe(itemForm);
}
}

View File

@ -34,6 +34,7 @@ import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.neoforged.neoforge.common.loot.IGlobalLootModifier;
import net.neoforged.neoforge.common.loot.LootModifier;
import org.jetbrains.annotations.NotNull;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
@ -47,7 +48,7 @@ public class CrookLootModifier extends LootModifier {
}
@Override
protected ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
protected @NotNull ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
var state = context.getParamOrNull(LootContextParams.BLOCK_STATE);
var stack = context.getParamOrNull(LootContextParams.TOOL);
@ -58,7 +59,7 @@ public class CrookLootModifier extends LootModifier {
var fortune = stack.getEnchantmentLevel(context.getLevel().holderLookup(Registries.ENCHANTMENT).getOrThrow(Enchantments.FORTUNE));
var rolls = Math.max(1, Mth.ceil(fortune / 3f));
for (CrookRecipe recipe : RecipeUtil.getCaches(context.getLevel()).getCrookRecipes(state)) {
for (CrookRecipe recipe : RecipeUtil.getCrookRecipes(state)) {
for (int i = 0; i < rolls; i++) {
if (rand.nextFloat() < recipe.chance()) {
generatedLoot.add(recipe.result().copy());

View File

@ -23,7 +23,6 @@ import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries;
import net.minecraft.tags.TagKey;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -37,62 +36,47 @@ import net.neoforged.neoforge.common.loot.LootModifier;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.RecipeUtil;
import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
import thedarkcolour.exdeorum.tag.EItemTags;
public class HammerLootModifier extends LootModifier {
public static final MapCodec<HammerLootModifier> CODEC = RecordCodecBuilder.mapCodec(inst -> LootModifier.codecStart(inst).apply(inst, HammerLootModifier::new));
private final TagKey<Item> fortuneBlacklistTag;
public HammerLootModifier(LootItemCondition[] conditionsIn) {
super(conditionsIn);
this.fortuneBlacklistTag = EItemTags.HAMMER_FORTUNE_BLACKLIST;
}
protected HammerLootModifier(LootItemCondition[] conditionsIn, TagKey<Item> fortuneBlacklistTag) {
super(conditionsIn);
this.fortuneBlacklistTag = fortuneBlacklistTag;
}
@Override
protected ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
var state = context.getParamOrNull(LootContextParams.BLOCK_STATE);
if (state == null) {
return generatedLoot;
if (state != null) {
var itemForm = state.getBlock().asItem();
if (itemForm != Items.AIR) {
var recipe = getRecipe(itemForm);
if (recipe != null) {
ObjectArrayList<ItemStack> newLoot = new ObjectArrayList<>();
var resultAmount = recipe.resultAmount.getInt(context);
// fortune handling; more likely to boost drops if there are none to begin with
if (context.hasParam(LootContextParams.TOOL)) {
var hammer = context.getParam(LootContextParams.TOOL);
resultAmount += calculateFortuneBonus(context.getLevel().registryAccess(), hammer, context.getRandom(), resultAmount == 0);
}
if (resultAmount > 0) {
newLoot.add(recipe.result.copyWithCount(resultAmount));
}
return newLoot;
}
}
}
var itemForm = state.getBlock().asItem();
if (itemForm == Items.AIR) {
return generatedLoot;
}
var recipe = getRecipe(itemForm, context);
if (recipe == null) {
return generatedLoot;
}
ObjectArrayList<ItemStack> newLoot = new ObjectArrayList<>();
var resultAmount = recipe.resultAmount.getInt(context);
if (!itemForm.builtInRegistryHolder().is(this.fortuneBlacklistTag) && context.hasParam(LootContextParams.TOOL)) {
var hammer = context.getParam(LootContextParams.TOOL);
// fortune handling; more likely to boost drops if there are none to begin with
resultAmount += calculateFortuneBonus(context.getLevel().registryAccess(), hammer, context.getRandom(), resultAmount == 0);
}
if (resultAmount > 0) {
newLoot.add(recipe.result.copyWithCount(resultAmount));
}
return newLoot;
return generatedLoot;
}
@Nullable
protected HammerRecipe getRecipe(Item itemForm, LootContext context) {
return RecipeUtil.getCaches(context.getLevel()).getHammerRecipe(itemForm);
protected HammerRecipe getRecipe(Item itemForm) {
return RecipeUtil.getHammerRecipe(itemForm);
}
@Override

View File

@ -20,7 +20,6 @@ package thedarkcolour.exdeorum.material;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SoundType;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.block.CompressedSieveBlock;
public class CompressedSieveMaterial extends SieveMaterial {
@ -32,18 +31,4 @@ public class CompressedSieveMaterial extends SieveMaterial {
protected Block createBlock() {
return new CompressedSieveBlock(props().noOcclusion());
}
@Nullable
public static CompressedSieveMaterial readFromJson(MaterialParser parser) {
SoundType soundType = parser.getSoundType();
float strength = parser.getStrength();
boolean needsCorrectTool = parser.getOptionalBoolean("needs_correct_tool");
String requiredModId = parser.getRequiredModId();
if (parser.error) {
return null;
} else {
return new CompressedSieveMaterial(soundType, strength, needsCorrectTool, requiredModId);
}
}
}

View File

@ -239,7 +239,7 @@ public class DefaultMaterials {
public static void registerMaterials() {
BARRELS.search(BarrelMaterial::readFromJson);
SIEVES.search(SieveMaterial::readFromJson);
COMPRESSED_SIEVES.search(CompressedSieveMaterial::readFromJson);
// todo compressed sieve JSON
LAVA_CRUCIBLES.search(parser -> AbstractCrucibleMaterial.readFromJson(parser, LavaCrucibleMaterial::new));
WATER_CRUCIBLES.search(parser -> AbstractCrucibleMaterial.readFromJson(parser, WaterCrucibleMaterial::new));
}

View File

@ -70,7 +70,7 @@ public class MechanicalHammerMenu extends AbstractMachineMenu<MechanicalHammerBl
if (!moveItemStackTo(clickedStack, NUM_SLOTS, NUM_SLOTS + PLAYER_SLOTS, false)) {
return ItemStack.EMPTY;
}
} else if (MechanicalHammerBlockEntity.isValidInput(player.level(), clickedStack)) { // attempting to move into input slot
} else if (MechanicalHammerBlockEntity.isValidInput(clickedStack)) { // attempting to move into input slot
if (!moveItemStackTo(clickedStack, 0, 1, false)) {
return ItemStack.EMPTY;
}

View File

@ -63,8 +63,6 @@ public class VisualUpdateTracker {
}
}
}
pendingUpdates.clear();
}
}
}

View File

@ -1,158 +0,0 @@
package thedarkcolour.exdeorum.recipe;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import net.neoforged.neoforge.fluids.FluidStack;
import org.jetbrains.annotations.Nullable;
import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.BarrelMixingRecipe;
import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
import thedarkcolour.exdeorum.recipe.cache.*;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
import thedarkcolour.exdeorum.recipe.crucible.CrucibleRecipe;
import thedarkcolour.exdeorum.recipe.hammer.CompressedHammerRecipe;
import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
import thedarkcolour.exdeorum.recipe.sieve.CompressedSieveRecipe;
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
import thedarkcolour.exdeorum.registry.ERecipeTypes;
import java.util.Collection;
import java.util.List;
public class RecipeCaches {
private SingleIngredientRecipeCache<BarrelCompostRecipe> barrelCompostRecipeCache;
private SingleIngredientRecipeCache<CrucibleRecipe> lavaCrucibleRecipeCache;
private SingleIngredientRecipeCache<CrucibleRecipe> waterCrucibleRecipeCache;
private SingleIngredientRecipeCache<HammerRecipe> hammerRecipeCache;
private SingleIngredientRecipeCache<CompressedHammerRecipe> compressedHammerRecipeCache;
private SieveRecipeCache<SieveRecipe> sieveRecipeCache;
private SieveRecipeCache<CompressedSieveRecipe> compressedSieveRecipeCache;
private BarrelFluidMixingRecipeCache barrelFluidMixingRecipeCache;
private FluidTransformationRecipeCache fluidTransformationRecipeCache;
private CrookRecipeCache crookRecipeCache;
private CrucibleHeatRecipeCache crucibleHeatRecipeCache;
public List<SieveRecipe> getSieveRecipes(Item mesh, ItemStack item) {
return this.sieveRecipeCache.getRecipe(mesh, item);
}
public List<CompressedSieveRecipe> getCompressedSieveRecipes(Item mesh, ItemStack item) {
return this.compressedSieveRecipeCache.getRecipe(mesh, item);
}
@Nullable
public CrucibleRecipe getLavaCrucibleRecipe(ItemStack item) {
return this.lavaCrucibleRecipeCache.getRecipe(item);
}
@Nullable
public CrucibleRecipe getWaterCrucibleRecipe(ItemStack item) {
return this.waterCrucibleRecipeCache.getRecipe(item);
}
@Nullable
public BarrelCompostRecipe getBarrelCompostRecipe(ItemStack item) {
return this.barrelCompostRecipeCache.getRecipe(item);
}
@Nullable
public HammerRecipe getHammerRecipe(Item item) {
return this.hammerRecipeCache.getRecipe(item);
}
public Collection<RecipeHolder<HammerRecipe>> getCachedHammerRecipes() {
return this.hammerRecipeCache.getAllRecipes();
}
@Nullable
public CompressedHammerRecipe getCompressedHammerRecipe(Item item) {
return this.compressedHammerRecipeCache.getRecipe(item);
}
public Collection<RecipeHolder<CompressedHammerRecipe>> getCachedCompressedHammerRecipes() {
return this.compressedHammerRecipeCache.getAllRecipes();
}
public List<CrookRecipe> getCrookRecipes(BlockState state) {
return this.crookRecipeCache.getRecipes(state);
}
public boolean isCompostable(ItemStack stack) {
return this.barrelCompostRecipeCache != null && this.barrelCompostRecipeCache.getRecipe(stack) != null;
}
public int getHeatValue(BlockState state) {
return this.crucibleHeatRecipeCache.getValue(state);
}
public ObjectSet<Object2IntMap.Entry<BlockState>> getHeatSources() {
return this.crucibleHeatRecipeCache.getEntries();
}
// todo stop using the RecipeManager
@Nullable
public BarrelMixingRecipe getBarrelMixingRecipe(RecipeManager recipes, ItemStack stack, FluidStack fluid) {
for (var recipe : recipes.byType(ERecipeTypes.BARREL_MIXING.get())) {
if (recipe.value().matches(stack, fluid)) {
return recipe.value();
}
}
return null;
}
@Nullable
public BarrelFluidMixingRecipe getFluidMixingRecipe(FluidStack base, Fluid additive) {
var recipe = this.barrelFluidMixingRecipeCache.getRecipe(base.getFluid(), additive);
if (recipe != null && base.getAmount() >= recipe.baseFluid().amount()) {
return recipe;
} else {
return null;
}
}
@Nullable
public FluidTransformationRecipe getFluidTransformationRecipe(Fluid baseFluid, BlockState catalystState) {
if (baseFluid != Fluids.EMPTY) {
return this.fluidTransformationRecipeCache.getRecipe(baseFluid, catalystState);
} else {
return null;
}
}
public void reload(RecipeManager recipes) {
this.barrelCompostRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.BARREL_COMPOST);
this.lavaCrucibleRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.LAVA_CRUCIBLE);
this.waterCrucibleRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.WATER_CRUCIBLE);
this.hammerRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.HAMMER).trackAllRecipes();
this.compressedHammerRecipeCache = new SingleIngredientRecipeCache<>(recipes, ERecipeTypes.COMPRESSED_HAMMER).trackAllRecipes();
this.sieveRecipeCache = new SieveRecipeCache<>(recipes, ERecipeTypes.SIEVE);
this.compressedSieveRecipeCache = new SieveRecipeCache<>(recipes, ERecipeTypes.COMPRESSED_SIEVE);
this.barrelFluidMixingRecipeCache = new BarrelFluidMixingRecipeCache(recipes);
this.fluidTransformationRecipeCache = new FluidTransformationRecipeCache(recipes);
this.crookRecipeCache = new CrookRecipeCache(recipes);
this.crucibleHeatRecipeCache = new CrucibleHeatRecipeCache(recipes);
}
public void unload() {
this.barrelCompostRecipeCache = null;
this.lavaCrucibleRecipeCache = null;
this.waterCrucibleRecipeCache = null;
this.hammerRecipeCache = null;
this.compressedHammerRecipeCache = null;
this.sieveRecipeCache = null;
this.compressedSieveRecipeCache = null;
this.barrelFluidMixingRecipeCache = null;
this.fluidTransformationRecipeCache = null;
this.crookRecipeCache = null;
this.crucibleHeatRecipeCache = null;
}
}

Some files were not shown because too many files have changed in this diff Show More