Ex Deorum 1.14
This commit is contained in:
parent
0c7913cd12
commit
d06f8ab8ff
21
build.gradle
21
build.gradle
|
|
@ -5,7 +5,7 @@ plugins {
|
|||
id 'org.spongepowered.mixin' version '0.7.+'
|
||||
}
|
||||
|
||||
version = '1.13'
|
||||
version = '1.14'
|
||||
group = 'thedarkcolour.exdeorum'
|
||||
base {
|
||||
archivesName = 'exdeorum'
|
||||
|
|
@ -112,6 +112,10 @@ 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"
|
||||
|
|
@ -135,12 +139,6 @@ repositories {
|
|||
includeModule("maven.modrinth", "embeddium")
|
||||
}
|
||||
}
|
||||
/*maven {
|
||||
url "https://cursemaven.com"
|
||||
content {
|
||||
includeGroup "curse.maven"
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
@ -153,7 +151,10 @@ dependencies {
|
|||
// JEI OPTIONAL
|
||||
compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}"))
|
||||
compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}"))
|
||||
runtimeOnly(fg.deobf("mezz.jei:jei-${mc_version}-forge:${jei_version}"))
|
||||
implementation(fg.deobf("mezz.jei:jei-${mc_version}-forge:${jei_version}"))
|
||||
// REI OPTIONAL
|
||||
compileOnly(fg.deobf("me.shedaniel:RoughlyEnoughItems-forge:${rei_version}"))
|
||||
compileOnly(fg.deobf("me.shedaniel.cloth:cloth-config-forge:${cloth_config_version}"))
|
||||
// KubeJS OPTIONAL
|
||||
implementation fg.deobf("dev.architectury:architectury-forge:${architectury_version}")
|
||||
implementation fg.deobf("dev.latvian.mods:rhino-forge:${rhino_version}")
|
||||
|
|
@ -163,8 +164,8 @@ dependencies {
|
|||
implementation fg.deobf('com.github.thedarkcolour:ModKit:78f393bfac')
|
||||
|
||||
// Oculus + Embeddium OPTIONAL
|
||||
implementation fg.deobf('maven.modrinth:oculus:1.20.1-1.6.9')
|
||||
implementation fg.deobf('maven.modrinth:embeddium:0.2.12+mc1.20.1')
|
||||
compileOnly fg.deobf('maven.modrinth:oculus:1.20.1-1.6.9')
|
||||
compileOnly fg.deobf('maven.modrinth:embeddium:0.2.12+mc1.20.1')
|
||||
|
||||
// testing
|
||||
//implementation fg.deobf("curse.maven:allthecompressed-514045:4938351")
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
## Ex Deorum 1.14
|
||||
- Added Mechanical Sieve, a machine that uses FE to sift blocks automatically. Uses 40 FE a tick by default and takes 100 ticks to sift an item with no efficiency enchantment.
|
||||
- Added `by_hand_only` boolean field to Sieve recipes, which allows modpack makers to add sieve drops that don't drop from the Mechanical Sieve.
|
||||
- Added JEI information telling the player that meshes can be enchanted with Fortune and Efficiency.
|
||||
- Fixed minor rendering bug with infested leaves and Ars Nouveau leaves not rotating properly.
|
||||
- Optimized syncing block entity visual updates from the server to the client.
|
||||
|
||||
## Ex Deorum 1.13
|
||||
- Added new icon for JEI compost recipes to help differentiate from the other categories.
|
||||
- Added `sieve_mesh` property to KubeJS's RecipeFilter, for usage in `RecipesEventJS.remove` to remove sieve recipes using a specific mesh. View the [updated documentation](https://exdeorum.readthedocs.io/en/latest).
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ parchment_mappings=1.20.1-2023.06.26
|
|||
geckolib_version=4.2
|
||||
modonomicon_version=1.36.0
|
||||
jei_version=15.2.0.23
|
||||
rei_version=12.0.684
|
||||
cloth_config_version=11.1.118
|
||||
curios_version=5.2.0-beta.3
|
||||
top_version=10.0.1-3
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2023-11-25T19:04:39.9783304 Loot Tables
|
||||
// 1.20.1 2024-01-10T20:18:25.7260241 Loot Tables
|
||||
105d8a61ea7145d7798146d385d4aad24fd1588d data/exdeorum/loot_tables/blocks/acacia_barrel.json
|
||||
1e77127a82cbba0937bb02694f65cf1893aeffcb data/exdeorum/loot_tables/blocks/acacia_crucible.json
|
||||
fcc00910a8cc94bed6339d6833fcec53c501a0d7 data/exdeorum/loot_tables/blocks/acacia_sieve.json
|
||||
|
|
@ -73,6 +73,7 @@ b38104ee25127d9c65ad9e323ed879f76df7a048 data/exdeorum/loot_tables/blocks/mangro
|
|||
475b89fd8f09834652f80c93d8a6d0964d708ead data/exdeorum/loot_tables/blocks/maple_barrel.json
|
||||
54f36187d7fb97dedc4680d14e2ad7d70b5c64af data/exdeorum/loot_tables/blocks/maple_crucible.json
|
||||
7ffe80360af055f3977d05b5684a299886bcb756 data/exdeorum/loot_tables/blocks/maple_sieve.json
|
||||
a84508222cb36b07cb20ee31915d802bcc411149 data/exdeorum/loot_tables/blocks/mechanical_sieve.json
|
||||
cad973c873a2e50ccfac91e88eadb3c2462d39d1 data/exdeorum/loot_tables/blocks/oak_barrel.json
|
||||
f94bc97efbfd26ccf7dba32d414fb5e33decd5f6 data/exdeorum/loot_tables/blocks/oak_crucible.json
|
||||
8d69a87e09fc8a179d5a1bc8eba5faab66e77a6c data/exdeorum/loot_tables/blocks/oak_sieve.json
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
// 1.20.1 2023-12-31T14:34:20.2470503 ModKit Language: en_us for mod 'exdeorum'
|
||||
9889f8490849977914579142b0e2de1d19ecd6f9 assets/exdeorum/lang/en_us.json
|
||||
// 1.20.1 2024-01-12T17:15:18.0568334 ModKit Language: en_us for mod 'exdeorum'
|
||||
134e71f17cef95d72141a3d6431db5eb8438f3a0 assets/exdeorum/lang/en_us.json
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2024-01-01T15:35:52.3392677 Recipes
|
||||
// 1.20.1 2024-01-11T17:10:41.051025 Recipes
|
||||
e37b64428f17e304e91539ac0513456d7ce40cd1 data/exdeorum/advancements/recipes/building_blocks/sponge.json
|
||||
5ad481a0c376c1a1785a5d3b992064d0ec0bf3b0 data/exdeorum/advancements/recipes/food/end_cake.json
|
||||
25dd027e844a72b03c95dbe5e3c3dd8c738ceb00 data/exdeorum/advancements/recipes/misc/acacia_barrel.json
|
||||
|
|
@ -43,6 +43,7 @@ f3d25fad0818f06ed341008daa157732a41702f0 data/exdeorum/advancements/recipes/misc
|
|||
ef344cd03adefba1ff628f494569cb1e61ff5a5f data/exdeorum/advancements/recipes/misc/mangrove_barrel.json
|
||||
a4325e653eba3a2cd86fa5055414c0b8f391d80d data/exdeorum/advancements/recipes/misc/mangrove_crucible.json
|
||||
47657db106b7291a5fc2ebf281daa03dc7ec71c0 data/exdeorum/advancements/recipes/misc/mangrove_sieve.json
|
||||
3dc9943b92b254be691be3f6f555992e687fe0e1 data/exdeorum/advancements/recipes/misc/mechanical_sieve.json
|
||||
8cde46d6245da58277653bb9877518f099150e3d data/exdeorum/advancements/recipes/misc/moss_block.json
|
||||
a21315f6c45ed3300ae2dd79b1dbdbecce9d1305 data/exdeorum/advancements/recipes/misc/netherite_mesh.json
|
||||
d85bf493287a94e61ee13f713625b3dec0624706 data/exdeorum/advancements/recipes/misc/oak_barrel.json
|
||||
|
|
@ -291,6 +292,7 @@ b012c1b39678d3e560365bc01a59c9a88182388e data/exdeorum/recipes/mahogany_barrel.j
|
|||
e288683a0ad5496b43667307e9a22b35a0482d77 data/exdeorum/recipes/maple_barrel.json
|
||||
c6ab33d03646b9af8b2d624e28b7d21083772dda data/exdeorum/recipes/maple_crucible.json
|
||||
f1b143b0f52102366fd79d608540e67e9909c43f data/exdeorum/recipes/maple_sieve.json
|
||||
0e8f6c50263bda0f9c41da7df9f726f27ff0b374 data/exdeorum/recipes/mechanical_sieve.json
|
||||
962586e6665baef84b573df40211ff3ce36d88b0 data/exdeorum/recipes/moss_block.json
|
||||
f92abca4ddd5f75b770e81fc745a735a7fd0ee68 data/exdeorum/recipes/netherite_hammer.json
|
||||
c7d0c0109b34ee2e325c42b6664d5fe6b8ea5117 data/exdeorum/recipes/netherite_mesh.json
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 1.20.1 2023-12-31T14:34:20.2490508 ModKit Item Models for mod 'exdeorum'
|
||||
// 1.20.1 2024-01-10T20:18:25.7240245 ModKit Item Models for mod 'exdeorum'
|
||||
4ba3bb2c6174ac3728a4b85e34681f118ec8eb34 assets/exdeorum/models/item/acacia_barrel.json
|
||||
c03ce41f7c071498fcbd5f5225e91dcb2f365fbb assets/exdeorum/models/item/acacia_crucible.json
|
||||
3b4f1d45c0d9c4cd1d9a5cdf6ddc8d2c9791bca5 assets/exdeorum/models/item/acacia_sieve.json
|
||||
|
|
@ -105,6 +105,7 @@ ff89dc05408074da0e9d41bfef91dfe975302403 assets/exdeorum/models/item/mahogany_cr
|
|||
c3f2af2a88cd97148b05efbd6e24fc2558fcc0b8 assets/exdeorum/models/item/maple_barrel.json
|
||||
cc045825c562e9133858ce5cfe6e6f1dcb747d8e assets/exdeorum/models/item/maple_crucible.json
|
||||
a64e9b9ce91ac6b2f36690a770afc52b8900a614 assets/exdeorum/models/item/maple_sieve.json
|
||||
1e2b482f5fc4d283f5ca12919b575f86dc4a9541 assets/exdeorum/models/item/mechanical_sieve.json
|
||||
d543d3e18bdcf2bf79a762b52cc61a4161124db1 assets/exdeorum/models/item/mycelium_spores.json
|
||||
1f48b2ce3452ce5d02142c9f663ae7bdb7d1d934 assets/exdeorum/models/item/netherite_hammer.json
|
||||
248ebed818e2e4a5eb7ce78363f56433a3066646 assets/exdeorum/models/item/netherite_mesh.json
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
"block.exdeorum.maple_barrel": "Maple Barrel",
|
||||
"block.exdeorum.maple_crucible": "Maple Crucible",
|
||||
"block.exdeorum.maple_sieve": "Maple Sieve",
|
||||
"block.exdeorum.mechanical_sieve": "Mechanical Sieve",
|
||||
"block.exdeorum.oak_barrel": "Oak Barrel",
|
||||
"block.exdeorum.oak_crucible": "Oak Crucible",
|
||||
"block.exdeorum.oak_sieve": "Oak Sieve",
|
||||
|
|
@ -117,6 +118,7 @@
|
|||
"block.exdeorum.willow_crucible": "Willow Crucible",
|
||||
"block.exdeorum.willow_sieve": "Willow Sieve",
|
||||
"block.exdeorum.witch_water": "Witch Water",
|
||||
"exdeorum.container.mechanical_sieve": "Mechanical Sieve",
|
||||
"fluid_type.exdeorum.witch_water": "Witch Water",
|
||||
"generator.exdeorum.void_world": "Void World",
|
||||
"gui.exdeorum.category.barrel_compost": "Barrel Compost",
|
||||
|
|
@ -129,15 +131,24 @@
|
|||
"gui.exdeorum.category.lava_crucible": "Lava Crucible",
|
||||
"gui.exdeorum.category.sieve": "Sieve",
|
||||
"gui.exdeorum.category.sieve.average_output": "Avg. Output: %s",
|
||||
"gui.exdeorum.category.sieve.by_hand_only": "Does not drop from Mechanical Sieve",
|
||||
"gui.exdeorum.category.sieve.chance": "Chance: %s%%",
|
||||
"gui.exdeorum.category.sieve.max_output": "Max: %s",
|
||||
"gui.exdeorum.category.sieve.min_output": "Min: %s",
|
||||
"gui.exdeorum.category.water_crucible": "Water Crucible",
|
||||
"gui.exdeorum.energy_label": "Energy",
|
||||
"gui.exdeorum.redstone_control.always": "Always",
|
||||
"gui.exdeorum.redstone_control.label": "Redstone Mode",
|
||||
"gui.exdeorum.redstone_control.mode": "Mode: ",
|
||||
"gui.exdeorum.redstone_control.powered": "Powered",
|
||||
"gui.exdeorum.redstone_control.unpowered": "Unpowered",
|
||||
"info.exdeorum.crimson_nylium_spores": "Use on netherrack to turn it into a crimson nylium block.",
|
||||
"info.exdeorum.grass_seeds": "Use on dirt to turn it into a grass block.",
|
||||
"info.exdeorum.mechanical_sieve": "The Mechanical Sieve is a machine that, when supplied with a mesh and Forge Energy (FE), will sift blocks without a player having to do it themselves. It also supports three different modes of redstone control. Since Ex Deorum does not provide a way to generate FE, you will need another mod to provide power.",
|
||||
"info.exdeorum.mycelium_spores": "Use on dirt to turn it into mycelium.",
|
||||
"info.exdeorum.sculk_core": "Use a sculk core on a Sculk Shrieker to enable it to spawn Wardens. Normally, Sculk Shriekers placed by players cannot spawn Wardens, so this item is useful for obtaining Sculk items in a SkyBlock world.",
|
||||
"info.exdeorum.sieve": "Sieves are used to sift for items from soft blocks like gravel and dirt. A mesh is required to use the sieve. Meshes can be enchanted with Fortune and Efficiency. Sieves in a 3x3 area can be used simultaneously.",
|
||||
"info.exdeorum.sieve_mesh": "Meshes are used in sieves. Different meshes yield different drops. Meshes can be enchanted with Fortune and Efficiency to increase likelihood of drops and sifting speed, respectively.",
|
||||
"info.exdeorum.silk_worm": "Silk worms have a 1 in 100 chance to drop from leaves harvested with a Crook. Using a silk worm on a tree's leaves will infest them, gradually spreading through the entire tree. 100% infested leaves can be harvested for string, but do not drop saplings.",
|
||||
"info.exdeorum.warped_nylium_spores": "Use on netherrack to turn it into a warped nylium block.",
|
||||
"info.exdeorum.watering_can": "Watering cans speed up crop growth, tree growth, and grass spreading, among other things. They can be filled with water from barrels and wooden crucibles. Golden and above watering cans do not need to be refilled once full. Diamond watering cans water in a 3x3 area, and Netherite watering cans are usable by machinery.",
|
||||
|
|
@ -174,6 +185,7 @@
|
|||
"item.exdeorum.lead_ore_chunk": "Lead Ore Chunk",
|
||||
"item.exdeorum.lithium_ore_chunk": "Lithium Ore Chunk",
|
||||
"item.exdeorum.magnesium_ore_chunk": "Magnesium Ore Chunk",
|
||||
"item.exdeorum.mechanical_sieve.mesh_label": "Mesh: ",
|
||||
"item.exdeorum.mycelium_spores": "Mycelium Spores",
|
||||
"item.exdeorum.netherite_hammer": "Netherite Hammer",
|
||||
"item.exdeorum.netherite_mesh": "Netherite Mesh",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"parent": "exdeorum:block/mechanical_sieve"
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"parent": "minecraft:recipes/root",
|
||||
"criteria": {
|
||||
"has_item": {
|
||||
"conditions": {
|
||||
"items": [
|
||||
{
|
||||
"items": [
|
||||
"minecraft:hopper"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"trigger": "minecraft:inventory_changed"
|
||||
},
|
||||
"has_the_recipe": {
|
||||
"conditions": {
|
||||
"recipe": "exdeorum:mechanical_sieve"
|
||||
},
|
||||
"trigger": "minecraft:recipe_unlocked"
|
||||
}
|
||||
},
|
||||
"requirements": [
|
||||
[
|
||||
"has_item",
|
||||
"has_the_recipe"
|
||||
]
|
||||
],
|
||||
"rewards": {
|
||||
"recipes": [
|
||||
"exdeorum:mechanical_sieve"
|
||||
]
|
||||
},
|
||||
"sends_telemetry_event": true
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"bonus_rolls": 0.0,
|
||||
"conditions": [
|
||||
{
|
||||
"condition": "minecraft:survives_explosion"
|
||||
}
|
||||
],
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"functions": [
|
||||
{
|
||||
"function": "exdeorum:machine"
|
||||
}
|
||||
],
|
||||
"name": "exdeorum:mechanical_sieve"
|
||||
}
|
||||
],
|
||||
"rolls": 1.0
|
||||
}
|
||||
],
|
||||
"random_sequence": "exdeorum:blocks/mechanical_sieve"
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"category": "misc",
|
||||
"key": {
|
||||
"#": {
|
||||
"item": "minecraft:iron_block"
|
||||
},
|
||||
"G": {
|
||||
"item": "minecraft:glass"
|
||||
},
|
||||
"H": {
|
||||
"item": "minecraft:hopper"
|
||||
},
|
||||
"I": {
|
||||
"item": "minecraft:iron_bars"
|
||||
}
|
||||
},
|
||||
"pattern": [
|
||||
"#G#",
|
||||
"IHI",
|
||||
"I I"
|
||||
],
|
||||
"result": {
|
||||
"item": "exdeorum:mechanical_sieve"
|
||||
},
|
||||
"show_notification": true
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ import thedarkcolour.exdeorum.registry.EFluids;
|
|||
import thedarkcolour.exdeorum.registry.EGlobalLootModifiers;
|
||||
import thedarkcolour.exdeorum.registry.EItems;
|
||||
import thedarkcolour.exdeorum.registry.ELootFunctions;
|
||||
import thedarkcolour.exdeorum.registry.EMenus;
|
||||
import thedarkcolour.exdeorum.registry.ERecipeSerializers;
|
||||
import thedarkcolour.exdeorum.registry.ERecipeTypes;
|
||||
import thedarkcolour.exdeorum.registry.EChunkGenerators;
|
||||
|
|
@ -77,6 +78,7 @@ public class ExDeorum {
|
|||
EGlobalLootModifiers.GLOBAL_LOOT_MODIFIERS.register(modBus);
|
||||
EItems.ITEMS.register(modBus);
|
||||
ELootFunctions.LOOT_FUNCTIONS.register(modBus);
|
||||
EMenus.MENUS.register(modBus);
|
||||
ERecipeSerializers.RECIPE_SERIALIZERS.register(modBus);
|
||||
ERecipeTypes.RECIPE_TYPES.register(modBus);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,9 @@ import net.minecraft.world.phys.shapes.VoxelShape;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.blockentity.BarrelBlockEntity;
|
||||
import thedarkcolour.exdeorum.registry.EBlockEntities;
|
||||
import thedarkcolour.exdeorum.registry.EBlocks;
|
||||
|
||||
public class BarrelBlock extends Block implements EntityBlock {
|
||||
public class BarrelBlock extends EBlock {
|
||||
public static final VoxelShape SHAPE = Shapes.join(
|
||||
box(1, 0, 1, 15, 16, 15),
|
||||
box(2, 1, 2, 14, 16, 14),
|
||||
|
|
@ -47,12 +48,7 @@ public class BarrelBlock extends Block implements EntityBlock {
|
|||
);
|
||||
|
||||
public BarrelBlock(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new BarrelBlockEntity(pos, state);
|
||||
super(properties, EBlockEntities.BARREL);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
@ -66,15 +62,6 @@ public class BarrelBlock extends Block implements EntityBlock {
|
|||
return SHAPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult result) {
|
||||
if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) {
|
||||
return barrel.use(level, pos, player, hand);
|
||||
}
|
||||
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
if (!level.isClientSide) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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.block;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.pathfinder.PathComputationType;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.blockentity.MechanicalSieveBlockEntity;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
import thedarkcolour.exdeorum.registry.EBlockEntities;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MechanicalSieveBlock extends EBlock {
|
||||
private static final VoxelShape SHAPE = Shapes.or(
|
||||
box(0, 8, 0, 16, 16, 16),
|
||||
box(1, 0, 1, 3, 8, 3),
|
||||
box(1, 0, 13, 3, 8, 15),
|
||||
box(13, 0, 1, 15, 8, 3),
|
||||
box(13, 0, 13, 15, 8, 15)
|
||||
);
|
||||
|
||||
public MechanicalSieveBlock(Properties properties) {
|
||||
super(properties, EBlockEntities.MECHANICAL_SIEVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
|
||||
return SHAPE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState pState, BlockEntityType<T> type) {
|
||||
return type == EBlockEntities.MECHANICAL_SIEVE.get() && !level.isClientSide ? (BlockEntityTicker<T>) new MechanicalSieveBlockEntity.ServerTicker() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(ItemStack stack, @Nullable BlockGetter level, List<Component> tooltip, TooltipFlag flag) {
|
||||
var nbt = BlockItem.getBlockEntityData(stack);
|
||||
if (nbt != null) {
|
||||
var inventoryNbt = nbt.getCompound("inventory");
|
||||
var inventory = new ItemStackHandler();
|
||||
inventory.deserializeNBT(inventoryNbt);
|
||||
var mesh = inventory.getStackInSlot(MechanicalSieveBlockEntity.MESH_SLOT);
|
||||
if (!mesh.isEmpty()) {
|
||||
tooltip.add(Component.translatable(TranslationKeys.MECHANICAL_SIEVE_MESH_LABEL).withStyle(ChatFormatting.GRAY).append(Component.translatable(mesh.getDescriptionId())));
|
||||
}
|
||||
var energy = nbt.getInt("energy");
|
||||
tooltip.add(Component.translatable(TranslationKeys.ENERGY).withStyle(ChatFormatting.GRAY).append(Component.translatable(TranslationKeys.FRACTION_DISPLAY, energy, EConfig.SERVER.mechanicalSieveEnergyStorage.get())).append(" FE"));
|
||||
}
|
||||
}
|
||||
|
||||
// Drops the item for creative mode players
|
||||
@Override
|
||||
public void playerWillDestroy(Level level, BlockPos pos, BlockState pState, Player player) {
|
||||
if (!level.isClientSide && player.isCreative() && level.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) {
|
||||
if (level.getBlockEntity(pos) instanceof MechanicalSieveBlockEntity sieve) {
|
||||
if (!sieve.getMesh().isEmpty()) {
|
||||
var stack = new ItemStack(this);
|
||||
BlockItem.setBlockEntityData(stack, EBlockEntities.MECHANICAL_SIEVE.get(), sieve.saveWithoutMetadata());
|
||||
var itemEntity = new ItemEntity(level, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, stack);
|
||||
itemEntity.setDefaultPickUpDelay();
|
||||
level.addFreshEntity(itemEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.playerWillDestroy(level, pos, pState, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||
if (!oldState.is(state.getBlock())) {
|
||||
if (level.getBlockEntity(pos) instanceof MechanicalSieveBlockEntity sieve) {
|
||||
sieve.checkPoweredState(level, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) {
|
||||
if (level.getBlockEntity(pos) instanceof MechanicalSieveBlockEntity sieve) {
|
||||
sieve.checkPoweredState(level, pos);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPathfindable(BlockState state, BlockGetter level, BlockPos pos, PathComputationType type) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,9 @@ package thedarkcolour.exdeorum.blockentity;
|
|||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
|
|
@ -58,6 +60,7 @@ import thedarkcolour.exdeorum.registry.EItems;
|
|||
import java.util.HashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
|
||||
public static final Lazy<HashMap<Item, Block>> MELT_OVERRIDES = Lazy.concurrentOf(() -> {
|
||||
var map = new HashMap<Item, Block>();
|
||||
|
|
@ -70,8 +73,8 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
|
|||
private final AbstractCrucibleBlockEntity.ItemHandler item = new AbstractCrucibleBlockEntity.ItemHandler();
|
||||
private final AbstractCrucibleBlockEntity.FluidHandler tank = new AbstractCrucibleBlockEntity.FluidHandler();
|
||||
// Capabilities
|
||||
private final LazyOptional<IItemHandler> itemHandler = LazyOptional.of(() -> item);
|
||||
private final LazyOptional<IFluidHandler> fluidHandler = LazyOptional.of(() -> tank);
|
||||
private final LazyOptional<IItemHandler> itemHandler = LazyOptional.of(() -> this.item);
|
||||
private final LazyOptional<IFluidHandler> fluidHandler = LazyOptional.of(() -> this.tank);
|
||||
|
||||
@Nullable
|
||||
private Block lastMelted;
|
||||
|
|
@ -87,51 +90,80 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
|
|||
@NotNull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
|
||||
if (!remove) {
|
||||
if (!this.remove) {
|
||||
if (cap == ForgeCapabilities.FLUID_HANDLER) {
|
||||
return fluidHandler.cast();
|
||||
return this.fluidHandler.cast();
|
||||
} else if (cap == ForgeCapabilities.ITEM_HANDLER) {
|
||||
return itemHandler.cast();
|
||||
return this.itemHandler.cast();
|
||||
}
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
this.fluidHandler.invalidate();
|
||||
this.itemHandler.invalidate();
|
||||
}
|
||||
|
||||
// NBT
|
||||
@Override
|
||||
public void saveAdditional(CompoundTag nbt) {
|
||||
super.saveAdditional(nbt);
|
||||
|
||||
nbt.put("Tank", tank.writeToNBT(new CompoundTag()));
|
||||
nbt.putString("LastMelted", ForgeRegistries.BLOCKS.getKey(lastMelted).toString());
|
||||
nbt.putString("Fluid", ForgeRegistries.FLUIDS.getKey(fluid).toString());
|
||||
nbt.putShort("Solids", solids);
|
||||
nbt.put("Tank", this.tank.writeToNBT(new CompoundTag()));
|
||||
nbt.putString("LastMelted", ForgeRegistries.BLOCKS.getKey(this.lastMelted).toString());
|
||||
nbt.putString("Fluid", ForgeRegistries.FLUIDS.getKey(this.fluid).toString());
|
||||
nbt.putShort("Solids", this.solids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
|
||||
tank.readFromNBT(nbt.getCompound("Tank"));
|
||||
lastMelted = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(nbt.getString("LastMelted")));
|
||||
fluid = ForgeRegistries.FLUIDS.getValue(new ResourceLocation(nbt.getString("Fluid")));
|
||||
solids = nbt.getShort("Solids");
|
||||
needsLightUpdate = true;
|
||||
this.tank.readFromNBT(nbt.getCompound("Tank"));
|
||||
this.lastMelted = ForgeRegistries.BLOCKS.getValue(new ResourceLocation(nbt.getString("LastMelted")));
|
||||
this.fluid = ForgeRegistries.FLUIDS.getValue(new ResourceLocation(nbt.getString("Fluid")));
|
||||
this.solids = nbt.getShort("Solids");
|
||||
this.needsLightUpdate = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVisualData(FriendlyByteBuf buffer) {
|
||||
buffer.writeId(BuiltInRegistries.FLUID, this.tank.getFluid().getFluid());
|
||||
buffer.writeVarInt(this.tank.getFluidAmount());
|
||||
buffer.writeId(BuiltInRegistries.BLOCK, this.lastMelted != null ? this.lastMelted : Blocks.AIR);
|
||||
buffer.writeShort(this.solids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVisualData(FriendlyByteBuf buffer) {
|
||||
Fluid fluid = buffer.readById(BuiltInRegistries.FLUID);
|
||||
if (fluid == null) {
|
||||
this.tank.setFluid(FluidStack.EMPTY);
|
||||
buffer.readVarInt();
|
||||
} else {
|
||||
this.tank.setFluid(new FluidStack(fluid, buffer.readVarInt()));
|
||||
}
|
||||
var lastMelted = buffer.readById(BuiltInRegistries.BLOCK);
|
||||
this.lastMelted = lastMelted == Blocks.AIR ? null : lastMelted;
|
||||
this.solids = buffer.readShort();
|
||||
}
|
||||
|
||||
public InteractionResult use(Level level, Player player, InteractionHand hand) {
|
||||
var playerItem = player.getItemInHand(hand);
|
||||
|
||||
if (playerItem.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).isPresent()) {
|
||||
return FluidUtil.interactWithFluidHandler(player, hand, tank) ? InteractionResult.sidedSuccess(level.isClientSide) : InteractionResult.PASS;
|
||||
return FluidUtil.interactWithFluidHandler(player, hand, this.tank) ? InteractionResult.sidedSuccess(level.isClientSide) : InteractionResult.PASS;
|
||||
}
|
||||
|
||||
if (!level.isClientSide) {
|
||||
if (playerItem.getItem() == Items.GLASS_BOTTLE && this.getType() == EBlockEntities.WATER_CRUCIBLE.get() && EConfig.SERVER.allowWaterBottleTransfer.get()) {
|
||||
var fluid = new FluidStack(Fluids.WATER, 250);
|
||||
|
||||
if (tank.drain(fluid, IFluidHandler.FluidAction.SIMULATE).getAmount() == 250) {
|
||||
if (this.tank.drain(fluid, IFluidHandler.FluidAction.SIMULATE).getAmount() == 250) {
|
||||
BarrelBlockEntity.extractWaterBottle(this.tank, level, player, playerItem, fluid);
|
||||
markUpdated();
|
||||
}
|
||||
|
|
@ -165,22 +197,22 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
|
|||
var result = recipe.getResult();
|
||||
var contained = this.tank.getFluid();
|
||||
shrinkAction.accept(item);
|
||||
this.solids = (short) Math.min(solids + result.getAmount(), MAX_SOLIDS);
|
||||
this.solids = (short) Math.min(this.solids + result.getAmount(), MAX_SOLIDS);
|
||||
|
||||
if (contained.isEmpty()) {
|
||||
fluid = result.getFluid();
|
||||
needsLightUpdate = true;
|
||||
this.fluid = result.getFluid();
|
||||
this.needsLightUpdate = true;
|
||||
}
|
||||
|
||||
var melts = MELT_OVERRIDES.get();
|
||||
if (melts.containsKey(meltItem)) {
|
||||
lastMelted = melts.get(meltItem);
|
||||
this.lastMelted = melts.get(meltItem);
|
||||
} else if (meltItem.getClass() == BlockItem.class) {
|
||||
lastMelted = ((BlockItem) meltItem).getBlock();
|
||||
this.lastMelted = ((BlockItem) meltItem).getBlock();
|
||||
} else {
|
||||
// If we already have something else inside just use that instead of switching to default
|
||||
if (lastMelted == null) {
|
||||
lastMelted = getDefaultMeltBlock();
|
||||
if (this.lastMelted == null) {
|
||||
this.lastMelted = getDefaultMeltBlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,9 +226,9 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
|
|||
|
||||
if (recipe != null) {
|
||||
var result = recipe.getResult();
|
||||
var contained = tank.getFluid();
|
||||
var contained = this.tank.getFluid();
|
||||
|
||||
return (result.isFluidEqual(contained) || contained.isEmpty()) && result.getAmount() + solids <= MAX_SOLIDS;
|
||||
return (result.isFluidEqual(contained) || contained.isEmpty()) && result.getAmount() + this.solids <= MAX_SOLIDS;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -207,24 +239,24 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
|
|||
}
|
||||
|
||||
public int getSolids() {
|
||||
return solids;
|
||||
return this.solids;
|
||||
}
|
||||
|
||||
public FluidTank getTank() {
|
||||
return tank;
|
||||
return this.tank;
|
||||
}
|
||||
|
||||
public abstract Block getDefaultMeltBlock();
|
||||
|
||||
@Nullable
|
||||
public Block getLastMelted() {
|
||||
return lastMelted;
|
||||
return this.lastMelted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
itemHandler.invalidate();
|
||||
fluidHandler.invalidate();
|
||||
this.itemHandler.invalidate();
|
||||
this.fluidHandler.invalidate();
|
||||
super.setRemoved();
|
||||
}
|
||||
|
||||
|
|
@ -288,7 +320,7 @@ public abstract class AbstractCrucibleBlockEntity extends EBlockEntity {
|
|||
}
|
||||
|
||||
public ItemStack getItem() {
|
||||
return stacks.get(0);
|
||||
return this.stacks.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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.blockentity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import thedarkcolour.exdeorum.blockentity.logic.SieveLogic;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class AbstractSieveBlockEntity extends EBlockEntity implements SieveLogic.Owner {
|
||||
protected final SieveLogic logic;
|
||||
|
||||
public AbstractSieveBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state, Function<SieveLogic.Owner, SieveLogic> logic) {
|
||||
super(type, pos, state);
|
||||
|
||||
this.logic = logic.apply(this);
|
||||
}
|
||||
|
||||
public static ItemStack singleCopy(ItemStack stack) {
|
||||
var copy = stack.copy();
|
||||
copy.setCount(1);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLevel getServerLevel() {
|
||||
return (ServerLevel) this.level;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag nbt) {
|
||||
super.saveAdditional(nbt);
|
||||
|
||||
this.logic.saveNbt(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
|
||||
this.logic.loadNbt(nbt);
|
||||
}
|
||||
|
||||
// Used for rendering and for TOP
|
||||
public ItemStack getMesh() {
|
||||
return this.logic.getMesh();
|
||||
}
|
||||
|
||||
// Used for rendering
|
||||
public float getProgress() {
|
||||
return this.logic.getProgress();
|
||||
}
|
||||
|
||||
// Used for rendering
|
||||
public ItemStack getContents() {
|
||||
return this.logic.getContents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVisualData(FriendlyByteBuf buffer) {
|
||||
buffer.writeItem(this.logic.getMesh());
|
||||
buffer.writeFloat(this.logic.getProgress());
|
||||
buffer.writeItem(this.logic.getContents());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVisualData(FriendlyByteBuf buffer) {
|
||||
this.logic.setMesh(buffer.readItem(), false);
|
||||
this.logic.setProgress(buffer.readFloat());
|
||||
this.logic.setContents(buffer.readItem());
|
||||
}
|
||||
}
|
||||
|
|
@ -96,6 +96,13 @@ public class BarrelBlockEntity extends EBlockEntity {
|
|||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
this.fluidHandler.invalidate();
|
||||
this.itemHandler.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAdditional(CompoundTag nbt) {
|
||||
super.saveAdditional(nbt);
|
||||
|
|
@ -175,10 +182,11 @@ public class BarrelBlockEntity extends EBlockEntity {
|
|||
return this.tank;
|
||||
}
|
||||
|
||||
public InteractionResult use(Level level, BlockPos pos, Player player, InteractionHand hand) {
|
||||
@Override
|
||||
public InteractionResult use(Level level, Player player, InteractionHand hand) {
|
||||
// Collect an item
|
||||
if (!getItem().isEmpty()) {
|
||||
return giveResultItem(level, pos);
|
||||
return giveResultItem(level);
|
||||
}
|
||||
|
||||
// Handle item fluid interaction first
|
||||
|
|
@ -249,7 +257,7 @@ public class BarrelBlockEntity extends EBlockEntity {
|
|||
|
||||
if (!player.getAbilities().instabuild) {
|
||||
player.setItemInHand(hand, handItem);
|
||||
giveResultItem(level, pos);
|
||||
giveResultItem(level);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -270,9 +278,9 @@ public class BarrelBlockEntity extends EBlockEntity {
|
|||
}
|
||||
|
||||
// Pops the item out of the barrel (ex. dirt that has finished composting)
|
||||
private InteractionResult giveResultItem(Level level, BlockPos pos) {
|
||||
private InteractionResult giveResultItem(Level level) {
|
||||
if (!level.isClientSide) {
|
||||
popOutItem(level, pos, item.extract(false));
|
||||
popOutItem(level, this.worldPosition, item.extract(false));
|
||||
|
||||
// Empty contents
|
||||
setItem(ItemStack.EMPTY);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package thedarkcolour.exdeorum.blockentity;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
|
|
@ -29,6 +30,7 @@ import net.minecraft.world.level.Level;
|
|||
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 javax.annotation.Nullable;
|
||||
|
||||
|
|
@ -50,6 +52,7 @@ public abstract class EBlockEntity extends BlockEntity {
|
|||
|
||||
@Override
|
||||
public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
|
||||
// todo consider removing the load with an empty tag
|
||||
if (pkt.getTag() == null) {
|
||||
load(new CompoundTag());
|
||||
} else {
|
||||
|
|
@ -57,12 +60,20 @@ public abstract class EBlockEntity extends BlockEntity {
|
|||
}
|
||||
}
|
||||
|
||||
protected void markUpdated() {
|
||||
public void markUpdated() {
|
||||
setChanged();
|
||||
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 2);
|
||||
VisualUpdateTracker.sendVisualUpdate(this);
|
||||
}
|
||||
|
||||
public InteractionResult use(Level level, Player player, InteractionHand hand) {
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
public void writeVisualData(FriendlyByteBuf buffer) {
|
||||
|
||||
}
|
||||
|
||||
public void readVisualData(FriendlyByteBuf buffer) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import net.minecraft.core.registries.BuiltInRegistries;
|
|||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
|
|
@ -54,25 +55,35 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
|
|||
super(EBlockEntities.INFESTED_LEAVES.get(), pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeVisualData(FriendlyByteBuf buffer) {
|
||||
buffer.writeFloat(this.progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readVisualData(FriendlyByteBuf buffer) {
|
||||
buffer.readFloat();
|
||||
}
|
||||
|
||||
// Attempt to convert a leaf block within 1 block radius around this block
|
||||
private void trySpread() {
|
||||
// Get random offset
|
||||
int x = level.random.nextInt(3) - 1;
|
||||
int y = level.random.nextInt(3) - 1;
|
||||
int z = level.random.nextInt(3) - 1;
|
||||
int x = this.level.random.nextInt(3) - 1;
|
||||
int y = this.level.random.nextInt(3) - 1;
|
||||
int z = this.level.random.nextInt(3) - 1;
|
||||
|
||||
// Get the block in the world
|
||||
BlockPos targetPos = getBlockPos().offset(x, y, z);
|
||||
BlockState state = level.getBlockState(targetPos);
|
||||
BlockState state = this.level.getBlockState(targetPos);
|
||||
|
||||
// DO NOT SPREAD TO ALREADY INFESTED LEAVES
|
||||
if (state.is(BlockTags.LEAVES) && state.getBlock() != EBlocks.INFESTED_LEAVES.get()) {
|
||||
// Spread and keep distance/persistent properties
|
||||
level.setBlock(targetPos, EBlocks.INFESTED_LEAVES.get().defaultBlockState()
|
||||
this.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);
|
||||
var te = this.level.getBlockEntity(targetPos);
|
||||
|
||||
// Set mimic state of other block
|
||||
if (te instanceof InfestedLeavesBlockEntity leaves) {
|
||||
|
|
@ -89,27 +100,27 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
|
|||
// From PistonMovingBlockEntity
|
||||
@SuppressWarnings("deprecation")
|
||||
var holderLookup = this.level != null ? this.level.holderLookup(Registries.BLOCK) : BuiltInRegistries.BLOCK.asLookup();
|
||||
mimic = NbtUtils.readBlockState(holderLookup, nbt.getCompound("mimic"));
|
||||
progress = nbt.getFloat("progress");
|
||||
this.mimic = NbtUtils.readBlockState(holderLookup, nbt.getCompound("mimic"));
|
||||
this.progress = nbt.getFloat("progress");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAdditional(CompoundTag nbt) {
|
||||
super.saveAdditional(nbt);
|
||||
|
||||
if (mimic == null || mimic.getBlock() == EBlocks.INFESTED_LEAVES.get()) {
|
||||
mimic = Blocks.OAK_LEAVES.defaultBlockState();
|
||||
if (this.mimic == null || this.mimic.getBlock() == EBlocks.INFESTED_LEAVES.get()) {
|
||||
this.mimic = Blocks.OAK_LEAVES.defaultBlockState();
|
||||
}
|
||||
nbt.put("mimic", NbtUtils.writeBlockState(mimic));
|
||||
nbt.putFloat("progress", progress);
|
||||
nbt.put("mimic", NbtUtils.writeBlockState(this.mimic));
|
||||
nbt.putFloat("progress", this.progress);
|
||||
}
|
||||
|
||||
public float getProgress() {
|
||||
return progress;
|
||||
return this.progress;
|
||||
}
|
||||
|
||||
public BlockState getMimic() {
|
||||
return mimic;
|
||||
return this.mimic;
|
||||
}
|
||||
|
||||
public void setMimic(BlockState mimic) {
|
||||
|
|
@ -118,7 +129,7 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
|
|||
|
||||
@Override
|
||||
public @NotNull ModelData getModelData() {
|
||||
return ModelData.builder().with(MIMIC_PROPERTY, mimic).build();
|
||||
return ModelData.builder().with(MIMIC_PROPERTY, this.mimic).build();
|
||||
}
|
||||
|
||||
public static class Ticker implements BlockEntityTicker<InfestedLeavesBlockEntity> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* 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.blockentity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
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.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.energy.EnergyStorage;
|
||||
import net.minecraftforge.items.ItemHandlerHelper;
|
||||
import net.minecraftforge.network.NetworkHooks;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.blockentity.helper.EnergyHelper;
|
||||
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
|
||||
import thedarkcolour.exdeorum.blockentity.logic.SieveLogic;
|
||||
import thedarkcolour.exdeorum.client.screen.RedstoneControlWidget;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
import thedarkcolour.exdeorum.menu.MechanicalSieveMenu;
|
||||
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
||||
import thedarkcolour.exdeorum.registry.EBlockEntities;
|
||||
import thedarkcolour.exdeorum.tag.EItemTags;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class MechanicalSieveBlockEntity extends AbstractSieveBlockEntity implements MenuProvider {
|
||||
private static final Component TITLE = Component.translatable(TranslationKeys.MECHANICAL_SIEVE_SCREEN_TITLE);
|
||||
private static final int INPUT_SLOT = 0;
|
||||
public static final int MESH_SLOT = 1;
|
||||
|
||||
public final ItemHelper inventory;
|
||||
public final EnergyHelper energy;
|
||||
private int redstoneMode;
|
||||
// not saved to NBT
|
||||
public boolean hasRedstonePower;
|
||||
|
||||
private final LazyOptional<ItemHelper> capabilityInventory;
|
||||
private final LazyOptional<EnergyStorage> capabilityEnergy;
|
||||
|
||||
public MechanicalSieveBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(EBlockEntities.MECHANICAL_SIEVE.get(), pos, state, owner -> new SieveLogic(owner, false, true));
|
||||
|
||||
this.inventory = new ItemHandler(22);
|
||||
this.energy = new EnergyHelper(40000);
|
||||
|
||||
this.capabilityInventory = LazyOptional.of(() -> this.inventory);
|
||||
this.capabilityEnergy = LazyOptional.of(() -> this.energy);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag nbt) {
|
||||
super.saveAdditional(nbt);
|
||||
|
||||
nbt.put("inventory", this.inventory.serializeNBT());
|
||||
nbt.putInt("energy", this.energy.getEnergyStored());
|
||||
nbt.putInt("redstoneMode", this.redstoneMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
|
||||
this.inventory.deserializeNBT(nbt.getCompound("inventory"));
|
||||
this.energy.setStoredEnergy(nbt.getInt("energy"));
|
||||
this.redstoneMode = Mth.clamp(nbt.getInt("redstoneMode"), 0, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
checkPoweredState(this.level, this.worldPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult use(Level level, Player player, InteractionHand hand) {
|
||||
if (player instanceof ServerPlayer serverPlayer) {
|
||||
NetworkHooks.openScreen(serverPlayer, this, buffer -> {
|
||||
buffer.writeBlockPos(getBlockPos());
|
||||
buffer.writeByte(this.redstoneMode);
|
||||
});
|
||||
return InteractionResult.CONSUME;
|
||||
} else {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @javax.annotation.Nullable Direction side) {
|
||||
if (cap == ForgeCapabilities.ENERGY) {
|
||||
return this.capabilityEnergy.cast();
|
||||
} else if (cap == ForgeCapabilities.ITEM_HANDLER) {
|
||||
return this.capabilityInventory.cast();
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
|
||||
this.capabilityEnergy.invalidate();
|
||||
this.capabilityInventory.invalidate();
|
||||
}
|
||||
|
||||
private void serverTick() {
|
||||
if (this.redstoneMode == RedstoneControlWidget.REDSTONE_MODE_IGNORED || ((this.redstoneMode == RedstoneControlWidget.REDSTONE_MODE_UNPOWERED)) != this.hasRedstonePower) {
|
||||
var energyConsumption = EConfig.SERVER.mechanicalSieveEnergyConsumption.get();
|
||||
|
||||
if (this.energy.getEnergyStored() >= energyConsumption) {
|
||||
if (this.logic.getContents().isEmpty()) {
|
||||
var input = this.inventory.getStackInSlot(INPUT_SLOT);
|
||||
|
||||
if (this.logic.isValidInput(input)) {
|
||||
this.logic.startSifting(AbstractSieveBlockEntity.singleCopy(input));
|
||||
input.shrink(1);
|
||||
}
|
||||
}
|
||||
if (!this.logic.getContents().isEmpty()) {
|
||||
this.energy.extractEnergy(energyConsumption, false);
|
||||
this.logic.sift(0.01f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleResultItem(ItemStack result, ServerLevel level, RandomSource rand) {
|
||||
var remainder = result.copy();
|
||||
|
||||
for (int i = 2; i < 22; ++i) {
|
||||
// Try to forcefully insert remainder into the output slots, since insertItem will deny it
|
||||
// See ItemStackHandler.insertItem for reference
|
||||
var existing = this.inventory.getStackInSlot(i);
|
||||
// The maximum number of items that can be added to the slot
|
||||
var limit = this.inventory.getSlotLimit(i);
|
||||
|
||||
if (!existing.isEmpty()) {
|
||||
if (!ItemHandlerHelper.canItemStacksStack(remainder, existing)) {
|
||||
continue;
|
||||
}
|
||||
limit -= existing.getCount();
|
||||
}
|
||||
|
||||
// If slot is full
|
||||
if (limit <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If only part of the remainder can fit into the slot
|
||||
var splitRemainder = remainder.getCount() > limit;
|
||||
|
||||
if (existing.isEmpty()) {
|
||||
this.inventory.setStackInSlot(i, splitRemainder ? ItemHandlerHelper.copyStackWithSize(remainder, limit) : remainder);
|
||||
} else {
|
||||
existing.grow(splitRemainder ? limit : remainder.getCount());
|
||||
}
|
||||
if (splitRemainder) {
|
||||
remainder = ItemHandlerHelper.copyStackWithSize(remainder, remainder.getCount() - limit);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// item was "handled" if the remainder is smaller than the original result
|
||||
return remainder.getCount() < result.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDisplayName() {
|
||||
return TITLE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player pPlayer) {
|
||||
return new MechanicalSieveMenu(containerId, playerInventory, this);
|
||||
}
|
||||
|
||||
public boolean stillValid(Player player) {
|
||||
if (this.level.getBlockEntity(this.worldPosition) != this) {
|
||||
return false;
|
||||
} else {
|
||||
return player.distanceToSqr(this.worldPosition.getX() + 0.5, this.worldPosition.getY() + 0.5, this.worldPosition.getZ() + 0.5) <= 64.0;
|
||||
}
|
||||
}
|
||||
|
||||
public SieveLogic getLogic() {
|
||||
return this.logic;
|
||||
}
|
||||
|
||||
public void setRedstoneMode(int redstoneMode) {
|
||||
this.redstoneMode = redstoneMode;
|
||||
}
|
||||
|
||||
public int getRedstoneMode() {
|
||||
return this.redstoneMode;
|
||||
}
|
||||
|
||||
public void checkPoweredState(Level level, BlockPos pos) {
|
||||
this.hasRedstonePower = level.hasNeighborSignal(pos);
|
||||
}
|
||||
|
||||
private class ItemHandler extends ItemHelper {
|
||||
public ItemHandler(int size) {
|
||||
super(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemValid(int slot, @NotNull ItemStack stack) {
|
||||
if (slot == INPUT_SLOT) {
|
||||
return !RecipeUtil.getSieveRecipes(getStackInSlot(1).getItem(), stack).isEmpty();
|
||||
} else if (slot == MESH_SLOT) {
|
||||
return stack.is(EItemTags.SIEVE_MESHES);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSlotLimit(int slot) {
|
||||
return slot == MESH_SLOT ? 1 : super.getSlotLimit(slot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMachineExtract(int slot) {
|
||||
return slot > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onContentsChanged(int slot) {
|
||||
if (slot == MESH_SLOT) {
|
||||
MechanicalSieveBlockEntity.this.logic.setMesh(MechanicalSieveBlockEntity.this.inventory.getStackInSlot(MESH_SLOT));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad() {
|
||||
MechanicalSieveBlockEntity.this.logic.setMesh(MechanicalSieveBlockEntity.this.inventory.getStackInSlot(MESH_SLOT), false);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ServerTicker implements BlockEntityTicker<MechanicalSieveBlockEntity> {
|
||||
@Override
|
||||
public void tick(Level level, BlockPos pos, BlockState state, MechanicalSieveBlockEntity sieve) {
|
||||
sieve.serverTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,68 +19,34 @@
|
|||
package thedarkcolour.exdeorum.blockentity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
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 net.minecraft.world.level.storage.loot.LootParams;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import thedarkcolour.exdeorum.blockentity.logic.SieveLogic;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
||||
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
|
||||
import thedarkcolour.exdeorum.registry.EBlockEntities;
|
||||
import thedarkcolour.exdeorum.tag.EItemTags;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SieveBlockEntity extends EBlockEntity {
|
||||
public static final short MAX_SIEVE_CAPACITY = 100;
|
||||
public static final short SIEVE_INTERVAL = 10;
|
||||
|
||||
private ItemStack contents = ItemStack.EMPTY;
|
||||
private ItemStack mesh = ItemStack.EMPTY;
|
||||
private short progress = 0; // Max is 100
|
||||
private float efficiency = 1f;
|
||||
private int fortune = 0;
|
||||
public class SieveBlockEntity extends AbstractSieveBlockEntity {
|
||||
public static final float SIEVE_INTERVAL = 0.1f;
|
||||
|
||||
public SieveBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(EBlockEntities.SIEVE.get(), pos, state);
|
||||
super(EBlockEntities.SIEVE.get(), pos, state, (owner) -> new SieveLogic(owner, true, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveAdditional(CompoundTag nbt) {
|
||||
super.saveAdditional(nbt);
|
||||
|
||||
nbt.put("contents", contents.serializeNBT());
|
||||
nbt.putShort("progress", progress);
|
||||
if (!mesh.isEmpty()) {
|
||||
nbt.put("mesh", mesh.save(new CompoundTag()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
if (nbt.contains("contents")) {
|
||||
this.contents = ItemStack.of(nbt.getCompound("contents"));
|
||||
} else {
|
||||
this.contents = ItemStack.EMPTY;
|
||||
}
|
||||
this.progress = nbt.getShort("progress");
|
||||
if (nbt.contains("mesh")) {
|
||||
setMesh(ItemStack.of(nbt.getCompound("mesh")));
|
||||
} else {
|
||||
setMesh(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
super.load(nbt);
|
||||
public boolean handleResultItem(ItemStack result, ServerLevel level, RandomSource rand) {
|
||||
var pos = this.worldPosition;
|
||||
var itemEntity = new ItemEntity(level, pos.getX() + 0.5, pos.getY() + 1.5, pos.getZ() + 0.5, result);
|
||||
itemEntity.setDeltaMovement(rand.nextGaussian() * 0.05, 0.2, rand.nextGaussian() * 0.05);
|
||||
level.addFreshEntity(itemEntity);
|
||||
return true;
|
||||
}
|
||||
|
||||
public InteractionResult use(Level level, Player player, InteractionHand hand) {
|
||||
|
|
@ -88,14 +54,10 @@ public class SieveBlockEntity extends EBlockEntity {
|
|||
boolean isClientSide = level.isClientSide;
|
||||
|
||||
// Try insert mesh
|
||||
if (mesh.isEmpty()) {
|
||||
if (isMesh(playerItem)) {
|
||||
if (!level.isClientSide) {
|
||||
var meshCopy = playerItem.copy();
|
||||
meshCopy.setCount(1);
|
||||
setMesh(meshCopy);
|
||||
|
||||
markUpdated();
|
||||
if (this.logic.getMesh().isEmpty()) {
|
||||
if (this.logic.isValidMesh(playerItem)) {
|
||||
if (!isClientSide) {
|
||||
this.logic.setMesh(singleCopy(playerItem));
|
||||
|
||||
if (!player.getAbilities().instabuild) {
|
||||
playerItem.shrink(1);
|
||||
|
|
@ -105,73 +67,71 @@ public class SieveBlockEntity extends EBlockEntity {
|
|||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
} else if (contents.isEmpty()) {
|
||||
} else if (this.logic.getContents().isEmpty()) {
|
||||
// remove mesh with sneak right click
|
||||
if (player.isShiftKeyDown() && player.getMainHandItem().isEmpty()) {
|
||||
removeMesh();
|
||||
popOutMesh(level, this.worldPosition, this.logic);
|
||||
}
|
||||
}
|
||||
|
||||
if (contents.isEmpty()) {
|
||||
if (!isClientSide) {
|
||||
// Insert an item
|
||||
if (!isClientSide) {
|
||||
if (this.logic.getContents().isEmpty()) {
|
||||
// If the input has any sieve drops, insert it into the mesh
|
||||
if (!RecipeUtil.getSieveRecipes(mesh.getItem(), playerItem).isEmpty()) {
|
||||
playerItem = this.insertContents(player, hand);
|
||||
markUpdated();
|
||||
if (this.logic.isValidInput(playerItem)) {
|
||||
playerItem = insertContents(player, hand, this.logic);
|
||||
|
||||
if (EConfig.SERVER.simultaneousSieveUsage.get()) {
|
||||
var cursor = worldPosition.mutable().move(-1, 0, -1);
|
||||
int range = EConfig.SERVER.simultaneousSieveUsageRange.get();
|
||||
var cursor = this.worldPosition.mutable().move(-range, 0, -range);
|
||||
|
||||
// Fill adjacent sieves
|
||||
otherSieves:
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
for (int x = -range; x <= range; x++) {
|
||||
for (int z = -range; z <= range; z++) {
|
||||
if (playerItem.isEmpty()) {
|
||||
break otherSieves;
|
||||
}
|
||||
|
||||
if ((x | z) != 0) {
|
||||
if (level.getBlockEntity(cursor) instanceof SieveBlockEntity other) {
|
||||
if (other.contents.isEmpty()) {
|
||||
if (this.mesh.getItem() == other.mesh.getItem()) {
|
||||
playerItem = other.insertContents(player, hand);
|
||||
other.markUpdated();
|
||||
if (other.logic.getContents().isEmpty()) {
|
||||
if (this.logic.getMesh().getItem() == other.logic.getMesh().getItem()) {
|
||||
playerItem = insertContents(player, hand, other.logic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cursor.move(0, 0, 1);
|
||||
}
|
||||
cursor.move(1, 0, -3);
|
||||
cursor.move(1, 0, (-2 * range) - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var realPlayer = !(player instanceof FakePlayer);
|
||||
} else {
|
||||
var realPlayer = !(player instanceof FakePlayer);
|
||||
|
||||
if (realPlayer && EConfig.SERVER.simultaneousSieveUsage.get()) {
|
||||
var cursor = worldPosition.mutable().move(-1, 0, -1);
|
||||
if (realPlayer && EConfig.SERVER.simultaneousSieveUsage.get()) {
|
||||
int range = EConfig.SERVER.simultaneousSieveUsageRange.get();
|
||||
var cursor = this.worldPosition.mutable().move(-range, 0, -range);
|
||||
|
||||
// Sieve with adjacent sieves
|
||||
for (int x = -1; x <= 1; x++) {
|
||||
for (int z = -1; z <= 1; z++) {
|
||||
if (level.getBlockEntity(cursor) instanceof SieveBlockEntity other) {
|
||||
if (!other.contents.isEmpty()) {
|
||||
if (this.mesh.getItem() == other.mesh.getItem()) {
|
||||
other.performSift(player);
|
||||
// Sieve with adjacent sieves
|
||||
for (int x = -range; x <= range; x++) {
|
||||
for (int z = -range; z <= range; z++) {
|
||||
if (level.getBlockEntity(cursor) instanceof SieveBlockEntity other) {
|
||||
if (!other.logic.getContents().isEmpty()) {
|
||||
if (this.logic.getMesh().getItem() == other.logic.getMesh().getItem()) {
|
||||
other.logic.sift(SIEVE_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
cursor.move(0, 0, 1);
|
||||
}
|
||||
|
||||
cursor.move(0, 0, 1);
|
||||
cursor.move(1, 0, (-2 * range) - 1);
|
||||
}
|
||||
cursor.move(1, 0, -3);
|
||||
} else if (realPlayer || EConfig.SERVER.automatedSieves.get()) {
|
||||
this.logic.sift(SIEVE_INTERVAL);
|
||||
}
|
||||
} else if (realPlayer || EConfig.SERVER.automatedSieves.get()) {
|
||||
performSift(player);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -179,115 +139,37 @@ public class SieveBlockEntity extends EBlockEntity {
|
|||
}
|
||||
|
||||
// Fills the sieve (assumes contents is EMPTY) and returns the remaining item, putting it in the player's hand
|
||||
private ItemStack insertContents(Player player, InteractionHand hand) {
|
||||
public static ItemStack insertContents(Player player, InteractionHand hand, SieveLogic logic) {
|
||||
var consume = !player.getAbilities().instabuild;
|
||||
var playerItem = player.getItemInHand(hand);
|
||||
|
||||
if (consume) {
|
||||
if (playerItem.getCount() == 1) {
|
||||
this.contents = playerItem;
|
||||
logic.startSifting(playerItem);
|
||||
player.setItemInHand(hand, ItemStack.EMPTY);
|
||||
playerItem = ItemStack.EMPTY;
|
||||
} else {
|
||||
this.contents = singleCopy(playerItem);
|
||||
logic.startSifting(singleCopy(playerItem));
|
||||
playerItem.shrink(1);
|
||||
}
|
||||
} else {
|
||||
this.contents = singleCopy(playerItem);
|
||||
logic.startSifting(singleCopy(playerItem));
|
||||
}
|
||||
|
||||
this.progress = MAX_SIEVE_CAPACITY;
|
||||
|
||||
return playerItem;
|
||||
}
|
||||
|
||||
private static ItemStack singleCopy(ItemStack stack) {
|
||||
var copy = stack.copy();
|
||||
copy.setCount(1);
|
||||
return copy;
|
||||
}
|
||||
|
||||
private void performSift(Player player) {
|
||||
progress -= efficiency * SIEVE_INTERVAL;
|
||||
|
||||
if (progress <= 0) {
|
||||
progress = 0;
|
||||
|
||||
if (!level.isClientSide) {
|
||||
giveItems(player);
|
||||
}
|
||||
} else {
|
||||
markUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeMesh() {
|
||||
// Do not call on client side
|
||||
public static void popOutMesh(Level level, BlockPos sievePos, SieveLogic logic) {
|
||||
if (!level.isClientSide) {
|
||||
// Pop out item
|
||||
var itemEntity = new ItemEntity(level, worldPosition.getX() + 0.5, worldPosition.getY() + 1.5, worldPosition.getZ() + 0.5, mesh);
|
||||
var itemEntity = new ItemEntity(level, sievePos.getX() + 0.5, sievePos.getY() + 1.5, sievePos.getZ() + 0.5, logic.getMesh());
|
||||
var rand = level.random;
|
||||
itemEntity.setDeltaMovement(rand.nextGaussian() * 0.05, 0.2, rand.nextGaussian() * 0.05);
|
||||
level.addFreshEntity(itemEntity);
|
||||
|
||||
// Empty contents
|
||||
setMesh(ItemStack.EMPTY);
|
||||
markUpdated();
|
||||
logic.setMesh(ItemStack.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
private void setMesh(ItemStack mesh) {
|
||||
this.mesh = mesh;
|
||||
this.efficiency = 1f + mesh.getEnchantmentLevel(Enchantments.BLOCK_EFFICIENCY) * 0.17f;
|
||||
this.fortune = mesh.getEnchantmentLevel(Enchantments.BLOCK_FORTUNE);
|
||||
}
|
||||
|
||||
private void giveItems(Player player) {
|
||||
var pos = this.worldPosition;
|
||||
var level = this.level;
|
||||
var context = new LootContext.Builder(new LootParams((ServerLevel) level, Map.of(), Map.of(), player.getLuck())).create(null);
|
||||
var rand = this.level.random;
|
||||
var limitDrops = this.contents.getItem() == Items.MOSS_BLOCK && EConfig.SERVER.limitMossSieveDrops.get();
|
||||
|
||||
for (SieveRecipe recipe : RecipeUtil.getSieveRecipes(this.mesh.getItem(), this.contents)) {
|
||||
var amount = recipe.resultAmount.getInt(context);
|
||||
|
||||
for (int i = 0; i < this.fortune; i++) {
|
||||
if (rand.nextFloat() < 0.3f) {
|
||||
amount += recipe.resultAmount.getInt(context);
|
||||
}
|
||||
}
|
||||
|
||||
if (amount >= 1) {
|
||||
var itemEntity = new ItemEntity(level, pos.getX() + 0.5, pos.getY() + 1.5, pos.getZ() + 0.5, new ItemStack(recipe.result, amount));
|
||||
itemEntity.setDeltaMovement(rand.nextGaussian() * 0.05, 0.2, rand.nextGaussian() * 0.05);
|
||||
level.addFreshEntity(itemEntity);
|
||||
|
||||
// limit drops to 1 or two items (could be more than 2 but unlikely)
|
||||
if (limitDrops && rand.nextInt(5) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.contents = ItemStack.EMPTY;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
private boolean isMesh(ItemStack stack) {
|
||||
return stack.is(EItemTags.SIEVE_MESHES);
|
||||
}
|
||||
|
||||
public ItemStack getMesh() {
|
||||
return this.mesh;
|
||||
}
|
||||
|
||||
// Used for rendering
|
||||
public short getProgress() {
|
||||
return this.progress;
|
||||
}
|
||||
|
||||
// Used for rendering
|
||||
public ItemStack getContents() {
|
||||
return this.contents;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.blockentity.helper;
|
||||
|
||||
import net.minecraftforge.energy.EnergyStorage;
|
||||
|
||||
public class EnergyHelper extends EnergyStorage {
|
||||
public EnergyHelper(int capacity) {
|
||||
super(capacity);
|
||||
}
|
||||
|
||||
public EnergyHelper(int capacity, int maxTransfer) {
|
||||
super(capacity, maxTransfer);
|
||||
}
|
||||
|
||||
public EnergyHelper(int capacity, int maxReceive, int maxExtract) {
|
||||
super(capacity, maxReceive, maxExtract);
|
||||
}
|
||||
|
||||
public EnergyHelper(int capacity, int maxReceive, int maxExtract, int energy) {
|
||||
super(capacity, maxReceive, maxExtract, energy);
|
||||
}
|
||||
|
||||
public void setStoredEnergy(int energy) {
|
||||
this.energy = energy;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.blockentity.helper;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.items.ItemStackHandler;
|
||||
import net.minecraftforge.items.SlotItemHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ItemHelper extends ItemStackHandler {
|
||||
public ItemHelper(int size) {
|
||||
super(size);
|
||||
}
|
||||
|
||||
// Whether an item can be extracted from this slot (GUI ignores this and just takes it out)
|
||||
public boolean canMachineExtract(int slot) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack extractItem(int slot, int amount, boolean simulate) {
|
||||
if (canMachineExtract(slot)) {
|
||||
return takeOutItem(slot, amount, simulate);
|
||||
} else {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
public ItemStack takeOutItem(int slot, int amount, boolean simulate) {
|
||||
return super.extractItem(slot, amount, simulate);
|
||||
}
|
||||
|
||||
public ItemHelper.Slot createSlot(int index, int x, int y) {
|
||||
return new ItemHelper.Slot(index, x, y);
|
||||
}
|
||||
|
||||
public class Slot extends SlotItemHandler {
|
||||
public Slot(int index, int x, int y) {
|
||||
super(ItemHelper.this, index, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack remove(int amount) {
|
||||
return ItemHelper.this.takeOutItem(getContainerSlot(), amount, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPickup(Player playerIn) {
|
||||
return !ItemHelper.this.takeOutItem(getContainerSlot(), 1, true).isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* 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.blockentity.logic;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.enchantment.Enchantments;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import net.minecraft.world.level.storage.loot.LootParams;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
||||
import thedarkcolour.exdeorum.recipe.sieve.SieveRecipe;
|
||||
import thedarkcolour.exdeorum.tag.EItemTags;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SieveLogic {
|
||||
private final Owner owner;
|
||||
private final boolean saveMesh;
|
||||
private final boolean mechanical;
|
||||
|
||||
// block currently being sifted
|
||||
private ItemStack contents = ItemStack.EMPTY;
|
||||
// mesh
|
||||
private ItemStack mesh = ItemStack.EMPTY;
|
||||
// from 0.0 to 1.0
|
||||
private float progress;
|
||||
private float efficiency;
|
||||
private int fortune;
|
||||
|
||||
public SieveLogic(Owner owner, boolean saveMesh, boolean mechanical) {
|
||||
this.owner = owner;
|
||||
this.saveMesh = saveMesh;
|
||||
this.mechanical = mechanical;
|
||||
}
|
||||
|
||||
public ItemStack getMesh() {
|
||||
return this.mesh;
|
||||
}
|
||||
|
||||
public boolean isValidInput(ItemStack stack) {
|
||||
return !RecipeUtil.getSieveRecipes(this.mesh.getItem(), stack).isEmpty();
|
||||
}
|
||||
|
||||
public boolean isValidMesh(ItemStack stack) {
|
||||
return stack.is(EItemTags.SIEVE_MESHES);
|
||||
}
|
||||
|
||||
// not pure, modifies the received stack
|
||||
public void startSifting(ItemStack stack) {
|
||||
this.contents = stack;
|
||||
this.owner.markUpdated();
|
||||
}
|
||||
|
||||
// Do not call on the client side
|
||||
public void sift(float incrementProgress) {
|
||||
this.progress += incrementProgress * this.efficiency;
|
||||
|
||||
// Need epsilon because floating point decimals suck
|
||||
if (this.progress >= 1.0f - Mth.EPSILON) {
|
||||
var level = this.owner.getServerLevel();
|
||||
var context = new LootContext.Builder(new LootParams(level, Map.of(), Map.of(), 0)).create(null);
|
||||
var rand = level.random;
|
||||
var limitDrops = this.contents.getItem() == Items.MOSS_BLOCK && EConfig.SERVER.limitMossSieveDrops.get();
|
||||
var handledAnyDrops = false;
|
||||
var hasDrops = false;
|
||||
|
||||
for (SieveRecipe recipe : RecipeUtil.getSieveRecipes(this.mesh.getItem(), this.contents)) {
|
||||
var amount = getResultAmount(recipe, context, rand);
|
||||
|
||||
// Split overflowing stacks (64+) into multiple stacks
|
||||
while (amount > 0) {
|
||||
hasDrops = true;
|
||||
// make a single item copy of recipe result
|
||||
var result = new ItemStack(recipe.result, 1);
|
||||
// the size of the stack respecting stack limits (ex. ender pearl limits to 16)
|
||||
var stackAmount = Math.min(amount, recipe.result.getMaxStackSize(result));
|
||||
result.setCount(stackAmount);
|
||||
amount -= stackAmount;
|
||||
var handleDrop = this.owner.handleResultItem(result, level, rand);
|
||||
handledAnyDrops = handledAnyDrops || handleDrop;
|
||||
|
||||
// limit drops to 1 or two items (could be more than 2 but unlikely)
|
||||
if (limitDrops && rand.nextInt(5) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (handledAnyDrops || !hasDrops) {
|
||||
this.contents = ItemStack.EMPTY;
|
||||
this.progress = 0.0f;
|
||||
} else {
|
||||
this.progress = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
this.owner.markUpdated();
|
||||
}
|
||||
|
||||
protected int getResultAmount(SieveRecipe recipe, LootContext context, RandomSource rand) {
|
||||
if (recipe.byHandOnly && this.mechanical) return 0;
|
||||
|
||||
var amount = recipe.resultAmount.getInt(context);
|
||||
|
||||
// Each level of fortune grants a 30% chance for an extra roll
|
||||
for (int i = 0; i < this.fortune; ++i) {
|
||||
if (rand.nextFloat() < 0.3f) {
|
||||
amount += recipe.resultAmount.getInt(context);
|
||||
}
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setMesh(ItemStack mesh) {
|
||||
this.setMesh(mesh, true);
|
||||
}
|
||||
|
||||
public void setMesh(ItemStack mesh, boolean needsUpdate) {
|
||||
this.mesh = mesh;
|
||||
this.efficiency = 1f + mesh.getEnchantmentLevel(Enchantments.BLOCK_EFFICIENCY) * 0.17f;
|
||||
this.fortune = mesh.getEnchantmentLevel(Enchantments.BLOCK_FORTUNE);
|
||||
if (mesh.isEmpty()) {
|
||||
this.progress = 0.0f;
|
||||
this.contents = ItemStack.EMPTY;
|
||||
}
|
||||
if (needsUpdate) {
|
||||
this.owner.markUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
public void saveNbt(CompoundTag nbt) {
|
||||
if (!this.contents.isEmpty()) {
|
||||
nbt.put("contents", this.contents.serializeNBT());
|
||||
}
|
||||
if (this.saveMesh && !this.mesh.isEmpty()) {
|
||||
nbt.put("mesh", this.mesh.save(new CompoundTag()));
|
||||
}
|
||||
nbt.putFloat("progress", this.progress);
|
||||
}
|
||||
|
||||
public void loadNbt(CompoundTag nbt) {
|
||||
if (nbt.contains("contents")) {
|
||||
this.contents = ItemStack.of(nbt.getCompound("contents"));
|
||||
} else {
|
||||
this.contents = ItemStack.EMPTY;
|
||||
}
|
||||
if (nbt.getTagType("progress") == Tag.TAG_SHORT) {
|
||||
this.progress = (float) nbt.getShort("progress") / 100f;
|
||||
} else {
|
||||
this.progress = nbt.getFloat("progress");
|
||||
}
|
||||
if (this.saveMesh) {
|
||||
if (nbt.contains("mesh")) {
|
||||
setMesh(ItemStack.of(nbt.getCompound("mesh")), false);
|
||||
} else {
|
||||
setMesh(ItemStack.EMPTY, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ItemStack getContents() {
|
||||
return this.contents;
|
||||
}
|
||||
|
||||
// client only
|
||||
public void setContents(ItemStack contents) {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
public float getProgress() {
|
||||
return this.progress;
|
||||
}
|
||||
|
||||
// client only
|
||||
public void setProgress(float progress) {
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
public CompoundTag writeUpdateTag() {
|
||||
var tag = new CompoundTag();
|
||||
tag.putBoolean("logic", true);
|
||||
tag.putFloat("progress", this.progress);
|
||||
tag.put("mesh", this.mesh.serializeNBT());
|
||||
tag.put("contents", this.contents.serializeNBT());
|
||||
return tag;
|
||||
}
|
||||
|
||||
public void readUpdateTag(CompoundTag nbt) {
|
||||
this.progress = nbt.getFloat("progress");
|
||||
this.mesh = nbt.contains("mesh") ? ItemStack.of(nbt.getCompound("mesh")) : ItemStack.EMPTY;
|
||||
this.contents = nbt.contains("contents") ? ItemStack.of(nbt.getCompound("contents")) : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
// implement on the owner of this sieve logic
|
||||
public interface Owner {
|
||||
ServerLevel getServerLevel();
|
||||
|
||||
// Return whether the result item was consumed
|
||||
boolean handleResultItem(ItemStack result, ServerLevel level, RandomSource rand);
|
||||
|
||||
void markUpdated();
|
||||
}
|
||||
}
|
||||
|
|
@ -16,12 +16,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains all data generation for Ex Deorum. It is not to be used outside of data generation.
|
||||
* <p>
|
||||
* Ex Deorum uses the ModKit library, which adds several utilities primarily for data generation
|
||||
* without needing to be shaded or depended upon outside a development environment.
|
||||
*/
|
||||
@net.minecraft.MethodsReturnNonnullByDefault
|
||||
@javax.annotation.ParametersAreNonnullByDefault
|
||||
package thedarkcolour.exdeorum.blockentity;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package thedarkcolour.exdeorum.client;
|
|||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
|
||||
import net.minecraft.client.gui.screens.worldselection.WorldCreationUiState;
|
||||
import net.minecraft.client.renderer.ItemBlockRenderTypes;
|
||||
|
|
@ -42,6 +43,7 @@ import net.minecraftforge.fml.event.config.ModConfigEvent;
|
|||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.client.screen.MechanicalSieveScreen;
|
||||
import thedarkcolour.exdeorum.client.ter.BarrelRenderer;
|
||||
import thedarkcolour.exdeorum.client.ter.CrucibleRenderer;
|
||||
import thedarkcolour.exdeorum.client.ter.InfestedLeavesRenderer;
|
||||
|
|
@ -52,9 +54,11 @@ import thedarkcolour.exdeorum.network.ClientMessageHandler;
|
|||
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
||||
import thedarkcolour.exdeorum.registry.EBlockEntities;
|
||||
import thedarkcolour.exdeorum.registry.EFluids;
|
||||
import thedarkcolour.exdeorum.registry.EMenus;
|
||||
import thedarkcolour.exdeorum.registry.EWorldPresets;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class ClientHandler {
|
||||
// Used for the composting recipe category in JEI
|
||||
|
|
@ -95,7 +99,10 @@ public class ClientHandler {
|
|||
}
|
||||
|
||||
private static void clientSetup(FMLClientSetupEvent event) {
|
||||
event.enqueueWork(ClientHandler::setRenderLayers);
|
||||
event.enqueueWork(() -> {
|
||||
setRenderLayers();
|
||||
MenuScreens.register(EMenus.MECHANICAL_SIEVE.get(), MechanicalSieveScreen::new);
|
||||
});
|
||||
}
|
||||
|
||||
private static void setRenderLayers() {
|
||||
|
|
@ -128,7 +135,8 @@ public class ClientHandler {
|
|||
event.registerBlockEntityRenderer(EBlockEntities.BARREL.get(), BarrelRenderer::new);
|
||||
event.registerBlockEntityRenderer(EBlockEntities.LAVA_CRUCIBLE.get(), ctx -> new CrucibleRenderer());
|
||||
event.registerBlockEntityRenderer(EBlockEntities.WATER_CRUCIBLE.get(), ctx -> new CrucibleRenderer());
|
||||
event.registerBlockEntityRenderer(EBlockEntities.SIEVE.get(), SieveRenderer::new);
|
||||
event.registerBlockEntityRenderer(EBlockEntities.SIEVE.get(), ctx -> new SieveRenderer<>());
|
||||
event.registerBlockEntityRenderer(EBlockEntities.MECHANICAL_SIEVE.get(), ctx -> new SieveRenderer<>());
|
||||
}
|
||||
|
||||
private static void registerShaders(RegisterShadersEvent event) {
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|||
import java.util.List;
|
||||
|
||||
public interface RenderFace {
|
||||
void renderFlatSprite(MultiBufferSource buffers, PoseStack stack, float y, int r, int g, int b, int light, float edge);
|
||||
|
||||
void renderFlatSpriteLerp(MultiBufferSource buffers, PoseStack stack, float percentage, int r, int g, int b, int light, float edge, float minY, float maxY);
|
||||
void renderFlatSpriteLerp(MultiBufferSource buffers, PoseStack stack, float percentage, int r, int g, int b, int light, float edge, float yStart, float yEnd);
|
||||
|
||||
boolean isMissingTexture();
|
||||
|
||||
|
|
@ -37,14 +35,10 @@ public interface RenderFace {
|
|||
public Single(RenderType renderType, TextureAtlasSprite sprite) {
|
||||
this(renderType, sprite, RenderUtil.isMissingTexture(sprite));
|
||||
}
|
||||
@Override
|
||||
public void renderFlatSprite(MultiBufferSource buffers, PoseStack stack, float y, int r, int g, int b, int light, float edge) {
|
||||
RenderUtil.renderFlatSprite(buffers.getBuffer(this.renderType), stack, y, r, g, b, this.sprite, light, edge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFlatSpriteLerp(MultiBufferSource buffers, PoseStack stack, float percentage, int r, int g, int b, int light, float edge, float minY, float maxY) {
|
||||
RenderUtil.renderFlatSpriteLerp(buffers.getBuffer(this.renderType), stack, percentage, r, g, b, this.sprite, light, edge, minY, maxY);
|
||||
public void renderFlatSpriteLerp(MultiBufferSource buffers, PoseStack stack, float percentage, int r, int g, int b, int light, float edge, float yStart, float yEnd) {
|
||||
RenderUtil.renderFlatSpriteLerp(buffers.getBuffer(this.renderType), stack, percentage, r, g, b, this.sprite, light, edge, yStart, yEnd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,16 +48,9 @@ public interface RenderFace {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void renderFlatSprite(MultiBufferSource buffers, PoseStack stack, float y, int r, int g, int b, int light, float edge) {
|
||||
public void renderFlatSpriteLerp(MultiBufferSource buffers, PoseStack stack, float percentage, int r, int g, int b, int light, float edge, float yStart, float yEnd) {
|
||||
for (var layer : this.layers) {
|
||||
RenderUtil.renderFlatSprite(buffers.getBuffer(layer.first()), stack, y, r, g, b, layer.second(), light, edge);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderFlatSpriteLerp(MultiBufferSource buffers, PoseStack stack, float percentage, int r, int g, int b, int light, float edge, float minY, float maxY) {
|
||||
for (var layer : this.layers) {
|
||||
RenderUtil.renderFlatSpriteLerp(buffers.getBuffer(layer.first()), stack, percentage, r, g, b, layer.second(), light, edge, minY, maxY);
|
||||
RenderUtil.renderFlatSpriteLerp(buffers.getBuffer(layer.first()), stack, percentage, r, g, b, layer.second(), light, edge, yStart, yEnd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,11 +56,12 @@ import thedarkcolour.exdeorum.client.ter.SieveRenderer;
|
|||
import java.awt.Color;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class RenderUtil {
|
||||
private static final VarHandle COMPOSITE_MODEL_CHILDREN;
|
||||
private static final IdentityHashMap<Block, RenderFace> TOP_FACES = new IdentityHashMap<>();
|
||||
private static final Map<Block, RenderFace> TOP_FACES = new HashMap<>();
|
||||
public static final RenderStateShard.ShaderStateShard RENDER_TYPE_TINTED_CUTOUT_MIPPED_SHADER = new RenderStateShard.ShaderStateShard(RenderUtil::getRenderTypeTintedCutoutMippedShader);
|
||||
public static final RenderType TINTED_CUTOUT_MIPPED = RenderType.create(ExDeorum.ID + ":tinted_cutout_mipped", DefaultVertexFormat.NEW_ENTITY, VertexFormat.Mode.QUADS, RenderType.SMALL_BUFFER_SIZE, false, false, RenderType.CompositeState.builder().setLightmapState(RenderStateShard.LIGHTMAP).setShaderState(RENDER_TYPE_TINTED_CUTOUT_MIPPED_SHADER).setTextureState(RenderStateShard.BLOCK_SHEET_MIPPED).createCompositeState(true));
|
||||
public static TextureAtlas blockAtlas;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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.screen;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
import thedarkcolour.exdeorum.menu.MechanicalSieveMenu;
|
||||
|
||||
public class MechanicalSieveScreen extends AbstractContainerScreen<MechanicalSieveMenu> {
|
||||
private static final ResourceLocation BACKGROUND_TEXTURE = new ResourceLocation(ExDeorum.ID, "textures/gui/container/mechanical_sieve.png");
|
||||
|
||||
// Used by JEI and REI, these are bounds of the little grains texture between the mesh/input and the output slots
|
||||
public static final int RECIPE_CLICK_AREA_POS_X = 51;
|
||||
public static final int RECIPE_CLICK_AREA_POS_Y = 42;
|
||||
public static final int RECIPE_CLICK_AREA_WIDTH = 21;
|
||||
public static final int RECIPE_CLICK_AREA_HEIGHT = 14;
|
||||
|
||||
private final MechanicalSieveMenu menu;
|
||||
@Nullable
|
||||
private RedstoneControlWidget redstoneControlWidget;
|
||||
|
||||
public MechanicalSieveScreen(MechanicalSieveMenu menu, Inventory playerInventory, Component title) {
|
||||
super(menu, playerInventory, title);
|
||||
|
||||
this.menu = menu;
|
||||
this.imageWidth = 176;
|
||||
this.imageHeight = 173;
|
||||
this.inventoryLabelY += 7;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
this.redstoneControlWidget = new RedstoneControlWidget(this, BACKGROUND_TEXTURE, this.leftPos + 176, this.topPos + 3);
|
||||
addRenderableWidget(this.redstoneControlWidget);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RedstoneControlWidget getRedstoneControlWidget() {
|
||||
return this.redstoneControlWidget;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderBg(GuiGraphics graphics, float partialTick, int mX, int mY) {
|
||||
int left = this.leftPos;
|
||||
int top = this.topPos;
|
||||
graphics.blit(BACKGROUND_TEXTURE, left, top, 0, 0, this.imageWidth, this.imageHeight);
|
||||
|
||||
// energy bar
|
||||
int energy = Mth.floor(54 * ((float) this.menu.prevSieveEnergy / EConfig.SERVER.mechanicalSieveEnergyStorage.get()));
|
||||
graphics.blit(BACKGROUND_TEXTURE, left + 10, top + 22 + 54 - energy, this.imageWidth, 14 + 54 - energy, 12, energy);
|
||||
|
||||
// progress arrow
|
||||
int progress = Math.min(21, (int) (this.menu.sieve.getProgress() * 22));
|
||||
graphics.blit(BACKGROUND_TEXTURE, left + 51, top + 42, this.imageWidth, 0, progress, 14);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(GuiGraphics graphics, int mx, int my, float partialTicks) {
|
||||
renderBackground(graphics);
|
||||
super.render(graphics, mx, my, partialTicks);
|
||||
renderTooltip(graphics, mx, my);
|
||||
|
||||
int rx = mx - this.leftPos;
|
||||
int ry = my - this.topPos;
|
||||
|
||||
if (9 <= rx && rx < 23 && 21 <= ry && ry < 77) {
|
||||
var energyTooltip = Component.translatable(TranslationKeys.ENERGY).append(Component.translatable(TranslationKeys.FRACTION_DISPLAY, this.menu.prevSieveEnergy, EConfig.SERVER.mechanicalSieveEnergyStorage.get())).append(" FE");
|
||||
graphics.renderTooltip(Minecraft.getInstance().font, energyTooltip, mx, my);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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.screen;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.components.Renderable;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
||||
import net.minecraft.client.renderer.Rect2i;
|
||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RedstoneControlWidget implements GuiEventListener, NarratableEntry, Renderable {
|
||||
public static final int REDSTONE_MODE_IGNORED = 0;
|
||||
public static final int REDSTONE_MODE_UNPOWERED = 1;
|
||||
public static final int REDSTONE_MODE_POWERED = 2;
|
||||
|
||||
private static final Component[] REDSTONE_MODES = new Component[] {
|
||||
Component.translatable(TranslationKeys.REDSTONE_CONTROL_MODES[REDSTONE_MODE_IGNORED]).withStyle(ChatFormatting.YELLOW),
|
||||
Component.translatable(TranslationKeys.REDSTONE_CONTROL_MODES[REDSTONE_MODE_UNPOWERED]).withStyle(ChatFormatting.GRAY),
|
||||
Component.translatable(TranslationKeys.REDSTONE_CONTROL_MODES[REDSTONE_MODE_POWERED]).withStyle(ChatFormatting.WHITE),
|
||||
};
|
||||
private static final Component REDSTONE_CONTROL_LABEL = Component.translatable(TranslationKeys.REDSTONE_CONTROL_LABEL);
|
||||
|
||||
private final MechanicalSieveScreen screen;
|
||||
private final ResourceLocation texture;
|
||||
private final int posX;
|
||||
private final int posY;
|
||||
private final int tabU;
|
||||
private final int tabV;
|
||||
private final int tabWidth;
|
||||
private final int tabHeight;
|
||||
private final int expandedV;
|
||||
private final int expandedU;
|
||||
private final int expandedWidth;
|
||||
private final int expandedHeight;
|
||||
private final int buttonsPosX;
|
||||
private final int buttonsPosY;
|
||||
|
||||
// Percentage of the widget currently being displayed
|
||||
private float percentage = 0.0f;
|
||||
// Whether full widget is displayed
|
||||
private boolean expanded = false;
|
||||
// Last time (from currentTimeMillis) this button was clicked, used in animation lerp
|
||||
private long lastClicked = -1L;
|
||||
|
||||
public RedstoneControlWidget(MechanicalSieveScreen screen, ResourceLocation texture, int posX, int posY) {
|
||||
this.screen = screen;
|
||||
this.texture = texture;
|
||||
this.posX = posX;
|
||||
this.posY = posY;
|
||||
|
||||
this.expandedU = 0;
|
||||
this.expandedV = 189;
|
||||
this.expandedWidth = 94;
|
||||
this.expandedHeight = 67;
|
||||
this.tabU = this.expandedWidth;
|
||||
this.tabV = 189;
|
||||
this.tabWidth = 26;
|
||||
this.tabHeight = 28;
|
||||
this.buttonsPosX = this.posX + 18;
|
||||
this.buttonsPosY = this.posY + 44;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(GuiGraphics graphics, int mx, int my, float pPartialTick) {
|
||||
if (this.lastClicked != -1L) {
|
||||
// animation is 200 ms
|
||||
this.percentage = (System.currentTimeMillis() - this.lastClicked) / 200.0f;
|
||||
|
||||
if (this.percentage >= 1.0f) {
|
||||
this.percentage = 0.0f;
|
||||
this.expanded = !this.expanded;
|
||||
this.lastClicked = -1L;
|
||||
} else {
|
||||
drawPartialConfig(graphics);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, render the full widget or the tab only
|
||||
var font = Minecraft.getInstance().font;
|
||||
|
||||
if (this.expanded) {
|
||||
var redstoneMode = this.screen.getMenu().sieve.getRedstoneMode();
|
||||
graphics.blit(this.texture, this.posX, this.posY, this.expandedU, this.expandedV, this.expandedWidth, this.expandedHeight);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
graphics.blit(this.texture, this.buttonsPosX + (i * 19), this.buttonsPosY, (redstoneMode == i ? this.tabU + 16 : this.tabU), this.tabV + this.tabHeight, 16, 16);
|
||||
}
|
||||
graphics.blit(this.texture, this.buttonsPosX, this.buttonsPosY, this.tabU, this.tabV + this.tabHeight + 16, 52, 14);
|
||||
|
||||
graphics.drawString(font, Component.translatable(TranslationKeys.REDSTONE_CONTROL_LABEL), this.posX + 16, this.posY + 10, 0xffffff);
|
||||
// The label
|
||||
graphics.drawString(font, Component.translatable(TranslationKeys.REDSTONE_CONTROL_MODE).append(REDSTONE_MODES[redstoneMode]), this.posX + 4, this.posY + 26, 0xffffff);
|
||||
} else {
|
||||
graphics.blit(this.texture, this.posX, this.posY, this.tabU, this.tabV, this.tabWidth, this.tabHeight);
|
||||
|
||||
if (this.posX <= mx && mx < this.posX + this.tabWidth && this.posY <= my && my < this.posY + this.tabHeight) {
|
||||
graphics.renderTooltip(font, REDSTONE_CONTROL_LABEL, mx, my);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
// relative xy
|
||||
int mx = (int) mouseX;
|
||||
int my = (int) mouseY;
|
||||
var rx = mx - this.posX;
|
||||
var ry = my - this.posY;
|
||||
|
||||
float percentage = this.expanded ? 1.0f - this.percentage : this.percentage;
|
||||
|
||||
if (0 <= rx && rx < getWidth(percentage) && 0 <= ry && ry < getHeight(percentage)) {
|
||||
if (this.expanded) {
|
||||
if (this.buttonsPosY <= my && my < this.buttonsPosY + 16) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
int buttonStartX = this.buttonsPosX + (i * 19);
|
||||
|
||||
if (buttonStartX <= mx && mx < buttonStartX + 16) {
|
||||
setRedstoneMode(i);
|
||||
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.05f));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.lastClicked == -1L && rx < this.tabWidth && ry < this.tabHeight) {
|
||||
this.lastClicked = System.currentTimeMillis();
|
||||
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0f));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setRedstoneMode(int redstoneMode) {
|
||||
this.screen.getMenu().clickMenuButton(Minecraft.getInstance().player, redstoneMode);
|
||||
Minecraft.getInstance().gameMode.handleInventoryButtonClick(this.screen.getMenu().containerId, redstoneMode);
|
||||
}
|
||||
|
||||
private void drawPartialConfig(GuiGraphics graphics) {
|
||||
float percentage = this.expanded ? 1.0f - this.percentage : this.percentage;
|
||||
// top left without edge
|
||||
int width = getWidth(percentage) - 3;
|
||||
int height = getHeight(percentage) - 3;
|
||||
// edge
|
||||
int edgeU = this.expandedU + this.expandedWidth - 3;
|
||||
int edgeV = this.expandedV + this.expandedHeight - 3;
|
||||
|
||||
// top left section (no edges)
|
||||
graphics.blit(this.texture, this.posX, this.posY, this.expandedU, this.expandedV, width, height);
|
||||
// bottom edge
|
||||
graphics.blit(this.texture, this.posX, this.posY + height, this.expandedU, edgeV, width, 3);
|
||||
// right edge
|
||||
graphics.blit(this.texture, this.posX + width, this.posY, edgeU, this.expandedV, 3, height);
|
||||
// bottom right corner
|
||||
graphics.blit(this.texture, this.posX + width, this.posY + height, edgeU, edgeV, 3, 3);
|
||||
}
|
||||
|
||||
public int getWidth(float percentage) {
|
||||
return this.tabWidth + Math.round((this.expandedWidth - this.tabWidth) * percentage);
|
||||
}
|
||||
|
||||
public int getHeight(float percentage) {
|
||||
return this.tabHeight + Math.round((this.expandedHeight - this.tabHeight) * percentage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocused(boolean pFocused) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFocused() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NarrationPriority narrationPriority() {
|
||||
return NarrationPriority.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNarration(NarrationElementOutput narration) {
|
||||
}
|
||||
|
||||
public List<Rect2i> getJeiBounds() {
|
||||
float percentage = this.expanded ? 1.0f - this.percentage : this.percentage;
|
||||
return List.of(new Rect2i(this.posX, this.posY, getWidth(percentage), getHeight(percentage)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Ex Deorum
|
||||
* Copyright (c) 2023 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.client.screen;
|
||||
|
|
@ -50,6 +50,7 @@ public class InfestedLeavesRenderer implements BlockEntityRenderer<InfestedLeave
|
|||
int progress = Math.min((int) (te.getProgress() * 16000), 16000);
|
||||
// Render
|
||||
var model = mc.getBlockRenderer().getBlockModel(state);
|
||||
mc.getBlockRenderer().getModelRenderer().tesselateBlock(level, model, state, te.getBlockPos(), stack, buffer.getBuffer(RenderUtil.TINTED_CUTOUT_MIPPED), false, level.random, 42L, progress, ModelData.EMPTY, null);
|
||||
var pos = te.getBlockPos();
|
||||
mc.getBlockRenderer().getModelRenderer().tesselateBlock(level, model, state, pos, stack, buffer.getBuffer(RenderUtil.TINTED_CUTOUT_MIPPED), false, level.random, state.getSeed(pos), progress, ModelData.EMPTY, null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,32 +22,29 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
|||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import thedarkcolour.exdeorum.blockentity.SieveBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.AbstractSieveBlockEntity;
|
||||
import thedarkcolour.exdeorum.client.RenderUtil;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SieveRenderer implements BlockEntityRenderer<SieveBlockEntity> {
|
||||
public static final Map<Item, TextureAtlasSprite> MESH_TEXTURES = new IdentityHashMap<>();
|
||||
|
||||
public SieveRenderer(BlockEntityRendererProvider.Context ctx) {}
|
||||
public class SieveRenderer<T extends AbstractSieveBlockEntity> implements BlockEntityRenderer<T> {
|
||||
public static final Map<Item, TextureAtlasSprite> MESH_TEXTURES = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void render(SieveBlockEntity sieve, float partialTicks, PoseStack stack, MultiBufferSource buffers, int light, int overlay) {
|
||||
public void render(T sieve, float partialTicks, PoseStack stack, MultiBufferSource buffers, int light, int overlay) {
|
||||
var contents = sieve.getContents();
|
||||
|
||||
if (!contents.isEmpty() && contents.getItem() instanceof BlockItem blockItem) {
|
||||
var block = blockItem.getBlock();
|
||||
var percentage = (float) sieve.getProgress() / 100.0f;
|
||||
var percentage = sieve.getProgress();
|
||||
var face = RenderUtil.getTopFace(block);
|
||||
face.renderFlatSpriteLerp(buffers, stack, percentage, 0xff, 0xff, 0xff, light, 1.0f, 13f, 15f);
|
||||
face.renderFlatSpriteLerp(buffers, stack, percentage, 0xff, 0xff, 0xff, light, 1.0f, 15f, 13f);
|
||||
}
|
||||
|
||||
var mesh = sieve.getMesh();
|
||||
|
|
@ -56,20 +53,20 @@ public class SieveRenderer implements BlockEntityRenderer<SieveBlockEntity> {
|
|||
var builder = buffers.getBuffer(RenderType.cutoutMipped());
|
||||
var meshItem = mesh.getItem();
|
||||
|
||||
TextureAtlasSprite sprite;
|
||||
TextureAtlasSprite meshSprite;
|
||||
if (MESH_TEXTURES.containsKey(meshItem)) {
|
||||
sprite = MESH_TEXTURES.get(meshItem);
|
||||
meshSprite = MESH_TEXTURES.get(meshItem);
|
||||
} else {
|
||||
ResourceLocation registryName = ForgeRegistries.ITEMS.getKey(meshItem);
|
||||
ResourceLocation textureLoc = registryName.withPrefix("item/mesh/");
|
||||
sprite = RenderUtil.blockAtlas.getSprite(textureLoc);
|
||||
MESH_TEXTURES.put(meshItem, sprite);
|
||||
meshSprite = RenderUtil.blockAtlas.getSprite(textureLoc);
|
||||
MESH_TEXTURES.put(meshItem, meshSprite);
|
||||
}
|
||||
|
||||
RenderUtil.renderFlatSprite(builder, stack, 0.75f, 0xff, 0xff, 0xff, sprite, light, 1f);
|
||||
RenderUtil.renderFlatSprite(builder, stack, 0.75f, 0xff, 0xff, 0xff, meshSprite, light, 1f);
|
||||
|
||||
if (mesh.hasFoil()) {
|
||||
RenderUtil.renderFlatSprite(buffers.getBuffer(RenderType.glint()), stack, 0.75f, 0xff, 0xff, 0xff, sprite, light, 1f);
|
||||
RenderUtil.renderFlatSprite(buffers.getBuffer(RenderType.glint()), stack, 0.75f, 0xff, 0xff, 0xff, meshSprite, light, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Ex Deorum
|
||||
* Copyright (c) 2023 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
|
||||
|
|
@ -16,13 +16,11 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package thedarkcolour.exdeorum.compat.jei;
|
||||
package thedarkcolour.exdeorum.compat;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Multimap;
|
||||
import mezz.jei.api.recipe.RecipeType;
|
||||
import mezz.jei.api.registration.IRecipeRegistration;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.util.Mth;
|
||||
|
|
@ -41,10 +39,11 @@ import java.util.Comparator;
|
|||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
record JeiSieveRecipeGroup(Ingredient ingredient, ItemStack mesh, List<Result> results) {
|
||||
// Since no JEI code is used here, this can be reused for REI
|
||||
public record GroupedSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Result> results) {
|
||||
public static int maxSieveRows;
|
||||
|
||||
public static void addGroupedRecipes(IRecipeRegistration registration, RecipeType<JeiSieveRecipeGroup> recipeType) {
|
||||
public static ImmutableList<GroupedSieveRecipe> getAllRecipesGrouped() {
|
||||
maxSieveRows = 1;
|
||||
|
||||
// copy the list so we can do removals
|
||||
|
|
@ -67,11 +66,11 @@ record JeiSieveRecipeGroup(Ingredient ingredient, ItemStack mesh, List<Result> r
|
|||
}
|
||||
}
|
||||
|
||||
ImmutableList.Builder<JeiSieveRecipeGroup> 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(JeiSieveRecipeGroup::meshOrder);
|
||||
var meshSorter = Comparator.comparingInt(GroupedSieveRecipe::meshOrder);
|
||||
|
||||
// ingredients with common ingredients are grouped into lists (ex. dirt)
|
||||
for (var ingredient : ingredientGrouper.keySet()) {
|
||||
|
|
@ -93,12 +92,12 @@ record JeiSieveRecipeGroup(Ingredient ingredient, ItemStack mesh, List<Result> r
|
|||
|
||||
for (var recipe : meshRecipes) {
|
||||
int resultCount = recipe.resultAmount instanceof ConstantValue constant ? Math.round(constant.value) : 1;
|
||||
results.add(new Result(new ItemStack(recipe.result, resultCount), recipe.resultAmount));
|
||||
results.add(new Result(new ItemStack(recipe.result, resultCount), recipe.resultAmount, recipe.byHandOnly));
|
||||
}
|
||||
|
||||
results.sort(resultSorter);
|
||||
|
||||
var jeiRecipe = new JeiSieveRecipeGroup(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);
|
||||
|
|
@ -107,10 +106,10 @@ record JeiSieveRecipeGroup(Ingredient ingredient, ItemStack mesh, List<Result> r
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
registration.addRecipes(recipeType, jeiRecipes.build());
|
||||
return jeiRecipes.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static int meshOrder(Item mesh) {
|
||||
if (mesh == EItems.STRING_MESH.get()) {
|
||||
return -5;
|
||||
|
|
@ -129,14 +128,16 @@ record JeiSieveRecipeGroup(Ingredient ingredient, ItemStack mesh, List<Result> r
|
|||
}
|
||||
}
|
||||
|
||||
static final class Result {
|
||||
final ItemStack item;
|
||||
final NumberProvider provider;
|
||||
final double expectedCount;
|
||||
public static final class Result {
|
||||
public final ItemStack item;
|
||||
public final NumberProvider provider;
|
||||
public final boolean byHandOnly;
|
||||
private final double expectedCount;
|
||||
|
||||
Result(ItemStack item, NumberProvider provider) {
|
||||
Result(ItemStack item, NumberProvider provider, boolean byHandOnly) {
|
||||
this.item = item;
|
||||
this.provider = provider;
|
||||
this.byHandOnly = byHandOnly;
|
||||
this.expectedCount = RecipeUtil.getExpectedValue(this.provider);
|
||||
}
|
||||
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package thedarkcolour.exdeorum.compat.jei;
|
||||
|
||||
import com.mojang.blaze3d.platform.Lighting;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
|
|
@ -28,16 +27,10 @@ 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.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.texture.OverlayTexture;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.joml.Matrix4f;
|
||||
import thedarkcolour.exdeorum.client.ClientHandler;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
import thedarkcolour.exdeorum.recipe.barrel.BarrelCompostRecipe;
|
||||
|
|
@ -86,7 +79,7 @@ class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
|
|||
|
||||
@Override
|
||||
public void draw(BarrelCompostRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
|
||||
slot.draw(graphics);
|
||||
this.slot.draw(graphics);
|
||||
|
||||
var volume = recipe.getVolume();
|
||||
var volumeLabel = Component.translatable(TranslationKeys.BARREL_COMPOST_RECIPE_VOLUME, volume);
|
||||
|
|
@ -112,40 +105,10 @@ class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
|
|||
// From mezz.jei.library.render.ItemStackRenderer
|
||||
RenderSystem.enableDepthTest();
|
||||
|
||||
// From GuiGraphics.renderFakeItem
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
var model = mc.getModelManager().getModel(ClientHandler.OAK_BARREL_COMPOSTING);
|
||||
var pose = guiGraphics.pose();
|
||||
pose.pushPose();
|
||||
pose.translate(8 + xOffset, 8 + yOffset, 150);
|
||||
|
||||
try {
|
||||
pose.mulPoseMatrix((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(oakBarrel, ItemDisplayContext.GUI, false, pose, guiGraphics.bufferSource(), 0xf000f0, OverlayTexture.NO_OVERLAY, model);
|
||||
guiGraphics.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(oakBarrel.getItem());
|
||||
});
|
||||
crashreportcategory.setDetail("Registry Name", () -> "exdeorum:oak_barrel");
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
|
||||
pose.popPose();
|
||||
|
||||
// From end of ItemStackRenderer
|
||||
RenderSystem.disableBlend();
|
||||
// From GuiGraphics.renderFakeItem
|
||||
ClientJeiUtil.renderItemAlternativeModel(guiGraphics, model, this.oakBarrel, xOffset, yOffset);
|
||||
// From end of DrawableIngredient
|
||||
RenderSystem.disableDepthTest();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,17 +24,29 @@ import com.mojang.blaze3d.vertex.BufferBuilder;
|
|||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.Tesselator;
|
||||
import com.mojang.math.Axis;
|
||||
import mezz.jei.api.gui.ingredient.IRecipeSlotTooltipCallback;
|
||||
import mezz.jei.api.gui.ingredient.IRecipeSlotView;
|
||||
import mezz.jei.api.ingredients.IIngredientRenderer;
|
||||
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.GameRenderer;
|
||||
import net.minecraft.client.renderer.ItemBlockRenderTypes;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
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.world.inventory.InventoryMenu;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
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;
|
||||
|
|
@ -45,11 +57,17 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
|
|||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class ClientJeiUtil {
|
||||
private static final FluidState EMPTY = Fluids.EMPTY.defaultFluidState();
|
||||
private static final BlockState AIR = Blocks.AIR.defaultBlockState();
|
||||
|
||||
private static final IIngredientRenderer<ItemStack> ASTERISK_RENDERER = AsteriskRenderer.INSTANCE;
|
||||
|
||||
// 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) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
|
@ -105,6 +123,53 @@ class ClientJeiUtil {
|
|||
poseStack.popPose();
|
||||
}
|
||||
|
||||
static void renderItemWithAsterisk(GuiGraphics graphics, ItemStack stack, int xOffset, int yOffset) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
BakedModel model = mc.getItemRenderer().getModel(stack, mc.level, null, 0);
|
||||
renderItemAlternativeModel(graphics, model, stack, xOffset, yOffset);
|
||||
graphics.pose().pushPose();
|
||||
graphics.pose().translate(0f, 0f, 200f);
|
||||
// 0xff5555 is Minecraft's red text color.
|
||||
graphics.drawString(mc.font, "*", xOffset + 19 - 2 - mc.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.mulPoseMatrix((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();
|
||||
}
|
||||
|
||||
private enum Dummy implements BlockAndTintGetter {
|
||||
INSTANCE;
|
||||
|
||||
|
|
@ -162,4 +227,32 @@ class ClientJeiUtil {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
enum AsteriskRenderer implements IIngredientRenderer<ItemStack> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public void render(GuiGraphics graphics, ItemStack ingredient) {
|
||||
// From mezz.jei.library.render.ItemStackRenderer
|
||||
RenderSystem.enableDepthTest();
|
||||
ClientJeiUtil.renderItemWithAsterisk(graphics, ingredient, 0, 0);
|
||||
// From end of DrawableIngredient
|
||||
RenderSystem.disableDepthTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Component> getTooltip(ItemStack ingredient, TooltipFlag tooltipFlag) {
|
||||
// Copied from ItemStackRenderer
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
Player player = minecraft.player;
|
||||
try {
|
||||
return ingredient.getTooltipLines(player, tooltipFlag);
|
||||
} catch (RuntimeException | LinkageError e) {
|
||||
List<Component> list = new ArrayList<>();
|
||||
MutableComponent crash = Component.translatable("jei.tooltip.error.crash");
|
||||
list.add(crash.withStyle(ChatFormatting.RED));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,15 @@ import mezz.jei.api.IModPlugin;
|
|||
import mezz.jei.api.JeiPlugin;
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.forge.ForgeTypes;
|
||||
import mezz.jei.api.gui.handlers.IGuiClickableArea;
|
||||
import mezz.jei.api.gui.handlers.IGuiContainerHandler;
|
||||
import mezz.jei.api.recipe.RecipeType;
|
||||
import mezz.jei.api.registration.IGuiHandlerRegistration;
|
||||
import mezz.jei.api.registration.IRecipeCatalystRegistration;
|
||||
import mezz.jei.api.registration.IRecipeCategoryRegistration;
|
||||
import mezz.jei.api.registration.IRecipeRegistration;
|
||||
import mezz.jei.api.registration.IVanillaCategoryExtensionRegistration;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.Rect2i;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.Container;
|
||||
|
|
@ -44,8 +47,9 @@ import net.minecraft.world.level.block.WallTorchBlock;
|
|||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.block.SieveBlock;
|
||||
import thedarkcolour.exdeorum.blockentity.LavaCrucibleBlockEntity;
|
||||
import thedarkcolour.exdeorum.client.screen.MechanicalSieveScreen;
|
||||
import thedarkcolour.exdeorum.compat.GroupedSieveRecipe;
|
||||
import thedarkcolour.exdeorum.compat.ModIds;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
import thedarkcolour.exdeorum.item.WateringCanItem;
|
||||
|
|
@ -62,6 +66,7 @@ import thedarkcolour.exdeorum.registry.ERecipeTypes;
|
|||
import thedarkcolour.exdeorum.tag.EItemTags;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
|
@ -76,7 +81,7 @@ public class ExDeorumJeiPlugin implements IModPlugin {
|
|||
static final RecipeType<CrucibleRecipe> LAVA_CRUCIBLE = RecipeType.create(ExDeorum.ID, "lava_crucible", CrucibleRecipe.class);
|
||||
static final RecipeType<CrucibleRecipe> WATER_CRUCIBLE = RecipeType.create(ExDeorum.ID, "water_crucible", CrucibleRecipe.class);
|
||||
static final RecipeType<CrucibleHeatSourceRecipe> CRUCIBLE_HEAT_SOURCES = RecipeType.create(ExDeorum.ID, "crucible_heat_sources", CrucibleHeatSourceRecipe.class);
|
||||
static final RecipeType<JeiSieveRecipeGroup> SIEVE = RecipeType.create(ExDeorum.ID, "sieve", JeiSieveRecipeGroup.class);
|
||||
static final RecipeType<GroupedSieveRecipe> SIEVE = RecipeType.create(ExDeorum.ID, "sieve", GroupedSieveRecipe.class);
|
||||
static final RecipeType<HammerRecipe> HAMMER = RecipeType.create(ExDeorum.ID, "hammer", HammerRecipe.class);
|
||||
|
||||
@Override
|
||||
|
|
@ -114,7 +119,8 @@ public class ExDeorumJeiPlugin implements IModPlugin {
|
|||
EItems.CHERRY_SIEVE.get(),
|
||||
EItems.BAMBOO_SIEVE.get(),
|
||||
EItems.CRIMSON_SIEVE.get(),
|
||||
EItems.WARPED_SIEVE.get()
|
||||
EItems.WARPED_SIEVE.get(),
|
||||
EItems.MECHANICAL_SIEVE.get()
|
||||
);
|
||||
var lavaCrucibles = Lists.newArrayList(
|
||||
EItems.PORCELAIN_CRUCIBLE.get(),
|
||||
|
|
@ -214,6 +220,7 @@ public class ExDeorumJeiPlugin implements IModPlugin {
|
|||
public void registerRecipes(IRecipeRegistration registration) {
|
||||
registration.addItemStackInfo(new ItemStack(EItems.SILK_WORM.get()), Component.translatable(TranslationKeys.SILK_WORM_JEI_INFO));
|
||||
registration.addItemStackInfo(List.of(new ItemStack(EBlocks.OAK_SIEVE.get()), new ItemStack(EBlocks.SPRUCE_SIEVE.get()), new ItemStack(EBlocks.BIRCH_SIEVE.get()), new ItemStack(EBlocks.JUNGLE_SIEVE.get()), new ItemStack(EBlocks.ACACIA_SIEVE.get()), new ItemStack(EBlocks.DARK_OAK_SIEVE.get()), new ItemStack(EBlocks.MANGROVE_SIEVE.get()), new ItemStack(EBlocks.CHERRY_SIEVE.get()), new ItemStack(EBlocks.BAMBOO_SIEVE.get()), new ItemStack(EBlocks.CRIMSON_SIEVE.get()), new ItemStack(EBlocks.WARPED_SIEVE.get())), Component.translatable(TranslationKeys.SIEVE_JEI_INFO));
|
||||
registration.addItemStackInfo(List.of(new ItemStack(EItems.STRING_MESH.get()), new ItemStack(EItems.STRING_MESH.get()), new ItemStack(EItems.FLINT_MESH.get()), new ItemStack(EItems.IRON_MESH.get()), new ItemStack(EItems.GOLDEN_MESH.get()), new ItemStack(EItems.DIAMOND_MESH.get()), new ItemStack(EItems.NETHERITE_MESH.get())), Component.translatable(TranslationKeys.SIEVE_MESH_JEI_INFO));
|
||||
registration.addItemStackInfo(List.of(WateringCanItem.getFull(EItems.WOODEN_WATERING_CAN), WateringCanItem.getFull(EItems.STONE_WATERING_CAN), WateringCanItem.getFull(EItems.IRON_WATERING_CAN), WateringCanItem.getFull(EItems.GOLDEN_WATERING_CAN), WateringCanItem.getFull(EItems.DIAMOND_WATERING_CAN), WateringCanItem.getFull(EItems.NETHERITE_WATERING_CAN)), Component.translatable(TranslationKeys.WATERING_CAN_JEI_INFO));
|
||||
var witchWaterInfo = Component.translatable(TranslationKeys.WITCH_WATER_JEI_INFO);
|
||||
registration.addItemStackInfo(List.of(new ItemStack(EItems.WITCH_WATER_BUCKET.get()), new ItemStack(EItems.PORCELAIN_WITCH_WATER_BUCKET.get())), witchWaterInfo);
|
||||
|
|
@ -223,6 +230,7 @@ public class ExDeorumJeiPlugin implements IModPlugin {
|
|||
registration.addItemStackInfo(new ItemStack(EItems.WARPED_NYLIUM_SPORES.get()), Component.translatable(TranslationKeys.WARPED_NYLIUM_SPORES_JEI_INFO));
|
||||
registration.addItemStackInfo(new ItemStack(EItems.CRIMSON_NYLIUM_SPORES.get()), Component.translatable(TranslationKeys.CRIMSON_NYLIUM_SPORES_JEI_INFO));
|
||||
registration.addItemStackInfo(new ItemStack(EItems.SCULK_CORE.get()), Component.translatable(TranslationKeys.SCULK_CORE_JEI_INFO));
|
||||
registration.addItemStackInfo(new ItemStack(EItems.MECHANICAL_SIEVE.get()), Component.translatable(TranslationKeys.MECHANICAL_SIEVE_JEI_INFO));
|
||||
|
||||
var toRemove = new ArrayList<ItemStack>();
|
||||
|
||||
|
|
@ -250,7 +258,7 @@ public class ExDeorumJeiPlugin implements IModPlugin {
|
|||
addRecipes(registration, LAVA_CRUCIBLE, ERecipeTypes.LAVA_CRUCIBLE);
|
||||
addRecipes(registration, WATER_CRUCIBLE, ERecipeTypes.WATER_CRUCIBLE);
|
||||
addRecipes(registration, HAMMER, ERecipeTypes.HAMMER);
|
||||
JeiSieveRecipeGroup.addGroupedRecipes(registration, SIEVE);
|
||||
registration.addRecipes(SIEVE, GroupedSieveRecipe.getAllRecipesGrouped());
|
||||
|
||||
addCrucibleHeatSources(registration);
|
||||
}
|
||||
|
|
@ -296,8 +304,24 @@ public class ExDeorumJeiPlugin implements IModPlugin {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void registerVanillaCategoryExtensions(IVanillaCategoryExtensionRegistration registration) {
|
||||
IModPlugin.super.registerVanillaCategoryExtensions(registration);
|
||||
public void registerGuiHandlers(IGuiHandlerRegistration registration) {
|
||||
// see addRecipeClickArea for reference
|
||||
registration.addGuiContainerHandler(MechanicalSieveScreen.class, new IGuiContainerHandler<>() {
|
||||
@Override
|
||||
public Collection<IGuiClickableArea> getGuiClickableAreas(MechanicalSieveScreen containerScreen, double mouseX, double mouseY) {
|
||||
IGuiClickableArea clickableArea = IGuiClickableArea.createBasic(MechanicalSieveScreen.RECIPE_CLICK_AREA_POS_X, MechanicalSieveScreen.RECIPE_CLICK_AREA_POS_Y, MechanicalSieveScreen.RECIPE_CLICK_AREA_WIDTH, MechanicalSieveScreen.RECIPE_CLICK_AREA_HEIGHT, SIEVE);
|
||||
return List.of(clickableArea);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Rect2i> getGuiExtraAreas(MechanicalSieveScreen containerScreen) {
|
||||
var widget = containerScreen.getRedstoneControlWidget();
|
||||
if (widget != null) {
|
||||
return widget.getJeiBounds();
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <C extends Container, T extends Recipe<C>> void addRecipes(IRecipeRegistration registration, RecipeType<T> category, Supplier<net.minecraft.world.item.crafting.RecipeType<T>> type) {
|
||||
|
|
@ -353,7 +377,8 @@ public class ExDeorumJeiPlugin implements IModPlugin {
|
|||
EItems.CHERRY_SIEVE.get(),
|
||||
EItems.BAMBOO_SIEVE.get(),
|
||||
EItems.CRIMSON_SIEVE.get(),
|
||||
EItems.WARPED_SIEVE.get()
|
||||
EItems.WARPED_SIEVE.get(),
|
||||
EItems.MECHANICAL_SIEVE.get()
|
||||
);
|
||||
|
||||
return sieves;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,6 @@ class HammerCategory extends OneToOneCategory<HammerRecipe> {
|
|||
@Override
|
||||
protected void addOutput(IRecipeSlotBuilder slot, HammerRecipe recipe) {
|
||||
slot.addItemStack(new ItemStack(recipe.result));
|
||||
SieveCategory.addTooltips(slot, recipe.resultAmount);
|
||||
SieveCategory.addTooltips(slot, false, recipe.resultAmount);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
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;
|
||||
import mezz.jei.api.gui.drawable.IDrawable;
|
||||
|
|
@ -36,14 +38,17 @@ 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.minecraftforge.common.util.Lazy;
|
||||
import thedarkcolour.exdeorum.compat.GroupedSieveRecipe;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
||||
import thedarkcolour.exdeorum.registry.EBlocks;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
class SieveCategory implements IRecipeCategory<JeiSieveRecipeGroup> {
|
||||
class SieveCategory implements IRecipeCategory<GroupedSieveRecipe> {
|
||||
private static final DecimalFormat FORMATTER = new DecimalFormat();
|
||||
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;
|
||||
|
||||
|
|
@ -59,7 +64,7 @@ class SieveCategory implements IRecipeCategory<JeiSieveRecipeGroup> {
|
|||
private final Component title;
|
||||
|
||||
public SieveCategory(IGuiHelper helper) {
|
||||
this.background = Lazy.of(() -> helper.createBlankDrawable(WIDTH, ROW_START + 18 * JeiSieveRecipeGroup.maxSieveRows));
|
||||
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(EBlocks.OAK_SIEVE.get()));
|
||||
|
|
@ -67,7 +72,7 @@ class SieveCategory implements IRecipeCategory<JeiSieveRecipeGroup> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public RecipeType<JeiSieveRecipeGroup> getRecipeType() {
|
||||
public RecipeType<GroupedSieveRecipe> getRecipeType() {
|
||||
return ExDeorumJeiPlugin.SIEVE;
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +92,7 @@ class SieveCategory implements IRecipeCategory<JeiSieveRecipeGroup> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setRecipe(IRecipeLayoutBuilder builder, JeiSieveRecipeGroup 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());
|
||||
|
||||
|
|
@ -95,56 +100,63 @@ class SieveCategory implements IRecipeCategory<JeiSieveRecipeGroup> {
|
|||
var result = recipe.results().get(i);
|
||||
var slot = builder.addSlot(RecipeIngredientRole.OUTPUT, 1 + (i % 9) * 18, 1 + ROW_START + 18 * (i / 9)).addItemStack(result.item);
|
||||
|
||||
addTooltips(slot, result.provider);
|
||||
addTooltips(slot, result.byHandOnly, result.provider);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addTooltips(IRecipeSlotBuilder slot, NumberProvider 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.AsteriskRenderer.INSTANCE);
|
||||
}
|
||||
if (provider instanceof BinomialDistributionGenerator binomial) {
|
||||
if (binomial.n instanceof ConstantValue constant && constant.value == 1) {
|
||||
var chance = FORMATTER.format(RecipeUtil.getExpectedValue(binomial.p) * 100);
|
||||
slot.addTooltipCallback((slotView, tooltip) -> tooltip.add(Component.translatable(TranslationKeys.SIEVE_RECIPE_CHANCE, chance).withStyle(ChatFormatting.GRAY)));
|
||||
tooltipLines.add(Component.translatable(TranslationKeys.SIEVE_RECIPE_CHANCE, chance).withStyle(ChatFormatting.GRAY));
|
||||
} else {
|
||||
addAvgOutput(slot, RecipeUtil.getExpectedValue(provider));
|
||||
addAvgOutput(tooltipLines, RecipeUtil.getExpectedValue(provider));
|
||||
}
|
||||
|
||||
addMinMaxes(slot, ConstantValue.exactly(0), binomial.n);
|
||||
addMinMaxes(tooltipLines, ConstantValue.exactly(0), binomial.n);
|
||||
} else if (provider.getClass() != ConstantValue.class) {
|
||||
var val = RecipeUtil.getExpectedValue(provider);
|
||||
if (val != -1.0) {
|
||||
addAvgOutput(slot, val);
|
||||
addAvgOutput(tooltipLines, val);
|
||||
|
||||
if (provider instanceof UniformGenerator uniform) {
|
||||
addMinMaxes(slot, uniform.min, uniform.max);
|
||||
addMinMaxes(tooltipLines, uniform.min, uniform.max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addAvgOutput(IRecipeSlotBuilder slot, double avgValue) {
|
||||
String avgOutput = FORMATTER.format(avgValue);
|
||||
slot.addTooltipCallback((slotView, tooltip) -> tooltip.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(IRecipeSlotBuilder slot, NumberProvider min, NumberProvider max) {
|
||||
var minFormatted = FORMATTER.format(RecipeUtil.getExpectedValue(min));
|
||||
var maxFormatted = FORMATTER.format(RecipeUtil.getExpectedValue(max));
|
||||
|
||||
var tooltipLinesList = tooltipLines.build();
|
||||
slot.addTooltipCallback((slotView, tooltip) -> {
|
||||
//if (Screen.hasShiftDown()) {
|
||||
tooltip.add(Component.translatable(TranslationKeys.SIEVE_RECIPE_MIN_OUTPUT, minFormatted).withStyle(ChatFormatting.GRAY));
|
||||
tooltip.add(Component.translatable(TranslationKeys.SIEVE_RECIPE_MAX_OUTPUT, maxFormatted).withStyle(ChatFormatting.GRAY));
|
||||
//}
|
||||
tooltip.addAll(tooltipLinesList);
|
||||
});
|
||||
}
|
||||
|
||||
private static void addAvgOutput(ImmutableList.Builder<Component> tooltipLines, double avgValue) {
|
||||
String avgOutput = 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, NumberProvider min, NumberProvider max) {
|
||||
var minFormatted = FORMATTER.format(RecipeUtil.getExpectedValue(min));
|
||||
var maxFormatted = FORMATTER.format(RecipeUtil.getExpectedValue(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(JeiSieveRecipeGroup 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);
|
||||
|
||||
for (int i = 0; i < JeiSieveRecipeGroup.maxSieveRows; i++) {
|
||||
for (int i = 0; i < GroupedSieveRecipe.maxSieveRows; i++) {
|
||||
this.row.draw(graphics, 0, 28 + i * 18);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public class ExDeorumInfoProvider implements IProbeInfoProvider {
|
|||
}
|
||||
} else if (te instanceof SieveBlockEntity sieve) {
|
||||
if (!sieve.getContents().isEmpty()) {
|
||||
info.text(CompoundText.create().style(TextStyleClass.LABEL).text("Progress: ").style(TextStyleClass.WARNING).text((100 - sieve.getProgress()) + "%"));
|
||||
info.text(CompoundText.create().style(TextStyleClass.LABEL).text("Progress: ").style(TextStyleClass.WARNING).text((Math.round(1000 * sieve.getProgress()) / 10) + "%"));
|
||||
}
|
||||
if (playerEntity.isShiftKeyDown()) {
|
||||
var mesh = sieve.getMesh();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import net.minecraftforge.common.ForgeConfigSpec;
|
|||
import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
|
||||
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
|
||||
import net.minecraftforge.common.ForgeConfigSpec.DoubleValue;
|
||||
import net.minecraftforge.common.ForgeConfigSpec.IntValue;
|
||||
import org.apache.commons.lang3.text.WordUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import thedarkcolour.exdeorum.compat.ModIds;
|
||||
|
|
@ -117,6 +118,7 @@ public class EConfig {
|
|||
public final BooleanValue startingTorch;
|
||||
public final BooleanValue startingWateringCan;
|
||||
public final BooleanValue simultaneousSieveUsage;
|
||||
public final IntValue simultaneousSieveUsageRange;
|
||||
public final BooleanValue automatedSieves;
|
||||
public final DoubleValue barrelProgressStep;
|
||||
public final BooleanValue witchWaterNetherrackGenerator;
|
||||
|
|
@ -126,6 +128,10 @@ public class EConfig {
|
|||
public final BooleanValue limitMossSieveDrops;
|
||||
public final BooleanValue allowWaterBottleTransfer;
|
||||
public final BooleanValue allowWitchWaterEntityConversion;
|
||||
public final IntValue mechanicalSieveEnergyStorage;
|
||||
public final IntValue mechanicalSieveEnergyConsumption;
|
||||
//public final IntValue mechanicalHammerEnergyStorage;
|
||||
//public final IntValue mechanicalHammerEnergyConsumption;
|
||||
|
||||
public Server(ForgeConfigSpec.Builder builder) {
|
||||
builder.comment("Server configuration for Ex Deorum").push("server");
|
||||
|
|
@ -137,8 +143,11 @@ public class EConfig {
|
|||
.comment("Whether players in a void world start out with a full wooden watering can.")
|
||||
.define("starting_watering_can", true);
|
||||
this.simultaneousSieveUsage = builder
|
||||
.comment("Whether players can use multiple sieves in a 3x3 area at once.")
|
||||
.comment("Whether players can use multiple sieves in a 3x3 or larger area at once.")
|
||||
.define("simultaneous_sieve_usage", true);
|
||||
this.simultaneousSieveUsageRange = builder
|
||||
.comment("The range from which simultaneous sieve usage can reach. 1 means a maximum of 3x3 sieves at once, 2 means a maximum of 5x5, 3 means maximum of 7x7 simultaneous sieves, and so on.")
|
||||
.defineInRange("simultaneous_sieve_range", 2, 0, 6);
|
||||
this.automatedSieves = builder
|
||||
.comment("Whether machines/fake players can interact with the Sieve.")
|
||||
.define("automated_sieves", false);
|
||||
|
|
@ -166,6 +175,18 @@ public class EConfig {
|
|||
this.allowWitchWaterEntityConversion = builder
|
||||
.comment("Whether the entity conversion mechanic of Witch Water is enabled. If enabled, when an entity steps into Witch Water, the following conversions may happen: Villager -> Zombie Villager, Cleric Villager -> Witch, Skeleton -> Wither Skeleton, Creeper -> Charged Creeper, Spider -> Cave Spider, Pig & Piglin -> Zombified Piglin, Squid -> Ghast, Mooshroom -> Brown Mooshroom, Axolotl -> Blue Axolotl, Rabbit -> Killer Rabbit, Pufferfish -> Guardian, Horse -> Skeleton/Zombie Horse")
|
||||
.define("allow_witch_water_entity_conversion", true);
|
||||
this.mechanicalSieveEnergyStorage = builder
|
||||
.comment("The maximum amount of FE the mechanical sieve can have in its energy storage.")
|
||||
.defineInRange("mechanical_sieve_energy_storage", 40_000, 0, Integer.MAX_VALUE);
|
||||
this.mechanicalSieveEnergyConsumption = builder
|
||||
.comment("The amount of FE/t a tick consumed by the mechanical sieve when sifting a block.")
|
||||
.defineInRange("mechanical_sieve_energy_consumption", 40, 0, Integer.MAX_VALUE);
|
||||
//this.mechanicalHammerEnergyStorage = builder
|
||||
// .comment("The maximum amount of FE the mechanical hammer can have in its energy storage.")
|
||||
// .defineInRange("mechanical_hammer_energy_storage", 40_000, 0, Integer.MAX_VALUE);
|
||||
//this.mechanicalHammerEnergyConsumption = builder
|
||||
// .comment("The amount of FE/t a tick consumed by the mechanical hammer when sifting a block.")
|
||||
// .defineInRange("mechanical_hammer_energy_consumption", 40, 0, Integer.MAX_VALUE);
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@ import net.minecraft.world.level.storage.loot.LootTable;
|
|||
import net.minecraft.world.level.storage.loot.entries.LootItem;
|
||||
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.loot.InfestedStringCount;
|
||||
import thedarkcolour.exdeorum.loot.InfestedStringFunction;
|
||||
import thedarkcolour.exdeorum.loot.MachineLootFunction;
|
||||
import thedarkcolour.exdeorum.registry.EBlocks;
|
||||
import thedarkcolour.exdeorum.registry.EItems;
|
||||
import thedarkcolour.modkit.MKUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -52,10 +54,17 @@ class BlockLoot extends BlockLootSubProvider {
|
|||
}
|
||||
});
|
||||
|
||||
add(EBlocks.INFESTED_LEAVES.get(), new LootTable.Builder()
|
||||
.withPool(new LootPool.Builder()
|
||||
add(EBlocks.INFESTED_LEAVES.get(), LootTable.lootTable()
|
||||
.withPool(LootPool.lootPool()
|
||||
.setRolls(ConstantValue.exactly(1))
|
||||
.add(LootItem.lootTableItem(Items.STRING).apply(InfestedStringCount.infestedString()))));
|
||||
.add(LootItem.lootTableItem(Items.STRING)
|
||||
.apply(InfestedStringFunction.infestedString()))));
|
||||
// see createSingleItemTable() for reference
|
||||
add(EBlocks.MECHANICAL_SIEVE.get(), LootTable.lootTable()
|
||||
.withPool(applyExplosionCondition(EItems.MECHANICAL_SIEVE.get(), LootPool.lootPool()
|
||||
.setRolls(ConstantValue.exactly(1.0F))
|
||||
.add(LootItem.lootTableItem(EItems.MECHANICAL_SIEVE.get())
|
||||
.apply(MachineLootFunction.machineLoot())))));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
package thedarkcolour.exdeorum.data;
|
||||
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.client.screen.RedstoneControlWidget;
|
||||
import thedarkcolour.exdeorum.registry.EBlocks;
|
||||
import thedarkcolour.modkit.data.MKEnglishProvider;
|
||||
|
||||
|
|
@ -28,7 +29,9 @@ class English {
|
|||
|
||||
english.add(TranslationKeys.MAIN_CREATIVE_TAB, "Ex Deorum");
|
||||
english.add(TranslationKeys.VOID_WORLD_TYPE, "Void World");
|
||||
english.add(TranslationKeys.WATERING_CAN_FLUID_DISPLAY, ": %s / %s");
|
||||
english.add(TranslationKeys.FRACTION_DISPLAY, ": %s / %s");
|
||||
english.add(TranslationKeys.MECHANICAL_SIEVE_MESH_LABEL, "Mesh: ");
|
||||
english.add(TranslationKeys.ENERGY, "Energy");
|
||||
|
||||
english.add(TranslationKeys.ROOT_ADVANCEMENT_TITLE, "Don't Look Down...");
|
||||
english.add(TranslationKeys.ROOT_ADVANCEMENT_DESCRIPTION, "Spawn into a SkyBlock void world");
|
||||
|
|
@ -43,6 +46,7 @@ class English {
|
|||
|
||||
english.add(TranslationKeys.SILK_WORM_JEI_INFO, "Silk worms have a 1 in 100 chance to drop from leaves harvested with a Crook. Using a silk worm on a tree's leaves will infest them, gradually spreading through the entire tree. 100% infested leaves can be harvested for string, but do not drop saplings.");
|
||||
english.add(TranslationKeys.SIEVE_JEI_INFO, "Sieves are used to sift for items from soft blocks like gravel and dirt. A mesh is required to use the sieve. Meshes can be enchanted with Fortune and Efficiency. Sieves in a 3x3 area can be used simultaneously.");
|
||||
english.add(TranslationKeys.SIEVE_MESH_JEI_INFO, "Meshes are used in sieves. Different meshes yield different drops. Meshes can be enchanted with Fortune and Efficiency to increase likelihood of drops and sifting speed, respectively.");
|
||||
english.add(TranslationKeys.WATERING_CAN_JEI_INFO, "Watering cans speed up crop growth, tree growth, and grass spreading, among other things. They can be filled with water from barrels and wooden crucibles. Golden and above watering cans do not need to be refilled once full. Diamond watering cans water in a 3x3 area, and Netherite watering cans are usable by machinery.");
|
||||
english.add(TranslationKeys.WITCH_WATER_JEI_INFO, "Witch water is obtained by putting water in a barrel on top of mycelium. More mycelium speeds up the process. A barrel with witch water will grow mushrooms on nearby mycelium. Witch water and lava can make a netherrack generator, similar to a cobblestone generator.");
|
||||
english.add(TranslationKeys.MYCELIUM_SPORES_JEI_INFO, "Use on dirt to turn it into mycelium.");
|
||||
|
|
@ -50,6 +54,8 @@ class English {
|
|||
english.add(TranslationKeys.WARPED_NYLIUM_SPORES_JEI_INFO, "Use on netherrack to turn it into a warped nylium block.");
|
||||
english.add(TranslationKeys.CRIMSON_NYLIUM_SPORES_JEI_INFO, "Use on netherrack to turn it into a crimson nylium block.");
|
||||
english.add(TranslationKeys.SCULK_CORE_JEI_INFO, "Use a sculk core on a Sculk Shrieker to enable it to spawn Wardens. Normally, Sculk Shriekers placed by players cannot spawn Wardens, so this item is useful for obtaining Sculk items in a SkyBlock world.");
|
||||
english.add(TranslationKeys.MECHANICAL_SIEVE_JEI_INFO, "The Mechanical Sieve is a machine that, when supplied with a mesh and Forge Energy (FE), will sift blocks without a player having to do it themselves. It also supports three different modes of redstone control. Since Ex Deorum does not provide a way to generate FE, you will need another mod to provide power.");
|
||||
|
||||
english.add(TranslationKeys.BARREL_COMPOST_CATEGORY_TITLE, "Barrel Compost");
|
||||
english.add(TranslationKeys.BARREL_COMPOST_RECIPE_VOLUME, "Compost: %s");
|
||||
english.add(TranslationKeys.BARREL_MIXING_CATEGORY_TITLE, "Barrel Mixing");
|
||||
|
|
@ -64,6 +70,14 @@ class English {
|
|||
english.add(TranslationKeys.SIEVE_RECIPE_AVERAGE_OUTPUT, "Avg. Output: %s");
|
||||
english.add(TranslationKeys.SIEVE_RECIPE_MIN_OUTPUT, "Min: %s");
|
||||
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.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");
|
||||
english.add(TranslationKeys.REDSTONE_CONTROL_MODES[RedstoneControlWidget.REDSTONE_MODE_POWERED], "Powered");
|
||||
english.add(TranslationKeys.REDSTONE_CONTROL_LABEL, "Redstone Mode");
|
||||
english.add(TranslationKeys.REDSTONE_CONTROL_MODE, "Mode: ");
|
||||
|
||||
english.addBlock(EBlocks.VEXING_ARCHWOOD_CRUCIBLE, "Vexing Archwood Crucible");
|
||||
english.addBlock(EBlocks.CASCADING_ARCHWOOD_CRUCIBLE, "Cascading Archwood Crucible");
|
||||
|
|
|
|||
|
|
@ -29,14 +29,14 @@ import net.minecraftforge.registries.DeferredRegister;
|
|||
import net.minecraftforge.registries.RegistryObject;
|
||||
import thedarkcolour.exdeorum.compat.ModIds;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// Mocks modded items so that data generation can reference modded items without needing those mods installed.
|
||||
public class ModCompatData {
|
||||
// Identity maps because keys are just constants from ModIds
|
||||
private static final Map<String, DeferredRegister<Item>> itemRegistries = new IdentityHashMap<>();
|
||||
private static final Map<String, DeferredRegister<Block>> blockRegistries = new IdentityHashMap<>();
|
||||
private static final Map<String, DeferredRegister<Item>> itemRegistries = new HashMap<>();
|
||||
private static final Map<String, DeferredRegister<Block>> blockRegistries = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("DataFlowIssue")
|
||||
private static RegistryObject<Item> item(String modid, String name) {
|
||||
|
|
|
|||
|
|
@ -21,9 +21,13 @@ package thedarkcolour.exdeorum.data;
|
|||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
|
||||
public class TranslationKeys {
|
||||
// Misc
|
||||
public static final String MAIN_CREATIVE_TAB = "itemGroup." + ExDeorum.ID + ".main";
|
||||
public static final String VOID_WORLD_TYPE = "generator." + ExDeorum.ID + ".void_world";
|
||||
public static final String WATERING_CAN_FLUID_DISPLAY = "item." + ExDeorum.ID + ".watering_can_fluid_display";
|
||||
// ": %s / %s"
|
||||
public static final String FRACTION_DISPLAY = "item." + ExDeorum.ID + ".watering_can_fluid_display";
|
||||
public static final String MECHANICAL_SIEVE_MESH_LABEL = "item." + ExDeorum.ID + ".mechanical_sieve.mesh_label";
|
||||
public static final String ENERGY = "gui." + ExDeorum.ID + ".energy_label";
|
||||
|
||||
// Advancements
|
||||
public static final String ROOT_ADVANCEMENT_TITLE = "advancements." + ExDeorum.ID + ".core.root.title";
|
||||
|
|
@ -40,6 +44,7 @@ public class TranslationKeys {
|
|||
// JEI descriptions
|
||||
public static final String SILK_WORM_JEI_INFO = "info." + ExDeorum.ID + ".silk_worm";
|
||||
public static final String SIEVE_JEI_INFO = "info." + ExDeorum.ID + ".sieve";
|
||||
public static final String SIEVE_MESH_JEI_INFO = "info." + ExDeorum.ID + ".sieve_mesh";
|
||||
public static final String WATERING_CAN_JEI_INFO = "info." + ExDeorum.ID + ".watering_can";
|
||||
public static final String WITCH_WATER_JEI_INFO = "info." + ExDeorum.ID + ".witch_water";
|
||||
public static final String MYCELIUM_SPORES_JEI_INFO = "info." + ExDeorum.ID + ".mycelium_spores";
|
||||
|
|
@ -47,6 +52,7 @@ public class TranslationKeys {
|
|||
public static final String WARPED_NYLIUM_SPORES_JEI_INFO = "info." + ExDeorum.ID + ".warped_nylium_spores";
|
||||
public static final String CRIMSON_NYLIUM_SPORES_JEI_INFO = "info." + ExDeorum.ID + ".crimson_nylium_spores";
|
||||
public static final String SCULK_CORE_JEI_INFO = "info." + ExDeorum.ID + ".sculk_core";
|
||||
public static final String MECHANICAL_SIEVE_JEI_INFO = "info." + ExDeorum.ID + ".mechanical_sieve";
|
||||
|
||||
// JEI recipe categories
|
||||
public static final String BARREL_COMPOST_CATEGORY_TITLE = "gui." + ExDeorum.ID + ".category.barrel_compost";
|
||||
|
|
@ -63,4 +69,15 @@ public class TranslationKeys {
|
|||
public static final String SIEVE_RECIPE_AVERAGE_OUTPUT = "gui." + ExDeorum.ID + ".category.sieve.average_output";
|
||||
public static final String SIEVE_RECIPE_MIN_OUTPUT = "gui." + ExDeorum.ID + ".category.sieve.min_output";
|
||||
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";
|
||||
|
||||
// Screens
|
||||
public static final String MECHANICAL_SIEVE_SCREEN_TITLE = ExDeorum.ID + ".container.mechanical_sieve";
|
||||
public static final String[] REDSTONE_CONTROL_MODES = new String[] {
|
||||
"gui." + ExDeorum.ID + ".redstone_control.always",
|
||||
"gui." + ExDeorum.ID + ".redstone_control.unpowered",
|
||||
"gui." + ExDeorum.ID + ".redstone_control.powered"
|
||||
};
|
||||
public static final String REDSTONE_CONTROL_LABEL = "gui." + ExDeorum.ID + ".redstone_control.label";
|
||||
public static final String REDSTONE_CONTROL_MODE = "gui." + ExDeorum.ID + ".redstone_control.mode";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains all data generation for Ex Deorum. It is not to be used outside of data generation.
|
||||
* <p>
|
||||
* Ex Deorum uses the ModKit library, which adds several utilities primarily for data generation
|
||||
* without needing to be shaded or depended upon outside a development environment.
|
||||
*/
|
||||
@net.minecraft.MethodsReturnNonnullByDefault
|
||||
@javax.annotation.ParametersAreNonnullByDefault
|
||||
package thedarkcolour.exdeorum.data;
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@
|
|||
|
||||
package thedarkcolour.exdeorum.data.recipe;
|
||||
|
||||
import mcjty.theoneprobe.apiimpl.elements.ElementItemStack;
|
||||
import net.minecraft.data.recipes.FinishedRecipe;
|
||||
import net.minecraft.data.recipes.RecipeCategory;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
|
@ -282,6 +282,16 @@ public class Recipes {
|
|||
recipe.pattern("WCW");
|
||||
MKRecipeProvider.unlockedByHaving(recipe, EItems.WOOD_CHIPPINGS.get());
|
||||
});
|
||||
recipes.shapedCrafting(RecipeCategory.MISC, EItems.MECHANICAL_SIEVE.get(), recipe -> {
|
||||
recipe.define('#', Items.IRON_BLOCK);
|
||||
recipe.define('G', Items.GLASS);
|
||||
recipe.define('H', Items.HOPPER);
|
||||
recipe.define('I', Items.IRON_BARS);
|
||||
recipe.pattern("#G#");
|
||||
recipe.pattern("IHI");
|
||||
recipe.pattern("I I");
|
||||
MKRecipeProvider.unlockedByHaving(recipe, Items.HOPPER);
|
||||
});
|
||||
}
|
||||
|
||||
private static void modUShaped(MKRecipeProvider recipes, String modid, RegistryObject<? extends Item> sides, RegistryObject<? extends Item> middle, RegistryObject<? extends Item> result) {
|
||||
|
|
|
|||
|
|
@ -939,6 +939,7 @@ class SieveRecipes {
|
|||
void accept(BiConsumer<Item, NumberProvider> addDrop, BiConsumer<TagKey<Item>, NumberProvider> addTagDrop, AddConditionalTag addConditionalTag);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface AddConditionalTag {
|
||||
void accept(Either<Item, TagKey<Item>> result, NumberProvider resultAmount, ICondition condition);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import net.minecraftforge.common.ForgeMod;
|
|||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.AddReloadListenerEvent;
|
||||
import net.minecraftforge.event.OnDatapackSyncEvent;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.event.level.LevelEvent;
|
||||
import net.minecraftforge.event.server.ServerStoppingEvent;
|
||||
|
|
@ -62,6 +63,7 @@ import thedarkcolour.exdeorum.compat.top.ExDeorumTopCompat;
|
|||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
import thedarkcolour.exdeorum.item.WateringCanItem;
|
||||
import thedarkcolour.exdeorum.network.NetworkHandler;
|
||||
import thedarkcolour.exdeorum.network.VisualUpdateTracker;
|
||||
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
||||
import thedarkcolour.exdeorum.registry.EFluids;
|
||||
import thedarkcolour.exdeorum.registry.EItems;
|
||||
|
|
@ -85,6 +87,7 @@ public final class EventHandler {
|
|||
modBus.addListener(EventHandler::interModEnqueue);
|
||||
modBus.addListener(EventHandler::onCommonSetup);
|
||||
fmlBus.addListener(EventHandler::serverShutdown);
|
||||
fmlBus.addListener(EventHandler::serverTick);
|
||||
|
||||
if (ExDeorum.DEBUG) {
|
||||
fmlBus.addListener(EventHandler::handleDebugCommands);
|
||||
|
|
@ -223,7 +226,7 @@ public final class EventHandler {
|
|||
}
|
||||
|
||||
// Send messages to other mods
|
||||
public static void interModEnqueue(InterModEnqueueEvent event) {
|
||||
private static void interModEnqueue(InterModEnqueueEvent event) {
|
||||
if (ModList.get().isLoaded(ModIds.THE_ONE_PROBE)) {
|
||||
InterModComms.sendTo(ModIds.THE_ONE_PROBE, "getTheOneProbe", ExDeorumTopCompat::new);
|
||||
}
|
||||
|
|
@ -238,4 +241,10 @@ public final class EventHandler {
|
|||
}, gameExecutor);
|
||||
});
|
||||
}
|
||||
|
||||
private static void serverTick(TickEvent.ServerTickEvent event) {
|
||||
if (event.phase == TickEvent.Phase.END) {
|
||||
VisualUpdateTracker.syncVisualUpdates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ public class WitchWaterFluid extends FluidType {
|
|||
return new Vector3f(32f / 255f, 12f / 255f, 64f / 255f);
|
||||
}
|
||||
|
||||
// todo return the correct value here
|
||||
@Override
|
||||
public int getTintColor() {
|
||||
return 0xFFFFFFFF;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ import net.minecraft.world.level.block.Blocks;
|
|||
import net.minecraft.world.level.block.BucketPickup;
|
||||
import net.minecraft.world.level.block.FarmBlock;
|
||||
import net.minecraft.world.level.block.LevelEvent;
|
||||
import net.minecraft.world.level.block.SpreadingSnowyDirtBlock;
|
||||
import net.minecraft.world.level.block.SugarCaneBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
|
|
@ -132,9 +131,8 @@ public class WateringCanItem extends Item {
|
|||
@Override
|
||||
public void appendHoverText(ItemStack stack, @Nullable Level pLevel, List<Component> tooltip, TooltipFlag pIsAdvanced) {
|
||||
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresent(fluidHandler -> {
|
||||
var water = Component.translatable(ForgeMod.WATER_TYPE.get().getDescriptionId());
|
||||
|
||||
tooltip.add(water.append(Component.translatable(TranslationKeys.WATERING_CAN_FLUID_DISPLAY, fluidHandler.getFluidInTank(0).getAmount(), capacity)).withStyle(ChatFormatting.GRAY));
|
||||
// use the block name which is guaranteed to have a vanilla translation
|
||||
tooltip.add(Component.translatable("block.minecraft.water").append(Component.translatable(TranslationKeys.FRACTION_DISPLAY, fluidHandler.getFluidInTank(0).getAmount(), capacity)).withStyle(ChatFormatting.GRAY));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
21
src/main/java/thedarkcolour/exdeorum/item/package-info.java
Normal file
21
src/main/java/thedarkcolour/exdeorum/item/package-info.java
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Ex Deorum
|
||||
* Copyright (c) 2023 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.item;
|
||||
|
|
@ -31,11 +31,11 @@ import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity;
|
|||
import thedarkcolour.exdeorum.registry.ELootFunctions;
|
||||
|
||||
// Sets the correct amount based on the progress of the infested leaves
|
||||
public class InfestedStringCount extends LootItemConditionalFunction {
|
||||
public class InfestedStringFunction extends LootItemConditionalFunction {
|
||||
// todo move to config
|
||||
public static final float STRING_CHANCE = 0.4f;
|
||||
|
||||
protected InfestedStringCount(LootItemCondition[] conditions) {
|
||||
protected InfestedStringFunction(LootItemCondition[] conditions) {
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
|
|
@ -73,13 +73,13 @@ public class InfestedStringCount extends LootItemConditionalFunction {
|
|||
}
|
||||
|
||||
public static LootItemConditionalFunction.Builder<?> infestedString() {
|
||||
return LootItemConditionalFunction.simpleBuilder(InfestedStringCount::new);
|
||||
return LootItemConditionalFunction.simpleBuilder(InfestedStringFunction::new);
|
||||
}
|
||||
|
||||
public static class LootSerializer extends LootItemConditionalFunction.Serializer<InfestedStringCount> {
|
||||
public static class LootSerializer extends LootItemConditionalFunction.Serializer<InfestedStringFunction> {
|
||||
@Override
|
||||
public InfestedStringCount deserialize(JsonObject json, JsonDeserializationContext ctx, LootItemCondition[] conditions) {
|
||||
return new InfestedStringCount(conditions);
|
||||
public InfestedStringFunction deserialize(JsonObject json, JsonDeserializationContext ctx, LootItemCondition[] conditions) {
|
||||
return new InfestedStringFunction(conditions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.loot;
|
||||
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction;
|
||||
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
|
||||
import thedarkcolour.exdeorum.registry.ELootFunctions;
|
||||
|
||||
public class MachineLootFunction extends LootItemConditionalFunction {
|
||||
protected MachineLootFunction(LootItemCondition[] conditions) {
|
||||
super(conditions);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack run(ItemStack stack, LootContext ctx) {
|
||||
BlockEntity blockEntity = ctx.getParamOrNull(LootContextParams.BLOCK_ENTITY);
|
||||
if (blockEntity != null) {
|
||||
blockEntity.saveToItem(stack);
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LootItemFunctionType getType() {
|
||||
return ELootFunctions.MACHINE.get();
|
||||
}
|
||||
|
||||
public static LootItemConditionalFunction.Builder<?> machineLoot() {
|
||||
return LootItemConditionalFunction.simpleBuilder(MachineLootFunction::new);
|
||||
}
|
||||
|
||||
public static class LootSerializer extends LootItemConditionalFunction.Serializer<MachineLootFunction> {
|
||||
@Override
|
||||
public MachineLootFunction deserialize(JsonObject json, JsonDeserializationContext ctx, LootItemCondition[] conditions) {
|
||||
return new MachineLootFunction(conditions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.menu;
|
||||
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
|
||||
public abstract class EContainerMenu extends AbstractContainerMenu {
|
||||
protected EContainerMenu(MenuType<?> pMenuType, int pContainerId) {
|
||||
super(pMenuType, pContainerId);
|
||||
}
|
||||
|
||||
// When the server sends a menu property message, the client handles the synced property here.
|
||||
public abstract void setClientProperty(int index, int value);
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* 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.menu;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.InventoryMenu;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.blockentity.MechanicalSieveBlockEntity;
|
||||
import thedarkcolour.exdeorum.network.NetworkHandler;
|
||||
import thedarkcolour.exdeorum.registry.EMenus;
|
||||
|
||||
public class MechanicalSieveMenu extends EContainerMenu {
|
||||
private static final ResourceLocation EMPTY_SLOT_MESH = new ResourceLocation(ExDeorum.ID, "item/empty_slot_mesh");
|
||||
private static final int NUM_SLOTS = 22; // input + mesh, 20 output slots
|
||||
private static final int PLAYER_SLOTS = 36; // hotbar + inventory
|
||||
|
||||
public final MechanicalSieveBlockEntity sieve;
|
||||
@Nullable
|
||||
private final ServerPlayer player;
|
||||
|
||||
public int prevSieveEnergy;
|
||||
|
||||
public MechanicalSieveMenu(int containerId, Inventory playerInventory, FriendlyByteBuf data) {
|
||||
this(containerId, playerInventory, (MechanicalSieveBlockEntity) playerInventory.player.level().getBlockEntity(data.readBlockPos()));
|
||||
this.sieve.setRedstoneMode(data.readByte());
|
||||
}
|
||||
|
||||
public MechanicalSieveMenu(int containerId, Inventory playerInventory, MechanicalSieveBlockEntity sieve) {
|
||||
super(EMenus.MECHANICAL_SIEVE.get(), containerId);
|
||||
|
||||
this.sieve = sieve;
|
||||
|
||||
// input slot
|
||||
addSlot(sieve.inventory.createSlot(0, 26, 30));
|
||||
// mesh slot
|
||||
addSlot(sieve.inventory.createSlot(1, 26, 53).setBackground(InventoryMenu.BLOCK_ATLAS, EMPTY_SLOT_MESH));
|
||||
// output slots
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 5; ++c) {
|
||||
addSlot(sieve.inventory.createSlot(2 + r * 5 + c, 80 + c * 18, 15 + r * 18));
|
||||
}
|
||||
}
|
||||
// Player slots
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 9; ++j) {
|
||||
addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 7 + 84 + i * 18));
|
||||
}
|
||||
}
|
||||
for (int k = 0; k < 9; ++k) {
|
||||
addSlot(new Slot(playerInventory, k, 8 + k * 18, 149));
|
||||
}
|
||||
|
||||
if (playerInventory.player instanceof ServerPlayer serverPlayer) {
|
||||
this.player = serverPlayer;
|
||||
} else {
|
||||
this.player = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastChanges() {
|
||||
super.broadcastChanges();
|
||||
|
||||
if (this.player != null) {
|
||||
if (this.prevSieveEnergy != this.sieve.energy.getEnergyStored()) {
|
||||
this.prevSieveEnergy = this.sieve.energy.getEnergyStored();
|
||||
|
||||
NetworkHandler.sendMenuProperty(this.player, this.containerId, 0, this.prevSieveEnergy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastFullState() {
|
||||
super.broadcastFullState();
|
||||
|
||||
if (this.player != null) {
|
||||
if (this.prevSieveEnergy != this.sieve.energy.getEnergyStored()) {
|
||||
this.prevSieveEnergy = this.sieve.energy.getEnergyStored();
|
||||
|
||||
NetworkHandler.sendMenuProperty(this.player, this.containerId, 0, this.prevSieveEnergy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientProperty(int index, int value) {
|
||||
if (index == 0) {
|
||||
this.prevSieveEnergy = value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack quickMoveStack(Player player, int clickedSlot) {
|
||||
var stack = ItemStack.EMPTY;
|
||||
var slot = this.slots.get(clickedSlot);
|
||||
|
||||
if (slot.hasItem()) {
|
||||
var clickedStack = slot.getItem();
|
||||
stack = clickedStack.copy();
|
||||
|
||||
if (clickedSlot > 1 && clickedSlot <= NUM_SLOTS) { // moving out of output slots
|
||||
if (!moveItemStackTo(clickedStack, NUM_SLOTS, PLAYER_SLOTS + NUM_SLOTS, true)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (clickedSlot < 2) { // moving out of input/mesh slot
|
||||
if (!moveItemStackTo(clickedStack, NUM_SLOTS, NUM_SLOTS + PLAYER_SLOTS, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (this.sieve.getLogic().isValidInput(clickedStack)) { // attempting to move into input slot
|
||||
if (!moveItemStackTo(clickedStack, 0, 1, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (this.sieve.getLogic().isValidMesh(clickedStack)) { // attempting to move into mesh slot
|
||||
if (!moveItemStackTo(clickedStack, 1, 2, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (clickedSlot < NUM_SLOTS + 27) { // attempting to move from inventory to hotbar
|
||||
if (!moveItemStackTo(clickedStack, NUM_SLOTS + 27, NUM_SLOTS + PLAYER_SLOTS, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
} else if (clickedSlot < NUM_SLOTS + PLAYER_SLOTS) { // attempting to move from hotbar to inventory
|
||||
if (!moveItemStackTo(clickedStack, NUM_SLOTS, NUM_SLOTS + 27, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
if (clickedStack.isEmpty()) {
|
||||
slot.set(ItemStack.EMPTY);
|
||||
}
|
||||
slot.setChanged();
|
||||
if (clickedStack.getCount() == stack.getCount()) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
slot.onTake(player, clickedStack);
|
||||
broadcastChanges();
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clickMenuButton(Player player, int id) {
|
||||
if (0 <= id && id < 3) {
|
||||
this.sieve.setRedstoneMode(id);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player player) {
|
||||
return this.sieve.stillValid(player);
|
||||
}
|
||||
}
|
||||
21
src/main/java/thedarkcolour/exdeorum/menu/package-info.java
Normal file
21
src/main/java/thedarkcolour/exdeorum/menu/package-info.java
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Ex Deorum
|
||||
* Copyright (c) 2023 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.menu;
|
||||
|
|
@ -19,8 +19,11 @@
|
|||
package thedarkcolour.exdeorum.network;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import thedarkcolour.exdeorum.blockentity.EBlockEntity;
|
||||
import thedarkcolour.exdeorum.client.ClientHandler;
|
||||
import thedarkcolour.exdeorum.recipe.RecipeUtil;
|
||||
import thedarkcolour.exdeorum.menu.EContainerMenu;
|
||||
|
||||
public class ClientMessageHandler {
|
||||
public static boolean isInVoidWorld;
|
||||
|
|
@ -36,7 +39,23 @@ public class ClientMessageHandler {
|
|||
}
|
||||
|
||||
public static void reloadClientRecipeCache() {
|
||||
//RecipeUtil.reload(Minecraft.getInstance().level.getRecipeManager());
|
||||
ClientHandler.needsRecipeCacheRefresh = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("DataFlowIssue")
|
||||
public static void handleVisualUpdate(VisualUpdateMessage msg) {
|
||||
ClientLevel level = Minecraft.getInstance().level;
|
||||
if (level != null && level.getBlockEntity(msg.pos) instanceof EBlockEntity blockEntity) {
|
||||
// payload should be nonnull on the client side
|
||||
blockEntity.readVisualData(msg.payload);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleMenuProperty(MenuPropertyMessage msg) {
|
||||
Player player = Minecraft.getInstance().player;
|
||||
|
||||
if (player != null && player.containerMenu instanceof EContainerMenu menu && menu.containerId == msg.containerId()) {
|
||||
menu.setClientProperty(msg.index(), msg.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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.network;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
// Like ClientboundContainerSetDataPacket except that the value is 32 bits instead of 16 bits
|
||||
public record MenuPropertyMessage(int containerId, int index, int value) {
|
||||
public static void encode(MenuPropertyMessage msg, FriendlyByteBuf buffer) {
|
||||
buffer.writeByte(msg.containerId);
|
||||
buffer.writeShort(msg.index);
|
||||
buffer.writeVarInt(msg.value);
|
||||
}
|
||||
|
||||
public static MenuPropertyMessage decode(FriendlyByteBuf buffer) {
|
||||
return new MenuPropertyMessage(buffer.readByte(), buffer.readShort(), buffer.readVarInt());
|
||||
}
|
||||
|
||||
public static void handle(MenuPropertyMessage msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
NetworkHandler.handle(ctxSupplier, ctx -> {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientMessageHandler.handleMenuProperty(msg));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import net.minecraftforge.network.NetworkEvent;
|
|||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.blockentity.EBlockEntity;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
|
@ -36,6 +37,8 @@ public final class NetworkHandler {
|
|||
public static void register() {
|
||||
CHANNEL.registerMessage(0, VoidWorldMessage.class, VoidWorldMessage::encode, VoidWorldMessage::decode, VoidWorldMessage::handle);
|
||||
CHANNEL.registerMessage(1, PlayerDataMessage.class, (msg, buffer) -> {}, buffer -> new PlayerDataMessage(), PlayerDataMessage::handle);
|
||||
CHANNEL.registerMessage(2, VisualUpdateMessage.class, VisualUpdateMessage::encode, VisualUpdateMessage::decode, VisualUpdateMessage::handle);
|
||||
CHANNEL.registerMessage(3, MenuPropertyMessage.class, MenuPropertyMessage::encode, MenuPropertyMessage::decode, MenuPropertyMessage::handle);
|
||||
}
|
||||
|
||||
public static void sendVoidWorld(ServerPlayer pPlayer) {
|
||||
|
|
@ -51,4 +54,8 @@ public final class NetworkHandler {
|
|||
ctx.enqueueWork(() -> handler.accept(ctx));
|
||||
ctx.setPacketHandled(true);
|
||||
}
|
||||
|
||||
public static void sendMenuProperty(ServerPlayer player, int containerId, int index, int prevSieveEnergy) {
|
||||
CHANNEL.sendTo(new MenuPropertyMessage(containerId, index, prevSieveEnergy), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* 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.network;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.blockentity.EBlockEntity;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
class VisualUpdateMessage {
|
||||
final BlockEntityType<?> blockEntityType;
|
||||
final BlockPos pos;
|
||||
// Null on the client side
|
||||
@Nullable
|
||||
private final EBlockEntity blockEntity;
|
||||
// Null on the server side
|
||||
@Nullable
|
||||
final FriendlyByteBuf payload;
|
||||
|
||||
public VisualUpdateMessage(BlockPos pos, @Nullable EBlockEntity blockEntity, @Nullable FriendlyByteBuf payload) {
|
||||
this.pos = pos;
|
||||
this.blockEntity = blockEntity;
|
||||
// payload is saved on the client until it can be handled properly
|
||||
this.payload = payload;
|
||||
|
||||
// If the payload is null, we're on the server. Hence, the block entity is nonnull.
|
||||
if (payload == null) {
|
||||
this.blockEntityType = blockEntity.getType();
|
||||
} else {
|
||||
this.blockEntityType = payload.readById(BuiltInRegistries.BLOCK_ENTITY_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
public static void encode(VisualUpdateMessage msg, FriendlyByteBuf buffer) {
|
||||
buffer.writeBlockPos(msg.pos);
|
||||
buffer.writeId(BuiltInRegistries.BLOCK_ENTITY_TYPE, msg.blockEntityType);
|
||||
// never null on the server side, where this packet is meant to be encoded
|
||||
msg.blockEntity.writeVisualData(buffer);
|
||||
}
|
||||
|
||||
public static VisualUpdateMessage decode(FriendlyByteBuf buffer) {
|
||||
return new VisualUpdateMessage(buffer.readBlockPos(), null, buffer);
|
||||
}
|
||||
|
||||
public static void handle(VisualUpdateMessage msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
NetworkHandler.handle(ctxSupplier, ctx -> {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientMessageHandler.handleVisualUpdate(msg));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.network;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
import thedarkcolour.exdeorum.blockentity.EBlockEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
// Syncs certain block entity data to the client for visual purposes
|
||||
// Since some block entities might change their data multiple times a tick, this class keeps track of
|
||||
// whether a block entity has updated and then pushes out the changes once at the end of each tick.
|
||||
public class VisualUpdateTracker {
|
||||
// WeakHashMap is faster than Guava mapmaker
|
||||
private static final Map<LevelChunk, List<BlockPos>> UPDATES = new WeakHashMap<>();
|
||||
|
||||
public static void sendVisualUpdate(EBlockEntity blockEntity) {
|
||||
var level = blockEntity.getLevel();
|
||||
|
||||
if (level != null && !level.isClientSide) {
|
||||
var dimension = level.getChunkAt(blockEntity.getBlockPos());
|
||||
List<BlockPos> updatesList;
|
||||
if (!UPDATES.containsKey(dimension)) {
|
||||
UPDATES.put(dimension, updatesList = new ArrayList<>());
|
||||
} else {
|
||||
updatesList = UPDATES.get(dimension);
|
||||
}
|
||||
updatesList.add(blockEntity.getBlockPos());
|
||||
}
|
||||
}
|
||||
|
||||
public static void syncVisualUpdates() {
|
||||
for (var entry : UPDATES.entrySet()) {
|
||||
var pendingUpdates = entry.getValue();
|
||||
|
||||
for (var updatePos : pendingUpdates) {
|
||||
var chunk = entry.getKey();
|
||||
|
||||
if (chunk.getBlockEntity(updatePos) instanceof EBlockEntity blockEntity) {
|
||||
// packet uses strong reference
|
||||
NetworkHandler.CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(entry::getKey), new VisualUpdateMessage(updatePos, blockEntity, null));
|
||||
}
|
||||
}
|
||||
|
||||
pendingUpdates.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ public class VoidWorldMessage {
|
|||
return new VoidWorldMessage();
|
||||
}
|
||||
|
||||
public void handle(Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
public static void handle(VoidWorldMessage msg, Supplier<NetworkEvent.Context> ctxSupplier) {
|
||||
NetworkHandler.handle(ctxSupplier, ctx -> {
|
||||
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientMessageHandler::disableVoidFogRendering);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,13 +24,14 @@ import org.jetbrains.annotations.Nullable;
|
|||
import thedarkcolour.exdeorum.recipe.barrel.BarrelFluidMixingRecipe;
|
||||
import thedarkcolour.exdeorum.registry.ERecipeTypes;
|
||||
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// for now, only simple recipes
|
||||
public class BarrelFluidMixingRecipeCache {
|
||||
private RecipeManager recipeManager;
|
||||
@Nullable
|
||||
private IdentityHashMap<Fluid, IdentityHashMap<Fluid, BarrelFluidMixingRecipe>> recipes;
|
||||
private Map<Fluid, Map<Fluid, BarrelFluidMixingRecipe>> recipes;
|
||||
|
||||
public BarrelFluidMixingRecipeCache(RecipeManager recipeManager) {
|
||||
this.recipeManager = recipeManager;
|
||||
|
|
@ -49,10 +50,10 @@ public class BarrelFluidMixingRecipeCache {
|
|||
}
|
||||
|
||||
private void buildRecipes() {
|
||||
this.recipes = new IdentityHashMap<>();
|
||||
var recipes = new HashMap<Fluid, Map<Fluid, BarrelFluidMixingRecipe>>();
|
||||
|
||||
for (var recipe : this.recipeManager.byType(ERecipeTypes.BARREL_FLUID_MIXING.get()).values()) {
|
||||
recipes.computeIfAbsent(recipe.baseFluid, key -> new IdentityHashMap<>()).put(recipe.additiveFluid, recipe);
|
||||
recipes.computeIfAbsent(recipe.baseFluid, key -> new HashMap<>()).put(recipe.additiveFluid, recipe);
|
||||
}
|
||||
|
||||
this.recipeManager = null;
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ import thedarkcolour.exdeorum.registry.ERecipeTypes;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SieveRecipeCache {
|
||||
private RecipeManager recipeManager;
|
||||
@Nullable
|
||||
private IdentityHashMap<Item, MeshRecipeCache> meshCaches;
|
||||
private Map<Item, MeshRecipeCache> meshCaches;
|
||||
|
||||
public SieveRecipeCache(RecipeManager recipeManager) {
|
||||
this.recipeManager = recipeManager;
|
||||
|
|
@ -54,7 +54,7 @@ public class SieveRecipeCache {
|
|||
for (var recipe : recipeManager.byType(ERecipeTypes.SIEVE.get()).values()) {
|
||||
tempMap.computeIfAbsent(recipe.mesh, k -> new ArrayList<>()).add(recipe);
|
||||
}
|
||||
this.meshCaches = new IdentityHashMap<>();
|
||||
this.meshCaches = new HashMap<>();
|
||||
for (var mesh : tempMap.entrySet()) {
|
||||
this.meshCaches.put(mesh.getKey(), new MeshRecipeCache(mesh.getValue()));
|
||||
}
|
||||
|
|
@ -64,14 +64,14 @@ public class SieveRecipeCache {
|
|||
// For now, there will be no complex recipes. What that means is, recipes may not use NBT information of the
|
||||
// block being sifted to decide what its drops are. Firstly, this would be complicated for me to code. Secondly,
|
||||
// conveying this information in JEI would be difficult (ex. Bottle drops from Sand, but only if the Sand has a
|
||||
// certain NBT tag). Thirdly, I do not see anybody needing this use case, and if they do, they should contact
|
||||
// certain enchantment). Thirdly, I do not see anybody needing this use case, and if they do, they should contact
|
||||
// me on GitHub or Discord so that I can get around to actually implementing it.
|
||||
private static class MeshRecipeCache {
|
||||
private final IdentityHashMap<Item, List<SieveRecipe>> simpleRecipes;
|
||||
private final Map<Item, List<SieveRecipe>> simpleRecipes;
|
||||
|
||||
private MeshRecipeCache(List<SieveRecipe> recipes) {
|
||||
this.simpleRecipes = new IdentityHashMap<>();
|
||||
var temp = new IdentityHashMap<Item, ImmutableList.Builder<SieveRecipe>>();
|
||||
this.simpleRecipes = new HashMap<>();
|
||||
var temp = new HashMap<Item, ImmutableList.Builder<SieveRecipe>>();
|
||||
|
||||
for (var recipe : recipes) {
|
||||
for (var item : recipe.ingredient.getItems()) {
|
||||
|
|
|
|||
|
|
@ -26,15 +26,16 @@ import net.minecraft.world.item.crafting.RecipeType;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
|
||||
private final Supplier<RecipeType<T>> recipeType;
|
||||
private RecipeManager recipeManager;
|
||||
@Nullable
|
||||
private IdentityHashMap<Item, T> simpleRecipes;
|
||||
private Map<Item, T> simpleRecipes;
|
||||
@Nullable
|
||||
private List<T> complexRecipes;
|
||||
@Nullable
|
||||
|
|
@ -98,7 +99,7 @@ public class SingleIngredientRecipeCache<T extends SingleIngredientRecipe> {
|
|||
* have been scanned, the {@link #recipeManager} is set to null, since it is no longer needed.
|
||||
*/
|
||||
private void buildRecipes() {
|
||||
this.simpleRecipes = new IdentityHashMap<>();
|
||||
this.simpleRecipes = new HashMap<>();
|
||||
var complexRecipes = ImmutableList.<T>builder();
|
||||
|
||||
var allRecipes = this.recipeManager.byType(recipeType.get()).values();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Ex Deorum
|
||||
* Copyright (c) 2023 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.recipe.barrel;
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Ex Deorum
|
||||
* Copyright (c) 2023 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.recipe.crucible;
|
||||
|
|
@ -16,12 +16,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains all data generation for Ex Deorum. It is not to be used outside of data generation.
|
||||
* <p>
|
||||
* Ex Deorum uses the ModKit library, which adds several utilities primarily for data generation
|
||||
* without needing to be shaded or depended upon outside a development environment.
|
||||
*/
|
||||
@net.minecraft.MethodsReturnNonnullByDefault
|
||||
@javax.annotation.ParametersAreNonnullByDefault
|
||||
package thedarkcolour.exdeorum.recipe.hammer;
|
||||
|
|
|
|||
|
|
@ -16,12 +16,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains all data generation for Ex Deorum. It is not to be used outside of data generation.
|
||||
* <p>
|
||||
* Ex Deorum uses the ModKit library, which adds several utilities primarily for data generation
|
||||
* without needing to be shaded or depended upon outside a development environment.
|
||||
*/
|
||||
@net.minecraft.MethodsReturnNonnullByDefault
|
||||
@javax.annotation.ParametersAreNonnullByDefault
|
||||
package thedarkcolour.exdeorum.recipe;
|
||||
|
|
|
|||
|
|
@ -49,19 +49,19 @@ public class FinishedSieveRecipe implements EFinishedRecipe {
|
|||
|
||||
@Override
|
||||
public void serializeRecipeData(JsonObject object) {
|
||||
object.add("ingredient", ingredient.toJson());
|
||||
object.add("ingredient", this.ingredient.toJson());
|
||||
object.addProperty("mesh", ForgeRegistries.ITEMS.getKey(this.mesh).toString());
|
||||
this.result.ifLeft(item -> {
|
||||
object.addProperty("result", ForgeRegistries.ITEMS.getKey(item).toString());
|
||||
}).ifRight(tag -> {
|
||||
object.addProperty("result_tag", tag.location().toString());
|
||||
});
|
||||
object.add("result_amount", LootDataType.PREDICATE.parser().toJsonTree(resultAmount));
|
||||
object.add("result_amount", LootDataType.PREDICATE.parser().toJsonTree(this.resultAmount));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getId() {
|
||||
return id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -43,11 +43,13 @@ import thedarkcolour.exdeorum.registry.ERecipeTypes;
|
|||
|
||||
public class SieveRecipe extends ProbabilityRecipe {
|
||||
public final Item mesh;
|
||||
public final boolean byHandOnly;
|
||||
|
||||
public SieveRecipe(ResourceLocation id, Ingredient ingredient, Item mesh, Item result, NumberProvider resultAmount) {
|
||||
public SieveRecipe(ResourceLocation id, Ingredient ingredient, Item mesh, Item result, NumberProvider resultAmount, boolean byHandOnly) {
|
||||
super(id, ingredient, result, resultAmount);
|
||||
|
||||
this.mesh = mesh;
|
||||
this.byHandOnly = byHandOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -83,7 +85,8 @@ public class SieveRecipe extends ProbabilityRecipe {
|
|||
}
|
||||
|
||||
NumberProvider resultAmount = RecipeUtil.readNumberProvider(json, "result_amount");
|
||||
return new SieveRecipe(id, ingredient, mesh, result, resultAmount);
|
||||
boolean byHandOnly = json.has("by_hand_only") && json.get("by_hand_only").getAsBoolean();
|
||||
return new SieveRecipe(id, ingredient, mesh, result, resultAmount, byHandOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -92,7 +95,7 @@ public class SieveRecipe extends ProbabilityRecipe {
|
|||
Item mesh = buffer.readById(BuiltInRegistries.ITEM);
|
||||
Item result = buffer.readById(BuiltInRegistries.ITEM);
|
||||
NumberProvider resultAmount = RecipeUtil.fromNetworkNumberProvider(buffer);
|
||||
return new SieveRecipe(id, ingredient, mesh, result, resultAmount);
|
||||
return new SieveRecipe(id, ingredient, mesh, result, resultAmount, buffer.readBoolean());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -101,6 +104,7 @@ public class SieveRecipe extends ProbabilityRecipe {
|
|||
buffer.writeId(BuiltInRegistries.ITEM, recipe.mesh);
|
||||
buffer.writeId(BuiltInRegistries.ITEM, recipe.result);
|
||||
RecipeUtil.toNetworkNumberProvider(buffer, recipe.resultAmount);
|
||||
buffer.writeBoolean(recipe.byHandOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,8 +24,10 @@ import net.minecraftforge.registries.ForgeRegistries;
|
|||
import net.minecraftforge.registries.RegistryObject;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.blockentity.BarrelBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.CompressedSieveBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.LavaCrucibleBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.MechanicalSieveBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.SieveBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.WaterCrucibleBlockEntity;
|
||||
|
||||
|
|
@ -154,4 +156,5 @@ public class EBlockEntities {
|
|||
EBlocks.MAPLE_SIEVE.get(),
|
||||
EBlocks.CRYSTALLIZED_SIEVE.get()
|
||||
).build(null));
|
||||
public static final RegistryObject<BlockEntityType<MechanicalSieveBlockEntity>> MECHANICAL_SIEVE = BLOCK_ENTITIES.register("mechanical_sieve", () -> BlockEntityType.Builder.of(MechanicalSieveBlockEntity::new, EBlocks.MECHANICAL_SIEVE.get()).build(null));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ public class EBlocks {
|
|||
public static final RegistryObject<SieveBlock> DUSK_SIEVE = registerSieve("dusk_sieve");
|
||||
public static final RegistryObject<SieveBlock> MAPLE_SIEVE = registerSieve("maple_sieve");
|
||||
public static final RegistryObject<SieveBlock> CRYSTALLIZED_SIEVE = registerSieve("crystallized_sieve", SoundType.GLASS);
|
||||
// Mechanical Sieve (todo add properties)
|
||||
public static final RegistryObject<MechanicalSieveBlock> MECHANICAL_SIEVE = BLOCKS.register("mechanical_sieve", () -> new MechanicalSieveBlock(of()));
|
||||
|
||||
// Lava Crucibles
|
||||
public static final RegistryObject<LavaCrucibleBlock> PORCELAIN_CRUCIBLE = registerLavaCrucible("porcelain_crucible", true, SoundType.STONE);
|
||||
|
|
|
|||
|
|
@ -225,6 +225,8 @@ public class EItems {
|
|||
public static final RegistryObject<BlockItem> DUSK_SIEVE = registerItemBlock(EBlocks.DUSK_SIEVE);
|
||||
public static final RegistryObject<BlockItem> MAPLE_SIEVE = registerItemBlock(EBlocks.MAPLE_SIEVE);
|
||||
public static final RegistryObject<BlockItem> CRYSTALLIZED_SIEVE = registerItemBlock(EBlocks.CRYSTALLIZED_SIEVE);
|
||||
// Mechanical Sieves
|
||||
public static final RegistryObject<BlockItem> MECHANICAL_SIEVE = registerItemBlock(EBlocks.MECHANICAL_SIEVE);
|
||||
|
||||
// Lava Crucibles
|
||||
public static final RegistryObject<BlockItem> PORCELAIN_CRUCIBLE = registerItemBlock(EBlocks.PORCELAIN_CRUCIBLE);
|
||||
|
|
@ -364,6 +366,7 @@ public class EItems {
|
|||
output.accept(MAPLE_SIEVE.get());
|
||||
output.accept(CRYSTALLIZED_SIEVE.get());
|
||||
}
|
||||
output.accept(MECHANICAL_SIEVE.get());
|
||||
|
||||
output.accept(PORCELAIN_CRUCIBLE.get());
|
||||
output.accept(WARPED_CRUCIBLE.get());
|
||||
|
|
|
|||
|
|
@ -23,9 +23,12 @@ import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType;
|
|||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.loot.InfestedStringCount;
|
||||
import thedarkcolour.exdeorum.loot.InfestedStringFunction;
|
||||
import thedarkcolour.exdeorum.loot.MachineLootFunction;
|
||||
|
||||
public class ELootFunctions {
|
||||
public static final DeferredRegister<LootItemFunctionType> LOOT_FUNCTIONS = DeferredRegister.create(Registries.LOOT_FUNCTION_TYPE, ExDeorum.ID);
|
||||
public static final RegistryObject<LootItemFunctionType> INFESTED_STRING = LOOT_FUNCTIONS.register("infested_string", () -> new LootItemFunctionType(new InfestedStringCount.LootSerializer()));
|
||||
|
||||
public static final RegistryObject<LootItemFunctionType> INFESTED_STRING = LOOT_FUNCTIONS.register("infested_string", () -> new LootItemFunctionType(new InfestedStringFunction.LootSerializer()));
|
||||
public static final RegistryObject<LootItemFunctionType> MACHINE = LOOT_FUNCTIONS.register("machine", () -> new LootItemFunctionType(new MachineLootFunction.LootSerializer()));
|
||||
}
|
||||
|
|
|
|||
34
src/main/java/thedarkcolour/exdeorum/registry/EMenus.java
Normal file
34
src/main/java/thedarkcolour/exdeorum/registry/EMenus.java
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.registry;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.flag.FeatureFlags;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraftforge.network.IContainerFactory;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.menu.MechanicalSieveMenu;
|
||||
|
||||
public class EMenus {
|
||||
public static final DeferredRegister<MenuType<?>> MENUS = DeferredRegister.create(Registries.MENU, ExDeorum.ID);
|
||||
|
||||
public static final RegistryObject<MenuType<MechanicalSieveMenu>> MECHANICAL_SIEVE = MENUS.register("mechanical_sieve", () -> new MenuType<>((IContainerFactory<MechanicalSieveMenu>) MechanicalSieveMenu::new, FeatureFlags.DEFAULT_FLAGS));
|
||||
}
|
||||
|
|
@ -34,35 +34,35 @@ import java.util.Map;
|
|||
public class EBiomeTags {
|
||||
public static final Map<TagKey<Biome>, RegistryObject<ConfiguredFeature<?, ?>>> TREE_TAGS = new HashMap<>();
|
||||
|
||||
// Vanilla
|
||||
public static final TagKey<Biome> OAK_TREE_BIOMES = addTreeTag("oak_tree_biomes", TreeFeatures.OAK_BEES_005.location());
|
||||
public static final TagKey<Biome> SPRUCE_TREE_BIOMES = addTreeTag("spruce_tree_biomes", TreeFeatures.SPRUCE.location());
|
||||
public static final TagKey<Biome> BIRCH_TREE_BIOMES = addTreeTag("birch_tree_biomes", TreeFeatures.BIRCH_BEES_002.location());
|
||||
public static final TagKey<Biome> JUNGLE_TREE_BIOMES = addTreeTag("jungle_tree_biomes", TreeFeatures.JUNGLE_TREE_NO_VINE.location());
|
||||
public static final TagKey<Biome> ACACIA_TREE_BIOMES = addTreeTag("acacia_tree_biomes", TreeFeatures.ACACIA.location());
|
||||
public static final TagKey<Biome> CHERRY_TREE_BIOMES = addTreeTag("cherry_tree_biomes", TreeFeatures.CHERRY_BEES_005.location());
|
||||
public static final TagKey<Biome> DARK_OAK_TREE_BIOMES = addTreeTag("dark_oak_tree_biomes", TreeFeatures.DARK_OAK.location());
|
||||
public static final TagKey<Biome> MANGROVE_TREE_BIOMES = addTreeTag("mangrove_tree_biomes", TreeFeatures.MANGROVE.location());
|
||||
static {
|
||||
// Vanilla
|
||||
addTreeTag("oak_tree_biomes", TreeFeatures.OAK_BEES_005.location());
|
||||
addTreeTag("spruce_tree_biomes", TreeFeatures.SPRUCE.location());
|
||||
addTreeTag("birch_tree_biomes", TreeFeatures.BIRCH_BEES_002.location());
|
||||
addTreeTag("jungle_tree_biomes", TreeFeatures.JUNGLE_TREE_NO_VINE.location());
|
||||
addTreeTag("acacia_tree_biomes", TreeFeatures.ACACIA.location());
|
||||
addTreeTag("cherry_tree_biomes", TreeFeatures.CHERRY_BEES_005.location());
|
||||
addTreeTag("dark_oak_tree_biomes", TreeFeatures.DARK_OAK.location());
|
||||
addTreeTag("mangrove_tree_biomes", TreeFeatures.MANGROVE.location());
|
||||
// Bop tags
|
||||
addTreeTag("flowering_oak_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "flowering_oak_tree_bees"));
|
||||
addTreeTag("mahogany_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "mahogany_tree"));
|
||||
addTreeTag("jacaranda_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "jacaranda_tree_bees"));
|
||||
addTreeTag("palm_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "palm_tree"));
|
||||
addTreeTag("willow_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "willow_tree"));
|
||||
addTreeTag("dead_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "dead_tree_wasteland"));
|
||||
addTreeTag("magic_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "magic_tree"));
|
||||
addTreeTag("umbran_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "umbran_tree"));
|
||||
}
|
||||
|
||||
// Bop tags
|
||||
public static final TagKey<Biome> FLOWERING_OAK_TREE_BIOMES = addTreeTag("flowering_oak_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "flowering_oak_tree_bees"));
|
||||
public static final TagKey<Biome> MAHOGANY_TREE_BIOMES = addTreeTag("mahogany_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "mahogany_tree"));
|
||||
public static final TagKey<Biome> JACARANDA_TREE_BIOMES = addTreeTag("jacaranda_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "jacaranda_tree_bees"));
|
||||
public static final TagKey<Biome> PALM_TREE_BIOMES = addTreeTag("palm_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "palm_tree"));
|
||||
public static final TagKey<Biome> WILLOW_TREE_BIOMES = addTreeTag("willow_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "willow_tree"));
|
||||
public static final TagKey<Biome> DEAD_TREE_BIOMES = addTreeTag("dead_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "dead_tree_wasteland"));
|
||||
public static final TagKey<Biome> MAGIC_TREE_BIOMES = addTreeTag("magic_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "magic_tree"));
|
||||
public static final TagKey<Biome> UMBRAN_TREE_BIOMES = addTreeTag("umbran_tree_biomes", new ResourceLocation(ModIds.BIOMES_O_PLENTY, "umbran_tree"));
|
||||
|
||||
public static TagKey<Biome> addTreeTag(String tagName, ResourceLocation id) {
|
||||
private static void addTreeTag(String tagName, ResourceLocation id) {
|
||||
var tag = tag(tagName);
|
||||
if (TREE_TAGS.put(tag, RegistryObject.createOptional(id, Registries.CONFIGURED_FEATURE, ExDeorum.ID)) != null) {
|
||||
throw new IllegalStateException("Already added a tree tag under " + tag);
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static TagKey<Biome> tag(String name) {
|
||||
private static TagKey<Biome> tag(String name) {
|
||||
return TagKey.create(Registries.BIOME, new ResourceLocation(ExDeorum.ID, name));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"variants": {
|
||||
"": {
|
||||
"model": "exdeorum:block/mechanical_sieve"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,115 @@
|
|||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "block/block",
|
||||
"texture_size": [32, 32],
|
||||
"render_type": "cutout_mipped",
|
||||
"textures": {
|
||||
"0": "exdeorum:block/mechanical_sieve_top",
|
||||
"1": "exdeorum:block/mechanical_sieve_side",
|
||||
"2": "exdeorum:block/mechanical_sieve_top_inner",
|
||||
"3": "exdeorum:block/mechanical_sieve_bottom",
|
||||
"4": "exdeorum:block/mechanical_sieve_legs",
|
||||
"particle": "exdeorum:block/mechanical_sieve_top"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 8, 0],
|
||||
"to": [16, 11, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 5, 16, 8], "texture": "#1"},
|
||||
"east": {"uv": [0, 5, 16, 8], "texture": "#1"},
|
||||
"south": {"uv": [0, 5, 16, 8], "texture": "#1"},
|
||||
"west": {"uv": [0, 5, 16, 8], "texture": "#1"},
|
||||
"up": {"uv": [0, 0, 16, 16], "texture": "#2"},
|
||||
"down": {"uv": [0, 0, 16, 16], "texture": "#3"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 11, 14],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 8, 16, 13], "texture": "#1"},
|
||||
"east": {"uv": [0, 0, 2, 5], "texture": "#1"},
|
||||
"south": {"uv": [0, 0, 16, 5], "texture": "#1"},
|
||||
"west": {"uv": [14, 0, 16, 5], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [14, 11, 2],
|
||||
"to": [16, 16, 14],
|
||||
"faces": {
|
||||
"east": {"uv": [2, 0, 14, 5], "texture": "#1"},
|
||||
"west": {"uv": [2, 8, 14, 13], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 11, 2],
|
||||
"to": [2, 16, 14],
|
||||
"faces": {
|
||||
"east": {"uv": [2, 8, 14, 13], "texture": "#1"},
|
||||
"west": {"uv": [2, 0, 14, 5], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 11, 0],
|
||||
"to": [16, 16, 2],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 16, 5], "texture": "#1"},
|
||||
"east": {"uv": [14, 0, 16, 5], "texture": "#1"},
|
||||
"south": {"uv": [0, 8, 16, 13], "texture": "#1"},
|
||||
"west": {"uv": [0, 0, 2, 5], "texture": "#1"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 16, 0],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"up": {"uv": [0, 0, 16, 16], "texture": "#0"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1, 0, 1],
|
||||
"to": [3, 8, 3],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 1, 4], "texture": "#4"},
|
||||
"east": {"uv": [1, 0, 2, 4], "texture": "#4"},
|
||||
"south": {"uv": [2, 0, 3, 4], "texture": "#4"},
|
||||
"west": {"uv": [3, 0, 4, 4], "texture": "#4"},
|
||||
"down": {"uv": [5, 0, 4, 1], "texture": "#4"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [1, 0, 13],
|
||||
"to": [3, 8, 15],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 1, 4], "texture": "#4"},
|
||||
"east": {"uv": [1, 0, 2, 4], "texture": "#4"},
|
||||
"south": {"uv": [2, 0, 3, 4], "texture": "#4"},
|
||||
"west": {"uv": [3, 0, 4, 4], "texture": "#4"},
|
||||
"down": {"uv": [5, 0, 4, 1], "texture": "#4"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [13, 0, 13],
|
||||
"to": [15, 8, 15],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 1, 4], "texture": "#4"},
|
||||
"east": {"uv": [1, 0, 2, 4], "texture": "#4"},
|
||||
"south": {"uv": [2, 0, 3, 4], "texture": "#4"},
|
||||
"west": {"uv": [3, 0, 4, 4], "texture": "#4"},
|
||||
"down": {"uv": [5, 0, 4, 1], "texture": "#4"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [13, 0, 1],
|
||||
"to": [15, 8, 3],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 1, 4], "texture": "#4"},
|
||||
"east": {"uv": [1, 0, 2, 4], "texture": "#4"},
|
||||
"south": {"uv": [2, 0, 3, 4], "texture": "#4"},
|
||||
"west": {"uv": [3, 0, 4, 4], "texture": "#4"},
|
||||
"down": {"uv": [5, 0, 4, 1], "texture": "#4"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
|
|
@ -1,30 +0,0 @@
|
|||
package thedarkcolour.exdeorum.test;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
|
||||
@Mod(OresTestMod.ID)
|
||||
public class OresTestMod {
|
||||
public static final String ID = "orestestmod";
|
||||
|
||||
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(Registries.BLOCK, ID);
|
||||
public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(Registries.ITEM, ID);
|
||||
|
||||
public static final RegistryObject<Block> TIN_ORE = BLOCKS.register("tin_ore", () -> new Block(BlockBehaviour.Properties.copy(Blocks.IRON_ORE)));
|
||||
public static final RegistryObject<Item> TIN_ORE_ITEM = ITEMS.register("tin_ore", () -> new BlockItem(TIN_ORE.get(), new Item.Properties()));
|
||||
|
||||
public OresTestMod() {
|
||||
var modBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
|
||||
BLOCKS.register(modBus);
|
||||
ITEMS.register(modBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
modLoader="javafml"
|
||||
loaderVersion="[45,)"
|
||||
license='MIT License'
|
||||
|
||||
[[mods]]
|
||||
modId="orestestmod"
|
||||
version="${file.jarVersion}"
|
||||
displayName="TestMod"
|
||||
credits=""
|
||||
authors="TheDarkColour"
|
||||
description='''
|
||||
Blah
|
||||
'''
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"values": [
|
||||
"orestestmod:tin_ore"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"values": [
|
||||
"orestestmod:tin_ore"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"pack": {
|
||||
"description": "Ex Deorum Test resources",
|
||||
"pack_format": 6
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user