├── gradlew ├── src └── main │ ├── resources │ ├── META-INF │ │ ├── accesstransformer.cfg │ │ └── mods.toml │ ├── assets │ │ └── thirst │ │ │ ├── models │ │ │ └── item │ │ │ │ ├── sand_filter.json │ │ │ │ ├── clay_bowl.json │ │ │ │ ├── terracotta_bowl.json │ │ │ │ ├── wooden_water_bowl.json │ │ │ │ └── terracotta_water_bowl.json │ │ │ ├── blockstates │ │ │ └── sand_filter.json │ │ │ ├── ponder │ │ │ └── sand_filter.nbt │ │ │ ├── textures │ │ │ ├── item │ │ │ │ ├── bowl.png │ │ │ │ ├── clay_bowl.png │ │ │ │ ├── terracotta_bowl.png │ │ │ │ ├── wooden_water_bowl.png │ │ │ │ └── terracotta_water_bowl.png │ │ │ ├── block │ │ │ │ └── sand_filter.png │ │ │ └── gui │ │ │ │ ├── thirst_icons.png │ │ │ │ └── appleskin_icons.png │ │ │ └── lang │ │ │ ├── ja_jp.json │ │ │ ├── ko_kr.json │ │ │ ├── zh_cn.json │ │ │ ├── zh_tw.json │ │ │ ├── pl_pl.json │ │ │ ├── ru_ru.json │ │ │ ├── fr_fr.json │ │ │ └── en_us.json │ ├── thirstwastaken.png │ ├── pack.mcmeta │ ├── data │ │ ├── minecraft │ │ │ └── tags │ │ │ │ └── blocks │ │ │ │ └── mineable │ │ │ │ └── pickaxe.json │ │ ├── thirst │ │ │ ├── recipes │ │ │ │ ├── terracotta_bowl_from_smelting.json │ │ │ │ ├── terracotta_bowl_from_campfire_cooking.json │ │ │ │ ├── clay_bowl.json │ │ │ │ ├── water_bucket_from_campfire_purified.json │ │ │ │ ├── water_bucket_from_campfire_cooking_acceptable.json │ │ │ │ ├── terracotta_water_bowl_from_campfire_cooking_acceptable.json │ │ │ │ ├── terracotta_water_bowl_from_campfire_cooking_purified.json │ │ │ │ ├── compat │ │ │ │ │ ├── toughasnails │ │ │ │ │ │ ├── purified_water_bottle_2.json │ │ │ │ │ │ ├── purified_water_bottle_3.json │ │ │ │ │ │ ├── water_canteen_2.json │ │ │ │ │ │ ├── purified_water_canteen_2.json │ │ │ │ │ │ ├── purified_water_canteen_3.json │ │ │ │ │ │ ├── acceptable_water_bottle_2.json │ │ │ │ │ │ └── acceptable_water_bottle.json │ │ │ │ │ └── create │ │ │ │ │ │ ├── cactus.json │ │ │ │ │ │ ├── terracotta_water_bowl.json │ │ │ │ │ │ └── sand_filter.json │ │ │ │ ├── water_bottle_from_campfire_cooking_purified.json │ │ │ │ ├── water_bottle_from_campfire_cooking_acceptable.json │ │ │ │ ├── water_bucket_from_smelting_acceptable.json │ │ │ │ ├── water_bucket_from_smelting_purfied.json │ │ │ │ ├── water_bucket_from_campfire_cooking_slight_dirty.json │ │ │ │ ├── terracotta_water_bowl_from_smelting_purified.json │ │ │ │ ├── terracotta_water_bowl_from_smelting_acceptable.json │ │ │ │ ├── terracotta_water_bowl_from_campfire_cooking_slightly_dirty.json │ │ │ │ ├── water_bottle_from_smelting_purified.json │ │ │ │ ├── water_bottle_from_smelting_acceptable.json │ │ │ │ └── water_bottle_from_campfire_cooking_slightly_dirty.json │ │ │ ├── loot_modifiers │ │ │ │ ├── add_loot_bastion_other.json │ │ │ │ ├── add_loot_nether_bridge.json │ │ │ │ ├── add_loot_bastion_other_bc.json │ │ │ │ ├── add_loot_bastion_other_fr.json │ │ │ │ ├── add_loot_nether_bridge_bc.json │ │ │ │ ├── add_loot_nether_bridge_fr.json │ │ │ │ ├── add_loot_simple_dungeon.json │ │ │ │ ├── add_loot_shipwreck_supply.json │ │ │ │ ├── add_loot_shipwreck_supply_bc.json │ │ │ │ ├── add_loot_shipwreck_supply_fr.json │ │ │ │ ├── add_loot_simple_dungeon_bc.json │ │ │ │ ├── add_loot_simple_dungeon_fr.json │ │ │ │ ├── add_loot_abandoned_mineshaft.json │ │ │ │ ├── add_loot_abandoned_mineshaft_bc.json │ │ │ │ └── add_loot_abandoned_mineshaft_fr.json │ │ │ └── loot_tables │ │ │ │ ├── blocks │ │ │ │ └── sand_filter.json │ │ │ │ └── chests │ │ │ │ ├── simple_dungeon_bc.json │ │ │ │ ├── abandoned_mineshaft_bc.json │ │ │ │ ├── bastion_other_fr.json │ │ │ │ ├── nether_bridge_fr.json │ │ │ │ ├── shipwreck_supply_fr.json │ │ │ │ ├── bastion_other_bc.json │ │ │ │ ├── nether_bridge_bc.json │ │ │ │ ├── simple_dungeon_fr.json │ │ │ │ ├── abandoned_mineshaft_fr.json │ │ │ │ ├── shipwreck_supply_bc.json │ │ │ │ ├── bastion_other.json │ │ │ │ ├── nether_bridge.json │ │ │ │ ├── shipwreck_supply.json │ │ │ │ ├── simple_dungeon.json │ │ │ │ └── abandoned_mineshaft.json │ │ └── forge │ │ │ └── loot_modifiers │ │ │ └── global_loot_modifiers.json │ └── thirst.mixin.json │ └── java │ └── dev │ └── ghen │ └── thirst │ ├── foundation │ ├── common │ │ ├── damagesource │ │ │ └── ModDamageSource.java │ │ ├── event │ │ │ ├── ThirstEventFactory.java │ │ │ └── RegisterThirstValueEvent.java │ │ ├── capability │ │ │ ├── ModCapabilities.java │ │ │ └── IThirst.java │ │ ├── loot │ │ │ ├── ModLootModifiers.java │ │ │ └── AddLootTableModifier.java │ │ └── item │ │ │ └── DrinkableItem.java │ ├── mixin │ │ ├── accessors │ │ │ ├── farmersdelight │ │ │ │ └── SyncedBlockEntityAccessor.java │ │ │ ├── supplementaries │ │ │ │ └── FaucetBehaviorsManagerAccessor.java │ │ │ ├── brewinandchewin │ │ │ │ └── KegBlockEntityAccessor.java │ │ │ └── farmersrespite │ │ │ │ └── KettleBlockEntityAccessor.java │ │ ├── toughasnails │ │ │ ├── MixinThirstHelperImpl.java │ │ │ ├── MixinServerConfig.java │ │ │ ├── MixinThirstHandler.java │ │ │ └── MixinEmptyCanteenItem.java │ │ ├── MixinAbstractFurnaceEntity.java │ │ ├── farmersrespite │ │ │ ├── MixinKettleBlock.java │ │ │ ├── MixinKettleScreen.java │ │ │ └── MixinKettleBlockEntity.java │ │ ├── MixinLayeredCauldronBlock.java │ │ ├── MixinPotionItem.java │ │ ├── jade │ │ │ └── MixinFluidView.java │ │ ├── create │ │ │ ├── MixinGenericItemFilling.java │ │ │ ├── MixinFluidDrainingBehaviour.java │ │ │ ├── MixinGenericItemEmptying.java │ │ │ ├── MixinBasinRecipe.java │ │ │ ├── MixinOpenEndedPipe.java │ │ │ ├── MixinFillingBySpout.java │ │ │ └── MixinIHaveGoggleInformation.java │ │ ├── MixinItemStack.java │ │ ├── MixinLocalPlayer.java │ │ ├── MixinFluidUtil.java │ │ ├── MixinFluidBucketWrapper.java │ │ ├── botania │ │ │ └── MixinBotania.java │ │ ├── supplementaries │ │ │ └── MixinWaterBlockInteraction.java │ │ ├── MixinBottleItem.java │ │ ├── createcenterkitchen │ │ │ └── MixinKettlePoint.java │ │ ├── MixinBucketItem.java │ │ ├── MixinCampfireBlockEntity.java │ │ ├── MixinFoodData.java │ │ ├── brewinandchewin │ │ │ └── MixinKegBlockEntity.java │ │ └── MixinBootstrap.java │ ├── util │ │ ├── ReflectionUtil.java │ │ ├── LoadedValue.java │ │ ├── MathHelper.java │ │ ├── TickHelper.java │ │ └── ConfigHelper.java │ ├── network │ │ ├── ThirstModPacketHandler.java │ │ └── message │ │ │ ├── DrinkByHandMessage.java │ │ │ └── PlayerThirstSyncMessage.java │ ├── gui │ │ ├── appleskin │ │ │ └── ThirstValues.java │ │ └── ThirstBarRenderer.java │ ├── config │ │ ├── ContainerConfig.java │ │ ├── ClientConfig.java │ │ └── KeyWordConfig.java │ └── tab │ │ └── ThirstTab.java │ ├── content │ ├── purity │ │ ├── FillableWithPurity.java │ │ └── ContainerWithPurity.java │ ├── registry │ │ ├── ItemInit.java │ │ └── CommandInit.java │ └── thirst │ │ ├── DrinkByHandClient.java │ │ └── PlayerThirstManager.java │ ├── compat │ └── create │ │ ├── ponder │ │ ├── ThirstPonders.java │ │ └── scene │ │ │ └── SandFilterScene.java │ │ ├── CreateRegistry.java │ │ └── SandFilterBlock.java │ └── Thirst.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitattributes ├── .gitignore ├── gradle.properties ├── README.md ├── gradlew.bat └── CREDITS.txt /gradlew: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/gradlew -------------------------------------------------------------------------------- /src/main/resources/META-INF/accesstransformer.cfg: -------------------------------------------------------------------------------- 1 | public-f net.minecraft.world.food.FoodProperties f_38723_ -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/models/item/sand_filter.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "thirst:block/sand_filter" 3 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/thirstwastaken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/thirstwastaken.png -------------------------------------------------------------------------------- /src/main/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "Thirst was Taken resources", 4 | "pack_format": 9 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/blockstates/sand_filter.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "": { 4 | "model": "thirst:block/sand_filter" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/ponder/sand_filter.nbt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/ponder/sand_filter.nbt -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/textures/item/bowl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/textures/item/bowl.png -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/textures/item/clay_bowl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/textures/item/clay_bowl.png -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/models/item/clay_bowl.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "textures": { 4 | "layer0": "thirst:item/clay_bowl" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/textures/block/sand_filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/textures/block/sand_filter.png -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/textures/gui/thirst_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/textures/gui/thirst_icons.png -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/textures/gui/appleskin_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/textures/gui/appleskin_icons.png -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/textures/item/terracotta_bowl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/textures/item/terracotta_bowl.png -------------------------------------------------------------------------------- /src/main/resources/data/minecraft/tags/blocks/mineable/pickaxe.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "id": "thirst:sand_filter", 5 | "required": false 6 | } 7 | ] 8 | } -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/models/item/terracotta_bowl.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "textures": { 4 | "layer0": "thirst:item/terracotta_bowl" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/textures/item/wooden_water_bowl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/textures/item/wooden_water_bowl.png -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/models/item/wooden_water_bowl.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "textures": { 4 | "layer0": "thirst:item/wooden_water_bowl" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/textures/item/terracotta_water_bowl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghen-git/Thirst-Mod/HEAD/src/main/resources/assets/thirst/textures/item/terracotta_water_bowl.png -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/models/item/terracotta_water_bowl.json: -------------------------------------------------------------------------------- 1 | { 2 | "parent": "minecraft:item/generated", 3 | "textures": { 4 | "layer0": "thirst:item/terracotta_water_bowl" 5 | } 6 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable autocrlf on generated files, they always generate with LF 2 | # Add any extra files or paths here to make git stop saying they 3 | # are changed when only line endings change. 4 | src/generated/**/.cache/cache text eol=lf 5 | src/generated/**/*.json text eol=lf 6 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/terracotta_bowl_from_smelting.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:smelting", 3 | "ingredient": 4 | { 5 | "item": "thirst:clay_bowl" 6 | }, 7 | "result": "thirst:terracotta_bowl", 8 | "experience": 0.35, 9 | "cookingtime": 200 10 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/terracotta_bowl_from_campfire_cooking.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient": 4 | { 5 | "item": "thirst:clay_bowl" 6 | }, 7 | "result": "thirst:terracotta_bowl", 8 | "experience": 0.35, 9 | "cookingtime": 300 10 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # eclipse 2 | bin 3 | *.launch 4 | .settings 5 | .metadata 6 | .classpath 7 | .project 8 | 9 | # idea 10 | out 11 | *.ipr 12 | *.iws 13 | *.iml 14 | .idea 15 | 16 | # gradle 17 | build 18 | .gradle 19 | 20 | # other 21 | eclipse 22 | run 23 | 24 | # Files from Forge MDK 25 | forge*changelog.txt 26 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_bastion_other.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/bastion_other" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/bastion_other" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_nether_bridge.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/nether_bridge" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/nether_bridge" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_bastion_other_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/bastion_other" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/bastion_other_bc" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_bastion_other_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/bastion_other" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/bastion_other_fr" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_nether_bridge_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/nether_bridge" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/nether_bridge_bc" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_nether_bridge_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/nether_bridge" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/nether_bridge_fr" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_simple_dungeon.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/simple_dungeon" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/simple_dungeon" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/clay_bowl.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:crafting_shaped", 3 | "pattern": [ 4 | "# #", 5 | " # " 6 | ], 7 | "key": { 8 | "#": { 9 | "item": "minecraft:clay_ball" 10 | } 11 | }, 12 | "result": { 13 | "item": "thirst:clay_bowl", 14 | "count": 4 15 | } 16 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Sets default memory used for gradle commands. Can be overridden by user or command line properties. 2 | # This is required to provide enough memory for the Minecraft decompilation process. 3 | org.gradle.jvmargs=-Xmx3G 4 | org.gradle.daemon=false 5 | mc_version=1.19.2 6 | jei_version=11.5.0.297 7 | 8 | mod_version=1.19.2-1.3.11 -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_shipwreck_supply.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/shipwreck_supply" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/shipwreck_supply" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_shipwreck_supply_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/shipwreck_supply" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/shipwreck_supply_bc" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_shipwreck_supply_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/shipwreck_supply" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/shipwreck_supply_fr" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_simple_dungeon_bc.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "type": "thirst:add_loot_table", 4 | "conditions": 5 | [ 6 | { 7 | "condition": "forge:loot_table_id", 8 | "loot_table_id": "minecraft:chests/simple_dungeon" 9 | } 10 | ], 11 | "lootTable": "thirst:chests/simple_dungeon_bc" 12 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_simple_dungeon_fr.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "type": "thirst:add_loot_table", 4 | "conditions": 5 | [ 6 | { 7 | "condition": "forge:loot_table_id", 8 | "loot_table_id": "minecraft:chests/simple_dungeon" 9 | } 10 | ], 11 | "lootTable": "thirst:chests/simple_dungeon_fr" 12 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_abandoned_mineshaft.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/abandoned_mineshaft" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/abandoned_mineshaft" 11 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/common/damagesource/ModDamageSource.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.common.damagesource; 2 | 3 | import net.minecraft.world.damagesource.DamageSource; 4 | 5 | public class ModDamageSource 6 | { 7 | public static final DamageSource DEHYDRATE = (new DamageSource("dehydrate")).bypassArmor().bypassMagic(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_abandoned_mineshaft_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/abandoned_mineshaft" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/abandoned_mineshaft_bc" 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_modifiers/add_loot_abandoned_mineshaft_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "thirst:add_loot_table", 3 | "conditions": 4 | [ 5 | { 6 | "condition": "forge:loot_table_id", 7 | "loot_table_id": "minecraft:chests/abandoned_mineshaft" 8 | } 9 | ], 10 | "lootTable": "thirst:chests/abandoned_mineshaft_fr" 11 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/common/event/ThirstEventFactory.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.common.event; 2 | 3 | import net.minecraftforge.common.MinecraftForge; 4 | 5 | public class ThirstEventFactory { 6 | public static void onRegisterThirstValue() { 7 | MinecraftForge.EVENT_BUS.post(new RegisterThirstValueEvent()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bucket_from_campfire_purified.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:water_bucket", 7 | "nbt": "{Purity:2}" 8 | } 9 | ], 10 | "result": { 11 | "item": "minecraft:water_bucket", 12 | "nbt": { 13 | "Purity": 3 14 | } 15 | }, 16 | "experience": 0.35, 17 | "cookingtime": 300 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bucket_from_campfire_cooking_acceptable.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:water_bucket", 7 | "nbt": "{Purity:1}" 8 | } 9 | ], 10 | "result": { 11 | "item": "minecraft:water_bucket", 12 | "nbt": { 13 | "Purity": 2 14 | } 15 | }, 16 | "experience": 0.35, 17 | "cookingtime": 300 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/terracotta_water_bowl_from_campfire_cooking_acceptable.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "thirst:terracotta_water_bowl", 7 | "nbt": "{Purity:1}" 8 | } 9 | ], 10 | "result": { 11 | "item": "thirst:terracotta_water_bowl", 12 | "nbt": { 13 | "Purity": 2 14 | } 15 | }, 16 | "experience": 0.35, 17 | "cookingtime": 300 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/terracotta_water_bowl_from_campfire_cooking_purified.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "thirst:terracotta_water_bowl", 7 | "nbt": "{Purity:2}" 8 | } 9 | ], 10 | "result": { 11 | "item": "thirst:terracotta_water_bowl", 12 | "nbt": { 13 | "Purity": 3 14 | } 15 | }, 16 | "experience": 0.35, 17 | "cookingtime": 300 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/toughasnails/purified_water_bottle_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "toughasnails" 6 | } 7 | ], 8 | "type": "toughasnails:water_purifying", 9 | "ingredient": { 10 | "item": "minecraft:potion", 11 | "nbt": "{Potion:'minecraft:water',Purity:2}" 12 | }, 13 | "result": { 14 | "item": "toughasnails:purified_water_bottle" 15 | }, 16 | "purifytime": 200 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/toughasnails/purified_water_bottle_3.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "toughasnails" 6 | } 7 | ], 8 | "type": "toughasnails:water_purifying", 9 | "ingredient": { 10 | "item": "minecraft:potion", 11 | "nbt": "{Potion:'minecraft:water',Purity:1}" 12 | }, 13 | "result": { 14 | "item": "toughasnails:purified_water_bottle" 15 | }, 16 | "purifytime": 200 17 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/toughasnails/water_canteen_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "toughasnails" 6 | } 7 | ], 8 | "type": "toughasnails:water_purifying", 9 | "ingredient": { 10 | "item": "toughasnails:dirty_water_canteen", 11 | "nbt": "{Purity:0}" 12 | }, 13 | "result": { 14 | "item": "toughasnails:water_canteen", 15 | "nbt": "{Purity:2}" 16 | }, 17 | "purifytime": 400 18 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/common/capability/ModCapabilities.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.common.capability; 2 | 3 | import net.minecraftforge.common.capabilities.Capability; 4 | import net.minecraftforge.common.capabilities.CapabilityManager; 5 | import net.minecraftforge.common.capabilities.CapabilityToken; 6 | 7 | public class ModCapabilities 8 | { 9 | public static final Capability PLAYER_THIRST = CapabilityManager.get(new CapabilityToken<>() {}); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/toughasnails/purified_water_canteen_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "toughasnails" 6 | } 7 | ], 8 | "type": "toughasnails:water_purifying", 9 | "ingredient": { 10 | "item": "toughasnails:water_canteen", 11 | "nbt": "{Purity:2}" 12 | }, 13 | "result": { 14 | "item": "toughasnails:purified_water_canteen", 15 | "nbt": "{Purity:3}" 16 | }, 17 | "purifytime": 200 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/toughasnails/purified_water_canteen_3.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "toughasnails" 6 | } 7 | ], 8 | "type": "toughasnails:water_purifying", 9 | "ingredient": { 10 | "item": "toughasnails:water_canteen", 11 | "nbt": "{Purity:1}" 12 | }, 13 | "result": { 14 | "item": "toughasnails:purified_water_canteen", 15 | "nbt": "{Purity:3}" 16 | }, 17 | "purifytime": 200 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/toughasnails/acceptable_water_bottle_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "toughasnails" 6 | } 7 | ], 8 | "type": "toughasnails:water_purifying", 9 | "ingredient": { 10 | "item": "toughasnails:dirty_water_bottle", 11 | "nbt": "{Purity:0}" 12 | }, 13 | "result": { 14 | "item": "minecraft:potion", 15 | "nbt": "{Potion:'minecraft:water',Purity:2}" 16 | }, 17 | "purifytime": 200 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bottle_from_campfire_cooking_purified.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:potion", 7 | "nbt": "{Potion:'minecraft:water',Purity:2}" 8 | } 9 | ], 10 | "result": { 11 | "item":"minecraft:potion", 12 | "nbt": { 13 | "Potion": "minecraft:water", 14 | "Purity": 3 15 | } 16 | }, 17 | "experience": 0.35, 18 | "cookingtime": 300 19 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/accessors/farmersdelight/SyncedBlockEntityAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.accessors.farmersdelight; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.gen.Invoker; 5 | import vectorwing.farmersdelight.common.block.entity.SyncedBlockEntity; 6 | 7 | @Mixin(SyncedBlockEntity.class) 8 | public interface SyncedBlockEntityAccessor 9 | { 10 | @Invoker(remap = false) 11 | void invokeInventoryChanged(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/create/cactus.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "create" 6 | } 7 | ], 8 | "type": "create:compacting", 9 | "ingredients": [ 10 | { 11 | "item": "minecraft:cactus" 12 | } 13 | ], 14 | "results": [ 15 | { 16 | "amount": 250, 17 | "fluid": "minecraft:water", 18 | "nbt": "{Purity:3}" 19 | }, 20 | { 21 | "item": "minecraft:green_dye" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/toughasnails/acceptable_water_bottle.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "toughasnails" 6 | } 7 | ], 8 | "type": "toughasnails:water_purifying", 9 | "ingredient": { 10 | "item": "minecraft:potion", 11 | "nbt": "{Potion:'minecraft:water',Purity:0}" 12 | }, 13 | "result": { 14 | "item": "minecraft:potion", 15 | "nbt": "{Potion:'minecraft:water',Purity:2}" 16 | }, 17 | "purifytime": 200 18 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/create/terracotta_water_bowl.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "create" 6 | } 7 | ], 8 | "type": "create:filling", 9 | "ingredients": [ 10 | { 11 | "item": "thirst:terracotta_bowl" 12 | }, 13 | { 14 | "amount": 250, 15 | "fluid": "minecraft:water", 16 | "nbt": {} 17 | } 18 | ], 19 | "results": [ 20 | { 21 | "item": "thirst:terracotta_water_bowl" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bottle_from_campfire_cooking_acceptable.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:potion", 7 | "nbt": "{Potion:'minecraft:water',Purity:1}" 8 | } 9 | ], 10 | "result": { 11 | "type": "forge:nbt", 12 | "item":"minecraft:potion", 13 | "nbt": { 14 | "Potion": "minecraft:water", 15 | "Purity": 2 16 | } 17 | }, 18 | "experience": 0.35, 19 | "cookingtime": 300 20 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bucket_from_smelting_acceptable.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:smelting", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:water_bucket", 7 | "nbt": "{Purity:0}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item": "minecraft:water_bucket", 12 | "nbt": "{Purity:-1}" 13 | } 14 | ], 15 | "result": { 16 | "item": "minecraft:water_bucket", 17 | "nbt": { 18 | "Purity": 2 19 | } 20 | }, 21 | "experience": 0.35, 22 | "cookingtime": 200 23 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bucket_from_smelting_purfied.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:smelting", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:water_bucket", 7 | "nbt": "{Purity:1}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item": "minecraft:water_bucket", 12 | "nbt": "{Purity:2}" 13 | } 14 | ], 15 | "result": { 16 | "item": "minecraft:water_bucket", 17 | "nbt": { 18 | "Purity": 3 19 | } 20 | }, 21 | "experience": 0.35, 22 | "cookingtime": 200 23 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bucket_from_campfire_cooking_slight_dirty.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:water_bucket", 7 | "nbt": "{Purity:0}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item": "minecraft:water_bucket", 12 | "nbt": "{Purity:-1}" 13 | } 14 | ], 15 | "result": { 16 | "item": "minecraft:water_bucket", 17 | "nbt": { 18 | "Purity": 1 19 | } 20 | }, 21 | "experience": 0.35, 22 | "cookingtime": 300 23 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/blocks/sand_filter.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "create" 6 | } 7 | ], 8 | "type": "minecraft:block", 9 | "pools": [ 10 | { 11 | "bonus_rolls": 0.0, 12 | "conditions": [ 13 | { 14 | "condition": "minecraft:survives_explosion" 15 | } 16 | ], 17 | "entries": [ 18 | { 19 | "type": "minecraft:item", 20 | "name": "thirst:sand_filter" 21 | } 22 | ], 23 | "rolls": 1.0 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/compat/create/sand_filter.json: -------------------------------------------------------------------------------- 1 | { 2 | "conditions": [ 3 | { 4 | "type": "forge:mod_loaded", 5 | "modid": "create" 6 | } 7 | ], 8 | "type": "minecraft:crafting_shaped", 9 | "pattern": [ 10 | "A", 11 | "B", 12 | "C" 13 | ], 14 | "key": { 15 | "A": { 16 | "tag": "forge:sand" 17 | }, 18 | "B": { 19 | "item": "create:nozzle" 20 | }, 21 | "C": { 22 | "item": "create:fluid_tank" 23 | } 24 | }, 25 | "result": { 26 | "item": "thirst:sand_filter", 27 | "count": 1 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/terracotta_water_bowl_from_smelting_purified.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:smelting", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "thirst:terracotta_water_bowl", 7 | "nbt": "{Purity:1}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item": "thirst:terracotta_water_bowl", 12 | "nbt": "{Purity:2}" 13 | } 14 | ], 15 | "result": { 16 | "item": "thirst:terracotta_water_bowl", 17 | "nbt": { 18 | "Purity": 3 19 | } 20 | }, 21 | "experience": 0.35, 22 | "cookingtime": 200 23 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/terracotta_water_bowl_from_smelting_acceptable.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:smelting", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "thirst:terracotta_water_bowl", 7 | "nbt": "{Purity:0}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item": "thirst:terracotta_water_bowl", 12 | "nbt": "{Purity:-1}" 13 | } 14 | ], 15 | "result": { 16 | "item": "thirst:terracotta_water_bowl", 17 | "nbt": { 18 | "Purity": 2 19 | } 20 | }, 21 | "experience": 0.35, 22 | "cookingtime": 200 23 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/terracotta_water_bowl_from_campfire_cooking_slightly_dirty.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "thirst:terracotta_water_bowl", 7 | "nbt": "{Purity:0}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item": "thirst:terracotta_water_bowl", 12 | "nbt": "{Purity:-1}" 13 | } 14 | ], 15 | "result": { 16 | "item": "thirst:terracotta_water_bowl", 17 | "nbt": { 18 | "Purity": 1 19 | } 20 | }, 21 | "experience": 0.35, 22 | "cookingtime": 300 23 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bottle_from_smelting_purified.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:smelting", 3 | "ingredient": [ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:potion", 7 | "nbt": "{Potion:'minecraft:water',Purity:1}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item": "minecraft:potion", 12 | "nbt": "{Potion:'minecraft:water',Purity:2}" 13 | } 14 | ], 15 | "result": { 16 | "item":"minecraft:potion", 17 | "nbt": { 18 | "Potion": "minecraft:water", 19 | "Purity": 3 20 | } 21 | }, 22 | "experience": 0.35, 23 | "cookingtime": 200 24 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/simple_dungeon_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | } 14 | ], 15 | "name": "brewinandchewin:vodka", 16 | "weight": 10 17 | }, 18 | { 19 | "type": "minecraft:empty", 20 | "weight": 10 21 | } 22 | ], 23 | "rolls": 1 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bottle_from_smelting_acceptable.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:smelting", 3 | "ingredient": [ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:potion", 7 | "nbt": "{Potion:'minecraft:water',Purity:-1}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item": "minecraft:potion", 12 | "nbt": "{Potion:'minecraft:water',Purity:0}" 13 | } 14 | ], 15 | "result": { 16 | "item":"minecraft:potion", 17 | "nbt": { 18 | "Potion": "minecraft:water", 19 | "Purity": 2 20 | } 21 | }, 22 | "experience": 0.35, 23 | "cookingtime": 200 24 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/abandoned_mineshaft_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | } 14 | ], 15 | "name": "brewinandchewin:beer", 16 | "weight": 10 17 | }, 18 | { 19 | "type": "minecraft:empty", 20 | "weight": 10 21 | } 22 | ], 23 | "rolls": 1 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/bastion_other_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | } 14 | ], 15 | "name": "farmersrespite:rose_hip_tea", 16 | "weight": 10 17 | }, 18 | { 19 | "type": "minecraft:empty", 20 | "weight": 10 21 | } 22 | ], 23 | "rolls": 1 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/nether_bridge_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | } 14 | ], 15 | "name": "farmersrespite:rose_hip_tea", 16 | "weight": 10 17 | }, 18 | { 19 | "type": "minecraft:empty", 20 | "weight": 10 21 | } 22 | ], 23 | "rolls": 1 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/recipes/water_bottle_from_campfire_cooking_slightly_dirty.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:campfire_cooking", 3 | "ingredient":[ 4 | { 5 | "type": "forge:nbt", 6 | "item": "minecraft:potion", 7 | "nbt": "{Potion:'minecraft:water',Purity:0}" 8 | }, 9 | { 10 | "type": "forge:nbt", 11 | "item":"minecraft:potion", 12 | "nbt": "{Potion:'minecraft:water',Purity:-1}" 13 | } 14 | ], 15 | "result": { 16 | "item":"minecraft:potion", 17 | "nbt": { 18 | "Potion": "minecraft:water", 19 | "Purity": 1 20 | } 21 | }, 22 | "experience": 0.35, 23 | "cookingtime": 300 24 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/util/ReflectionUtil.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.util; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | 6 | public class ReflectionUtil 7 | { 8 | /* 9 | * HAHA fuck you, reflections 10 | * */ 11 | public static Object fuckYouReflections(Method method, Object obj, Object... args) 12 | { 13 | try 14 | { 15 | return method.invoke(obj, args); 16 | } 17 | catch (IllegalAccessException | InvocationTargetException e) 18 | { 19 | throw new RuntimeException(e); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/toughasnails/MixinThirstHelperImpl.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.toughasnails; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Inject; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 7 | import toughasnails.thirst.ThirstHelperImpl; 8 | 9 | @Mixin(value = ThirstHelperImpl.class,remap = false) 10 | public class MixinThirstHelperImpl { 11 | @Inject(method = "canDrink",at = @At("RETURN"), cancellable = true) 12 | private void canDrink(CallbackInfoReturnable cir){ 13 | cir.setReturnValue(true); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/toughasnails/MixinServerConfig.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.toughasnails; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.ModifyArg; 6 | import toughasnails.config.ServerConfig; 7 | 8 | @Mixin(value = ServerConfig.class,remap = false) 9 | public class MixinServerConfig { 10 | @ModifyArg(method ="", at = @At(value = "INVOKE", target = "Lnet/minecraftforge/common/ForgeConfigSpec$Builder;define(Ljava/lang/String;Z)Lnet/minecraftforge/common/ForgeConfigSpec$BooleanValue;", ordinal = 0),index = 1) 11 | private static boolean modifyBoolean(boolean defaultValue) { 12 | return false; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/content/purity/FillableWithPurity.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.content.purity; 2 | 3 | import net.minecraft.world.level.block.Block; 4 | import net.minecraft.world.level.block.state.BlockState; 5 | 6 | public class FillableWithPurity { 7 | private Block block; 8 | 9 | public FillableWithPurity(Block block) { 10 | this.block = block; 11 | } 12 | 13 | public int getPurity(BlockState blockState) { 14 | return !blockState.hasProperty(WaterPurity.BLOCK_PURITY) ? 15 | 3 : blockState.getValue(WaterPurity.BLOCK_PURITY); 16 | } 17 | 18 | public Block getBlock() { 19 | return this.block; 20 | } 21 | 22 | public void setBlock(Block block) { 23 | this.block = block; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/resources/data/forge/loot_modifiers/global_loot_modifiers.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "entries": [ 4 | "thirst:add_loot_shipwreck_supply", 5 | "thirst:add_loot_shipwreck_supply_fr", 6 | "thirst:add_loot_shipwreck_supply_bc", 7 | "thirst:add_loot_abandoned_mineshaft", 8 | "thirst:add_loot_abandoned_mineshaft_fr", 9 | "thirst:add_loot_abandoned_mineshaft_bc", 10 | "thirst:add_loot_simple_dungeon", 11 | "thirst:add_loot_simple_dungeon_fr", 12 | "thirst:add_loot_simple_dungeon_bc", 13 | "thirst:add_loot_nether_bridge", 14 | "thirst:add_loot_nether_bridge_fr", 15 | "thirst:add_loot_nether_bridge_bc", 16 | "thirst:add_loot_bastion_other", 17 | "thirst:add_loot_bastion_other_fr", 18 | "thirst:add_loot_bastion_other_bc" 19 | ] 20 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/toughasnails/MixinThirstHandler.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.toughasnails; 2 | 3 | import net.minecraftforge.event.entity.player.PlayerInteractEvent; 4 | import org.spongepowered.asm.mixin.Mixin; 5 | import org.spongepowered.asm.mixin.injection.At; 6 | import org.spongepowered.asm.mixin.injection.Inject; 7 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 8 | import toughasnails.thirst.ThirstHandler; 9 | 10 | @Mixin(value = ThirstHandler.class,remap = false) 11 | public class MixinThirstHandler { 12 | @Inject(method = "onPlayerInteractItem", at = @At("HEAD"), cancellable = true) 13 | private void onPlayerInteractItem(PlayerInteractEvent.RightClickItem event, CallbackInfo ci){ 14 | ci.cancel(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinAbstractFurnaceEntity.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import net.minecraft.world.item.ItemStack; 4 | import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.injection.At; 7 | import org.spongepowered.asm.mixin.injection.Redirect; 8 | 9 | @Mixin(AbstractFurnaceBlockEntity.class) 10 | public class MixinAbstractFurnaceEntity { 11 | @Redirect(method = "canBurn",at= @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;sameItem(Lnet/minecraft/world/item/ItemStack;)Z")) 12 | private boolean canBurn(ItemStack remainItem, ItemStack recipeResult){ 13 | return ItemStack.isSameItemSameTags(remainItem,recipeResult); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/accessors/supplementaries/FaucetBehaviorsManagerAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.accessors.supplementaries; 2 | 3 | import net.mehvahdjukaar.moonlight.api.fluids.SoftFluid; 4 | import net.mehvahdjukaar.moonlight.api.fluids.SoftFluidTank; 5 | import net.mehvahdjukaar.supplementaries.common.block.faucet.FaucetBehaviorsManager; 6 | import net.minecraft.nbt.CompoundTag; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.gen.Invoker; 9 | 10 | @Mixin(FaucetBehaviorsManager.class) 11 | public interface FaucetBehaviorsManagerAccessor 12 | { 13 | @Invoker(remap = false) 14 | static void invokePrepareToTransferBottle(SoftFluidTank tempFluidHolder, SoftFluid softFluid, CompoundTag tag){ 15 | throw new AssertionError(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/shipwreck_supply_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | }, 14 | { 15 | "count": { 16 | "type": "minecraft:uniform", 17 | "max": 3.0, 18 | "min": 1.0 19 | }, 20 | "function": "minecraft:set_count" 21 | } 22 | ], 23 | "name": "farmersrespite:black_tea", 24 | "weight": 10 25 | }, 26 | { 27 | "type": "minecraft:empty", 28 | "weight": 20 29 | } 30 | ], 31 | "rolls": 1 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/common/capability/IThirst.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.common.capability; 2 | 3 | import net.minecraft.nbt.CompoundTag; 4 | import net.minecraft.world.entity.player.Player; 5 | 6 | public interface IThirst 7 | { 8 | int getThirst(); 9 | void setThirst(int value); 10 | int getQuenched(); 11 | void setQuenched(int value); 12 | float getExhaustion(); 13 | void setExhaustion(float value); 14 | void addExhaustion(Player player, float amount); 15 | void tick(Player player); 16 | void drink(Player player, int thirst, int quenched); 17 | void updateThirstData(Player player); 18 | void setJustHealed(); 19 | void ExhaustionRecalculate(); 20 | void setShouldTickThirst(boolean value); 21 | boolean getShouldTickThirst(); 22 | void copy(IThirst cap); 23 | 24 | CompoundTag serializeNBT(); 25 | void deserializeNBT(CompoundTag tag); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/common/loot/ModLootModifiers.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.common.loot; 2 | 3 | 4 | import com.mojang.serialization.Codec; 5 | import net.minecraftforge.common.loot.IGlobalLootModifier; 6 | import net.minecraftforge.registries.DeferredRegister; 7 | import net.minecraftforge.registries.ForgeRegistries; 8 | import net.minecraftforge.registries.RegistryObject; 9 | 10 | public class ModLootModifiers { 11 | public static final DeferredRegister> LOOT_MODIFIERS; 12 | public static final RegistryObject> ADD_LOOT_TABLE; 13 | 14 | public ModLootModifiers() { 15 | } 16 | 17 | static { 18 | LOOT_MODIFIERS = DeferredRegister.create(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, "thirst"); 19 | ADD_LOOT_TABLE = LOOT_MODIFIERS.register("add_loot_table", AddLootTableModifier.CODEC); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/bastion_other_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | } 14 | ], 15 | "name": "brewinandchewin:red_rum", 16 | "weight": 10 17 | }, 18 | { 19 | "type": "minecraft:item", 20 | "functions": [ 21 | { 22 | "function": "set_nbt", 23 | "tag": "{Purity: 3}" 24 | } 25 | ], 26 | "name": "brewinandchewin:strongroot_ale", 27 | "weight": 10 28 | }, 29 | { 30 | "type": "minecraft:empty", 31 | "weight": 20 32 | } 33 | ], 34 | "rolls": 1 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/nether_bridge_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | } 14 | ], 15 | "name": "brewinandchewin:red_rum", 16 | "weight": 10 17 | }, 18 | { 19 | "type": "minecraft:item", 20 | "functions": [ 21 | { 22 | "function": "set_nbt", 23 | "tag": "{Purity: 3}" 24 | } 25 | ], 26 | "name": "brewinandchewin:strongroot_ale", 27 | "weight": 10 28 | }, 29 | { 30 | "type": "minecraft:empty", 31 | "weight": 20 32 | } 33 | ], 34 | "rolls": 1 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/simple_dungeon_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | } 14 | ], 15 | "name": "farmersrespite:dandelion_tea", 16 | "weight": 10 17 | }, 18 | { 19 | "type": "minecraft:item", 20 | "functions": [ 21 | { 22 | "function": "set_nbt", 23 | "tag": "{Purity: 3}" 24 | } 25 | ], 26 | "name": "farmersrespite:yellow_tea", 27 | "weight": 10 28 | }, 29 | { 30 | "type": "minecraft:empty", 31 | "weight": 20 32 | } 33 | ], 34 | "rolls": 1 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/abandoned_mineshaft_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | } 14 | ], 15 | "name": "farmersdelight:apple_cider", 16 | "weight": 10 17 | }, 18 | { 19 | "type": "minecraft:item", 20 | "functions": [ 21 | { 22 | "function": "set_nbt", 23 | "tag": "{Purity: 3}" 24 | } 25 | ], 26 | "name": "farmersrespite:yellow_tea", 27 | "weight": 10 28 | }, 29 | { 30 | "type": "minecraft:empty", 31 | "weight": 20 32 | } 33 | ], 34 | "rolls": 1 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/farmersrespite/MixinKettleBlock.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.farmersrespite; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import net.minecraft.world.level.block.Block; 5 | import net.minecraft.world.level.block.state.BlockState; 6 | import net.minecraft.world.level.block.state.StateDefinition; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Inject; 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 11 | import umpaz.farmersrespite.common.block.KettleBlock; 12 | 13 | @Mixin(KettleBlock.class) 14 | public abstract class MixinKettleBlock { 15 | 16 | @Inject(method = "createBlockStateDefinition", at = @At("HEAD")) 17 | protected void addPurityBlockState(StateDefinition.Builder p_153549_, CallbackInfo ci) { 18 | p_153549_.add(WaterPurity.BLOCK_PURITY); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinLayeredCauldronBlock.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | 5 | import net.minecraft.world.level.block.Block; 6 | import net.minecraft.world.level.block.LayeredCauldronBlock; 7 | import net.minecraft.world.level.block.state.BlockState; 8 | import net.minecraft.world.level.block.state.StateDefinition; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 13 | 14 | 15 | @Mixin(LayeredCauldronBlock.class) 16 | public abstract class MixinLayeredCauldronBlock 17 | { 18 | @Inject(method = "createBlockStateDefinition", at = @At("HEAD")) 19 | protected void addPurityBlockState(StateDefinition.Builder p_153549_, CallbackInfo ci) 20 | { 21 | p_153549_.add(WaterPurity.BLOCK_PURITY); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinPotionItem.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import net.minecraft.world.entity.item.ItemEntity; 4 | import net.minecraft.world.entity.player.Inventory; 5 | import net.minecraft.world.item.ItemStack; 6 | import net.minecraft.world.item.PotionItem; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Redirect; 10 | 11 | @Mixin(PotionItem.class) 12 | public class MixinPotionItem { 13 | 14 | @Redirect(method = "finishUsingItem",at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Inventory;add(Lnet/minecraft/world/item/ItemStack;)Z")) 15 | public boolean finishUsingItem(Inventory instance, ItemStack stack){ 16 | ItemEntity itemEntity = new ItemEntity(instance.player.level, instance.player.getX(), instance.player.getY(), instance.player.getZ(), stack); 17 | instance.player.level.addFreshEntity(itemEntity); 18 | return true; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/lang/ja_jp.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.attack.dehydrate": "%1$s が脱水で死亡しました。", 3 | "death.attack.dehydrate.player": "%1$s が %2$s と戦って脱水で死亡しました。", 4 | "item.thirst.wooden_water_bowl": "木の水入れ", 5 | "item.thirst.terracotta_water_bowl": "テラコッタ 水入れ", 6 | "item.thirst.terracotta_bowl": "テラコッタ 器", 7 | "item.thirst.clay_bowl": "粘土の器", 8 | "thirst.container.kettle.no_water": "水なし", 9 | "thirst.container.kettle.has_single_water": "%s 水 1杯 付き", 10 | "thirst.container.kettle.has_many_water": "%2$s 水 %1$s 杯 含む", 11 | "itemGroup.thirst": "渇き", 12 | "thirst.purity.dirty": "汚れ", 13 | "thirst.purity.slightly_dirty": "やや汚れ", 14 | "thirst.purity.acceptable": "許容", 15 | "thirst.purity.purified": "精製された", 16 | "block.thirst.sand_filter": "砂フィルター", 17 | 18 | "thirst.ponder.sand_filter.header": "Purifying Water with a Sand Filter", 19 | "thirst.ponder.sand_filter.text_1": "A Sand Filter purifies by one step water pumped through it", 20 | "thirst.ponder.sand_filter.text_2": "Dirty Water needs to be pumped in from the top...", 21 | "thirst.ponder.sand_filter.text_3": "and Purified Water can be pumped out from the bottom" 22 | } -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/lang/ko_kr.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.attack.dehydrate": "%1$s 이(가) 탈수로 사망했습니다.", 3 | "death.attack.dehydrate.player": "%1$s 이(가) %2$s 와 싸우다가 탈수로 사망했습니다.", 4 | "item.thirst.wooden_water_bowl": "나무 물그릇", 5 | "item.thirst.terracotta_water_bowl": "테라코타 물그릇", 6 | "item.thirst.terracotta_bowl": "테라코타 그릇", 7 | "item.thirst.clay_bowl": "점토 그릇", 8 | "thirst.container.kettle.no_water": "물 없음", 9 | "thirst.container.kettle.has_single_water": "%s 물 1잔 포함", 10 | "thirst.container.kettle.has_many_water": "%2$s 물 %1$s 잔 포함", 11 | "itemGroup.thirst": "갈증", 12 | "thirst.purity.dirty": "더러움", 13 | "thirst.purity.slightly_dirty": "약간 더러움", 14 | "thirst.purity.acceptable": "허용", 15 | "thirst.purity.purified": "정제된", 16 | "block.thirst.sand_filter": "모래 필터", 17 | 18 | "thirst.ponder.sand_filter.header": "Purifying Water with a Sand Filter", 19 | "thirst.ponder.sand_filter.text_1": "A Sand Filter purifies by one step water pumped through it", 20 | "thirst.ponder.sand_filter.text_2": "Dirty Water needs to be pumped in from the top...", 21 | "thirst.ponder.sand_filter.text_3": "and Purified Water can be pumped out from the bottom" 22 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/accessors/brewinandchewin/KegBlockEntityAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.accessors.brewinandchewin; 2 | 3 | import net.minecraft.world.item.ItemStack; 4 | import net.minecraftforge.items.wrapper.RecipeWrapper; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | import umpaz.brewinandchewin.common.block.entity.KegBlockEntity; 8 | import umpaz.brewinandchewin.common.crafting.KegRecipe; 9 | 10 | import java.util.Optional; 11 | 12 | @Mixin(value = KegBlockEntity.class,remap = false) 13 | public interface KegBlockEntityAccessor 14 | { 15 | @Invoker 16 | boolean invokeHasInput(); 17 | @Invoker 18 | Optional invokeGetMatchingRecipe(RecipeWrapper inventoryWrapper); 19 | @Invoker 20 | boolean invokeCanFerment(KegRecipe recipe); 21 | @Invoker 22 | boolean invokeDoesDrinkHaveContainer(ItemStack meal); 23 | @Invoker 24 | void invokeMoveDrinkToOutput(); 25 | @Invoker 26 | void invokeUseStoredContainersOnMeal(); 27 | 28 | @Invoker 29 | boolean invokeProcessFermenting(KegRecipe recipe, KegBlockEntity keg); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/network/ThirstModPacketHandler.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.network; 2 | 3 | import dev.ghen.thirst.Thirst; 4 | import dev.ghen.thirst.foundation.network.message.DrinkByHandMessage; 5 | import dev.ghen.thirst.foundation.network.message.PlayerThirstSyncMessage; 6 | import net.minecraftforge.network.NetworkRegistry; 7 | import net.minecraftforge.network.simple.SimpleChannel; 8 | 9 | public class ThirstModPacketHandler 10 | { 11 | private static final String PROTOCOL_VERSION = "0.1.2"; 12 | public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel( 13 | Thirst.asResource("main"), 14 | () -> PROTOCOL_VERSION, 15 | PROTOCOL_VERSION::equals, 16 | PROTOCOL_VERSION::equals 17 | ); 18 | 19 | public static void init() 20 | { 21 | INSTANCE.registerMessage(0, PlayerThirstSyncMessage.class, PlayerThirstSyncMessage::encode, PlayerThirstSyncMessage::decode, PlayerThirstSyncMessage::handle); 22 | INSTANCE.registerMessage(1, DrinkByHandMessage.class, DrinkByHandMessage::encode, DrinkByHandMessage::decode, DrinkByHandMessage::handle); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.attack.dehydrate": "%1$s脱水而死", 3 | "death.attack.dehydrate.player": "%1$s在与%2$s战斗时脱水而死", 4 | "item.thirst.wooden_water_bowl": "装水的木碗", 5 | "item.thirst.terracotta_water_bowl": "装水的陶碗", 6 | "item.thirst.terracotta_bowl": "陶碗", 7 | "item.thirst.clay_bowl": "粘土碗", 8 | "thirst.container.kettle.no_water": "没有水", 9 | "thirst.container.kettle.has_single_water": "含有一杯%s的水", 10 | "thirst.container.kettle.has_many_water": "含有%1$s杯%2$s的水", 11 | "itemGroup.thirst": "Thirst", 12 | "thirst.purity.dirty": "肮脏", 13 | "thirst.purity.slightly_dirty": "有点脏", 14 | "thirst.purity.acceptable": "可接受的", 15 | "thirst.purity.purified": "纯净", 16 | "block.thirst.sand_filter": "砂滤器", 17 | 18 | "thirst.ponder.sand_filter.header": "用砂滤器净化水", 19 | "thirst.ponder.sand_filter.text_1": "砂滤器会净化邻近泵入的水", 20 | "thirst.ponder.sand_filter.text_2": "脏水需要从上方泵入...", 21 | "thirst.ponder.sand_filter.text_3": "净化后的水会从底部泵出", 22 | "command.thirst.query": "当前口渴值: %1$s, 当前解渴值: %2$s", 23 | "command.thirst.set": "设置口渴值为 %1$s,解渴值为 %2$s", 24 | "command.thirst.enable": "已为玩家 %1$s 启用口渴", 25 | "command.thirst.disable": "已为玩家 %1$s 禁用口渴" 26 | } -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/lang/zh_tw.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.attack.dehydrate": "%1$s脫水而死", 3 | "death.attack.dehydrate.player": "%1$s在與%2$s戰鬥時脫水而死", 4 | "item.thirst.wooden_water_bowl": "裝水的木碗", 5 | "item.thirst.terracotta_water_bowl": "裝水的陶碗", 6 | "item.thirst.terracotta_bowl": "陶碗", 7 | "item.thirst.clay_bowl": "黏土碗", 8 | "thirst.container.kettle.no_water": "沒有水", 9 | "thirst.container.kettle.has_single_water": "含有一杯%s的水", 10 | "thirst.container.kettle.has_many_water": "含有%1$s杯%2$s的水", 11 | "itemGroup.thirst": "Thirst", 12 | "thirst.purity.dirty": "骯髒", 13 | "thirst.purity.slightly_dirty": "有點髒", 14 | "thirst.purity.acceptable": "可接受的", 15 | "thirst.purity.purified": "純淨", 16 | "block.thirst.sand_filter": "砂濾器", 17 | 18 | "thirst.ponder.sand_filter.header": "用砂濾器淨化水", 19 | "thirst.ponder.sand_filter.text_1": "砂濾器會淨化鄰近泵入的水", 20 | "thirst.ponder.sand_filter.text_2": "髒水需要從上方泵入...", 21 | "thirst.ponder.sand_filter.text_3": "淨化後的水會從底部泵出", 22 | "command.thirst.query": "當前口渴值: %1$s, 當前解渴值: %2$s", 23 | "command.thirst.set": "設置口渴值为 %1$s,解渴值为 %2$s", 24 | "command.thirst.enable": "已為玩家 %1$s 啟用口渴", 25 | "command.thirst.disable": "已為玩家 %1$s 禁用口渴" 26 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/compat/create/ponder/ThirstPonders.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.compat.create.ponder; 2 | 3 | import com.simibubi.create.foundation.ponder.PonderRegistrationHelper; 4 | import com.simibubi.create.foundation.ponder.PonderTag; 5 | import com.simibubi.create.infrastructure.ponder.AllPonderTags; 6 | import dev.ghen.thirst.Thirst; 7 | import dev.ghen.thirst.compat.create.CreateRegistry; 8 | import dev.ghen.thirst.compat.create.ponder.scene.SandFilterScene; 9 | 10 | 11 | public class ThirstPonders { 12 | public static final PonderTag PURIFICATION = new PonderTag(Thirst.asResource("purification")) 13 | .item(CreateRegistry.SAND_FILTER_BLOCK.get().asItem(), true, false) 14 | .defaultLang("Purification", "Components which purifying water"); 15 | 16 | static final PonderRegistrationHelper HELPER = new PonderRegistrationHelper(Thirst.ID); 17 | 18 | public static void register(){ 19 | HELPER.addStoryBoard( 20 | CreateRegistry.SAND_FILTER_BLOCK, 21 | "sand_filter", 22 | SandFilterScene::filtering, 23 | AllPonderTags.FLUIDS, 24 | PURIFICATION 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/util/LoadedValue.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.util; 2 | 3 | import net.minecraftforge.common.MinecraftForge; 4 | import net.minecraftforge.event.server.ServerStartedEvent; 5 | import net.minecraftforge.eventbus.api.SubscribeEvent; 6 | 7 | import java.util.function.Supplier; 8 | 9 | public class LoadedValue 10 | { 11 | /** 12 | * This class was taken from Cold Sweat 13 | */ 14 | 15 | T value; 16 | Supplier valueCreator; 17 | 18 | public LoadedValue(Supplier valueCreator) 19 | { 20 | this.valueCreator = valueCreator; 21 | this.value = valueCreator.get(); 22 | MinecraftForge.EVENT_BUS.register(this); 23 | } 24 | 25 | public static LoadedValue of(Supplier valueCreator) 26 | { 27 | return new LoadedValue<>(valueCreator); 28 | } 29 | 30 | @SubscribeEvent 31 | public void onLoaded(ServerStartedEvent event) 32 | { 33 | this.value = valueCreator.get(); 34 | } 35 | 36 | public T get() 37 | { 38 | return value; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/jade/MixinFluidView.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.jade; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import net.minecraft.network.chat.Component; 5 | import net.minecraftforge.fluids.FluidStack; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Redirect; 9 | import snownee.jade.api.view.FluidView; 10 | 11 | import java.util.Objects; 12 | 13 | @Mixin(value = FluidView.class,remap = false) 14 | public class MixinFluidView { 15 | 16 | @Redirect(method ="read", at = @At(value = "INVOKE",target = "Lnet/minecraftforge/fluids/FluidStack;getDisplayName()Lnet/minecraft/network/chat/Component;")) 17 | private static Component read(FluidStack instance){ 18 | if(WaterPurity.hasPurity(instance) && WaterPurity.getPurity(instance) != -1){ 19 | return Component.literal(Objects.requireNonNull( 20 | WaterPurity.getPurityText(WaterPurity.getPurity(instance)))) 21 | .append(" ") 22 | .append(instance.getDisplayName()); 23 | 24 | } 25 | 26 | return instance.getDisplayName(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/accessors/farmersrespite/KettleBlockEntityAccessor.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.accessors.farmersrespite; 2 | 3 | import net.minecraft.world.item.ItemStack; 4 | import net.minecraftforge.items.wrapper.RecipeWrapper; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.gen.Invoker; 7 | import umpaz.farmersrespite.common.block.entity.KettleBlockEntity; 8 | import umpaz.farmersrespite.common.crafting.KettleRecipe; 9 | 10 | import java.util.Optional; 11 | 12 | @Mixin(KettleBlockEntity.class) 13 | public interface KettleBlockEntityAccessor 14 | { 15 | @Invoker(remap = false) 16 | boolean invokeHasInput(); 17 | @Invoker(remap = false) 18 | Optional invokeGetMatchingRecipe(RecipeWrapper inventoryWrapper); 19 | @Invoker(remap = false) 20 | boolean invokeCanBrew(KettleRecipe recipe); 21 | @Invoker(remap = false) 22 | boolean invokeDoesMealHaveContainer(ItemStack meal); 23 | @Invoker(remap = false) 24 | void invokeMoveMealToOutput(); 25 | @Invoker(remap = false) 26 | void invokeUseStoredContainersOnMeal(); 27 | 28 | @Invoker(remap = false) 29 | boolean invokeProcessBrewing(KettleRecipe recipe, KettleBlockEntity kettle); 30 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/create/MixinGenericItemFilling.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.create; 2 | 3 | import com.simibubi.create.content.fluids.transfer.GenericItemFilling; 4 | import dev.ghen.thirst.content.purity.WaterPurity; 5 | import net.minecraft.world.item.ItemStack; 6 | import net.minecraft.world.level.Level; 7 | import net.minecraftforge.fluids.FluidStack; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.injection.At; 10 | import org.spongepowered.asm.mixin.injection.Inject; 11 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 12 | 13 | @Mixin(value= GenericItemFilling.class,remap = false) 14 | public class MixinGenericItemFilling { 15 | 16 | @Inject(method = "fillItem",at= @At("RETURN"), cancellable = true) 17 | private static void fillItem(Level world, int requiredAmount, ItemStack stack, FluidStack availableFluid, CallbackInfoReturnable cir) { 18 | ItemStack output = cir.getReturnValue(); 19 | if(WaterPurity.hasPurity(availableFluid) && WaterPurity.isWaterFilledContainer(output)){ 20 | WaterPurity.addPurity(output, WaterPurity.getPurity(availableFluid)); 21 | cir.setReturnValue(output); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | Supported Versions 4 | Discord 5 | CF 6 | Modrinth 7 |

8 |

9 | 10 | **Thirst was Taken** is a simple mod that adds a thirst mechanic to the game, but that fits well in modpacks (especially **aesthetics**-oriented ones) by adding diverse features and compatibility with a lot of often-used mods. 11 | 12 | This mod is heavily inspired by the other thirst/survival mods out there, including Dehydration, Tough as Nails, and Cold Sweat. 13 | 14 | To learn more about this mod, you can visit the [Wiki](https://github.com/ghen-git/Thirst-Mod/wiki). 15 | -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/lang/pl_pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.attack.dehydrate": "%1$s zmarł od odwodnienia", 3 | "death.attack.dehydrate.player": "%1$s zmarł od odwodnienia podczas walki z %2$s", 4 | "item.thirst.wooden_water_bowl": "Drewniana Miska z Wodą", 5 | "item.thirst.terracotta_water_bowl": "Miska z Wodą z Terakoty", 6 | "item.thirst.terracotta_bowl": "Miska z Terakoty", 7 | "item.thirst.clay_bowl": "Gliniana Miska", 8 | "thirst.container.kettle.no_water": "Brak Wody", 9 | "thirst.container.kettle.has_single_water": "Zawiera 1 szklankę %s wody", 10 | "thirst.container.kettle.has_many_water": "Zawiera %1$s szklanki %2$s wody", 11 | "itemGroup.thirst": "Pragnienie", 12 | "thirst.purity.dirty": "Brudna", 13 | "thirst.purity.slightly_dirty": "Lekko Zabrudzona", 14 | "thirst.purity.acceptable": "Akceptowalna", 15 | "thirst.purity.purified": "Oczyszczona", 16 | "block.thirst.sand_filter": "Filtr Piaskowy", 17 | 18 | "thirst.ponder.sand_filter.header": "Oczyszczanie wody Filtrem Piaskowym", 19 | "thirst.ponder.sand_filter.text_1": "Filter Piaskowy oczyszcza w jednym stopniu pompowaną przez niego wodę", 20 | "thirst.ponder.sand_filter.text_2": "Brudna Woda musi być pompowana z góry...", 21 | "thirst.ponder.sand_filter.text_3": "a Oczyszczona Woda może być wypompowywana z dołu" 22 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/gui/appleskin/ThirstValues.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.gui.appleskin; 2 | 3 | public class ThirstValues 4 | { 5 | /** 6 | * This is some of the most esoteric garbage code you'll ever see. Read at your own risk 7 | * also this is adapted from AppleSkin 8 | * */ 9 | public final int thirst; 10 | public final float quenchedModifier; 11 | 12 | public ThirstValues(int thirst, float saturationModifier) 13 | { 14 | this.thirst = thirst; 15 | this.quenchedModifier = saturationModifier; 16 | } 17 | 18 | public float getQuenchedIncrement() 19 | { 20 | return thirst * quenchedModifier * 2f; 21 | } 22 | 23 | @Override 24 | public boolean equals(Object o) 25 | { 26 | if (this == o) return true; 27 | if (!(o instanceof ThirstValues)) return false; 28 | 29 | ThirstValues that = (ThirstValues) o; 30 | 31 | return thirst == that.thirst && Float.compare(that.quenchedModifier, quenchedModifier) == 0; 32 | } 33 | 34 | @Override 35 | public int hashCode() 36 | { 37 | int result = thirst; 38 | result = 31 * result + (quenchedModifier != +0.0f ? Float.floatToIntBits(quenchedModifier) : 0); 39 | return result; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.attack.dehydrate": "%1$s умер от обезвоживания", 3 | "death.attack.dehydrate.player": "%1$s умер от обезвоживания, пока сражался с %2$s", 4 | "item.thirst.wooden_water_bowl": "Деревянная миска с водой", 5 | "item.thirst.terracotta_water_bowl": "Обожжённая глиняная миска с водой", 6 | "item.thirst.terracotta_bowl": "Обожённая глиняная миска", 7 | "item.thirst.clay_bowl": "Глиняная миска", 8 | "thirst.container.kettle.no_water": "Пусто.", 9 | "thirst.container.kettle.has_single_water": "Содерджит 1 пузырёк с %s водой", 10 | "thirst.container.kettle.has_many_water": "Содержит %1$s пузырка %2$s воды", 11 | "itemGroup.thirst": "Thirst was Taken", 12 | "thirst.purity.dirty": "Грязная", 13 | "thirst.purity.slightly_dirty": "Грязноватая", 14 | "thirst.purity.acceptable": "Приемлемая", 15 | "thirst.purity.purified": "Чистая", 16 | "block.thirst.sand_filter": "Песочный фильтр", 17 | 18 | "thirst.ponder.sand_filter.header": "Очищайте воду с помощью песочного фильтра", 19 | "thirst.ponder.sand_filter.text_1": "Песочный фильтр за один этап очищает прокачиваемую через него воду", 20 | "thirst.ponder.sand_filter.text_2": "Грязную воду нужно закачивать сверху...", 21 | "thirst.ponder.sand_filter.text_3": "и очищенную воду, соответственно, снизу." 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinItemStack.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.foundation.config.CommonConfig; 4 | import net.minecraft.nbt.CompoundTag; 5 | import net.minecraft.world.item.Item; 6 | import net.minecraft.world.item.ItemStack; 7 | import net.minecraft.world.item.Items; 8 | import net.minecraft.world.item.alchemy.PotionUtils; 9 | import net.minecraft.world.item.alchemy.Potions; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 15 | 16 | import javax.annotation.Nullable; 17 | 18 | @Mixin(ItemStack.class) 19 | public abstract class MixinItemStack 20 | { 21 | @Shadow public abstract Item getItem(); 22 | @Shadow @Nullable public abstract CompoundTag getTag(); 23 | 24 | @Inject(method="getMaxStackSize", at = @At("HEAD"), cancellable = true) 25 | public void changeWaterBottleStackSize(CallbackInfoReturnable cir) 26 | { 27 | if(getItem() == Items.POTION && PotionUtils.getPotion(getTag()) == Potions.WATER ) 28 | cir.setReturnValue(CommonConfig.WATER_BOTTLE_STACKSIZE.get()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/lang/fr_fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.attack.dehydrate": "%1$s est mort(e) de déshydratation", 3 | "death.attack.dehydrate.player": "%1$s est mort(e) de déshydratation en combattant %2$s", 4 | "item.thirst.wooden_water_bowl": "Bol d'eau en bois", 5 | "item.thirst.terracotta_water_bowl": "Bol d'eau en terre cuite", 6 | "item.thirst.terracotta_bowl": "Bol en terre cuite", 7 | "item.thirst.clay_bowl": "Bol en argile", 8 | "thirst.container.kettle.no_water": "Pas d'eau", 9 | "thirst.container.kettle.has_single_water": "Contient 1 verre d'eau %s", 10 | "thirst.container.kettle.has_many_water": "Contient %1$s verres d'eau %2$s", 11 | "itemGroup.thirst": "Thirst was Taken", 12 | "thirst.purity.dirty": "Sale", 13 | "thirst.purity.slightly_dirty": "Un peu sale", 14 | "thirst.purity.acceptable": "Buvable", 15 | "thirst.purity.purified": "Purifiée", 16 | "block.thirst.sand_filter": "Filtre à sable", 17 | 18 | "thirst.ponder.sand_filter.header": "Purifier de l'eau avec un Filtre à sable", 19 | "thirst.ponder.sand_filter.text_1": "Un Filtre à sable effectue une étape de purification quand de l'eau y est pompée à travers", 20 | "thirst.ponder.sand_filter.text_2": "L'eau sale doit être pompée dans le filtre par dessus...", 21 | "thirst.ponder.sand_filter.text_3": "et l'eau purifiée peut être pompée par le dessous" 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinLocalPlayer.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.foundation.common.capability.IThirst; 4 | import dev.ghen.thirst.foundation.common.capability.ModCapabilities; 5 | import dev.ghen.thirst.foundation.config.CommonConfig; 6 | import net.minecraft.client.Minecraft; 7 | import net.minecraft.client.player.LocalPlayer; 8 | import net.minecraft.world.food.FoodData; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Redirect; 12 | 13 | @Mixin(LocalPlayer.class) 14 | public class MixinLocalPlayer{ 15 | 16 | /** 17 | * @reason prevent sprinting when thirst 18 | * @return food level or thirst level 19 | */ 20 | 21 | @Redirect(method ="aiStep", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/food/FoodData;getFoodLevel()I")) 22 | public int aiStep(FoodData instance){ 23 | int Food = instance.getFoodLevel(); 24 | if(!CommonConfig.MOVE_SLOW_WHEN_THIRSTY.get()) return Food; 25 | 26 | if(Food < 6.0F){ 27 | return Food; 28 | }else { 29 | Food = Minecraft.getInstance().player.getCapability(ModCapabilities.PLAYER_THIRST) 30 | .lazyMap(IThirst::getThirst).orElse(Food); 31 | } 32 | return Food; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/content/registry/ItemInit.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.content.registry; 2 | 3 | import dev.ghen.thirst.foundation.common.item.DrinkableItem; 4 | import dev.ghen.thirst.foundation.tab.ThirstTab; 5 | import net.minecraft.world.item.Item; 6 | import net.minecraftforge.registries.DeferredRegister; 7 | import net.minecraftforge.registries.ForgeRegistries; 8 | import net.minecraftforge.registries.RegistryObject; 9 | 10 | public class ItemInit { 11 | public static final DeferredRegister ITEMS; 12 | public static final RegistryObject CLAY_BOWL; 13 | public static final RegistryObject TERRACOTTA_BOWL; 14 | public static final RegistryObject TERRACOTTA_WATER_BOWL; 15 | 16 | public ItemInit() { 17 | } 18 | 19 | static { 20 | ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, "thirst"); 21 | CLAY_BOWL = ITEMS.register("clay_bowl", () -> new Item((new Item.Properties()) 22 | .stacksTo(64) 23 | .tab(ThirstTab.THIRST_TAB) 24 | )); 25 | TERRACOTTA_BOWL = ITEMS.register("terracotta_bowl", () -> new Item((new Item.Properties()) 26 | .stacksTo(64) 27 | .tab(ThirstTab.THIRST_TAB) 28 | )); 29 | TERRACOTTA_WATER_BOWL = ITEMS.register("terracotta_water_bowl", () -> (new DrinkableItem()) 30 | .setContainer(TERRACOTTA_BOWL.get()) 31 | ); 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/shipwreck_supply_bc.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 3}" 13 | }, 14 | { 15 | "count": { 16 | "type": "minecraft:uniform", 17 | "max": 3.0, 18 | "min": 1.0 19 | }, 20 | "function": "minecraft:set_count" 21 | } 22 | ], 23 | "name": "brewinandchewin:mead", 24 | "weight": 10 25 | }, 26 | { 27 | "type": "minecraft:item", 28 | "functions": [ 29 | { 30 | "function": "set_nbt", 31 | "tag": "{Purity: 3}" 32 | }, 33 | { 34 | "count": { 35 | "type": "minecraft:uniform", 36 | "max": 3.0, 37 | "min": 1.0 38 | }, 39 | "function": "minecraft:set_count" 40 | } 41 | ], 42 | "name": "brewinandchewin:salty_folly", 43 | "weight": 10 44 | }, 45 | { 46 | "type": "minecraft:empty", 47 | "weight": 20 48 | } 49 | ], 50 | "rolls": 1 51 | } 52 | ] 53 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/create/MixinFluidDrainingBehaviour.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.create; 2 | 3 | import com.simibubi.create.content.fluids.transfer.FluidDrainingBehaviour; 4 | import com.simibubi.create.foundation.fluid.FluidHelper; 5 | import dev.ghen.thirst.content.purity.WaterPurity; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.nbt.CompoundTag; 8 | import net.minecraftforge.fluids.FluidStack; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | @Mixin(value = FluidDrainingBehaviour.class,remap = false) 15 | public abstract class MixinFluidDrainingBehaviour 16 | { 17 | 18 | @Inject(method = "getDrainableFluid", at = @At("RETURN"), remap = false, cancellable = true) 19 | public void getDrainableFluid(BlockPos rootPos, CallbackInfoReturnable cir){ 20 | FluidDrainingBehaviour behaviour = ((FluidDrainingBehaviour)(Object) this); 21 | FluidStack output=cir.getReturnValue(); 22 | if (FluidHelper.isWater(output.getFluid())){ 23 | CompoundTag tag = output.getOrCreateTag(); 24 | tag.putInt("Purity", WaterPurity.getBlockPurity(behaviour.getWorld(), rootPos)); 25 | output.setTag(tag); 26 | cir.setReturnValue(output); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | # The overall format is standard TOML format, v0.5.0. 2 | # Note that there are a couple of TOML lists in this file. 3 | # Find more information on toml format here: https://github.com/toml-lang/toml 4 | modLoader="javafml" 5 | loaderVersion="[43,)" 6 | license="MIT license" 7 | issueTrackerURL="https://github.com/ghen-git/Thirst-Mod/issues" 8 | [[mods]] 9 | modId="thirst" 10 | version="${file.jarVersion}" 11 | displayName="Thirst was Taken" 12 | # A URL to query for updates for this mod. See the JSON update specification https://mcforge.readthedocs.io/en/latest/gettingstarted/autoupdate/ 13 | #updateJSONURL="https://change.me.example.invalid/updates.json" #optional 14 | displayURL="https://github.com/ghen-git/Thirst-Mod" 15 | logoFile="thirstwastaken.png" 16 | credits="Cold Sweat, Create, Farmer's Delight and all the mods' sources that helped me actually program this." 17 | authors="ghen" 18 | description=''' 19 | Modern take on the thirst-bar mechanic, compatible with a lot of contemporary mods 20 | ''' 21 | [[dependencies.thirst]] 22 | modId="forge" 23 | mandatory=true 24 | versionRange="[43,)" 25 | ordering="NONE" 26 | side="BOTH" 27 | [[dependencies.thirst]] 28 | modId="minecraft" 29 | mandatory=true 30 | versionRange="[1.19.2,1.20)" 31 | ordering="NONE" 32 | side="BOTH" 33 | [[dependencies.thirst]] 34 | modId="create" 35 | mandatory=false 36 | versionRange="[0.5.1.a,)" 37 | ordering="NONE" 38 | side="BOTH" 39 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/util/MathHelper.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.util; 2 | 3 | import net.minecraft.util.Mth; 4 | import net.minecraft.world.entity.player.Player; 5 | import net.minecraft.world.level.ClipContext; 6 | import net.minecraft.world.level.Level; 7 | import net.minecraft.world.phys.BlockHitResult; 8 | import net.minecraft.world.phys.Vec3; 9 | 10 | public class MathHelper 11 | { 12 | public static BlockHitResult getPlayerPOVHitResult(Level p_41436_, Player p_41437_, ClipContext.Fluid p_41438_) 13 | { 14 | float f = p_41437_.getXRot(); 15 | float f1 = p_41437_.getYRot(); 16 | Vec3 vec3 = p_41437_.getEyePosition(); 17 | float f2 = Mth.cos(-f1 * ((float)Math.PI / 180F) - (float)Math.PI); 18 | float f3 = Mth.sin(-f1 * ((float)Math.PI / 180F) - (float)Math.PI); 19 | float f4 = -Mth.cos(-f * ((float)Math.PI / 180F)); 20 | float f5 = Mth.sin(-f * ((float)Math.PI / 180F)); 21 | float f6 = f3 * f4; 22 | float f7 = f2 * f4; 23 | double d0 = p_41437_.getAttribute(net.minecraftforge.common.ForgeMod.REACH_DISTANCE.get()).getValue(); 24 | Vec3 vec31 = vec3.add((double)f6 * d0, (double)f5 * d0, (double)f7 * d0); 25 | return p_41436_.clip(new ClipContext(vec3, vec31, ClipContext.Block.OUTLINE, p_41438_, p_41437_)); 26 | } 27 | 28 | public static BlockHitResult getPlayerPOVHitResult(Level p_41436_, Player p_41437_) 29 | { 30 | return getPlayerPOVHitResult(p_41436_, p_41437_, ClipContext.Fluid.NONE); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinFluidUtil.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import net.minecraft.world.item.ItemStack; 5 | import net.minecraft.world.item.Items; 6 | import net.minecraft.world.level.material.Fluid; 7 | import net.minecraft.world.level.material.Fluids; 8 | import net.minecraftforge.fluids.FluidStack; 9 | import net.minecraftforge.fluids.FluidUtil; 10 | import org.jetbrains.annotations.NotNull; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.Overwrite; 13 | 14 | @Mixin(value = FluidUtil.class,remap = false) 15 | public class MixinFluidUtil { 16 | /** 17 | * @author mlus 18 | * @reason add purity to the result bucket 19 | */ 20 | @Overwrite 21 | public static @NotNull ItemStack getFilledBucket(@NotNull FluidStack fluidStack) { 22 | Fluid fluid = fluidStack.getFluid(); 23 | if (!fluidStack.hasTag() || fluidStack.getTag().isEmpty()) { 24 | if (fluid == Fluids.WATER) { 25 | return new ItemStack(Items.WATER_BUCKET); 26 | } 27 | 28 | if (fluid == Fluids.LAVA) { 29 | return new ItemStack(Items.LAVA_BUCKET); 30 | } 31 | }else if(WaterPurity.hasPurity(fluidStack)){ 32 | return WaterPurity.addPurity(new ItemStack(fluidStack.getFluid().getBucket()),WaterPurity.getPurity(fluidStack)); 33 | } 34 | 35 | return new ItemStack(fluidStack.getFluid().getBucket()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/assets/thirst/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "death.attack.dehydrate": "%1$s died from dehydration", 3 | "death.attack.dehydrate.player": "%1$s died from dehydration while fighting %2$s", 4 | "item.thirst.wooden_water_bowl": "Wooden Water Bowl", 5 | "item.thirst.terracotta_water_bowl": "Terracotta Water Bowl", 6 | "item.thirst.terracotta_bowl": "Terracotta Bowl", 7 | "item.thirst.clay_bowl": "Clay Bowl", 8 | "thirst.container.kettle.no_water": "No Water", 9 | "thirst.container.kettle.has_single_water": "Contains 1 glass of %s water", 10 | "thirst.container.kettle.has_many_water": "Contains %1$s glasses of %2$s water", 11 | "itemGroup.thirst": "Thirst was Taken", 12 | "thirst.purity.dirty": "Dirty", 13 | "thirst.purity.slightly_dirty": "Slightly Dirty", 14 | "thirst.purity.acceptable": "Acceptable", 15 | "thirst.purity.purified": "Purified", 16 | "block.thirst.sand_filter": "Sand Filter", 17 | 18 | "thirst.ponder.sand_filter.header": "Purifying Water with a Sand Filter", 19 | "thirst.ponder.sand_filter.text_1": "A Sand Filter purifies by one step water pumped through it", 20 | "thirst.ponder.sand_filter.text_2": "Dirty Water needs to be pumped in from the top...", 21 | "thirst.ponder.sand_filter.text_3": "and Purified Water can be pumped out from the bottom", 22 | "command.thirst.query": "Current Thirst: %1$s, Current Quenched: %2$s", 23 | "command.thirst.set": "set thirst to %1$s, set quenched to %2$s", 24 | "command.thirst.enable": "Enable tick Thirst for %1$s", 25 | "command.thirst.disable": "Disable tick Thirst for %1$s" 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/create/MixinGenericItemEmptying.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.create; 2 | 3 | import com.simibubi.create.content.fluids.transfer.GenericItemEmptying; 4 | import com.simibubi.create.foundation.utility.Pair; 5 | import dev.ghen.thirst.content.purity.WaterPurity; 6 | import net.minecraft.nbt.CompoundTag; 7 | import net.minecraft.world.item.ItemStack; 8 | import net.minecraft.world.level.Level; 9 | import net.minecraftforge.fluids.FluidStack; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | @Mixin(value = GenericItemEmptying.class,remap = false) 16 | public class MixinGenericItemEmptying 17 | { 18 | 19 | @Inject(method = "emptyItem", at = @At("RETURN"), cancellable = true, remap = false) 20 | private static void emptyItem(Level world, ItemStack stack, boolean simulate, CallbackInfoReturnable> cir) 21 | { 22 | Pair output= cir.getReturnValue(); 23 | if(WaterPurity.hasPurity(stack)){ 24 | FluidStack fluidStack=output.getFirst(); 25 | if(fluidStack.isEmpty()) return; 26 | CompoundTag tag = fluidStack.getOrCreateTag(); 27 | tag.putInt("Purity", WaterPurity.getPurity(stack)); 28 | fluidStack.setTag(tag); 29 | cir.setReturnValue(Pair.of(fluidStack,output.getSecond())); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinFluidBucketWrapper.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import net.minecraft.world.item.BucketItem; 5 | import net.minecraft.world.item.Item; 6 | import net.minecraft.world.item.ItemStack; 7 | import net.minecraft.world.item.MilkBucketItem; 8 | import net.minecraftforge.common.ForgeMod; 9 | import net.minecraftforge.fluids.FluidStack; 10 | import net.minecraftforge.fluids.capability.wrappers.FluidBucketWrapper; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Overwrite; 14 | import org.spongepowered.asm.mixin.Shadow; 15 | 16 | @Mixin(value = FluidBucketWrapper.class,remap = false) 17 | public class MixinFluidBucketWrapper { 18 | @Shadow @NotNull protected ItemStack container; 19 | 20 | /** 21 | * @author mlus 22 | * @reason add purity to fluid stack in bucket 23 | */ 24 | @Overwrite 25 | public @NotNull FluidStack getFluid() { 26 | Item item = container.getItem(); 27 | if (item instanceof BucketItem) { 28 | FluidStack stack = new FluidStack(((BucketItem) item).getFluid(), 1000); 29 | if(WaterPurity.hasPurity(container)){ 30 | WaterPurity.addPurity(stack,WaterPurity.getPurity(container)); 31 | } 32 | return stack; 33 | } else { 34 | return item instanceof MilkBucketItem && ForgeMod.MILK.isPresent() ? new FluidStack(ForgeMod.MILK.get(), 1000) : FluidStack.EMPTY; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/bastion_other.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 2}" 13 | }, 14 | { 15 | "count": { 16 | "type": "minecraft:uniform", 17 | "max": 3.0, 18 | "min": 1.0 19 | }, 20 | "function": "minecraft:set_count" 21 | }, 22 | { 23 | "function": "set_potion", 24 | "id": "water" 25 | } 26 | ], 27 | "name": "minecraft:potion", 28 | "weight": 10 29 | }, 30 | { 31 | "type": "minecraft:item", 32 | "functions": [ 33 | { 34 | "function": "set_nbt", 35 | "tag": "{Purity: 3}" 36 | }, 37 | { 38 | "count": { 39 | "type": "minecraft:uniform", 40 | "max": 3.0, 41 | "min": 1.0 42 | }, 43 | "function": "minecraft:set_count" 44 | }, 45 | { 46 | "function": "set_potion", 47 | "id": "water" 48 | } 49 | ], 50 | "name": "minecraft:potion", 51 | "weight": 10 52 | }, 53 | { 54 | "type": "minecraft:empty", 55 | "weight": 20 56 | } 57 | ], 58 | "rolls": 1 59 | } 60 | ] 61 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/nether_bridge.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 2}" 13 | }, 14 | { 15 | "count": { 16 | "type": "minecraft:uniform", 17 | "max": 3.0, 18 | "min": 1.0 19 | }, 20 | "function": "minecraft:set_count" 21 | }, 22 | { 23 | "function": "set_potion", 24 | "id": "water" 25 | } 26 | ], 27 | "name": "minecraft:potion", 28 | "weight": 10 29 | }, 30 | { 31 | "type": "minecraft:item", 32 | "functions": [ 33 | { 34 | "function": "set_nbt", 35 | "tag": "{Purity: 3}" 36 | }, 37 | { 38 | "count": { 39 | "type": "minecraft:uniform", 40 | "max": 3.0, 41 | "min": 1.0 42 | }, 43 | "function": "minecraft:set_count" 44 | }, 45 | { 46 | "function": "set_potion", 47 | "id": "water" 48 | } 49 | ], 50 | "name": "minecraft:potion", 51 | "weight": 10 52 | }, 53 | { 54 | "type": "minecraft:empty", 55 | "weight": 20 56 | } 57 | ], 58 | "rolls": 1 59 | } 60 | ] 61 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/shipwreck_supply.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 2}" 13 | }, 14 | { 15 | "count": { 16 | "type": "minecraft:uniform", 17 | "max": 3.0, 18 | "min": 1.0 19 | }, 20 | "function": "minecraft:set_count" 21 | }, 22 | { 23 | "function": "set_potion", 24 | "id": "water" 25 | } 26 | ], 27 | "name": "minecraft:potion", 28 | "weight": 10 29 | }, 30 | { 31 | "type": "minecraft:item", 32 | "functions": [ 33 | { 34 | "function": "set_nbt", 35 | "tag": "{Purity: 3}" 36 | }, 37 | { 38 | "count": { 39 | "type": "minecraft:uniform", 40 | "max": 3.0, 41 | "min": 1.0 42 | }, 43 | "function": "minecraft:set_count" 44 | }, 45 | { 46 | "function": "set_potion", 47 | "id": "water" 48 | } 49 | ], 50 | "name": "minecraft:potion", 51 | "weight": 10 52 | }, 53 | { 54 | "type": "minecraft:empty", 55 | "weight": 20 56 | } 57 | ], 58 | "rolls": 1 59 | } 60 | ] 61 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/simple_dungeon.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 2}" 13 | }, 14 | { 15 | "count": { 16 | "type": "minecraft:uniform", 17 | "max": 3.0, 18 | "min": 1.0 19 | }, 20 | "function": "minecraft:set_count" 21 | }, 22 | { 23 | "function": "set_potion", 24 | "id": "water" 25 | } 26 | ], 27 | "name": "minecraft:potion", 28 | "weight": 10 29 | }, 30 | { 31 | "type": "minecraft:item", 32 | "functions": [ 33 | { 34 | "function": "set_nbt", 35 | "tag": "{Purity: 3}" 36 | }, 37 | { 38 | "count": { 39 | "type": "minecraft:uniform", 40 | "max": 3.0, 41 | "min": 1.0 42 | }, 43 | "function": "minecraft:set_count" 44 | }, 45 | { 46 | "function": "set_potion", 47 | "id": "water" 48 | } 49 | ], 50 | "name": "minecraft:potion", 51 | "weight": 10 52 | }, 53 | { 54 | "type": "minecraft:empty", 55 | "weight": 20 56 | } 57 | ], 58 | "rolls": 1 59 | } 60 | ] 61 | } -------------------------------------------------------------------------------- /src/main/resources/data/thirst/loot_tables/chests/abandoned_mineshaft.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "minecraft:chest", 3 | "pools": [ 4 | { 5 | "bonus_rolls": 0.0, 6 | "entries": [ 7 | { 8 | "type": "minecraft:item", 9 | "functions": [ 10 | { 11 | "function": "set_nbt", 12 | "tag": "{Purity: 2}" 13 | }, 14 | { 15 | "count": { 16 | "type": "minecraft:uniform", 17 | "max": 3.0, 18 | "min": 1.0 19 | }, 20 | "function": "minecraft:set_count" 21 | }, 22 | { 23 | "function": "set_potion", 24 | "id": "water" 25 | } 26 | ], 27 | "name": "minecraft:potion", 28 | "weight": 10 29 | }, 30 | { 31 | "type": "minecraft:item", 32 | "functions": [ 33 | { 34 | "function": "set_nbt", 35 | "tag": "{Purity: 3}" 36 | }, 37 | { 38 | "count": { 39 | "type": "minecraft:uniform", 40 | "max": 3.0, 41 | "min": 1.0 42 | }, 43 | "function": "minecraft:set_count" 44 | }, 45 | { 46 | "function": "set_potion", 47 | "id": "water" 48 | } 49 | ], 50 | "name": "minecraft:potion", 51 | "weight": 10 52 | }, 53 | { 54 | "type": "minecraft:empty", 55 | "weight": 20 56 | } 57 | ], 58 | "rolls": 1 59 | } 60 | ] 61 | } -------------------------------------------------------------------------------- /src/main/resources/thirst.mixin.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "dev.ghen.thirst.foundation.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "refmap": "thirst.refmap.json", 6 | "mixins": [ 7 | "MixinAbstractFurnaceEntity", 8 | "MixinBootstrap", 9 | "MixinBottleItem", 10 | "MixinBucketItem", 11 | "MixinCampfireBlockEntity", 12 | "MixinFluidBucketWrapper", 13 | "MixinFluidUtil", 14 | "MixinFoodData", 15 | "MixinItemStack", 16 | "MixinLayeredCauldronBlock", 17 | "MixinPotionItem", 18 | "accessors.brewinandchewin.KegBlockEntityAccessor", 19 | "accessors.farmersdelight.SyncedBlockEntityAccessor", 20 | "accessors.farmersrespite.KettleBlockEntityAccessor", 21 | "accessors.supplementaries.FaucetBehaviorsManagerAccessor", 22 | "brewinandchewin.MixinKegBlockEntity", 23 | "create.MixinBasinRecipe", 24 | "create.MixinFillingBySpout", 25 | "create.MixinFluidDrainingBehaviour", 26 | "create.MixinGenericItemEmptying", 27 | "create.MixinGenericItemFilling", 28 | "create.MixinIHaveGoggleInformation", 29 | "create.MixinOpenEndedPipe", 30 | "createcenterkitchen.MixinKettlePoint", 31 | "farmersrespite.MixinKettleBlock", 32 | "farmersrespite.MixinKettleBlockEntity", 33 | "jade.MixinFluidView", 34 | "supplementaries.MixinWaterBlockInteraction", 35 | "toughasnails.MixinEmptyCanteenItem", 36 | "toughasnails.MixinServerConfig", 37 | "toughasnails.MixinThirstHandler", 38 | "toughasnails.MixinThirstHelperImpl", 39 | "botania.MixinBotania" 40 | ], 41 | "client": [ 42 | "MixinLocalPlayer", 43 | "farmersrespite.MixinKettleScreen" 44 | ], 45 | "minVersion": "0.8" 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/config/ContainerConfig.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.config; 2 | 3 | import net.minecraftforge.common.ForgeConfigSpec; 4 | import net.minecraftforge.fml.ModLoadingContext; 5 | import net.minecraftforge.fml.config.ModConfig; 6 | import net.minecraftforge.fml.loading.FMLPaths; 7 | 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.nio.file.Paths; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | 14 | public class ContainerConfig { 15 | private static final ForgeConfigSpec SPEC; 16 | public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); 17 | public static final ForgeConfigSpec.ConfigValue> CONTAINERS; 18 | 19 | static { 20 | BUILDER.push("Container"); 21 | 22 | CONTAINERS = BUILDER.comment("Defineds drinks will be influenced by purity" 23 | ,"Format: [\"examplemod:example_item_1\", \"examplemod:example_item_2\"]") 24 | .defineList("Containers", Arrays.asList( 25 | "create:builders_tea" 26 | ), it-> it instanceof String); 27 | 28 | BUILDER.pop(); 29 | 30 | SPEC = BUILDER.build(); 31 | } 32 | 33 | public static void setup() 34 | { 35 | Path configPath = FMLPaths.CONFIGDIR.get(); 36 | Path configFolder = Paths.get(configPath.toAbsolutePath().toString(), "thirst"); 37 | 38 | try 39 | { 40 | Files.createDirectory(configFolder); 41 | } 42 | catch (Exception ignored) {} 43 | 44 | ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, SPEC, "thirst/container.toml"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/compat/create/CreateRegistry.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.compat.create; 2 | 3 | import com.simibubi.create.content.processing.AssemblyOperatorBlockItem; 4 | import com.simibubi.create.foundation.data.AssetLookup; 5 | import com.simibubi.create.foundation.data.SharedProperties; 6 | import com.tterrag.registrate.Registrate; 7 | import com.tterrag.registrate.util.entry.BlockEntityEntry; 8 | import com.tterrag.registrate.util.entry.BlockEntry; 9 | import com.tterrag.registrate.util.nullness.NonNullSupplier; 10 | import dev.ghen.thirst.Thirst; 11 | import dev.ghen.thirst.foundation.tab.ThirstTab; 12 | 13 | import static com.simibubi.create.foundation.data.ModelGen.customItemModel; 14 | 15 | public class CreateRegistry 16 | { 17 | public static final NonNullSupplier REGISTRATE=NonNullSupplier.lazy(() ->Registrate.create(Thirst.ID)); 18 | 19 | public static void register(){} 20 | 21 | static 22 | { 23 | REGISTRATE.get().creativeModeTab(() -> ThirstTab.THIRST_TAB); 24 | } 25 | 26 | public static final BlockEntry SAND_FILTER_BLOCK= REGISTRATE.get() 27 | .block("sand_filter", SandFilterBlock::new) 28 | .initialProperties(SharedProperties::copperMetal) 29 | .blockstate((ctx, prov) -> prov.simpleBlock(ctx.getEntry(), AssetLookup.partialBaseModel(ctx, prov))) 30 | .item(AssemblyOperatorBlockItem::new) 31 | .transform(customItemModel()) 32 | .register(); 33 | public static final BlockEntityEntry SAND_FILTER_TE= REGISTRATE.get() 34 | .blockEntity("sand_filter",SandFilterTileEntity::new) 35 | .validBlocks(SAND_FILTER_BLOCK) 36 | .register(); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/tab/ThirstTab.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.tab; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import dev.ghen.thirst.content.registry.ItemInit; 5 | import net.minecraft.core.NonNullList; 6 | import net.minecraft.world.item.CreativeModeTab; 7 | import net.minecraft.world.item.ItemStack; 8 | import net.minecraft.world.item.Items; 9 | import net.minecraft.world.item.alchemy.PotionUtils; 10 | import net.minecraft.world.item.alchemy.Potions; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class ThirstTab extends CreativeModeTab 14 | { 15 | public static final ThirstTab THIRST_TAB = new ThirstTab("thirst"); 16 | 17 | public ThirstTab(String label) 18 | { 19 | super(label); 20 | } 21 | 22 | @Override 23 | public @NotNull ItemStack makeIcon() 24 | { 25 | return new ItemStack(ItemInit.TERRACOTTA_WATER_BOWL.get()); 26 | } 27 | 28 | @Override 29 | public void fillItemList(@NotNull NonNullList list) 30 | { 31 | super.fillItemList(list); 32 | 33 | list.add(WaterPurity.addPurity(new ItemStack(Items.WATER_BUCKET), 0)); 34 | list.add(WaterPurity.addPurity(new ItemStack(Items.WATER_BUCKET), 1)); 35 | list.add(WaterPurity.addPurity(new ItemStack(Items.WATER_BUCKET), 2)); 36 | list.add(WaterPurity.addPurity(new ItemStack(Items.WATER_BUCKET), 3)); 37 | list.add(WaterPurity.addPurity(PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER), 0)); 38 | list.add(WaterPurity.addPurity(PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER), 1)); 39 | list.add(WaterPurity.addPurity(PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER), 2)); 40 | list.add(WaterPurity.addPurity(PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER), 3)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/botania/MixinBotania.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin 2 | 3 | import net.minecraft.world.InteractionHand; 4 | import net.minecraft.world.entity.player.Player; 5 | import net.minecraft.world.item.ItemStack; 6 | import net.minecraft.world.level.material.Fluid; 7 | import net.minecraftforge.common.capabilities.ForgeCapabilities; 8 | import net.minecraftforge.fluids.FluidStack; 9 | import net.minecraftforge.fluids.capability.IFluidHandler; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | import vazkii.botania.forge.xplat.ForgeXplatImpl; 15 | import vazkii.botania.xplat.XplatAbstractions; 16 | 17 | 18 | @Mixin(ForgeXplatImpl.class) 19 | public abstract class MixinBotania implements XplatAbstractions { 20 | @Inject(method = "extractFluidFromPlayerItem", at = @At("HEAD"), cancellable = true, remap = false) 21 | public void extractFluidFromPlayerItem(Player player, InteractionHand hand, Fluid fluid, CallbackInfoReturnable cir) { 22 | cir.cancel(); 23 | ItemStack a = player.getItemInHand(hand); 24 | ItemStack abc = new ItemStack(a.getItem()); 25 | cir.setReturnValue(abc.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).map((h) -> { 26 | FluidStack ex = h.drain(new FluidStack(fluid, 1000), IFluidHandler.FluidAction.SIMULATE); 27 | boolean su = ex.getFluid() == fluid && ex.getAmount() == 1000; 28 | if (su && !player.getAbilities().instabuild) { 29 | h.drain(new FluidStack(fluid, 1000), IFluidHandler.FluidAction.EXECUTE); 30 | player.setItemInHand(hand, h.getContainer()); 31 | } 32 | return su; 33 | }).orElse(false)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/util/TickHelper.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.util; 2 | 3 | 4 | import net.minecraft.server.level.ServerLevel; 5 | import net.minecraft.world.level.Level; 6 | import net.minecraftforge.event.TickEvent; 7 | import net.minecraftforge.eventbus.api.SubscribeEvent; 8 | import net.minecraftforge.fml.common.Mod; 9 | 10 | import java.util.*; 11 | 12 | @Mod.EventBusSubscriber 13 | public class TickHelper 14 | { 15 | /** 16 | * Util for running actions on the server delayed by n ticks 17 | * may not be the best implementation, i'm a dumb idiot. 18 | * */ 19 | private static final Map> tickTasks = new HashMap<>(); 20 | private static int tickTimerFsr = 0; 21 | 22 | public static void addTask(int tick, Runnable task) 23 | { 24 | if(!tickTasks.containsKey(tick)) 25 | tickTasks.put(tick, new ArrayList<>()); 26 | 27 | tickTasks.get(tick).add(task); 28 | } 29 | 30 | public static void nextTick(Level level, Runnable task) 31 | { 32 | addTask(Objects.requireNonNull(level.getServer()).getTickCount() + 1, task); 33 | } 34 | 35 | public static void TickLater(Level level, int tickNumber,Runnable task) 36 | { 37 | addTask(Objects.requireNonNull(level.getServer()).getTickCount() + tickNumber, task); 38 | } 39 | 40 | @SubscribeEvent 41 | static void runTasks(TickEvent.LevelTickEvent event) 42 | { 43 | if(event.level instanceof ServerLevel && tickTimerFsr == 0 && tickTasks.containsKey(event.level.getServer().getTickCount())) 44 | { 45 | tickTasks.get(event.level.getServer().getTickCount()).forEach(Runnable::run); 46 | tickTasks.remove(event.level.getServer().getTickCount()); 47 | 48 | tickTimerFsr += 3; 49 | } 50 | else if(tickTimerFsr > 0) 51 | tickTimerFsr--; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/common/event/RegisterThirstValueEvent.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.common.event; 2 | 3 | import dev.ghen.thirst.content.purity.ContainerWithPurity; 4 | import dev.ghen.thirst.content.purity.WaterPurity; 5 | import net.minecraft.world.item.Item; 6 | import net.minecraft.world.item.ItemStack; 7 | import net.minecraftforge.eventbus.api.Event; 8 | 9 | import static dev.ghen.thirst.api.ThirstHelper.VALID_DRINKS; 10 | import static dev.ghen.thirst.api.ThirstHelper.VALID_FOODS; 11 | 12 | @SuppressWarnings({"unused","deprecation"}) 13 | public class RegisterThirstValueEvent extends Event { 14 | public RegisterThirstValueEvent(){ 15 | } 16 | 17 | /** 18 | * Adds a hydration and "quenchness" value to an item via code, and treats it as food. 19 | * Can be overwritten by the player in the config. 20 | * */ 21 | public void addFood(Item item, int thirst, int quenched) 22 | { 23 | VALID_FOODS.putIfAbsent(item, new Number[]{thirst, quenched}); 24 | } 25 | 26 | /** 27 | * Adds a hydration and "quenchness" value to an item via code, and treats it as a drink. 28 | * Can be overwritten by the player in the config. 29 | * */ 30 | public void addDrink(Item item, int thirst, int quenched) 31 | { 32 | VALID_DRINKS.putIfAbsent(item, new Number[]{thirst, quenched}); 33 | } 34 | 35 | /** 36 | *Registers new custom water container 37 | *the container will be taken into consider of purity 38 | */ 39 | public void addContainer(ContainerWithPurity container){ 40 | WaterPurity.addContainer(container); 41 | } 42 | 43 | /** 44 | * A simple version, If you don't need your item to harvest water like bucket. 45 | */ 46 | public void addContainer(Item item){ 47 | WaterPurity.addContainer(new ContainerWithPurity(new ItemStack(item))); 48 | } 49 | 50 | 51 | @Override 52 | public boolean isCancelable() {return false;} 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/supplementaries/MixinWaterBlockInteraction.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.supplementaries; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import dev.ghen.thirst.foundation.mixin.accessors.supplementaries.FaucetBehaviorsManagerAccessor; 5 | import net.mehvahdjukaar.moonlight.api.fluids.SoftFluidTank; 6 | import net.mehvahdjukaar.moonlight.api.fluids.VanillaSoftFluids; 7 | import net.mehvahdjukaar.supplementaries.common.block.tiles.FaucetBlockTile; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.nbt.CompoundTag; 10 | import net.minecraft.world.InteractionResult; 11 | import net.minecraft.world.level.Level; 12 | import net.minecraft.world.level.material.FluidState; 13 | import net.minecraft.world.level.material.Fluids; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | import org.spongepowered.asm.mixin.injection.Inject; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 18 | 19 | @Mixin(targets = "net.mehvahdjukaar.supplementaries.common.block.faucet.WaterBlockInteraction") 20 | public class MixinWaterBlockInteraction 21 | { 22 | @Inject(method = "tryDrain", at = @At("HEAD"), cancellable = true, remap = false) 23 | protected void addPurityBlockState(Level level, SoftFluidTank faucetTank, BlockPos pos, FluidState fluidState, FaucetBlockTile.FillAction fillAction, CallbackInfoReturnable cir) { 24 | if (fluidState.getType() != Fluids.WATER) 25 | return; 26 | 27 | CompoundTag purityTag = new CompoundTag(); 28 | purityTag.putInt("Purity", WaterPurity.getBlockPurity(level, pos)); 29 | 30 | FaucetBehaviorsManagerAccessor.invokePrepareToTransferBottle(faucetTank, VanillaSoftFluids.WATER.get(), purityTag); 31 | if (fillAction == null || fillAction.tryExecute()) { 32 | cir.setReturnValue(InteractionResult.SUCCESS); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/common/loot/AddLootTableModifier.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.common.loot; 2 | 3 | 4 | import com.google.common.base.Suppliers; 5 | import com.mojang.serialization.Codec; 6 | import com.mojang.serialization.codecs.RecordCodecBuilder; 7 | import it.unimi.dsi.fastutil.objects.ObjectArrayList; 8 | import net.minecraft.resources.ResourceLocation; 9 | import net.minecraft.world.item.ItemStack; 10 | import net.minecraft.world.level.storage.loot.LootContext; 11 | import net.minecraft.world.level.storage.loot.LootTable; 12 | import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; 13 | import net.minecraftforge.common.loot.IGlobalLootModifier; 14 | import net.minecraftforge.common.loot.LootModifier; 15 | 16 | import javax.annotation.Nonnull; 17 | import java.util.Objects; 18 | import java.util.function.Supplier; 19 | 20 | public class AddLootTableModifier extends LootModifier { 21 | public static final Supplier> CODEC = Suppliers.memoize(() -> { 22 | return RecordCodecBuilder.create((inst) -> { 23 | return codecStart(inst).and(ResourceLocation.CODEC.fieldOf("lootTable").forGetter((m) -> { 24 | return m.lootTable; 25 | })).apply(inst, AddLootTableModifier::new); 26 | }); 27 | }); 28 | private final ResourceLocation lootTable; 29 | 30 | protected AddLootTableModifier(LootItemCondition[] conditionsIn, ResourceLocation lootTable) { 31 | super(conditionsIn); 32 | this.lootTable = lootTable; 33 | } 34 | 35 | @Nonnull 36 | protected ObjectArrayList doApply(ObjectArrayList generatedLoot, LootContext context) 37 | { 38 | LootTable extraTable = context.getLootTable(this.lootTable); 39 | Objects.requireNonNull(generatedLoot); 40 | extraTable.getRandomItems(context, generatedLoot::add); 41 | 42 | return generatedLoot; 43 | } 44 | 45 | public Codec codec() { 46 | return CODEC.get(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/content/thirst/DrinkByHandClient.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.content.thirst; 2 | 3 | import dev.ghen.thirst.foundation.config.ClientConfig; 4 | import dev.ghen.thirst.foundation.network.ThirstModPacketHandler; 5 | import dev.ghen.thirst.foundation.network.message.DrinkByHandMessage; 6 | import dev.ghen.thirst.foundation.util.MathHelper; 7 | import net.minecraft.client.Minecraft; 8 | import net.minecraft.core.BlockPos; 9 | import net.minecraft.sounds.SoundEvents; 10 | import net.minecraft.sounds.SoundSource; 11 | import net.minecraft.tags.FluidTags; 12 | import net.minecraft.world.InteractionHand; 13 | import net.minecraft.world.entity.player.Player; 14 | import net.minecraft.world.level.ClipContext; 15 | import net.minecraft.world.level.Level; 16 | import net.minecraftforge.api.distmarker.Dist; 17 | import net.minecraftforge.api.distmarker.OnlyIn; 18 | 19 | @OnlyIn(Dist.CLIENT) 20 | public class DrinkByHandClient 21 | { 22 | public static void drinkByHand() 23 | { 24 | Minecraft mc = Minecraft.getInstance(); 25 | 26 | Player player = mc.player; 27 | Level level = mc.level; 28 | BlockPos blockPos = MathHelper.getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY).getBlockPos(); 29 | boolean HandAvailable; 30 | 31 | if (level.getFluidState(blockPos).is(FluidTags.WATER) && player.isCrouching() && !player.isInvulnerable()) { 32 | 33 | if(!ClientConfig.DRINK_BOTH_HAND_NEEDED.get()){ 34 | HandAvailable = player.getItemInHand(InteractionHand.MAIN_HAND).isEmpty(); 35 | }else { 36 | HandAvailable = player.getItemInHand(InteractionHand.MAIN_HAND).isEmpty() && player.getItemInHand(InteractionHand.OFF_HAND).isEmpty(); 37 | } 38 | if(HandAvailable){ 39 | level.playSound(player, player.getX(), player.getY(), player.getZ(), SoundEvents.GENERIC_DRINK, SoundSource.NEUTRAL, 1.0F, 1.0F); 40 | ThirstModPacketHandler.INSTANCE.sendToServer(new DrinkByHandMessage(blockPos)); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinBottleItem.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import dev.ghen.thirst.foundation.util.MathHelper; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.tags.FluidTags; 7 | import net.minecraft.world.entity.player.Player; 8 | import net.minecraft.world.item.BottleItem; 9 | import net.minecraft.world.item.ItemStack; 10 | import net.minecraft.world.level.ClipContext; 11 | import net.minecraft.world.level.Level; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.ModifyArg; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 17 | 18 | @Mixin(BottleItem.class) 19 | public class MixinBottleItem 20 | { 21 | private boolean shouldModify; 22 | private int purity; 23 | 24 | @Inject(method = "turnBottleIntoItem", at = @At("HEAD")) 25 | public void setPurity(ItemStack source, Player player, ItemStack result, CallbackInfoReturnable cir) 26 | { 27 | Level level = player.getLevel(); 28 | BlockPos fluidPos = MathHelper.getPlayerPOVHitResult(player.getLevel(), player, ClipContext.Fluid.SOURCE_ONLY).getBlockPos(); 29 | 30 | shouldModify = level.getFluidState(fluidPos).is(FluidTags.WATER) && level.getFluidState(fluidPos).isSource(); 31 | if(shouldModify) 32 | purity = WaterPurity.getBlockPurity(level, fluidPos); 33 | } 34 | 35 | @ModifyArg(method = "turnBottleIntoItem", index = 2, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemUtils;createFilledResult(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;")) 36 | private ItemStack addPurity(ItemStack result) 37 | { 38 | if(shouldModify) 39 | WaterPurity.addPurity(result, purity); 40 | 41 | return result; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/compat/create/SandFilterBlock.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.compat.create; 2 | 3 | import com.simibubi.create.AllShapes; 4 | import com.simibubi.create.content.equipment.wrench.IWrenchable; 5 | import com.simibubi.create.foundation.advancement.AdvancementBehaviour; 6 | import com.simibubi.create.foundation.block.IBE; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.world.entity.LivingEntity; 9 | import net.minecraft.world.item.ItemStack; 10 | import net.minecraft.world.level.BlockGetter; 11 | import net.minecraft.world.level.Level; 12 | import net.minecraft.world.level.block.Block; 13 | import net.minecraft.world.level.block.entity.BlockEntityType; 14 | import net.minecraft.world.level.block.state.BlockState; 15 | import net.minecraft.world.phys.shapes.CollisionContext; 16 | import net.minecraft.world.phys.shapes.VoxelShape; 17 | import org.jetbrains.annotations.NotNull; 18 | 19 | @SuppressWarnings("deprecation") 20 | public class SandFilterBlock extends Block implements IWrenchable, IBE { 21 | 22 | public SandFilterBlock(Properties p_i48440_1_) { 23 | super(p_i48440_1_); 24 | } 25 | 26 | @Override 27 | public @NotNull VoxelShape getShape(@NotNull BlockState p_220053_1_, @NotNull BlockGetter p_220053_2_, 28 | @NotNull BlockPos p_220053_3_, @NotNull CollisionContext p_220053_4_) 29 | { 30 | return AllShapes.SPOUT; 31 | } 32 | 33 | @Override 34 | public void setPlacedBy(@NotNull Level pLevel, @NotNull BlockPos pPos, @NotNull BlockState pState, 35 | LivingEntity pPlacer, @NotNull ItemStack pStack) 36 | { 37 | super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack); 38 | AdvancementBehaviour.setPlacedBy(pLevel, pPos, pPlacer); 39 | } 40 | 41 | @Override 42 | public Class getBlockEntityClass() { 43 | return SandFilterTileEntity.class; 44 | } 45 | 46 | @Override 47 | public BlockEntityType getBlockEntityType() 48 | { 49 | return CreateRegistry.SAND_FILTER_TE.get(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/createcenterkitchen/MixinKettlePoint.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.createcenterkitchen; 2 | 3 | import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPoint; 4 | import com.simibubi.create.content.kinetics.mechanicalArm.ArmInteractionPointType; 5 | import dev.ghen.thirst.content.purity.WaterPurity; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.world.item.ItemStack; 8 | import net.minecraft.world.level.Level; 9 | import net.minecraft.world.level.block.state.BlockState; 10 | import net.minecraftforge.items.IItemHandler; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 15 | import plus.dragons.createcentralkitchen.content.logistics.block.mechanicalArm.KettlePoint; 16 | import plus.dragons.createcentralkitchen.content.logistics.item.guide.brewing.BrewingGuide; 17 | 18 | @Mixin(KettlePoint.class) 19 | public abstract class MixinKettlePoint extends ArmInteractionPoint { 20 | 21 | public MixinKettlePoint(ArmInteractionPointType type, Level level, BlockPos pos, BlockState state) { 22 | super(type, level, pos, state); 23 | } 24 | @Inject(method = "insertWater", at = @At(value = "INVOKE",target = "Lnet/minecraft/world/level/Level;setBlockAndUpdate(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)Z"),remap = false) 25 | private void insertWater(BrewingGuide guide, IItemHandler inventory, ItemStack stack, boolean simulate, CallbackInfoReturnable cir){ 26 | BlockState state = this.level.getBlockState(pos); 27 | int purity = WaterPurity.getPurity(stack); 28 | int blockPurity = !state.hasProperty(WaterPurity.BLOCK_PURITY) ? 29 | WaterPurity.MAX_PURITY : (state.getValue(WaterPurity.BLOCK_PURITY) - 1 < 0 ? 30 | WaterPurity.MAX_PURITY : state.getValue(WaterPurity.BLOCK_PURITY) - 1); 31 | level.setBlockAndUpdate(pos, state.setValue(WaterPurity.BLOCK_PURITY, Math.max(purity, blockPurity)+1)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/farmersrespite/MixinKettleScreen.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.farmersrespite; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import net.minecraft.network.chat.Component; 5 | import net.minecraft.network.chat.MutableComponent; 6 | import net.minecraft.world.level.block.state.BlockState; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Redirect; 10 | import umpaz.farmersrespite.client.gui.KettleScreen; 11 | import umpaz.farmersrespite.common.block.KettleBlock; 12 | 13 | import java.util.Objects; 14 | 15 | @Mixin(KettleScreen.class) 16 | public abstract class MixinKettleScreen 17 | { 18 | 19 | @Redirect(method = "renderWaterBarIndicatorTooltip", at = @At(value = "INVOKE", target = "Lumpaz/farmersrespite/common/utility/FRTextUtils;getTranslation(Ljava/lang/String;[Ljava/lang/Object;)Lnet/minecraft/network/chat/MutableComponent;"), remap = false) 20 | private MutableComponent addPurityTooltip(String key, Object[] oldArgs) 21 | { 22 | BlockState state = Objects.requireNonNull(((KettleScreen) (Object) this).getMenu().tileEntity.getLevel()).getBlockState(((KettleScreen)(Object)this).getMenu().tileEntity.getBlockPos()); 23 | 24 | int waterLevel = state.getValue(KettleBlock.WATER_LEVEL); 25 | int purity = WaterPurity.getBlockPurity(state); 26 | String purityString = purity == 0 ? Component.translatable("thirst.purity.dirty").getString() : 27 | purity == 1 ? Component.translatable("thirst.purity.slightly_dirty").getString(): 28 | purity == 2 ? Component.translatable("thirst.purity.acceptable").getString() : Component.translatable("thirst.purity.purified").getString(); 29 | 30 | Object[] args; 31 | if(purity == -1 || waterLevel == 0) 32 | { 33 | args = new Object[]{}; 34 | } 35 | else if(waterLevel == 1) 36 | { 37 | args = new Object[]{purityString}; 38 | } 39 | else 40 | { 41 | args = new Object[]{waterLevel, purityString}; 42 | } 43 | return Component.translatable("thirst." + key, args); 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinBucketItem.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import dev.ghen.thirst.foundation.util.MathHelper; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.nbt.CompoundTag; 7 | import net.minecraft.tags.FluidTags; 8 | import net.minecraft.world.InteractionHand; 9 | import net.minecraft.world.InteractionResultHolder; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraft.world.item.BucketItem; 12 | import net.minecraft.world.item.ItemStack; 13 | import net.minecraft.world.level.ClipContext; 14 | import net.minecraft.world.level.Level; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | import org.spongepowered.asm.mixin.injection.Inject; 18 | import org.spongepowered.asm.mixin.injection.ModifyArg; 19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 20 | 21 | @Mixin(BucketItem.class) 22 | public class MixinBucketItem 23 | { 24 | private boolean shouldModify; 25 | private int purity; 26 | 27 | @Inject(method = "use", at = @At("HEAD")) 28 | public void setPurity(Level level, Player player, InteractionHand hand, CallbackInfoReturnable> cir) 29 | { 30 | BlockPos blockPos = MathHelper.getPlayerPOVHitResult(player.getLevel(), player, ClipContext.Fluid.SOURCE_ONLY).getBlockPos(); 31 | 32 | shouldModify = (level.getFluidState(blockPos).is(FluidTags.WATER) && level.getFluidState(blockPos).isSource()); 33 | 34 | if(shouldModify) 35 | purity = WaterPurity.getBlockPurity(level, blockPos); 36 | } 37 | 38 | @ModifyArg(method = "use", index = 2, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemUtils;createFilledResult(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/item/ItemStack;)Lnet/minecraft/world/item/ItemStack;")) 39 | private ItemStack addPurity(ItemStack result) 40 | { 41 | if(shouldModify) 42 | { 43 | CompoundTag tag = result.getOrCreateTag(); 44 | tag.putInt("Purity", purity); 45 | } 46 | 47 | return result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/config/ClientConfig.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.config; 2 | 3 | import net.minecraftforge.common.ForgeConfigSpec; 4 | import net.minecraftforge.fml.ModLoadingContext; 5 | import net.minecraftforge.fml.config.ModConfig; 6 | import net.minecraftforge.fml.loading.FMLPaths; 7 | 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.nio.file.Paths; 11 | 12 | public class ClientConfig 13 | { 14 | private static final ForgeConfigSpec SPEC; 15 | public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); 16 | 17 | public static final ForgeConfigSpec.ConfigValue ONLY_SHOW_PURITY_WHEN_SHIFTING; 18 | public static final ForgeConfigSpec.ConfigValue THIRST_BAR_Y_OFFSET; 19 | public static final ForgeConfigSpec.ConfigValue THIRST_BAR_X_OFFSET; 20 | public static final ForgeConfigSpec.ConfigValue DRINK_BOTH_HAND_NEEDED; 21 | 22 | static 23 | { 24 | BUILDER.push("Purity tooltip"); 25 | ONLY_SHOW_PURITY_WHEN_SHIFTING = BUILDER.comment("If the purity tooltip should be shown only when the player is pressing the shift key").define("onlyShowPurityWhenShifting", false); 26 | BUILDER.pop(); 27 | 28 | BUILDER.push("Thirst Bar"); 29 | THIRST_BAR_Y_OFFSET = BUILDER.comment("How many pixels should the thirst bar be shifted vertically from its original position").define("thirstBarYOffset", 0); 30 | THIRST_BAR_X_OFFSET = BUILDER.comment("How many pixels should the thirst bar be shifted horizontally from its original position").define("thirstBarXOffset", 0); 31 | BUILDER.pop(); 32 | 33 | BUILDER.push("Client Drink Mechanics"); 34 | DRINK_BOTH_HAND_NEEDED = BUILDER.comment("Whether players needs two hands available to drink water from source").define("DrinkBothHandNeeded",true); 35 | BUILDER.pop(); 36 | 37 | SPEC = BUILDER.build(); 38 | } 39 | 40 | public static void setup() 41 | { 42 | Path configPath = FMLPaths.CONFIGDIR.get(); 43 | Path configFolder = Paths.get(configPath.toAbsolutePath().toString(), "thirst"); 44 | 45 | try 46 | { 47 | Files.createDirectory(configFolder); 48 | } 49 | catch (Exception ignored) {} 50 | 51 | ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, SPEC, "thirst/client.toml"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/network/message/DrinkByHandMessage.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.network.message; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import dev.ghen.thirst.foundation.common.capability.ModCapabilities; 5 | import dev.ghen.thirst.foundation.config.CommonConfig; 6 | import net.minecraft.core.BlockPos; 7 | import net.minecraft.network.FriendlyByteBuf; 8 | import net.minecraft.sounds.SoundEvents; 9 | import net.minecraft.sounds.SoundSource; 10 | import net.minecraft.world.entity.player.Player; 11 | import net.minecraft.world.level.Level; 12 | import net.minecraftforge.network.NetworkEvent; 13 | 14 | import java.util.function.Supplier; 15 | 16 | public class DrinkByHandMessage 17 | { 18 | public BlockPos pos; 19 | 20 | public DrinkByHandMessage(BlockPos pos) 21 | { 22 | this.pos = pos; 23 | } 24 | 25 | public static void encode(DrinkByHandMessage message, FriendlyByteBuf buffer) 26 | { 27 | buffer.writeBlockPos(message.pos); 28 | } 29 | 30 | public static DrinkByHandMessage decode(FriendlyByteBuf buffer) 31 | { 32 | return new DrinkByHandMessage(buffer.readBlockPos()); 33 | } 34 | 35 | public static void handle(DrinkByHandMessage message, Supplier contextSupplier) 36 | { 37 | NetworkEvent.Context context = contextSupplier.get(); 38 | 39 | if (context.getDirection().getReceptionSide().isServer()) 40 | { 41 | context.enqueueWork(() -> 42 | { 43 | Player player = context.getSender(); 44 | Level level = player.getLevel(); 45 | 46 | player.getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(cap -> 47 | { 48 | if(cap.getThirst()==20) 49 | return; 50 | 51 | int purity = WaterPurity.getBlockPurity(level, message.pos); 52 | level.playSound(player, player.getX(), player.getY(), player.getZ(), SoundEvents.GENERIC_DRINK, SoundSource.NEUTRAL, 1.0F, 1.0F); 53 | 54 | if(WaterPurity.givePurityEffects(player, purity)) 55 | cap.drink(player, CommonConfig.HAND_DRINKING_HYDRATION.get().intValue(), CommonConfig.HAND_DRINKING_QUENCHED.get().intValue()); 56 | }); 57 | }); 58 | } 59 | 60 | context.setPacketHandled(true); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/create/MixinBasinRecipe.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.create; 2 | 3 | import com.simibubi.create.content.processing.basin.BasinBlockEntity; 4 | import com.simibubi.create.content.processing.basin.BasinRecipe; 5 | import dev.ghen.thirst.content.purity.WaterPurity; 6 | import net.minecraft.core.NonNullList; 7 | import net.minecraft.world.item.crafting.Recipe; 8 | import net.minecraftforge.common.capabilities.ForgeCapabilities; 9 | import net.minecraftforge.fluids.FluidStack; 10 | import net.minecraftforge.fluids.capability.IFluidHandler; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 15 | 16 | import java.util.regex.Matcher; 17 | import java.util.regex.Pattern; 18 | 19 | @Mixin(BasinRecipe.class) 20 | public class MixinBasinRecipe { 21 | 22 | @Inject( 23 | method = {"apply(Lcom/simibubi/create/content/processing/basin/BasinBlockEntity;Lnet/minecraft/world/item/crafting/Recipe;Z)Z"}, 24 | at = @At( 25 | value = "INVOKE", 26 | target = "Ljava/util/List;addAll(Ljava/util/Collection;)Z", 27 | ordinal = 0 28 | ), 29 | remap = false) 30 | private static void setPurity(BasinBlockEntity basin, Recipe recipe, boolean test, CallbackInfoReturnable cir) 31 | { 32 | int purity = getWaterPurity(basin); 33 | NonNullList outputFluids = ((BasinRecipe) recipe).getFluidResults(); 34 | 35 | Pattern pattern = Pattern.compile("tea", Pattern.CASE_INSENSITIVE); 36 | 37 | outputFluids.forEach(fluid -> 38 | { 39 | Matcher matcher = pattern.matcher(fluid.getTranslationKey()); 40 | if(matcher.find()) { 41 | WaterPurity.addPurity(fluid, Math.min(purity, WaterPurity.MAX_PURITY)); 42 | } 43 | }); 44 | } 45 | 46 | private static int getWaterPurity(BasinBlockEntity basin) 47 | { 48 | IFluidHandler availableFluids = basin.getCapability(ForgeCapabilities.FLUID_HANDLER) 49 | .orElse(null); 50 | 51 | if(availableFluids == null) 52 | return WaterPurity.MAX_PURITY; 53 | 54 | for (int tank = 0; tank < availableFluids.getTanks(); tank++) 55 | { 56 | FluidStack fluidStack = availableFluids.getFluidInTank(tank); 57 | 58 | if(WaterPurity.hasPurity(fluidStack)) 59 | return WaterPurity.getPurity(fluidStack); 60 | } 61 | 62 | return -1; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/util/ConfigHelper.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.util; 2 | 3 | import net.minecraft.resources.ResourceLocation; 4 | import net.minecraft.world.item.Item; 5 | import net.minecraftforge.registries.ForgeRegistries; 6 | import net.minecraftforge.registries.tags.ITag; 7 | 8 | import java.util.*; 9 | 10 | public class ConfigHelper 11 | { 12 | /** 13 | * This class was taken from Cold Sweat 14 | */ 15 | 16 | public static Map getItemsWithValues(List> source) 17 | { 18 | Map map = new HashMap<>(); 19 | for (List entry : source) 20 | { 21 | String itemID = (String) entry.get(0); 22 | 23 | if (itemID.startsWith("#")) 24 | { 25 | final String tagID = itemID.replace("#", ""); 26 | Optional> optionalTag = ForgeRegistries.ITEMS.tags().stream().filter(tag -> 27 | tag.getKey().location().toString().equals(tagID)).findFirst(); 28 | optionalTag.ifPresent(itemITag -> 29 | { 30 | for (Item item : optionalTag.get().stream().toList()) 31 | { 32 | map.put(item, new Number[]{(Number) entry.get(1), (Number) entry.get(2)}); 33 | } 34 | }); 35 | } 36 | else 37 | { 38 | Item newItem = ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemID)); 39 | 40 | 41 | if (newItem != null) map.put(newItem, new Number[]{(Number) entry.get(1), (Number) entry.get(2)}); 42 | } 43 | } 44 | return map; 45 | } 46 | 47 | public static List getItems(List source){ 48 | List list = new ArrayList<>(); 49 | for(String itemID : source){ 50 | if (itemID.startsWith("#")) 51 | { 52 | final String tagID = itemID.replace("#", ""); 53 | Optional> optionalTag = ForgeRegistries.ITEMS.tags().stream().filter(tag -> 54 | tag.getKey().location().toString().equals(tagID)).findFirst(); 55 | optionalTag.ifPresent(itemITag -> 56 | list.addAll(optionalTag.get().stream().toList())); 57 | } 58 | else 59 | { 60 | Item newItem = ForgeRegistries.ITEMS.getValue(new ResourceLocation(itemID)); 61 | 62 | 63 | if (newItem != null) list.add(newItem); 64 | } 65 | } 66 | return list; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinCampfireBlockEntity.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.core.Direction; 6 | import net.minecraft.core.particles.ParticleTypes; 7 | import net.minecraft.util.RandomSource; 8 | import net.minecraft.world.item.ItemStack; 9 | import net.minecraft.world.level.Level; 10 | import net.minecraft.world.level.block.CampfireBlock; 11 | import net.minecraft.world.level.block.entity.CampfireBlockEntity; 12 | import net.minecraft.world.level.block.state.BlockState; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 17 | 18 | @Mixin({CampfireBlockEntity.class}) 19 | public class MixinCampfireBlockEntity 20 | { 21 | public MixinCampfireBlockEntity() { } 22 | 23 | @Inject( 24 | method = {"particleTick"}, 25 | at = {@At("HEAD")}, 26 | cancellable = true 27 | ) 28 | private static void waterVapour(Level level, BlockPos pos, BlockState blockState, CampfireBlockEntity campfire, CallbackInfo ci) { 29 | RandomSource random = level.getRandom(); 30 | int l = blockState.getValue(CampfireBlock.FACING).get2DDataValue(); 31 | boolean cancel = false; 32 | 33 | for(int i = 0; i < campfire.getItems().size(); ++i) { 34 | ItemStack itemstack = campfire.getItems().get(i); 35 | if (WaterPurity.isWaterFilledContainer(itemstack)) { 36 | cancel = true; 37 | if (random.nextFloat() < 0.2F) { 38 | Direction direction = Direction.from2DDataValue(Math.floorMod(i + l, 4)); 39 | final float f = 0.3125F; 40 | double d0 = (double)pos.getX() + 0.5 - (double)((float)direction.getStepX() * f) + (double)((float)direction.getClockWise().getStepX() * f); 41 | double d1 = (double)pos.getY() + 0.6; 42 | double d2 = (double)pos.getZ() + 0.5 - (double)((float)direction.getStepZ() * f) + (double)((float)direction.getClockWise().getStepZ() * f); 43 | level.addParticle(ParticleTypes.EFFECT, d0, d1, d2, 0.0, 0.001, 0.0); 44 | } 45 | } 46 | } 47 | 48 | if (cancel) { 49 | if (random.nextFloat() < 0.11F) { 50 | for(int i = 0; i < random.nextInt(2) + 2; ++i) { 51 | CampfireBlock.makeParticles(level, pos, blockState.getValue(CampfireBlock.SIGNAL_FIRE), false); 52 | } 53 | } 54 | 55 | ci.cancel(); 56 | } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/network/message/PlayerThirstSyncMessage.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.network.message; 2 | 3 | import dev.ghen.thirst.foundation.common.capability.ModCapabilities; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.network.FriendlyByteBuf; 6 | import net.minecraft.world.entity.player.Player; 7 | import net.minecraftforge.api.distmarker.Dist; 8 | import net.minecraftforge.api.distmarker.OnlyIn; 9 | import net.minecraftforge.fml.DistExecutor; 10 | import net.minecraftforge.network.NetworkEvent; 11 | 12 | import java.util.function.Supplier; 13 | 14 | public class PlayerThirstSyncMessage 15 | { 16 | public int thirst; 17 | public int quenched; 18 | public float exhaustion; 19 | public boolean enable; 20 | 21 | public PlayerThirstSyncMessage(int thirst, int quenched, float exhaustion,boolean enable) 22 | { 23 | this.thirst = thirst; 24 | this.quenched = quenched; 25 | this.exhaustion = exhaustion; 26 | this.enable = enable; 27 | } 28 | 29 | public PlayerThirstSyncMessage(boolean enable) 30 | { 31 | this.enable = enable; 32 | } 33 | 34 | public static void encode(PlayerThirstSyncMessage message, FriendlyByteBuf buffer) 35 | { 36 | buffer.writeInt(message.thirst); 37 | buffer.writeInt(message.quenched); 38 | buffer.writeFloat(message.exhaustion); 39 | buffer.writeBoolean(message.enable); 40 | } 41 | 42 | public static PlayerThirstSyncMessage decode(FriendlyByteBuf buffer) 43 | { 44 | return new PlayerThirstSyncMessage(buffer.readInt(), buffer.readInt(), buffer.readFloat(),buffer.readBoolean()); 45 | } 46 | 47 | public static void handle(PlayerThirstSyncMessage message, Supplier contextSupplier) 48 | { 49 | NetworkEvent.Context context = contextSupplier.get(); 50 | 51 | if (context.getDirection().getReceptionSide().isClient()) 52 | { 53 | context.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ClientThirstSyncMessage.handlePacket(message, contextSupplier))); 54 | } 55 | 56 | context.setPacketHandled(true); 57 | } 58 | } 59 | 60 | @OnlyIn(Dist.CLIENT) 61 | class ClientThirstSyncMessage 62 | { 63 | public static void handlePacket(PlayerThirstSyncMessage message, Supplier contextSupplier) 64 | { 65 | Player player = Minecraft.getInstance().player; 66 | 67 | if (player != null) 68 | { 69 | player.getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(cap -> 70 | { 71 | cap.setThirst(message.thirst); 72 | cap.setQuenched(message.quenched); 73 | cap.setExhaustion(message.exhaustion); 74 | cap.setShouldTickThirst(message.enable); 75 | }); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/common/item/DrinkableItem.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.common.item; 2 | 3 | import dev.ghen.thirst.foundation.tab.ThirstTab; 4 | import net.minecraft.advancements.CriteriaTriggers; 5 | import net.minecraft.server.level.ServerPlayer; 6 | import net.minecraft.stats.Stats; 7 | import net.minecraft.world.InteractionHand; 8 | import net.minecraft.world.InteractionResultHolder; 9 | import net.minecraft.world.entity.LivingEntity; 10 | import net.minecraft.world.entity.item.ItemEntity; 11 | import net.minecraft.world.entity.player.Player; 12 | import net.minecraft.world.item.Item; 13 | import net.minecraft.world.item.ItemStack; 14 | import net.minecraft.world.item.ItemUtils; 15 | import net.minecraft.world.item.UseAnim; 16 | import net.minecraft.world.level.Level; 17 | import net.minecraft.world.level.gameevent.GameEvent; 18 | import org.jetbrains.annotations.NotNull; 19 | 20 | public class DrinkableItem extends Item 21 | { 22 | private int drinkDuration = 32; 23 | private Item container; 24 | 25 | public DrinkableItem() 26 | { 27 | super(new Properties().stacksTo(64).tab(ThirstTab.THIRST_TAB)); 28 | } 29 | 30 | public DrinkableItem(Properties p_41383_) 31 | { 32 | super(p_41383_); 33 | } 34 | 35 | public DrinkableItem setContainer(Item item) 36 | { 37 | this.container = item; 38 | return this; 39 | } 40 | 41 | public DrinkableItem setDrinkDuration(int duration) 42 | { 43 | this.drinkDuration = duration; 44 | return this; 45 | } 46 | 47 | public @NotNull ItemStack finishUsingItem(@NotNull ItemStack item, @NotNull Level level, @NotNull LivingEntity entity) 48 | { 49 | Player player = entity instanceof Player ? (Player)entity : null; 50 | 51 | if (player instanceof ServerPlayer) 52 | { 53 | CriteriaTriggers.CONSUME_ITEM.trigger((ServerPlayer)player, item); 54 | } 55 | 56 | if (player != null) 57 | { 58 | player.awardStat(Stats.ITEM_USED.get(this)); 59 | if (!player.getAbilities().instabuild) 60 | { 61 | item.shrink(1); 62 | } 63 | } 64 | 65 | if (player == null || !player.getAbilities().instabuild) 66 | { 67 | if (item.isEmpty()) 68 | { 69 | return new ItemStack(container); 70 | } 71 | 72 | if (player != null) 73 | { 74 | ItemEntity itemEntity = new ItemEntity(level, player.getX(), player.getY(), player.getZ(), new ItemStack(container)); 75 | level.addFreshEntity(itemEntity); 76 | } 77 | } 78 | 79 | level.gameEvent(entity, GameEvent.ITEM_INTERACT_FINISH, entity.getEyePosition()); 80 | return item; 81 | } 82 | 83 | public int getUseDuration(@NotNull ItemStack p_43001_) { 84 | return drinkDuration; 85 | } 86 | 87 | public @NotNull UseAnim getUseAnimation(@NotNull ItemStack p_42997_) { 88 | return UseAnim.DRINK; 89 | } 90 | 91 | public @NotNull InteractionResultHolder use(@NotNull Level p_42993_, @NotNull Player p_42994_, @NotNull InteractionHand p_42995_) 92 | { 93 | return ItemUtils.startUsingInstantly(p_42993_, p_42994_, p_42995_); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/create/MixinOpenEndedPipe.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.create; 2 | 3 | import com.simibubi.create.content.fluids.OpenEndedPipe; 4 | import com.simibubi.create.foundation.advancement.AdvancementBehaviour; 5 | import com.simibubi.create.foundation.advancement.AllAdvancements; 6 | import com.simibubi.create.foundation.fluid.FluidHelper; 7 | import dev.ghen.thirst.content.purity.WaterPurity; 8 | import net.minecraft.nbt.CompoundTag; 9 | import net.minecraft.world.level.block.LiquidBlock; 10 | import net.minecraft.world.level.block.state.BlockState; 11 | import net.minecraft.world.level.block.state.properties.BlockStateProperties; 12 | import net.minecraft.world.level.material.FluidState; 13 | import net.minecraft.world.level.material.Fluids; 14 | import net.minecraftforge.fluids.FluidStack; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | import org.spongepowered.asm.mixin.injection.Inject; 18 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 19 | 20 | @Mixin(value = OpenEndedPipe.class,remap = false) 21 | public class MixinOpenEndedPipe 22 | { 23 | 24 | @Inject(method = "removeFluidFromSpace", at = @At("HEAD"), cancellable = true, remap = false) 25 | private void removeFluidFromSpace(boolean simulate, CallbackInfoReturnable cir) 26 | { 27 | OpenEndedPipe pipe = ((OpenEndedPipe)(Object)this); 28 | 29 | if(pipe.getWorld() != null && pipe.getWorld().isLoaded(pipe.getOutputPos())) 30 | { 31 | BlockState state = pipe.getWorld().getBlockState(pipe.getOutputPos()); 32 | FluidState fluidState = state.getFluidState(); 33 | boolean waterlog = state.hasProperty(BlockStateProperties.WATERLOGGED); 34 | 35 | if ((!fluidState.isEmpty() && fluidState.isSource())&&(waterlog || state.getMaterial().isReplaceable())) 36 | { 37 | FluidStack stack = new FluidStack(fluidState.getType(), 1000); 38 | if(FluidHelper.isWater(stack.getFluid())) 39 | { 40 | CompoundTag tag = stack.getOrCreateTag(); 41 | tag.putInt("Purity", WaterPurity.getBlockPurity(pipe.getWorld(), pipe.getOutputPos())); 42 | stack.setTag(tag); 43 | 44 | if (simulate) 45 | { 46 | cir.setReturnValue(stack); 47 | } 48 | else 49 | { 50 | AdvancementBehaviour.tryAward(pipe.getWorld(), pipe.getPos(), AllAdvancements.WATER_SUPPLY); 51 | 52 | if (waterlog) 53 | { 54 | pipe.getWorld().setBlock(pipe.getOutputPos(), state.setValue(BlockStateProperties.WATERLOGGED, false), 3); 55 | pipe.getWorld().scheduleTick(pipe.getOutputPos(), Fluids.WATER, 1); 56 | cir.setReturnValue(stack); 57 | } else { 58 | pipe.getWorld().setBlock(pipe.getOutputPos(), fluidState.createLegacyBlock().setValue(LiquidBlock.LEVEL, 14), 3); 59 | cir.setReturnValue(stack); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinFoodData.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.foundation.common.capability.IThirst; 4 | import dev.ghen.thirst.foundation.common.capability.ModCapabilities; 5 | import dev.ghen.thirst.foundation.config.CommonConfig; 6 | import net.minecraft.world.entity.player.Player; 7 | import net.minecraft.world.food.FoodData; 8 | import org.spongepowered.asm.mixin.Mixin; 9 | import org.spongepowered.asm.mixin.Shadow; 10 | import org.spongepowered.asm.mixin.Unique; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.Redirect; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(FoodData.class) 17 | public abstract class MixinFoodData 18 | { 19 | @Shadow 20 | public abstract void addExhaustion(float p_38704_); 21 | 22 | @Shadow private float exhaustionLevel; 23 | @Unique 24 | private int dehydratedHealTimer = 0; 25 | 26 | 27 | @Redirect( 28 | method = {"tick"}, 29 | at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;heal(F)V", ordinal = 0) 30 | ) 31 | private void healWithSaturation(Player player, float amount) 32 | { 33 | if(!player.getCapability(ModCapabilities.PLAYER_THIRST).isPresent()) 34 | return; 35 | FoodData foodData = player.getFoodData(); 36 | IThirst thirstData = player.getCapability(ModCapabilities.PLAYER_THIRST).orElse(null); 37 | 38 | float f = Math.min(foodData.getSaturationLevel(), 6.0F); 39 | 40 | boolean shouldHeal = !CommonConfig.DEHYDRATION_HALTS_HEALTH_REGEN.get() || thirstData.getThirst() >= 20; 41 | 42 | if(shouldHeal) 43 | { 44 | player.heal(f / 6.0F); 45 | thirstData.setJustHealed(); 46 | return; 47 | } 48 | 49 | dehydratedHealTimer++; 50 | if(dehydratedHealTimer >= 8 && thirstData.getThirst() > 18) 51 | { 52 | player.heal(f / 6.0F); 53 | thirstData.setJustHealed(); 54 | dehydratedHealTimer = 0; 55 | return; 56 | } 57 | 58 | this.addExhaustion(-f); 59 | } 60 | 61 | @Redirect( 62 | method = {"tick"}, 63 | at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;heal(F)V", ordinal = 1) 64 | ) 65 | private void healWithHunger(Player player, float amount) 66 | { 67 | if(!player.getCapability(ModCapabilities.PLAYER_THIRST).isPresent()) 68 | return; 69 | IThirst thirstData = player.getCapability(ModCapabilities.PLAYER_THIRST).orElse(null); 70 | boolean shouldHeal = !CommonConfig.DEHYDRATION_HALTS_HEALTH_REGEN.get() || thirstData.getThirst() > 18; 71 | 72 | if(shouldHeal) 73 | { 74 | player.heal(1.0F); 75 | thirstData.setJustHealed(); 76 | } 77 | else 78 | this.addExhaustion(-6.0F); 79 | } 80 | 81 | @Inject(method = "tick",at = @At(value = "HEAD")) 82 | private void DealWithExhaustionBySaturation(Player player, CallbackInfo ci){ 83 | if(exhaustionLevel>4.0F){ 84 | player.getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(IThirst::ExhaustionRecalculate); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/farmersrespite/MixinKettleBlockEntity.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.farmersrespite; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import dev.ghen.thirst.foundation.config.CommonConfig; 5 | import dev.ghen.thirst.foundation.mixin.accessors.farmersdelight.SyncedBlockEntityAccessor; 6 | import dev.ghen.thirst.foundation.mixin.accessors.farmersrespite.KettleBlockEntityAccessor; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.world.item.ItemStack; 9 | import net.minecraft.world.level.Level; 10 | import net.minecraft.world.level.block.state.BlockState; 11 | import net.minecraftforge.items.wrapper.RecipeWrapper; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.Inject; 15 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 16 | import umpaz.farmersrespite.common.block.entity.KettleBlockEntity; 17 | import umpaz.farmersrespite.common.crafting.KettleRecipe; 18 | 19 | import java.util.Optional; 20 | 21 | @Mixin(KettleBlockEntity.class) 22 | public abstract class MixinKettleBlockEntity { 23 | 24 | @Inject(method = "brewingTick", at = @At("HEAD"), remap = false, cancellable = true) 25 | private static void brewingTickWithPurity(Level level, BlockPos pos, BlockState state, KettleBlockEntity kettle, CallbackInfo ci) { 26 | boolean isHeated = kettle.isHeated(level, pos); 27 | boolean didInventoryChange; 28 | KettleBlockEntityAccessor kettleAcc = (KettleBlockEntityAccessor)kettle; 29 | if (isHeated && kettleAcc.invokeHasInput()) { 30 | Optional recipe = kettleAcc.invokeGetMatchingRecipe(new RecipeWrapper(kettle.getInventory())); 31 | if (recipe.isPresent() && kettleAcc.invokeCanBrew(recipe.get()) && WaterPurity.isWaterFilledContainer(recipe.get().getResultItem())) { 32 | didInventoryChange = kettleAcc.invokeProcessBrewing(recipe.get(), kettle); 33 | if(didInventoryChange) { 34 | 35 | //Reset Block Purity for next input 36 | if(recipe.get().getNeedWater() && !kettle.isWater()) 37 | kettle.getBlockState().setValue(WaterPurity.BLOCK_PURITY,0); 38 | 39 | int purity = Math.min(WaterPurity.getBlockPurity(kettle.getBlockState()) + CommonConfig.KETTLE_PURIFICATION_LEVELS.get().intValue(), WaterPurity.MAX_PURITY); 40 | kettle.getInventory().setStackInSlot(2, WaterPurity.addPurity(kettle.getInventory().getStackInSlot(2), purity)); 41 | } 42 | 43 | 44 | ItemStack mealStack = kettle.getMeal(); 45 | if (!mealStack.isEmpty()) { 46 | if (!kettleAcc.invokeDoesMealHaveContainer(mealStack)) { 47 | kettleAcc.invokeMoveMealToOutput(); 48 | didInventoryChange = true; 49 | } else if (!kettle.getInventory().getStackInSlot(3).isEmpty()) { 50 | kettleAcc.invokeUseStoredContainersOnMeal(); 51 | didInventoryChange = true; 52 | } 53 | } 54 | 55 | if (didInventoryChange) { 56 | ((SyncedBlockEntityAccessor)kettle).invokeInventoryChanged(); 57 | } 58 | 59 | ci.cancel(); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/content/purity/ContainerWithPurity.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.content.purity; 2 | 3 | import net.minecraft.world.item.ItemStack; 4 | 5 | import java.util.function.Predicate; 6 | 7 | public class ContainerWithPurity 8 | { 9 | private ItemStack filledItem; 10 | private ItemStack emptyItem; 11 | private final boolean isDrinkable; 12 | private final boolean isStatic; 13 | private Predicate equalsFilled; 14 | private Predicate equalsEmpty; 15 | private boolean canHarvestRunningWater; 16 | 17 | public ContainerWithPurity(ItemStack emptyItem, ItemStack filledItem) 18 | { 19 | this.emptyItem = emptyItem; 20 | this.filledItem = filledItem; 21 | this.isDrinkable = true; 22 | this.isStatic = false; 23 | this.canHarvestRunningWater = true; 24 | 25 | fillPredicates(); 26 | } 27 | 28 | public ContainerWithPurity(ItemStack emptyItem, ItemStack filledItem, boolean isDrinkable) 29 | { 30 | this.emptyItem = emptyItem; 31 | this.filledItem = filledItem; 32 | this.isDrinkable = isDrinkable; 33 | this.isStatic = false; 34 | this.canHarvestRunningWater = true; 35 | 36 | fillPredicates(); 37 | } 38 | 39 | /** 40 | * Creates a Static container (has purity but can only be 41 | * drunk, not used to fill anything) 42 | */ 43 | public ContainerWithPurity(ItemStack filledItem) 44 | { 45 | this.emptyItem = null; 46 | this.filledItem = filledItem; 47 | this.isDrinkable = true; 48 | this.isStatic = true; 49 | this.canHarvestRunningWater = false; 50 | 51 | fillPredicates(); 52 | } 53 | 54 | public ContainerWithPurity canHarvestRunningWater(boolean canHarvestRunningWater) 55 | { 56 | this.canHarvestRunningWater = canHarvestRunningWater; 57 | return this; 58 | } 59 | 60 | public boolean canHarvestRunningWater() 61 | { 62 | return canHarvestRunningWater; 63 | } 64 | 65 | void fillPredicates() 66 | { 67 | equalsFilled = itemStack -> itemStack.getItem() == filledItem.getItem(); 68 | equalsEmpty = itemStack -> itemStack.getItem() == emptyItem.getItem(); 69 | } 70 | 71 | public ContainerWithPurity setEqualsEmpty(Predicate predicate) 72 | { 73 | this.equalsEmpty = predicate; 74 | return this; 75 | } 76 | 77 | public ContainerWithPurity setEqualsFilled(Predicate predicate) 78 | { 79 | this.equalsFilled = predicate; 80 | return this; 81 | } 82 | 83 | public boolean equalsEmpty(ItemStack item) 84 | { 85 | return !isStatic && equalsEmpty.test(item); 86 | } 87 | 88 | public boolean equalsFilled(ItemStack item) 89 | { 90 | return equalsFilled.test(item); 91 | } 92 | 93 | public boolean isDrinkable() 94 | { 95 | return isDrinkable; 96 | } 97 | 98 | public ItemStack getFilledItem() 99 | { 100 | return filledItem; 101 | } 102 | 103 | public void setFilledItem(ItemStack filledItem) 104 | { 105 | this.filledItem = filledItem; 106 | } 107 | 108 | public ItemStack getEmptyItem() 109 | { 110 | return emptyItem; 111 | } 112 | 113 | public void setEmptyItem(ItemStack emptyItem) 114 | { 115 | this.emptyItem = emptyItem; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /CREDITS.txt: -------------------------------------------------------------------------------- 1 | Minecraft Forge: Credits/Thank You 2 | 3 | Forge is a set of tools and modifications to the Minecraft base game code to assist 4 | mod developers in creating new and exciting content. It has been in development for 5 | several years now, but I would like to take this time thank a few people who have 6 | helped it along it's way. 7 | 8 | First, the people who originally created the Forge projects way back in Minecraft 9 | alpha. Eloraam of RedPower, and SpaceToad of Buildcraft, without their acceptiance 10 | of me taking over the project, who knows what Minecraft modding would be today. 11 | 12 | Secondly, someone who has worked with me, and developed some of the core features 13 | that allow modding to be as functional, and as simple as it is, cpw. For developing 14 | FML, which stabelized the client and server modding ecosystem. As well as the base 15 | loading system that allows us to modify Minecraft's code as elegently as possible. 16 | 17 | Mezz, who has stepped up as the issue and pull request manager. Helping to keep me 18 | sane as well as guiding the community into creating better additions to Forge. 19 | 20 | Searge, Bspks, Fesh0r, ProfMobious, and all the rest over on the MCP team {of which 21 | I am a part}. For creating some of the core tools needed to make Minecraft modding 22 | both possible, and as stable as can be. 23 | On that note, here is some specific information of the MCP data we use: 24 | * Minecraft Coder Pack (MCP) * 25 | Forge Mod Loader and Minecraft Forge have permission to distribute and automatically 26 | download components of MCP and distribute MCP data files. This permission is not 27 | transitive and others wishing to redistribute the Minecraft Forge source independently 28 | should seek permission of MCP or remove the MCP data files and request their users 29 | to download MCP separately. 30 | 31 | And lastly, the countless community members who have spent time submitting bug reports, 32 | pull requests, and just helping out the community in general. Thank you. 33 | 34 | --LexManos 35 | 36 | ========================================================================= 37 | 38 | This is Forge Mod Loader. 39 | 40 | You can find the source code at all times at https://github.com/MinecraftForge/MinecraftForge/tree/1.12.x/src/main/java/net/minecraftforge/fml 41 | 42 | This minecraft mod is a clean open source implementation of a mod loader for minecraft servers 43 | and minecraft clients. 44 | 45 | The code is authored by cpw. 46 | 47 | It began by partially implementing an API defined by the client side ModLoader, authored by Risugami. 48 | http://www.minecraftforum.net/topic/75440- 49 | This support has been dropped as of Minecraft release 1.7, as Risugami no longer maintains ModLoader. 50 | 51 | It also contains suggestions and hints and generous helpings of code from LexManos, author of MinecraftForge. 52 | http://www.minecraftforge.net/ 53 | 54 | Additionally, it contains an implementation of topological sort based on that 55 | published at http://keithschwarz.com/interesting/code/?dir=topological-sort 56 | 57 | It also contains code from the Maven project for performing versioned dependency 58 | resolution. http://maven.apache.org/ 59 | 60 | It also contains a partial repackaging of the javaxdelta library from http://sourceforge.net/projects/javaxdelta/ 61 | with credit to it's authors. 62 | 63 | Forge Mod Loader downloads components from the Minecraft Coder Pack 64 | (http://mcp.ocean-labs.de/index.php/Main_Page) with kind permission from the MCP team. 65 | 66 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/create/MixinFillingBySpout.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.create; 2 | 3 | import com.simibubi.create.AllRecipeTypes; 4 | import com.simibubi.create.content.fluids.spout.FillingBySpout; 5 | import com.simibubi.create.content.fluids.transfer.FillingRecipe; 6 | import com.simibubi.create.content.fluids.transfer.GenericItemFilling; 7 | import com.simibubi.create.content.processing.sequenced.SequencedAssemblyRecipe; 8 | import com.simibubi.create.foundation.fluid.FluidIngredient; 9 | import dev.ghen.thirst.content.purity.WaterPurity; 10 | import net.minecraft.world.item.ItemStack; 11 | import net.minecraft.world.item.crafting.Recipe; 12 | import net.minecraft.world.level.Level; 13 | import net.minecraftforge.fluids.FluidStack; 14 | import net.minecraftforge.items.wrapper.RecipeWrapper; 15 | import org.spongepowered.asm.mixin.Final; 16 | import org.spongepowered.asm.mixin.Mixin; 17 | import org.spongepowered.asm.mixin.Shadow; 18 | import org.spongepowered.asm.mixin.injection.At; 19 | import org.spongepowered.asm.mixin.injection.Inject; 20 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 21 | 22 | import java.util.Iterator; 23 | import java.util.List; 24 | 25 | @Mixin(value = FillingBySpout.class,remap = false) 26 | public class MixinFillingBySpout 27 | { 28 | @Final 29 | @Shadow 30 | private static RecipeWrapper WRAPPER; 31 | 32 | @Inject(method = "fillItem", at = @At("HEAD"), cancellable = true, remap = false) 33 | private static void fillItem(Level world, int requiredAmount, ItemStack stack, FluidStack availableFluid, CallbackInfoReturnable cir) 34 | { 35 | FluidStack toFill = availableFluid.copy(); 36 | toFill.setAmount(requiredAmount); 37 | WRAPPER.setItem(0, stack); 38 | 39 | if(WaterPurity.hasPurity(availableFluid)) 40 | { 41 | int purity = WaterPurity.getPurity(availableFluid); 42 | 43 | FillingRecipe fillingRecipe = SequencedAssemblyRecipe.getRecipe(world, WRAPPER, AllRecipeTypes.FILLING.getType(), FillingRecipe.class).filter((fr) -> 44 | fr.getRequiredFluid().test(toFill)).orElseGet(() -> 45 | { 46 | Iterator> var2 = world.getRecipeManager().getRecipesFor(AllRecipeTypes.FILLING.getType(), WRAPPER, world).iterator(); 47 | 48 | FillingRecipe fr; 49 | FluidIngredient requiredFluid; 50 | do { 51 | if (!var2.hasNext()) { 52 | return null; 53 | } 54 | 55 | Recipe recipe = var2.next(); 56 | fr = (FillingRecipe)recipe; 57 | requiredFluid = fr.getRequiredFluid(); 58 | } while(!requiredFluid.test(toFill)); 59 | 60 | return fr; 61 | }); 62 | if (fillingRecipe != null) { 63 | List results = fillingRecipe.rollResults(); 64 | availableFluid.shrink(requiredAmount); 65 | stack.shrink(1); 66 | cir.setReturnValue(results.isEmpty() ? 67 | ItemStack.EMPTY : WaterPurity.isWaterFilledContainer(results.get(0))? 68 | WaterPurity.addPurity(results.get(0),purity):results.get(0)); 69 | } else { 70 | ItemStack output = GenericItemFilling.fillItem(world, requiredAmount, stack, availableFluid); 71 | cir.setReturnValue(output); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/compat/create/ponder/scene/SandFilterScene.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.compat.create.ponder.scene; 2 | 3 | import com.simibubi.create.content.fluids.tank.FluidTankBlockEntity; 4 | import com.simibubi.create.foundation.ponder.SceneBuilder; 5 | import com.simibubi.create.foundation.ponder.SceneBuildingUtil; 6 | import com.simibubi.create.foundation.ponder.Selection; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.core.Direction; 9 | import net.minecraft.world.level.material.Fluids; 10 | import net.minecraft.world.phys.Vec3; 11 | import net.minecraftforge.fluids.FluidStack; 12 | import net.minecraftforge.fluids.capability.IFluidHandler; 13 | 14 | public class SandFilterScene { 15 | public static void filtering(SceneBuilder scene, SceneBuildingUtil util) 16 | { 17 | scene.title("sand_filter", "Purifying Water with a Sand Filter"); 18 | scene.configureBasePlate(0, 0, 5); 19 | scene.showBasePlate(); 20 | scene.idle(5); 21 | 22 | Selection filter = util.select.position(2, 3, 2); 23 | BlockPos filterPos = util.grid.at(2, 3, 2); 24 | 25 | scene.world.showSection(filter, Direction.DOWN); 26 | scene.idle(5); 27 | 28 | Vec3 filterSide = util.vector.blockSurface(filterPos, Direction.WEST); 29 | scene.overlay.showText(80) 30 | .pointAt(filterSide) 31 | .placeNearTarget() 32 | .attachKeyFrame() 33 | .text("A Sand Filter purifies by one step water pumped through it"); 34 | 35 | scene.idle(70); 36 | 37 | Selection gears = util.select.fromTo(3, 1, 2, 3, 5, 5); 38 | Selection bottomGear = util.select.position(3, 0, 5); 39 | Selection topTank = util.select.fromTo(2, 4, 2, 2, 5, 2); 40 | BlockPos topTankPos = util.grid.at(2, 5, 2); 41 | 42 | scene.world.showSection(topTank, Direction.DOWN); 43 | scene.idle(5); 44 | scene.world.showSection(gears, Direction.WEST); 45 | scene.world.showSection(bottomGear, Direction.WEST); 46 | scene.idle(5); 47 | 48 | FluidStack content = new FluidStack(Fluids.WATER, 4000); 49 | scene.world.modifyBlockEntity(topTankPos, FluidTankBlockEntity.class, be -> be.getTankInventory() 50 | .fill(content, IFluidHandler.FluidAction.EXECUTE)); 51 | 52 | Vec3 topTankSide = util.vector.blockSurface(topTankPos, Direction.EAST); 53 | scene.overlay.showText(60) 54 | .pointAt(topTankSide) 55 | .placeNearTarget() 56 | .attachKeyFrame() 57 | .text("Dirty Water needs to be pumped in from the top..."); 58 | 59 | scene.idle(30); 60 | 61 | Selection bottomTank = util.select.fromTo(2, 1, 2, 2, 2, 2); 62 | BlockPos bottomTankPos = util.grid.at(2, 1, 2); 63 | 64 | scene.world.showSection(bottomTank, Direction.DOWN); 65 | scene.idle(30); 66 | 67 | Vec3 bottomTankSide = util.vector.blockSurface(bottomTankPos, Direction.WEST); 68 | scene.overlay.showText(60) 69 | .pointAt(bottomTankSide) 70 | .placeNearTarget() 71 | .attachKeyFrame() 72 | .text("and Purified Water can be pumped out from the bottom"); 73 | 74 | scene.idle(10); 75 | 76 | scene.world.modifyBlockEntity(topTankPos, FluidTankBlockEntity.class, be -> be.getTankInventory() 77 | .drain(4000, IFluidHandler.FluidAction.EXECUTE)); 78 | 79 | scene.world.modifyBlockEntity(bottomTankPos, FluidTankBlockEntity.class, be -> be.getTankInventory() 80 | .fill(content, IFluidHandler.FluidAction.EXECUTE)); 81 | 82 | scene.idle(50); 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/toughasnails/MixinEmptyCanteenItem.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.toughasnails; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import dev.ghen.thirst.foundation.util.MathHelper; 5 | import net.minecraft.core.BlockPos; 6 | import net.minecraft.sounds.SoundEvent; 7 | import net.minecraft.sounds.SoundEvents; 8 | import net.minecraft.sounds.SoundSource; 9 | import net.minecraft.tags.FluidTags; 10 | import net.minecraft.world.InteractionHand; 11 | import net.minecraft.world.InteractionResultHolder; 12 | import net.minecraft.world.entity.player.Player; 13 | import net.minecraft.world.item.ItemStack; 14 | import net.minecraft.world.item.ItemUtils; 15 | import net.minecraft.world.level.ClipContext; 16 | import net.minecraft.world.level.Level; 17 | import net.minecraft.world.level.block.state.BlockState; 18 | import net.minecraft.world.level.gameevent.GameEvent; 19 | import org.spongepowered.asm.mixin.Mixin; 20 | import org.spongepowered.asm.mixin.Shadow; 21 | import org.spongepowered.asm.mixin.injection.At; 22 | import org.spongepowered.asm.mixin.injection.Inject; 23 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 24 | import toughasnails.api.block.TANBlocks; 25 | import toughasnails.api.item.TANItems; 26 | import toughasnails.block.RainCollectorBlock; 27 | import toughasnails.item.EmptyCanteenItem; 28 | 29 | @Mixin(EmptyCanteenItem.class) 30 | public abstract class MixinEmptyCanteenItem { 31 | 32 | @Shadow(remap = false) 33 | protected abstract ItemStack replaceCanteen(ItemStack stack, Player player, ItemStack filledItem); 34 | @Inject(method = "use",at =@At("HEAD"), cancellable = true) 35 | private void use(Level world, Player player, InteractionHand hand, CallbackInfoReturnable> cir){ 36 | ItemStack stack = player.getItemInHand(hand); 37 | Level level = player.getLevel(); 38 | 39 | BlockPos blockPos = MathHelper.getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY).getBlockPos(); 40 | BlockState state = world.getBlockState(blockPos); 41 | 42 | if (!world.mayInteract(player, blockPos)){ 43 | cir.setReturnValue(InteractionResultHolder.pass(stack)); 44 | } 45 | 46 | if(level.getFluidState(blockPos).is(FluidTags.WATER)) 47 | { 48 | SoundEvent sound=SoundEvents.BOTTLE_FILL; 49 | ItemStack filledItem; 50 | 51 | level.playSound(player, player.getX(), player.getY(), player.getZ(), sound, SoundSource.NEUTRAL, 1.0F, 1.0F); 52 | level.gameEvent(player, GameEvent.FLUID_PICKUP, blockPos); 53 | 54 | int purity=WaterPurity.getBlockPurity(level, blockPos); 55 | if(purity==3){ 56 | filledItem = TANItems.PURIFIED_WATER_CANTEEN.get().getDefaultInstance(); 57 | } else if (purity==2) { 58 | filledItem = TANItems.WATER_CANTEEN.get().getDefaultInstance(); 59 | }else { 60 | filledItem = TANItems.DIRTY_WATER_CANTEEN.get().getDefaultInstance(); 61 | } 62 | 63 | ItemStack result = ItemUtils.createFilledResult(stack, player, filledItem); 64 | 65 | cir.setReturnValue(InteractionResultHolder.sidedSuccess(replaceCanteen(stack, player, result), world.isClientSide())); 66 | } 67 | else if (state.getBlock() instanceof RainCollectorBlock) { 68 | int waterLevel = state.getValue(RainCollectorBlock.LEVEL); 69 | if (waterLevel > 0 && !world.isClientSide()) { 70 | world.playSound(player, player.getX(), player.getY(), player.getZ(), SoundEvents.BOTTLE_FILL, SoundSource.NEUTRAL, 1.0F, 1.0F); 71 | ((RainCollectorBlock) TANBlocks.RAIN_COLLECTOR.get()).setWaterLevel(world, blockPos, state, waterLevel - 1); 72 | cir.setReturnValue(InteractionResultHolder.success(replaceCanteen(stack, player, new ItemStack(TANItems.PURIFIED_WATER_CANTEEN.get())))); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/gui/ThirstBarRenderer.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.gui; 2 | 3 | import com.mojang.blaze3d.systems.RenderSystem; 4 | import com.mojang.blaze3d.vertex.PoseStack; 5 | import de.teamlapen.vampirism.util.Helper; 6 | import dev.ghen.thirst.Thirst; 7 | import dev.ghen.thirst.foundation.common.capability.IThirst; 8 | import dev.ghen.thirst.foundation.common.capability.ModCapabilities; 9 | import dev.ghen.thirst.foundation.config.ClientConfig; 10 | import net.minecraft.client.Minecraft; 11 | import net.minecraft.client.gui.GuiComponent; 12 | import net.minecraft.resources.ResourceLocation; 13 | import net.minecraft.util.RandomSource; 14 | import net.minecraft.world.entity.LivingEntity; 15 | import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; 16 | import net.minecraftforge.client.gui.overlay.ForgeGui; 17 | import net.minecraftforge.client.gui.overlay.IGuiOverlay; 18 | import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; 19 | 20 | public class ThirstBarRenderer 21 | { 22 | public static IThirst PLAYER_THIRST = null; 23 | public static ResourceLocation THIRST_ICONS = Thirst.asResource("textures/gui/thirst_icons.png"); 24 | public static Boolean cancelRender = false; 25 | public static Boolean checkIfPlayerIsVampire = false; 26 | static Minecraft minecraft = Minecraft.getInstance(); 27 | protected final static RandomSource random = RandomSource.create(); 28 | public static IGuiOverlay THIRST_OVERLAY = (gui, poseStack, partialTicks, screenWidth, screenHeight) -> 29 | { 30 | boolean isMounted = gui.getMinecraft().player.getVehicle() instanceof LivingEntity; 31 | cancelRender =false; 32 | if (!isMounted && !gui.getMinecraft().options.hideGui && gui.shouldDrawSurvivalElements()) 33 | { 34 | if(checkIfPlayerIsVampire) 35 | { 36 | if(Helper.isVampire(gui.getMinecraft().player)) 37 | { 38 | cancelRender =true; 39 | return; 40 | } 41 | } 42 | 43 | if(minecraft.player.isAlive() && !minecraft.player.getCapability(ModCapabilities.PLAYER_THIRST).orElse(null).getShouldTickThirst()){ 44 | cancelRender = true; 45 | return; 46 | } 47 | gui.setupOverlayRenderState(true, false); 48 | render(gui, screenWidth, screenHeight, poseStack); 49 | } 50 | }; 51 | public static void registerThirstOverlay(RegisterGuiOverlaysEvent event) 52 | { 53 | event.registerAbove(VanillaGuiOverlay.FOOD_LEVEL.id(), "thirst_level", THIRST_OVERLAY); 54 | } 55 | public static void render(ForgeGui gui, int width, int height, PoseStack poseStack) 56 | { 57 | minecraft.getProfiler().push("thirst"); 58 | if (PLAYER_THIRST == null || minecraft.player.tickCount % 40 == 0) 59 | { 60 | PLAYER_THIRST = minecraft.player.getCapability(ModCapabilities.PLAYER_THIRST).orElse(null); 61 | } 62 | 63 | 64 | RenderSystem.enableBlend(); 65 | RenderSystem.setShaderTexture(0, THIRST_ICONS); 66 | int left = width / 2 + 91 + ClientConfig.THIRST_BAR_X_OFFSET.get(); 67 | int top = height - gui.rightHeight + ClientConfig.THIRST_BAR_Y_OFFSET.get(); 68 | gui.rightHeight += 10; 69 | 70 | int level = PLAYER_THIRST.getThirst(); 71 | 72 | for (int i = 0; i < 10; ++i) 73 | { 74 | int idx = i * 2 + 1; 75 | int x = left - i * 8 - 9; 76 | int y = top; 77 | 78 | if (PLAYER_THIRST.getQuenched() <= 0.0F && gui.getGuiTicks() % (level * 3 + 1) == 0) 79 | { 80 | y = top + (random.nextInt(3) - 1); 81 | } 82 | 83 | GuiComponent.blit(poseStack, x, y, 0, 0, 9, 9, 25, 9); 84 | 85 | if (idx < level) 86 | GuiComponent.blit(poseStack, x, y, 16, 0, 9, 9, 25, 9); 87 | else if (idx == level) 88 | GuiComponent.blit(poseStack, x, y, 8, 0, 9, 9, 25, 9); 89 | } 90 | RenderSystem.disableBlend(); 91 | RenderSystem.setShaderTexture(0, GuiComponent.GUI_ICONS_LOCATION); 92 | 93 | minecraft.getProfiler().pop(); 94 | } 95 | } -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/create/MixinIHaveGoggleInformation.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.create; 2 | 3 | import com.simibubi.create.content.equipment.goggles.IHaveGoggleInformation; 4 | import com.simibubi.create.foundation.utility.Lang; 5 | import com.simibubi.create.foundation.utility.LangBuilder; 6 | import dev.ghen.thirst.content.purity.WaterPurity; 7 | import net.minecraft.ChatFormatting; 8 | import net.minecraft.network.chat.Component; 9 | import net.minecraftforge.common.util.LazyOptional; 10 | import net.minecraftforge.fluids.FluidStack; 11 | import net.minecraftforge.fluids.capability.IFluidHandler; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Overwrite; 14 | 15 | import java.util.List; 16 | import java.util.Optional; 17 | 18 | @Mixin(value = IHaveGoggleInformation.class,remap = false) 19 | public interface MixinIHaveGoggleInformation { 20 | /** 21 | * @author mlus 22 | * @reason add purity information 23 | */ 24 | @Overwrite 25 | default boolean containedFluidTooltip(List tooltip, boolean isPlayerSneaking, 26 | LazyOptional handler) { 27 | Optional resolve = handler.resolve(); 28 | if (resolve.isEmpty()) 29 | return false; 30 | 31 | IFluidHandler tank = resolve.get(); 32 | if (tank.getTanks() == 0) 33 | return false; 34 | 35 | LangBuilder mb = Lang.translate("generic.unit.millibuckets"); 36 | Lang.translate("gui.goggles.fluid_container") 37 | .forGoggles(tooltip); 38 | 39 | boolean isEmpty = true; 40 | for (int i = 0; i < tank.getTanks(); i++) { 41 | FluidStack fluidStack = tank.getFluidInTank(i); 42 | if (fluidStack.isEmpty()) 43 | continue; 44 | 45 | if(WaterPurity.hasPurity(fluidStack) && WaterPurity.getPurity(fluidStack) != -1){ 46 | int purity = WaterPurity.getPurity(fluidStack); 47 | ChatFormatting color = getPurityColor(purity); 48 | Lang.builder() 49 | .text(WaterPurity.getPurityText(purity)+" ") 50 | .add(fluidStack.getDisplayName().copy()) 51 | .style(color) 52 | .forGoggles(tooltip, 1); 53 | }else { 54 | Lang.fluidName(fluidStack) 55 | .style(ChatFormatting.GRAY) 56 | .forGoggles(tooltip, 1); 57 | } 58 | 59 | 60 | 61 | Lang.builder() 62 | .add(Lang.number(fluidStack.getAmount()) 63 | .add(mb) 64 | .style(ChatFormatting.GOLD)) 65 | .text(ChatFormatting.GRAY, " / ") 66 | .add(Lang.number(tank.getTankCapacity(i)) 67 | .add(mb) 68 | .style(ChatFormatting.DARK_GRAY)) 69 | .forGoggles(tooltip, 1); 70 | 71 | isEmpty = false; 72 | } 73 | 74 | if (tank.getTanks() > 1) { 75 | if (isEmpty) 76 | tooltip.remove(tooltip.size() - 1); 77 | return true; 78 | } 79 | 80 | if (!isEmpty) 81 | return true; 82 | 83 | Lang.translate("gui.goggles.fluid_container.capacity") 84 | .add(Lang.number(tank.getTankCapacity(0)) 85 | .add(mb) 86 | .style(ChatFormatting.GOLD)) 87 | .style(ChatFormatting.GRAY) 88 | .forGoggles(tooltip, 1); 89 | 90 | return true; 91 | } 92 | 93 | default ChatFormatting getPurityColor(int purity){ 94 | if(purity == 3){ 95 | return ChatFormatting.AQUA; 96 | }else if(purity == 2){ 97 | return ChatFormatting.BLUE; 98 | }else if(purity == 1){ 99 | return ChatFormatting.GRAY; 100 | }else if(purity == 0){ 101 | return ChatFormatting.DARK_GRAY; 102 | }else{ 103 | return ChatFormatting.GRAY; 104 | } 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/Thirst.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst; 2 | 3 | import dev.ghen.thirst.api.ThirstHelper; 4 | import dev.ghen.thirst.compat.create.CreateRegistry; 5 | import dev.ghen.thirst.compat.create.ponder.ThirstPonders; 6 | import dev.ghen.thirst.content.purity.WaterPurity; 7 | import dev.ghen.thirst.content.registry.ItemInit; 8 | import dev.ghen.thirst.content.thirst.PlayerThirst; 9 | import dev.ghen.thirst.foundation.common.capability.IThirst; 10 | import dev.ghen.thirst.foundation.common.loot.ModLootModifiers; 11 | import dev.ghen.thirst.foundation.config.*; 12 | import dev.ghen.thirst.foundation.gui.ThirstBarRenderer; 13 | import dev.ghen.thirst.foundation.gui.appleskin.HUDOverlayHandler; 14 | import dev.ghen.thirst.foundation.gui.appleskin.TooltipOverlayHandler; 15 | import dev.ghen.thirst.foundation.network.ThirstModPacketHandler; 16 | import net.minecraft.resources.ResourceLocation; 17 | import net.minecraftforge.client.event.RegisterClientTooltipComponentFactoriesEvent; 18 | import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; 19 | import net.minecraftforge.eventbus.api.IEventBus; 20 | import net.minecraftforge.fml.ModList; 21 | import net.minecraftforge.fml.common.Mod; 22 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; 23 | import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; 24 | import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 25 | import net.minecraftforge.fml.loading.FMLEnvironment; 26 | 27 | @Mod(Thirst.ID) 28 | public class Thirst 29 | { 30 | public static final String ID = "thirst"; 31 | 32 | public Thirst() 33 | { 34 | IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); 35 | 36 | modBus.addListener(this::commonSetup); 37 | modBus.addListener(this::clientSetup); 38 | modBus.addListener(this::registerCapabilities); 39 | 40 | if(FMLEnvironment.dist.isClient()){ 41 | modBus.addListener(ThirstBarRenderer::registerThirstOverlay); 42 | 43 | if(ModList.get().isLoaded("appleskin")) 44 | { 45 | HUDOverlayHandler.init(); 46 | TooltipOverlayHandler.init(); 47 | modBus.addListener(this::onRegisterClientTooltipComponentFactories); 48 | } 49 | } 50 | 51 | 52 | ItemInit.ITEMS.register(modBus); 53 | ModLootModifiers.LOOT_MODIFIERS.register(modBus); 54 | 55 | if(ModList.get().isLoaded("create")) 56 | { 57 | CreateRegistry.register(); 58 | } 59 | 60 | //configs 61 | ItemSettingsConfig.setup(); 62 | CommonConfig.setup(); 63 | ClientConfig.setup(); 64 | KeyWordConfig.setup(); 65 | ContainerConfig.setup(); 66 | } 67 | 68 | private void commonSetup(final FMLCommonSetupEvent event) 69 | { 70 | WaterPurity.init(); 71 | ThirstModPacketHandler.init(); 72 | 73 | if(ModList.get().isLoaded("coldsweat")) 74 | ThirstHelper.shouldUseColdSweatCaps(true); 75 | 76 | if(ModList.get().isLoaded("tombstone")) 77 | PlayerThirst.checkTombstoneEffects = true; 78 | 79 | if(ModList.get().isLoaded("vampirism")) 80 | PlayerThirst.checkVampirismEffects = true; 81 | 82 | if(ModList.get().isLoaded("farmersdelight")) 83 | PlayerThirst.checkFDEffects = true; 84 | 85 | if(ModList.get().isLoaded("bakery")) 86 | PlayerThirst.checkLetsDoBakeryEffects = true; 87 | } 88 | 89 | private void clientSetup(final FMLClientSetupEvent event) 90 | { 91 | if(ModList.get().isLoaded("create")){ 92 | event.enqueueWork(ThirstPonders::register); 93 | } 94 | 95 | if(ModList.get().isLoaded("vampirism")) 96 | { 97 | ThirstBarRenderer.checkIfPlayerIsVampire = true; 98 | } 99 | } 100 | 101 | public void registerCapabilities(RegisterCapabilitiesEvent event) 102 | { 103 | event.register(IThirst.class); 104 | } 105 | 106 | //this is from Create but it looked very cool 107 | public static ResourceLocation asResource(String path) 108 | { 109 | return new ResourceLocation(ID, path); 110 | } 111 | private void onRegisterClientTooltipComponentFactories(RegisterClientTooltipComponentFactoriesEvent event) { 112 | TooltipOverlayHandler.register(event); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/brewinandchewin/MixinKegBlockEntity.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin.brewinandchewin; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import dev.ghen.thirst.foundation.config.CommonConfig; 5 | import dev.ghen.thirst.foundation.mixin.accessors.brewinandchewin.KegBlockEntityAccessor; 6 | import dev.ghen.thirst.foundation.mixin.accessors.farmersdelight.SyncedBlockEntityAccessor; 7 | import net.minecraft.core.BlockPos; 8 | import net.minecraft.world.item.ItemStack; 9 | import net.minecraft.world.level.Level; 10 | import net.minecraft.world.level.block.state.BlockState; 11 | import net.minecraftforge.items.ItemStackHandler; 12 | import net.minecraftforge.items.wrapper.RecipeWrapper; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.Redirect; 17 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 18 | import umpaz.brewinandchewin.common.block.entity.KegBlockEntity; 19 | import umpaz.brewinandchewin.common.crafting.KegRecipe; 20 | 21 | import java.util.Optional; 22 | 23 | 24 | @Mixin(KegBlockEntity.class) 25 | public class MixinKegBlockEntity 26 | { 27 | @Inject(method = "fermentingTick", at = @At("HEAD"), remap = false, cancellable = true) 28 | private static void brewingTickWithPurity(Level level, BlockPos pos, BlockState state, KegBlockEntity keg, CallbackInfo ci) 29 | { 30 | boolean didInventoryChange; 31 | KegBlockEntityAccessor kegAcc = (KegBlockEntityAccessor) keg; 32 | keg.updateTemperature(); 33 | 34 | if (kegAcc.invokeHasInput()) { 35 | Optional recipe = kegAcc.invokeGetMatchingRecipe(new RecipeWrapper(keg.getInventory())); 36 | if (recipe.isPresent() && kegAcc.invokeCanFerment(recipe.get()) && 37 | WaterPurity.isWaterFilledContainer(recipe.get().getResultItem())) 38 | { 39 | int purity = WaterPurity.getPurity(keg.getInventory().getStackInSlot(4)); 40 | didInventoryChange = kegAcc.invokeProcessFermenting(recipe.get(), keg); 41 | if(didInventoryChange) 42 | { 43 | purity = purity < CommonConfig.FERMENTATION_MOLDING_THRESHOLD.get().intValue() ? 44 | Math.max(purity - CommonConfig.FERMENTATION_MOLDING_HARSHNESS.get().intValue(), WaterPurity.MIN_PURITY) : purity; 45 | 46 | keg.getInventory().setStackInSlot(5, WaterPurity.addPurity(keg.getInventory().getStackInSlot(5), purity)); 47 | } 48 | } else 49 | return; 50 | } else 51 | return; 52 | 53 | ItemStack mealStack = keg.getDrink(); 54 | if (!mealStack.isEmpty()) 55 | { 56 | if (!kegAcc.invokeDoesDrinkHaveContainer(mealStack)) 57 | { 58 | kegAcc.invokeMoveDrinkToOutput(); 59 | didInventoryChange = true; 60 | } else if (!keg.getInventory().getStackInSlot(6).isEmpty()) 61 | { 62 | kegAcc.invokeUseStoredContainersOnMeal(); 63 | didInventoryChange = true; 64 | } 65 | } 66 | 67 | if (didInventoryChange) 68 | { 69 | ((SyncedBlockEntityAccessor) keg).invokeInventoryChanged(); 70 | } 71 | 72 | ci.cancel(); 73 | } 74 | 75 | /** 76 | * The origin use new ItemStack() so it will lose purity after fermentation. 77 | **/ 78 | 79 | @Redirect(method = "processFermenting", at = @At(value = "INVOKE",target = "Lnet/minecraftforge/items/ItemStackHandler;setStackInSlot(ILnet/minecraft/world/item/ItemStack;)V",ordinal = 3), remap = false) 80 | private void AddPurityToInputFluid(ItemStackHandler instance, int slot, ItemStack stack){ 81 | ItemStack fluid_input=instance.getStackInSlot(4); 82 | fluid_input.shrink(1); 83 | instance.setStackInSlot(4, fluid_input); 84 | } 85 | 86 | @Redirect(method = "processFermenting", at = @At(value = "INVOKE",target = "Lnet/minecraftforge/items/ItemStackHandler;setStackInSlot(ILnet/minecraft/world/item/ItemStack;)V",ordinal = 5), remap = false) 87 | private void AddPurityToInputFluid_2(ItemStackHandler instance, int slot, ItemStack stack){ 88 | ItemStack fluid_input=instance.getStackInSlot(4); 89 | fluid_input.shrink(1); 90 | instance.setStackInSlot(4, fluid_input); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/mixin/MixinBootstrap.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.mixin; 2 | 3 | import dev.ghen.thirst.content.purity.WaterPurity; 4 | import net.minecraft.core.BlockPos; 5 | import net.minecraft.core.cauldron.CauldronInteraction; 6 | import net.minecraft.server.Bootstrap; 7 | import net.minecraft.sounds.SoundEvent; 8 | import net.minecraft.sounds.SoundEvents; 9 | import net.minecraft.sounds.SoundSource; 10 | import net.minecraft.stats.Stats; 11 | import net.minecraft.world.InteractionHand; 12 | import net.minecraft.world.InteractionResult; 13 | import net.minecraft.world.entity.player.Player; 14 | import net.minecraft.world.item.Item; 15 | import net.minecraft.world.item.ItemStack; 16 | import net.minecraft.world.item.ItemUtils; 17 | import net.minecraft.world.item.Items; 18 | import net.minecraft.world.item.alchemy.PotionUtils; 19 | import net.minecraft.world.item.alchemy.Potions; 20 | import net.minecraft.world.level.Level; 21 | import net.minecraft.world.level.block.Blocks; 22 | import net.minecraft.world.level.block.LayeredCauldronBlock; 23 | import net.minecraft.world.level.block.state.BlockState; 24 | import net.minecraft.world.level.gameevent.GameEvent; 25 | import org.spongepowered.asm.mixin.Mixin; 26 | import org.spongepowered.asm.mixin.injection.At; 27 | import org.spongepowered.asm.mixin.injection.Inject; 28 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 29 | 30 | import java.util.function.Predicate; 31 | 32 | @Mixin({Bootstrap.class}) 33 | public class MixinBootstrap 34 | { 35 | public MixinBootstrap() { } 36 | 37 | @Inject( 38 | method = {"bootStrap"}, 39 | at = {@At( 40 | value = "INVOKE", 41 | target = "Lnet/minecraft/core/cauldron/CauldronInteraction;bootStrap()V", 42 | shift = At.Shift.AFTER 43 | )}, remap = true 44 | ) 45 | private static void modifyCauldronInteractions(CallbackInfo ci) { 46 | CauldronInteraction.WATER.remove(Items.GLASS_BOTTLE); 47 | CauldronInteraction.WATER.put(Items.GLASS_BOTTLE, (blockState, level, pos, player, hand, itemStack) -> { 48 | if (!level.isClientSide()) { 49 | Item item = itemStack.getItem(); 50 | ItemStack result = PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER); 51 | WaterPurity.addPurity(result, pos, level); 52 | player.setItemInHand(hand, ItemUtils.createFilledResult(itemStack, player, result)); 53 | player.awardStat(Stats.USE_CAULDRON); 54 | player.awardStat(Stats.ITEM_USED.get(item)); 55 | LayeredCauldronBlock.lowerFillLevel(blockState, level, pos); 56 | level.playSound(null, pos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F); 57 | level.gameEvent(null, GameEvent.FLUID_PICKUP, pos); 58 | } 59 | 60 | return InteractionResult.sidedSuccess(level.isClientSide); 61 | }); 62 | CauldronInteraction.WATER.remove(Items.BUCKET); 63 | CauldronInteraction.WATER.put(Items.BUCKET, (blockState, level, pos, player, hand, item) -> 64 | fillBucket(blockState, 65 | level, 66 | pos, 67 | player, 68 | hand, 69 | item, 70 | WaterPurity.addPurity(new ItemStack(Items.WATER_BUCKET), pos, level), 71 | (p_175660_) -> p_175660_.getValue(LayeredCauldronBlock.LEVEL) == 3, SoundEvents.BUCKET_FILL) 72 | ); 73 | } 74 | 75 | private static InteractionResult fillBucket(BlockState p_175636_, Level p_175637_, BlockPos p_175638_, Player p_175639_, InteractionHand p_175640_, ItemStack p_175641_, ItemStack p_175642_, Predicate p_175643_, SoundEvent p_175644_) { 76 | if (!p_175643_.test(p_175636_)) { 77 | return InteractionResult.PASS; 78 | } else { 79 | if (!p_175637_.isClientSide()) { 80 | Item item = p_175641_.getItem(); 81 | p_175639_.setItemInHand(p_175640_, ItemUtils.createFilledResult(p_175641_, p_175639_, p_175642_)); 82 | p_175639_.awardStat(Stats.USE_CAULDRON); 83 | p_175639_.awardStat(Stats.ITEM_USED.get(item)); 84 | p_175637_.setBlockAndUpdate(p_175638_, Blocks.CAULDRON.defaultBlockState()); 85 | p_175637_.playSound(null, p_175638_, p_175644_, SoundSource.BLOCKS, 1.0F, 1.0F); 86 | p_175637_.gameEvent(null, GameEvent.FLUID_PICKUP, p_175638_); 87 | } 88 | 89 | return InteractionResult.sidedSuccess(p_175637_.isClientSide); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/content/registry/CommandInit.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.content.registry; 2 | 3 | import com.mojang.brigadier.CommandDispatcher; 4 | import com.mojang.brigadier.arguments.BoolArgumentType; 5 | import com.mojang.brigadier.arguments.IntegerArgumentType; 6 | import dev.ghen.thirst.Thirst; 7 | import dev.ghen.thirst.foundation.common.capability.IThirst; 8 | import dev.ghen.thirst.foundation.common.capability.ModCapabilities; 9 | import dev.ghen.thirst.foundation.network.ThirstModPacketHandler; 10 | import dev.ghen.thirst.foundation.network.message.PlayerThirstSyncMessage; 11 | import net.minecraft.commands.CommandSourceStack; 12 | import net.minecraft.commands.Commands; 13 | import net.minecraft.commands.arguments.EntityArgument; 14 | import net.minecraft.network.chat.Component; 15 | import net.minecraft.server.level.ServerPlayer; 16 | import net.minecraftforge.event.RegisterCommandsEvent; 17 | import net.minecraftforge.eventbus.api.SubscribeEvent; 18 | import net.minecraftforge.fml.common.Mod; 19 | import net.minecraftforge.network.PacketDistributor; 20 | 21 | import java.util.ArrayList; 22 | import java.util.Collection; 23 | 24 | @Mod.EventBusSubscriber(modid = Thirst.ID) 25 | public class CommandInit { 26 | 27 | @SubscribeEvent 28 | public static void RegisterCommand(RegisterCommandsEvent event){ 29 | CommandDispatcher dispatcher=event.getDispatcher(); 30 | dispatcher.register(Commands.literal("thirst") 31 | .requires(cs->cs.hasPermission(2)) 32 | .then(Commands.literal("query").then(Commands.argument("Player", EntityArgument.player()) 33 | .executes(context -> { 34 | ServerPlayer player = EntityArgument.getPlayer(context,"Player"); 35 | IThirst iThirst = player.getCapability(ModCapabilities.PLAYER_THIRST).orElse(null); 36 | int thirst = iThirst.getThirst(); 37 | int quenched = iThirst.getQuenched(); 38 | context.getSource().sendSuccess(Component.translatable("command.thirst.query", thirst, quenched),false); 39 | return 0; 40 | } 41 | ))) 42 | .then(Commands.literal("set").then(Commands.argument("Player", EntityArgument.player()) 43 | .then(Commands.argument("thirst", IntegerArgumentType.integer(0,20)) 44 | .then(Commands.argument("quenched", IntegerArgumentType.integer(0,20)) 45 | .executes(context -> { 46 | ServerPlayer player = EntityArgument.getPlayer(context,"Player"); 47 | IThirst iThirst = player.getCapability(ModCapabilities.PLAYER_THIRST).orElse(null); 48 | int thirst= IntegerArgumentType.getInteger(context,"thirst"); 49 | int quenched= IntegerArgumentType.getInteger(context,"quenched"); 50 | iThirst.setThirst(thirst); 51 | iThirst.setQuenched(quenched); 52 | context.getSource().sendSuccess(Component.translatable("command.thirst.set",thirst,quenched),false); 53 | return 0; 54 | }))) 55 | )) 56 | .then(Commands.literal("enable").then(Commands.argument("Player",EntityArgument.players()) 57 | .then(Commands.argument("bool", BoolArgumentType.bool()) 58 | .executes(context ->{ 59 | Collection players = EntityArgument.getPlayers(context,"Player"); 60 | boolean shouldTick = BoolArgumentType.getBool(context,"bool"); 61 | Collection playersName = new ArrayList<>(); 62 | for(ServerPlayer player:players){ 63 | IThirst thirstData = player.getCapability(ModCapabilities.PLAYER_THIRST).orElse(null); 64 | thirstData.setShouldTickThirst(shouldTick); 65 | ThirstModPacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), 66 | new PlayerThirstSyncMessage(shouldTick)); 67 | playersName.add(player.getName()); 68 | } 69 | 70 | if(shouldTick){ 71 | context.getSource().sendSuccess(Component.translatable("command.thirst.enable",playersName.toArray()),false); 72 | }else { 73 | context.getSource().sendSuccess(Component.translatable("command.thirst.disable",playersName.toArray()),false); 74 | } 75 | return 0; 76 | })))) 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/foundation/config/KeyWordConfig.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.foundation.config; 2 | 3 | import net.minecraftforge.common.ForgeConfigSpec; 4 | import net.minecraftforge.fml.ModLoadingContext; 5 | import net.minecraftforge.fml.config.ModConfig; 6 | import net.minecraftforge.fml.loading.FMLPaths; 7 | 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.nio.file.Paths; 11 | 12 | public class KeyWordConfig { 13 | private static final ForgeConfigSpec SPEC; 14 | public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder(); 15 | public static final ForgeConfigSpec.ConfigValue ENABLE_KEYWORD_CONFIG; 16 | 17 | public static final ForgeConfigSpec.ConfigValue DEFAULT_DRINK_HYDRATION; 18 | public static final ForgeConfigSpec.ConfigValue DEFAULT_DRINK_QUENCHNESS; 19 | public static final ForgeConfigSpec.ConfigValue DEFAULT_SOUP_HYDRATION; 20 | public static final ForgeConfigSpec.ConfigValue DEFAULT_SOUP_QUENCHNESS; 21 | public static final ForgeConfigSpec.ConfigValue DEFAULT_FRUIT_HYDRATION; 22 | public static final ForgeConfigSpec.ConfigValue DEFAULT_FRUIT_QUENCHNESS; 23 | public static final ForgeConfigSpec.ConfigValue KEYWORD_BLACKLIST; 24 | public static final ForgeConfigSpec.ConfigValue KEYWORD_DRINK; 25 | public static final ForgeConfigSpec.ConfigValue KEYWORD_SOUP; 26 | 27 | public static final ForgeConfigSpec.ConfigValue KEYWORD_FRUIT; 28 | 29 | 30 | static { 31 | BUILDER.push("Keyword config") 32 | .comment("This config allows for faster implementation of new thirst quenching items. It works by defining", 33 | "lists of regular expressions to select items by their id name. It divides the items into categories", 34 | "that have preset values for hydration and quenching"); 35 | ENABLE_KEYWORD_CONFIG = BUILDER.comment("If the keyword config should be taken into consideration").define("enableKeywordConfig", false); 36 | 37 | BUILDER.push("Default Hydration values"); 38 | DEFAULT_DRINK_HYDRATION = BUILDER.comment("Default hydration for drinks selected with keywords [0-20]") 39 | .define("defaultDrinkHydration", 10); 40 | DEFAULT_DRINK_QUENCHNESS = BUILDER.comment("Default quenchness for drinks selected with keywords [0-20]") 41 | .define("defaultDrinkQuenchness", 14); 42 | DEFAULT_SOUP_HYDRATION = BUILDER.comment("Default hydration for soups selected with keywords [0-20]") 43 | .define("defaultSoupHydration", 4); 44 | DEFAULT_SOUP_QUENCHNESS = BUILDER.comment("Default quenchness for soups selected with keywords [0-20]") 45 | .define("defaultSoupQuenchness", 5); 46 | DEFAULT_FRUIT_HYDRATION = BUILDER.comment("Default hydration for fruits selected with keywords [0-20]") 47 | .define("defaultFruitHydration", 2); 48 | DEFAULT_FRUIT_QUENCHNESS = BUILDER.comment("Default quenchness for fruits selected with keywords [0-20]") 49 | .define("defaultFruitQuenchness", 3); 50 | 51 | BUILDER.push("Blacklisted Keywords") 52 | .comment("The list of items to be ignored if they get selected by mistake by other keywords", 53 | "Format: [(keyword1|keyword2|keyword3)]"); 54 | KEYWORD_BLACKLIST = BUILDER.define("keyword_blacklist", "(?:\\b|[^a-zA-Z])(dried|candied|leaf|leaves|gummy|crate|jam|sauce|bucket|seed|cookie|pie|bush|sapling|bean|curry|cake|candy)(?:\\b|[^a-zA-Z])"); 55 | BUILDER.pop(); 56 | 57 | BUILDER.push("Drink Keywords") 58 | .comment("List of keywords for drinks", 59 | "Format: [(keyword1|keyword2|keyword3)]"); 60 | KEYWORD_DRINK = BUILDER.define("keyword_drink", "(?:\\b|[^a-zA-Z])(drink|juice|tea|soda|coffee|wine|beer|cider|yogurt|milkshake|smoothie)(?:\\b|[^a-zA-Z])"); 61 | BUILDER.pop(); 62 | 63 | BUILDER.push("Soup Keywords") 64 | .comment("List of keywords for soups", 65 | "Format: [(keyword1|keyword2|keyword3)]"); 66 | KEYWORD_SOUP = BUILDER.define("keyword_soup", "(?:\\b|[^a-zA-Z])(soup|stew|porridge)(?:\\b|[^a-zA-Z])"); 67 | BUILDER.pop(); 68 | 69 | BUILDER.push("Fruit Keywords") 70 | .comment("List of keywords for fruits", 71 | "Format: [(keyword1|keyword2|keyword3)]"); 72 | KEYWORD_FRUIT = BUILDER.define("keyword_fruit", "(?:\\b|[^a-zA-Z])(fruit|berry|berries|grape|orange|peach|pear|coconut|lemon|melon|cherry|apple)(?:\\b|[^a-zA-Z])"); 73 | BUILDER.pop(); 74 | 75 | SPEC = BUILDER.build(); 76 | } 77 | 78 | public static void setup() 79 | { 80 | Path configPath = FMLPaths.CONFIGDIR.get(); 81 | Path configFolder = Paths.get(configPath.toAbsolutePath().toString(), "thirst"); 82 | 83 | try 84 | { 85 | Files.createDirectory(configFolder); 86 | } 87 | catch (Exception ignored) {} 88 | 89 | ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, SPEC, "thirst/keyword.toml"); 90 | } 91 | 92 | public static int getDrinkHydration() 93 | { 94 | return DEFAULT_DRINK_HYDRATION.get().intValue(); 95 | } 96 | 97 | public static int getDrinkQuenchness() 98 | { 99 | return DEFAULT_DRINK_QUENCHNESS.get().intValue(); 100 | } 101 | 102 | public static int getSoupHydration() 103 | { 104 | return DEFAULT_SOUP_HYDRATION.get().intValue(); 105 | } 106 | 107 | public static int getSoupQuenchness() 108 | { 109 | return DEFAULT_SOUP_QUENCHNESS.get().intValue(); 110 | } 111 | 112 | public static int getFruitHydration() 113 | { 114 | return DEFAULT_FRUIT_HYDRATION.get().intValue(); 115 | } 116 | 117 | public static int getFruitQuenchness() 118 | { 119 | return DEFAULT_FRUIT_QUENCHNESS.get().intValue(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/dev/ghen/thirst/content/thirst/PlayerThirstManager.java: -------------------------------------------------------------------------------- 1 | package dev.ghen.thirst.content.thirst; 2 | 3 | import dev.ghen.thirst.Thirst; 4 | import dev.ghen.thirst.api.ThirstHelper; 5 | import dev.ghen.thirst.content.purity.WaterPurity; 6 | import dev.ghen.thirst.foundation.common.capability.IThirst; 7 | import dev.ghen.thirst.foundation.common.capability.ModCapabilities; 8 | import dev.ghen.thirst.foundation.config.CommonConfig; 9 | import net.minecraft.core.Direction; 10 | import net.minecraft.nbt.CompoundTag; 11 | import net.minecraft.server.level.ServerPlayer; 12 | import net.minecraft.world.entity.Entity; 13 | import net.minecraft.world.entity.player.Player; 14 | import net.minecraft.world.item.ItemStack; 15 | import net.minecraftforge.api.distmarker.Dist; 16 | import net.minecraftforge.common.capabilities.Capability; 17 | import net.minecraftforge.common.capabilities.ICapabilityProvider; 18 | import net.minecraftforge.common.capabilities.ICapabilitySerializable; 19 | import net.minecraftforge.common.util.LazyOptional; 20 | import net.minecraftforge.event.AttachCapabilitiesEvent; 21 | import net.minecraftforge.event.TickEvent; 22 | import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent; 23 | import net.minecraftforge.event.entity.player.PlayerEvent; 24 | import net.minecraftforge.event.entity.player.PlayerInteractEvent; 25 | import net.minecraftforge.event.server.ServerStartedEvent; 26 | import net.minecraftforge.eventbus.api.SubscribeEvent; 27 | import net.minecraftforge.fml.DistExecutor; 28 | import net.minecraftforge.fml.common.Mod; 29 | 30 | import javax.annotation.Nonnull; 31 | import javax.annotation.Nullable; 32 | 33 | @Mod.EventBusSubscriber 34 | public class PlayerThirstManager 35 | { 36 | 37 | @SubscribeEvent 38 | public static void attachCapabilityToEntityHandler(AttachCapabilitiesEvent event) 39 | { 40 | if (event.getObject() instanceof Player) 41 | { 42 | IThirst playerThirstCap = new PlayerThirst(); 43 | LazyOptional capOptional = LazyOptional.of(() -> playerThirstCap); 44 | Capability capability = ModCapabilities.PLAYER_THIRST; 45 | 46 | ICapabilityProvider provider = new ICapabilitySerializable() 47 | { 48 | @Nonnull 49 | @Override 50 | public LazyOptional getCapability(@Nonnull Capability cap, @Nullable Direction direction) 51 | { 52 | if (cap == capability) 53 | { 54 | return capOptional.cast(); 55 | } 56 | return LazyOptional.empty(); 57 | } 58 | 59 | @Override 60 | public CompoundTag serializeNBT() 61 | { 62 | return playerThirstCap.serializeNBT(); 63 | } 64 | 65 | @Override 66 | public void deserializeNBT(CompoundTag nbt) 67 | { 68 | playerThirstCap.deserializeNBT(nbt); 69 | } 70 | }; 71 | 72 | event.addCapability(Thirst.asResource("thirst"), provider); 73 | } 74 | } 75 | 76 | @SubscribeEvent 77 | public static void drinkByHand(PlayerInteractEvent.RightClickBlock event) 78 | { 79 | if(CommonConfig.CAN_DRINK_BY_HAND.get() && event.getEntity().level.isClientSide) 80 | DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> DrinkByHandClient::drinkByHand); 81 | } 82 | 83 | @SubscribeEvent 84 | public static void drinkByHand(PlayerInteractEvent.RightClickEmpty event) 85 | { 86 | if(CommonConfig.CAN_DRINK_BY_HAND.get() && event.getEntity().level.isClientSide) 87 | DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> DrinkByHandClient::drinkByHand); 88 | } 89 | 90 | @SubscribeEvent 91 | public static void drink(LivingEntityUseItemEvent.Finish event) 92 | { 93 | if(event.getEntity() instanceof Player && ThirstHelper.itemRestoresThirst(event.getItem())) 94 | { 95 | event.getEntity().getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(cap -> 96 | { 97 | ItemStack item = event.getItem(); 98 | if(WaterPurity.givePurityEffects((Player) event.getEntity(), item)) 99 | cap.drink((Player) event.getEntity(), ThirstHelper.getThirst(item), ThirstHelper.getQuenched(item)); 100 | }); 101 | } 102 | } 103 | 104 | @SubscribeEvent 105 | public static void onPlayerTick(TickEvent.PlayerTickEvent event) 106 | { 107 | if (event.phase == TickEvent.Phase.START && event.player instanceof ServerPlayer serverPlayer) 108 | { 109 | serverPlayer.getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(cap -> cap.tick(serverPlayer)); 110 | } 111 | } 112 | 113 | /** 114 | * Adds the thirst capability to the player if they returned from the end 115 | * without dying. 116 | */ 117 | @SubscribeEvent 118 | public static void endFix(PlayerEvent.Clone event) 119 | { 120 | if (!event.getEntity().level.isClientSide) 121 | { 122 | Player oldPlayer = event.getOriginal(); 123 | oldPlayer.reviveCaps(); 124 | 125 | if(!event.isWasDeath()) { 126 | event.getEntity().getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(cap -> 127 | oldPlayer.getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(cap::copy)); 128 | } 129 | else { 130 | event.getEntity().getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(cap -> 131 | oldPlayer.getCapability(ModCapabilities.PLAYER_THIRST).ifPresent(oldCap->cap.setShouldTickThirst(oldCap.getShouldTickThirst()))); 132 | } 133 | oldPlayer.invalidateCaps(); 134 | } 135 | } 136 | 137 | @SubscribeEvent 138 | public static void initDrinks(ServerStartedEvent event){ 139 | ThirstHelper.init(); 140 | } 141 | } --------------------------------------------------------------------------------