diff --git a/build.gradle b/build.gradle index bb4584d..7017e6f 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,10 @@ repositories { maven { url "https://maven.fabricmc.net/io/github/prospector/modmenu/" } + maven { + name = "Ladysnake Libs" + url = "https://dl.bintray.com/ladysnake/libs" + } maven { url "https://jitpack.io" } @@ -34,6 +38,13 @@ dependencies { exclude(group: "net.fabricmc.fabric-api") } + // CardinalComponentsAPI + modApi "io.github.onyxstudios.Cardinal-Components-API:cardinal-components-base:${cca_version}" + modApi "io.github.onyxstudios.Cardinal-Components-API:cardinal-components-entity:${cca_version}" + + include "io.github.onyxstudios.Cardinal-Components-API:cardinal-components-base:${cca_version}" + include "io.github.onyxstudios.Cardinal-Components-API:cardinal-components-entity:${cca_version}" + // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. } diff --git a/gradle.properties b/gradle.properties index 3370532..e2ad87e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,3 +16,4 @@ org.gradle.jvmargs=-Xmx1G # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api fabric_version=0.25.1+build.416-1.16 modmenu_version=1.14.6+build.31 + cca_version=2.7.9 \ No newline at end of file diff --git a/src/main/java/dev/agatharose/asbestos/Asbestos.java b/src/main/java/dev/agatharose/asbestos/Asbestos.java index 8f26501..9281cc5 100644 --- a/src/main/java/dev/agatharose/asbestos/Asbestos.java +++ b/src/main/java/dev/agatharose/asbestos/Asbestos.java @@ -1,13 +1,26 @@ package dev.agatharose.asbestos; +import dev.agatharose.asbestos.component.MesotheliomaComponent; +import dev.agatharose.asbestos.component.PlayerMesotheliomaComponent; import dev.agatharose.asbestos.item.ScraperItem; import dev.agatharose.asbestos.item.ScraperToolMaterial; +import dev.agatharose.asbestos.scheduler.MesotheliomaSched; +import dev.onyxstudios.cca.api.v3.component.ComponentKey; +import dev.onyxstudios.cca.api.v3.component.ComponentRegistryV3; +import dev.onyxstudios.cca.api.v3.entity.EntityComponentFactoryRegistry; +import dev.onyxstudios.cca.api.v3.entity.EntityComponentInitializer; +import nerdhub.cardinal.components.api.util.RespawnCopyStrategy; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.item.v1.FabricItemSettings; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.minecraft.block.Block; import net.minecraft.block.Material; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.item.BlockItem; +import net.minecraft.item.FoodComponent; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.ToolItem; @@ -15,10 +28,17 @@ import net.minecraft.sound.BlockSoundGroup; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; -public class Asbestos implements ModInitializer { +public class Asbestos implements ModInitializer, EntityComponentInitializer { - public static final Item ASBESTOS_FIBERS = new Item( - new FabricItemSettings().group(ItemGroup.MATERIALS).fireproof()); + // mesothelioma player component key + public static final ComponentKey MESOTHELIOMA = ComponentRegistryV3.INSTANCE + .getOrCreate(new Identifier("asbestos:mesothelioma"), MesotheliomaComponent.class); + + // block/item/effect definitions + public static final Item ASBESTOS_FIBERS = new Item(new FabricItemSettings().group(ItemGroup.MATERIALS).fireproof() + .food(new FoodComponent.Builder().alwaysEdible() + .statusEffect(new StatusEffectInstance(StatusEffects.WITHER, 30 * 20, 4, false, false), 1.0f) + .build())); public static final Block ASBESTOS_BLOCK = new Block( FabricBlockSettings.of(Material.WOOL).hardness(1.0f).sounds(BlockSoundGroup.WOOL)); @@ -26,6 +46,10 @@ public class Asbestos implements ModInitializer { public static ToolItem IRON_SCRAPER = new ScraperItem(ScraperToolMaterial.INSTANCE, 0.0f, -3.0f, new Item.Settings().group(ItemGroup.TOOLS)); + public static final StatusEffect MESOTHELIOMA_EFFECT = new MesotheliomaStatusEffect(); + + public static final DamageSource MESOTHELIOMA_DAMAGE = new MesotheliomaDamageSource(); + @Override public void onInitialize() { // asbestos fibers item @@ -38,5 +62,17 @@ public class Asbestos implements ModInitializer { // scraper tool Registry.register(Registry.ITEM, new Identifier("asbestos", "iron_scraper"), IRON_SCRAPER); + + // mesothelioma status effect + Registry.register(Registry.STATUS_EFFECT, new Identifier("asbestos", "mesothelioma"), MESOTHELIOMA_EFFECT); + + // Mesothelioma tick scheduler + MesotheliomaSched.init(); + } + + @Override + public void registerEntityComponentFactories(EntityComponentFactoryRegistry registry) { + registry.registerForPlayers(MESOTHELIOMA, player -> new PlayerMesotheliomaComponent(player), + RespawnCopyStrategy.NEVER_COPY); } } \ No newline at end of file diff --git a/src/main/java/dev/agatharose/asbestos/MesotheliomaDamageSource.java b/src/main/java/dev/agatharose/asbestos/MesotheliomaDamageSource.java new file mode 100644 index 0000000..bce2a24 --- /dev/null +++ b/src/main/java/dev/agatharose/asbestos/MesotheliomaDamageSource.java @@ -0,0 +1,14 @@ +package dev.agatharose.asbestos; + +import net.minecraft.entity.damage.DamageSource; + +public class MesotheliomaDamageSource extends DamageSource { + public MesotheliomaDamageSource() { + super("mesotheliomaDamage"); + } + + @Override + public boolean bypassesArmor() { + return true; + } +} diff --git a/src/main/java/dev/agatharose/asbestos/MesotheliomaStatusEffect.java b/src/main/java/dev/agatharose/asbestos/MesotheliomaStatusEffect.java new file mode 100644 index 0000000..111e23a --- /dev/null +++ b/src/main/java/dev/agatharose/asbestos/MesotheliomaStatusEffect.java @@ -0,0 +1,41 @@ +package dev.agatharose.asbestos; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffectType; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.player.PlayerEntity; + +public class MesotheliomaStatusEffect extends StatusEffect { + public MesotheliomaStatusEffect() { + super(StatusEffectType.HARMFUL, 0x302412); + } + + @Override + public boolean canApplyUpdateEffect(int duration, int amplifier) { + return true; + } + + @Override + public void applyUpdateEffect(LivingEntity entity, int amplifier) { + // TODO: move into mod config + int threshold = 50; + + // for the sake of performance, non-players are immune to mesothelioma + // and will not receive financial compensation + if (entity instanceof PlayerEntity) { + PlayerEntity player = (PlayerEntity) entity; + int exposure = Asbestos.MESOTHELIOMA.get(player).getMesothelioma(); + + // slows you down because breathing is hard + if (exposure >= (threshold / 1.5)) { + player.addStatusEffect(new StatusEffectInstance(StatusEffects.SLOWNESS, 32767, 1)); + } + + if (exposure >= threshold) { + player.damage(Asbestos.MESOTHELIOMA_DAMAGE, 1 << amplifier); + } + } + } +} diff --git a/src/main/java/dev/agatharose/asbestos/component/MesotheliomaComponent.java b/src/main/java/dev/agatharose/asbestos/component/MesotheliomaComponent.java new file mode 100644 index 0000000..8b12b62 --- /dev/null +++ b/src/main/java/dev/agatharose/asbestos/component/MesotheliomaComponent.java @@ -0,0 +1,9 @@ +package dev.agatharose.asbestos.component; + +import dev.onyxstudios.cca.api.v3.component.ComponentV3; + +public interface MesotheliomaComponent extends ComponentV3 { + int getMesothelioma(); + + void setMesothelioma(int exposure); +} diff --git a/src/main/java/dev/agatharose/asbestos/component/PlayerMesotheliomaComponent.java b/src/main/java/dev/agatharose/asbestos/component/PlayerMesotheliomaComponent.java new file mode 100644 index 0000000..a386d29 --- /dev/null +++ b/src/main/java/dev/agatharose/asbestos/component/PlayerMesotheliomaComponent.java @@ -0,0 +1,37 @@ +package dev.agatharose.asbestos.component; + +import dev.agatharose.asbestos.Asbestos; +import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundTag; + +public class PlayerMesotheliomaComponent implements MesotheliomaComponent, AutoSyncedComponent { + private PlayerEntity player; + private int mesothelioma; + + public PlayerMesotheliomaComponent(PlayerEntity player) { + this.player = player; + this.mesothelioma = 0; + } + + @Override + public int getMesothelioma() { + return this.mesothelioma; + } + + @Override + public void setMesothelioma(int exposure) { + this.mesothelioma = exposure; + Asbestos.MESOTHELIOMA.sync(player); + } + + @Override + public void readFromNbt(CompoundTag tag) { + this.mesothelioma = tag.getInt("mesothelioma"); + } + + @Override + public void writeToNbt(CompoundTag tag) { + tag.putInt("mesothelioma", this.mesothelioma); + } +} diff --git a/src/main/java/dev/agatharose/asbestos/scheduler/MesotheliomaSched.java b/src/main/java/dev/agatharose/asbestos/scheduler/MesotheliomaSched.java new file mode 100644 index 0000000..11f255b --- /dev/null +++ b/src/main/java/dev/agatharose/asbestos/scheduler/MesotheliomaSched.java @@ -0,0 +1,53 @@ +package dev.agatharose.asbestos.scheduler; + +import dev.agatharose.asbestos.Asbestos; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.block.Block; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class MesotheliomaSched { + public static void init() { + // how many blocks around the player will be checked + // TODO: move into mod config + int offset = 3; + int period = 5; + int threshold = 50; + + ServerTickEvents.END_SERVER_TICK.register(server -> { + // run every 5 seconds + if (server.getTicks() % (period * 20) == 0) { + server.getWorlds().forEach(world -> { + world.getPlayers().forEach(player -> { + // iterate over every block in the cuboid + findasbestos: for (int i = -offset; i < offset; i++) { + for (int j = -offset; j < offset; j++) { + for (int k = -offset; k < offset; k++) { + // offset player position + Vec3d offsetPos = player.getPos().add(i, j, k); + BlockPos pos = new BlockPos(offsetPos); + + Block block = world.getBlockState(pos).getBlock(); + + if (block.equals(Asbestos.ASBESTOS_BLOCK)) { + int exposure = Asbestos.MESOTHELIOMA.get(player).getMesothelioma(); + Asbestos.MESOTHELIOMA.get(player).setMesothelioma(exposure + 1); + + if (exposure >= (threshold / 2)) { + // give the player infinite mesothelioma effect + player.addStatusEffect( + new StatusEffectInstance(Asbestos.MESOTHELIOMA_EFFECT, 32767)); + } + + break findasbestos; + } + } + } + } + }); + }); + } + }); + } +} diff --git a/src/main/resources/assets/asbestos/lang/en_us.json b/src/main/resources/assets/asbestos/lang/en_us.json index e7ce7fd..f3e58c8 100644 --- a/src/main/resources/assets/asbestos/lang/en_us.json +++ b/src/main/resources/assets/asbestos/lang/en_us.json @@ -1,5 +1,7 @@ { "block.asbestos.asbestos_block": "Asbestos Block", "item.asbestos.asbestos_fibers": "Asbests Fibers", - "item.asbestos.iron_scraper": "Asbestos Scraper" + "item.asbestos.iron_scraper": "Asbestos Scraper", + "effect.asbestos.mesothelioma": "Mesothelioma", + "death.attack.mesotheliomaDamage": "%1$s was entitled to financial compensation" } \ No newline at end of file diff --git a/src/main/resources/assets/asbestos/textures/mob_effect/mesothelioma.png b/src/main/resources/assets/asbestos/textures/mob_effect/mesothelioma.png new file mode 100644 index 0000000..876d42f Binary files /dev/null and b/src/main/resources/assets/asbestos/textures/mob_effect/mesothelioma.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 8576792..6ea14f4 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -9,7 +9,7 @@ ], "contact": { "homepage": "https://agatharose.dev", - "sources": "https://github.com/FabricMC/fabric-example-mod" + "sources": "https://git.lain.faith/sorceress/Asbestos" }, "license": "CC0-1.0", "icon": "assets/asbestos/icon.png", @@ -17,11 +17,16 @@ "entrypoints": { "main": [ "dev.agatharose.asbestos.Asbestos" + ], + "cardinal-components-entity": [ + "dev.agatharose.asbestos.Asbestos" + ] + }, + "custom": { + "cardinal-components": [ + "asbestos:mesothelioma" ] }, - "mixins": [ - "modid.mixins.json" - ], "depends": { "fabricloader": ">=0.7.4", "fabric": "*", diff --git a/src/main/resources/modid.mixins.json b/src/main/resources/modid.mixins.json deleted file mode 100644 index 21fe73a..0000000 --- a/src/main/resources/modid.mixins.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "net.fabricmc.example.mixin", - "compatibilityLevel": "JAVA_8", - "mixins": [ - ], - "client": [ - "ExampleMixin" - ], - "injectors": { - "defaultRequire": 1 - } -}