From 1a468f98173e3139c1e00ced7541653feb1ce6bd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 2 Oct 2022 13:00:47 +0700 Subject: [PATCH] Advancements! --- .../ru/dbotthepony/mc/otm/datagen/DataGen.kt | 8 +- .../mc/otm/datagen/ResearchData.kt | 3 + .../datagen/advancements/AdvancementData.kt | 46 +++++ .../advancements/AndroidAdvancementsData.kt | 183 ++++++++++++++++++ .../mc/otm/datagen/advancements/Helpers.kt | 12 ++ .../ru/dbotthepony/mc/otm/ServerConfig.kt | 5 + .../mc/otm/android/AndroidResearch.kt | 7 + .../android/AndroidResearchDataProvider.kt | 5 + .../otm/android/feature/ShockwaveFeature.kt | 56 +++++- .../otm/capability/MatteryPlayerCapability.kt | 43 +++- .../ru/dbotthepony/mc/otm/core/LevelExt.kt | 49 ++++- .../dbotthepony/mc/otm/registry/MRegistry.kt | 14 ++ .../mc/otm/triggers/AndroidResearchTrigger.kt | 54 ++++++ .../mc/otm/triggers/AndroidStatusTriggers.kt | 98 ++++++++++ .../otm/triggers/ShockwaveDamageMobTrigger.kt | 63 ++++++ .../mc/otm/triggers/ShockwaveTrigger.kt | 32 +++ 16 files changed, 664 insertions(+), 14 deletions(-) create mode 100644 src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/AndroidAdvancementsData.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/triggers/AndroidResearchTrigger.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/triggers/AndroidStatusTriggers.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/triggers/ShockwaveDamageMobTrigger.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/triggers/ShockwaveTrigger.kt diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt index a415d9d5d..4bf2e6c8f 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt @@ -30,6 +30,7 @@ import ru.dbotthepony.mc.otm.registry.* import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.datagen.advancements.AdvancementProvider import ru.dbotthepony.mc.otm.datagen.advancements.addAdvancements +import ru.dbotthepony.mc.otm.datagen.advancements.addAndroidAdvancements import ru.dbotthepony.mc.otm.datagen.blocks.addBlockStates import ru.dbotthepony.mc.otm.datagen.blocks.addComplexBlockStates import ru.dbotthepony.mc.otm.datagen.items.addItemModels @@ -69,6 +70,8 @@ object DataGen { private set var languageProvider: MatteryLanguageProvider by WriteOnce() private set + var researchProvider: AndroidResearchDataProvider by WriteOnce() + private set fun decorativeCubeAll(vararg blocks: Block) { blockModelProvider.decorativeCubeAll(*blocks) @@ -300,6 +303,7 @@ object DataGen { val recipeProvider = MatteryRecipeProvider(event.generator) val lootModifier = LootModifiers(event.generator) val languageProvider = MatteryLanguageProvider(event.generator) + val researchProvider = AndroidResearchDataProvider(event.generator).also { it.exec { addResearchData(it, languageProvider) } } this.blockModelProvider = blockModelProvider this.blockStateProvider = blockStateProvider @@ -308,6 +312,7 @@ object DataGen { this.recipeProvider = recipeProvider this.lootModifier = lootModifier this.languageProvider = languageProvider + this.researchProvider = researchProvider val tagsProvider = TagsProvider(event) val advancementProvider = AdvancementProvider(event) @@ -323,7 +328,7 @@ object DataGen { event.generator.addProvider(true, lootTableProvider) event.generator.addProvider(true, lootModifier) event.generator.addProvider(true, SoundDataProvider(event)) - event.generator.addProvider(true, AndroidResearchDataProvider(event.generator).also { it.exec { addResearchData(it, languageProvider) } }) + event.generator.addProvider(true, researchProvider) event.generator.addProvider(true, advancementProvider) AddEnglishLanguage(languageProvider) @@ -348,6 +353,7 @@ object DataGen { advancementProvider.exec { it, files -> addAdvancements(it, files, languageProvider) + addAndroidAdvancements(it, files, languageProvider) } addPlatePressRecipes(recipeProvider) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/ResearchData.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/ResearchData.kt index 27ced70b4..cf4baf2a6 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/ResearchData.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/ResearchData.kt @@ -458,6 +458,9 @@ fun addResearchData(serializer: Consumer, lang: MatteryLang add(ENDER_TELEPORTER, "Ender Teleporter") add(ENDER_TELEPORTER, "description", "Allows unit to perform instant, short distance teleports without damage to internal systems") + add(NIGHT_VISION, "Night Vision") + add(NIGHT_VISION, "description", "Allows unit to clearly see in the dark") + add(attackBoostList[0], "Attack Boost %s") add(attackBoostList[0], "description", "Increases total melee attack strength by %s%%") } diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/AdvancementData.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/AdvancementData.kt index 0d9bf74e3..d9503fb12 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/AdvancementData.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/AdvancementData.kt @@ -40,4 +40,50 @@ fun addAdvancements(serializer: Consumer, existingFileHelper: Exist ) .addCriterion("pulled_by_black_hole", BlackHoleTrigger.Instance) .save(serializer, modLocation("regular/black_hole"), existingFileHelper) + + val ore = AdvancementBuilder() + .parent(root) + .requirements(RequirementsStrategy.OR) + .display( + itemStack = ItemStack(MItems.TRITANIUM_ORE_CLUMP), + title = TranslatableComponent(translation.add("ore", "Blue Metal Discovery")), + description = TranslatableComponent(translation.add("ore.desc", "Mine some Tritanium")), + ) + .addCriterion("has_tritanium_ore", criterion(MItemTags.TRITANIUM_ORES)) + .addCriterion("has_tritanium_ore_clump", criterion(MItemTags.TRITANIUM_ORE_CLUMPS)) + .save(serializer, modLocation("regular/ore"), existingFileHelper) + + val ingot = AdvancementBuilder() + .parent(ore) + .display( + itemStack = ItemStack(MItems.TRITANIUM_INGOT), + title = TranslatableComponent(translation.add("ingot", "Acquire Harder-ware")), + description = TranslatableComponent(translation.add("ingot.desc", "Smelt a Tritanium ingot")), + ) + .addCriterion("has_tritanium_ingot", criterion(MItemTags.TRITANIUM_INGOTS)) + .save(serializer, modLocation("regular/ingot"), existingFileHelper) + + AdvancementBuilder() + .parent(ingot) + .display( + itemStack = ItemStack(MItems.TRITANIUM_PICKAXE), + title = TranslatableComponent(translation.add("pickaxe", "A Tool for Patient Miners")), + description = TranslatableComponent(translation.add("pickaxe.desc", "Craft a Tritanium Pickaxe")), + ) + .addCriterion("has_tritanium_pickaxe", criterion(MItems.TRITANIUM_PICKAXE)) + .save(serializer, modLocation("regular/pickaxe"), existingFileHelper) + + val pill = AdvancementBuilder() + .parent(root) + .display( + itemStack = ItemStack(MItems.PILL_ANDROID), + title = TranslatableComponent(translation.add("pill", "Side Colored Mystery")), + description = TranslatableComponent(translation.add("pill.desc", "Find some of those mysterious pills. Consult with Cleric before trying to ingest them.")), + ) + .requirements(RequirementsStrategy.OR) + .addCriterion("pill1", criterion(MItems.PILL_ANDROID)) + .addCriterion("pill2", criterion(MItems.PILL_HEAL)) + .addCriterion("pill3", criterion(MItems.PILL_HUMANE)) + .addCriterion("pill4", criterion(MItems.PILL_OBLIVION)) + .save(serializer, modLocation("regular/pill"), existingFileHelper) } diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/AndroidAdvancementsData.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/AndroidAdvancementsData.kt new file mode 100644 index 000000000..6ff720a41 --- /dev/null +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/AndroidAdvancementsData.kt @@ -0,0 +1,183 @@ +package ru.dbotthepony.mc.otm.datagen.advancements + +import net.minecraft.advancements.Advancement +import net.minecraft.advancements.FrameType +import net.minecraft.advancements.RequirementsStrategy +import net.minecraft.advancements.critereon.DamagePredicate +import net.minecraft.advancements.critereon.DamageSourcePredicate +import net.minecraft.advancements.critereon.EntityPredicate +import net.minecraft.advancements.critereon.InventoryChangeTrigger +import net.minecraft.advancements.critereon.PlayerHurtEntityTrigger +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.entity.EntityType +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraftforge.common.data.ExistingFileHelper +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.datagen.DataGen +import ru.dbotthepony.mc.otm.datagen.lang.MatteryLanguageProvider +import ru.dbotthepony.mc.otm.datagen.modLocation +import ru.dbotthepony.mc.otm.registry.MItemTags +import ru.dbotthepony.mc.otm.registry.MItems +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeHumaneTrigger +import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger +import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger +import java.util.function.Consumer + +fun addAndroidAdvancements(serializer: Consumer, existingFileHelper: ExistingFileHelper, lang: MatteryLanguageProvider) { + val translation = lang.english.Prepended("otm.advancements.android") + + val root = AdvancementBuilder() + .display( + itemStack = ItemStack(MItems.PILL_ANDROID), + title = TranslatableComponent(translation.add("root", "Androids and Humans")), + description = TranslatableComponent(translation.add("root.desc", "Can you make out who is cruel machine and who can make love?")), + showToast = false, + announceChat = false, + background = modLocation("textures/block/decorative/metal_beam_top.png") + ) + .addCriterion("became_android", BecomeAndroidTrigger.Instance) + .save(serializer, modLocation("android/root"), existingFileHelper) + + AdvancementBuilder() + .parent(root) + .display( + itemStack = ItemStack(MItems.PILL_ANDROID), + title = TranslatableComponent(translation.add("normal", "Last Sweet Dreams")), + description = TranslatableComponent(translation.add("normal.desc", "Become an Android in your dreams, a soulless machine... Or is it?")), + hidden = true, + ) + .addCriterion("became_android", BecomeAndroidSleepTrigger.Instance) + .save(serializer, modLocation("android/become_thru_sleep"), existingFileHelper) + + AdvancementBuilder() + .parent(root) + .display( + itemStack = ItemStack(MItems.PILL_ANDROID), + title = TranslatableComponent(translation.add("death", "The Old Way")), + description = TranslatableComponent(translation.add("death.desc", "Become an Android in event of death, veteran's favorite")), + hidden = true, + ) + .addCriterion("became_android", BecomeAndroidDeathTrigger.Instance) + .save(serializer, modLocation("android/become_thru_death"), existingFileHelper) + + AdvancementBuilder() + .parent(root) + .display( + itemStack = ItemStack(MItems.PILL_HUMANE), + title = TranslatableComponent(translation.add("unandroid", "Feel Humane Again")), + description = TranslatableComponent(translation.add("unandroid.desc", "Become fleshy after being a machine, yet something is still missing that you had before...")), + hidden = true, + frameType = FrameType.GOAL + ) + .addCriterion("become_humane", BecomeHumaneTrigger.Instance) + .save(serializer, modLocation("android/become_humane"), existingFileHelper) + + val researchAnything = AdvancementBuilder() + .parent(root) + .display( + itemStack = ItemStack(MItems.ANDROID_STATION), + title = TranslatableComponent(translation.add("research_anything", "New Trick")), + description = TranslatableComponent(translation.add("research_anything.desc", "Research anything as Android")), + ) + .addCriterion("research_anything", AndroidResearchTrigger.Instance(null)) + .save(serializer, modLocation("android/research_anything"), existingFileHelper) + + AdvancementBuilder() + .parent(researchAnything) + .display( + itemStack = ItemStack(Items.WATER_BUCKET), + title = TranslatableComponent(translation.add("air_bags", "Patching Up Wooden Vessel")), + description = TranslatableComponent(translation.add("air_bags.desc", "Research Air Bags as Android, to float in water")), + ) + .addCriterion("air_bags", AndroidResearchTrigger.Instance(modLocation(MNames.AIR_BAGS))) + .save(serializer, modLocation("android/research_air_bags"), existingFileHelper) + + AdvancementBuilder() + .parent(researchAnything) + .display( + itemStack = ItemStack(Items.ENDER_EYE), + title = TranslatableComponent(translation.add("night_vision", "Second Pair of Eyes")), + description = TranslatableComponent(translation.add("night_vision.desc", "Research Night Vision as Android, to see in the dark")), + ) + .addCriterion("night_vision", AndroidResearchTrigger.Instance(modLocation(MNames.NIGHT_VISION))) + .save(serializer, modLocation("android/research_night_vision"), existingFileHelper) + + val nanobots = AdvancementBuilder() + .parent(researchAnything) + .display( + itemStack = ItemStack(MItems.MATTER_TRANSFORM_MATRIX), + title = TranslatableComponent(translation.add("nanobots", "Nanomachines, Son!")), + description = TranslatableComponent(translation.add("nanobots.desc", "Research Nanobots as Android, to unlock potent research that come after it")), + hidden = true + ) + .addCriterion("nanobots", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS))) + .save(serializer, modLocation("android/research_nanobots"), existingFileHelper) + + val regen = AdvancementBuilder() + .parent(nanobots) + .display( + itemStack = ItemStack(Items.GOLDEN_APPLE), + title = TranslatableComponent(translation.add("regen", "Field Repair Done Easy")), + description = TranslatableComponent(translation.add("regen.desc", "Research Nanobots Regeneration as Android")), + ) + .addCriterion("regen0", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_1))) + .save(serializer, modLocation("android/regen"), existingFileHelper) + + AdvancementBuilder() + .parent(regen) + .display( + itemStack = ItemStack(Items.ENCHANTED_GOLDEN_APPLE), + title = TranslatableComponent(translation.add("regen_all", "Field Repair Done Effortless")), + description = TranslatableComponent(translation.add("regen_all.desc", "Max out Nanobots Regeneration research")), + frameType = FrameType.GOAL, + ) + .addCriterion("regen0", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_1))) + .addCriterion("regen1", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_2))) + .addCriterion("regen2", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_3))) + .addCriterion("regen3", AndroidResearchTrigger.Instance(modLocation(MNames.NANOBOTS_REGENERATION_4))) + .save(serializer, modLocation("android/regen_all"), existingFileHelper) + + AdvancementBuilder() + .parent(researchAnything) + .display( + itemStack = ItemStack(MItems.ANDROID_STATION), + title = TranslatableComponent(translation.add("research_all", "Mecha-agnomination")), + description = TranslatableComponent(translation.add("research_all.desc", "Research everything (that don't block any other research)")), + frameType = FrameType.CHALLENGE + ) + .also { advancement -> + DataGen.researchProvider.generatedView.stream() + .filter { it.allBlockedBy.isEmpty() && it.allBlocking.isEmpty() } + .forEach { + advancement.addCriterion(it.id.toString(), AndroidResearchTrigger.Instance(it)) + } + } + .save(serializer, modLocation("android/research_everything"), existingFileHelper) + + val shockwave = AdvancementBuilder() + .parent(researchAnything) + .display( + itemStack = ItemStack(Items.PISTON), + title = TranslatableComponent(translation.add("shockwave", "Supersonic Landing")), + description = TranslatableComponent(translation.add("shockwave.desc", "Perform a Shockwave upon landing")), + ) + .addCriterion("shockwave", ShockwaveTrigger.Instance) + .save(serializer, modLocation("android/shockwave"), existingFileHelper) + + AdvancementBuilder() + .parent(shockwave) + .display( + itemStack = ItemStack(Items.WARDEN_SPAWN_EGG), + title = TranslatableComponent(translation.add("shockwave_warden", "Music To Their Ears")), + description = TranslatableComponent(translation.add("shockwave_warden.desc", "Hurt Warden using Shockwave ability")), + frameType = FrameType.GOAL + ) + .addCriterion("shockwave_warden", ShockwaveDamageMobTrigger.Instance(EntityPredicate.Builder.entity().of(EntityType.WARDEN).build().wrap())) + .save(serializer, modLocation("android/shockwave_warden"), existingFileHelper) +} diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/Helpers.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/Helpers.kt index df01e8361..4a5289f30 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/Helpers.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/advancements/Helpers.kt @@ -4,6 +4,7 @@ import net.minecraft.advancements.Advancement import net.minecraft.advancements.CriterionTriggerInstance import net.minecraft.advancements.DisplayInfo import net.minecraft.advancements.FrameType +import net.minecraft.advancements.critereon.EntityPredicate import net.minecraft.advancements.critereon.InventoryChangeTrigger import net.minecraft.advancements.critereon.ItemPredicate import net.minecraft.network.chat.Component @@ -11,6 +12,7 @@ import net.minecraft.resources.ResourceLocation import net.minecraft.tags.TagKey import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.ItemLike import ru.dbotthepony.mc.otm.core.TextComponent fun AdvancementBuilder(): Advancement.Builder = Advancement.Builder.advancement() @@ -57,3 +59,13 @@ fun predicate(tag: TagKey): ItemPredicate { fun criterion(tag: TagKey): CriterionTriggerInstance { return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(tag)) } + +fun predicate(item: ItemLike): ItemPredicate { + return ItemPredicate.Builder.item().of(item).build() +} + +fun criterion(item: ItemLike): CriterionTriggerInstance { + return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(item)) +} + +fun EntityPredicate.wrap(): EntityPredicate.Composite = EntityPredicate.Composite.wrap(this) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt index 63b2450b4..a87d520f6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt @@ -200,8 +200,13 @@ object ServerConfig { val COOLDOWN: Int by specBuilder.comment("In ticks").defineInRange("cooldown", 30, 1) val RADIUS_HORIZONTAL: Double by specBuilder.comment("In meters").defineInRange("radiusHorizontal", 4.0, 0.0) val RADIUS_VERTICAL: Double by specBuilder.comment("In meters").defineInRange("radiusVertical", 1.0, 0.0) + + val RADIUS_HORIZONTAL_WARDEN: Double by specBuilder.comment("In meters, when searching for Warden").defineInRange("radiusHorizontalWarden", 16.0, 0.0) + val RADIUS_VERTICAL_WARDEN: Double by specBuilder.comment("In meters, when searching for Warden").defineInRange("radiusVerticalWarden", 6.0, 0.0) + val BREAK_BLOCKS: Boolean by specBuilder.comment("Break blocks without any blast resistance").define("breakBlocks", true) val DAMAGE: Double by specBuilder.comment("Max potential damage done by shockwave").defineInRange("damage", 12.0, 0.0, Float.MAX_VALUE.toDouble()) + val WARDEN_DAMAGE_MULT: Double by specBuilder.defineInRange("wardenDamageMultiplier", 4.0, 0.0, Float.MAX_VALUE.toDouble()) val ENERGY_COST by specBuilder.defineImpreciseFraction("energyCost", ImpreciseFraction(2048), ImpreciseFraction.ZERO) init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt index 8c3d3d037..cac5340a4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt @@ -7,6 +7,7 @@ import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import net.minecraftforge.common.util.INBTSerializable @@ -25,6 +26,7 @@ import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.network.FieldSynchronizer import ru.dbotthepony.mc.otm.registry.MRegistry +import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger import java.io.DataInputStream import java.io.InputStream import kotlin.math.absoluteValue @@ -273,6 +275,11 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay if (force || canResearch && consumeResearchCost(false)) { onResearched() isResearched = true + + if (ply is ServerPlayer) { + AndroidResearchTrigger.trigger(ply as ServerPlayer, this.type) + } + return true } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDataProvider.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDataProvider.kt index 191119617..550c2a973 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDataProvider.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearchDataProvider.kt @@ -5,6 +5,7 @@ import net.minecraft.data.CachedOutput import net.minecraft.data.DataGenerator import net.minecraft.data.DataProvider import net.minecraft.resources.ResourceLocation +import java.util.Collections import java.util.LinkedList import java.util.function.Consumer @@ -14,6 +15,9 @@ open class AndroidResearchDataProvider(protected val dataGenerator: DataGenerato protected val callbacks = LinkedList<(Consumer) -> Unit>() + private val generated = LinkedList() + val generatedView: List = Collections.unmodifiableList(generated) + /** * override this */ @@ -49,6 +53,7 @@ open class AndroidResearchDataProvider(protected val dataGenerator: DataGenerato for (value in added) { value.validate() + generated.add(value) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt index d5b0a9f1f..8edf7944d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt @@ -2,10 +2,14 @@ package ru.dbotthepony.mc.otm.android.feature import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.PoseStack +import it.unimi.dsi.fastutil.objects.ReferenceArraySet import net.minecraft.ChatFormatting import net.minecraft.network.FriendlyByteBuf import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.entity.Entity import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.monster.warden.Warden import net.minecraftforge.network.NetworkEvent import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.ServerConfig @@ -33,6 +37,8 @@ import ru.dbotthepony.mc.otm.network.sender import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.ShockwaveDamageSource +import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger +import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger import java.util.function.Supplier import kotlin.math.pow import kotlin.math.roundToInt @@ -77,6 +83,10 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF cooldown = ServerConfig.Shockwave.COOLDOWN + if (ply is ServerPlayer) { + ShockwaveTrigger.trigger(ply as ServerPlayer) + } + // TODO: raycasting val entities = ply.level.getEntitiesInEllipsoid( ply.position, @@ -84,15 +94,45 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF except = ply, ) { (it !is LivingEntity || !it.isSpectator && it.isAlive) } - for ((entity, distanceMultiplier) in entities) { - val multiplier = (1.0 - distanceMultiplier).pow(1.25) + val wardens = ply.level.getEntitiesInEllipsoid( + Warden::class.java, + ply.position, + Vector(ServerConfig.Shockwave.RADIUS_HORIZONTAL_WARDEN, ServerConfig.Shockwave.RADIUS_VERTICAL_WARDEN, ServerConfig.Shockwave.RADIUS_HORIZONTAL_WARDEN), + ) { true } - // don't hurt items, arrows, etc etc - if (entity is LivingEntity) { - entity.hurt(ShockwaveDamageSource(ply), multiplier.toFloat() * ServerConfig.Shockwave.DAMAGE.toFloat()) - entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 3.0) - } else { - entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 6.0) + val seen = ReferenceArraySet() + + for ((entity, distanceMultiplier) in wardens) { + seen.add(entity) + val multiplier = (1.0 - distanceMultiplier).pow(0.5) + + val source = ShockwaveDamageSource(ply) + val damage = multiplier.toFloat() * ServerConfig.Shockwave.DAMAGE.toFloat() * ServerConfig.Shockwave.WARDEN_DAMAGE_MULT.toFloat() + entity.hurt(source, damage) + entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 3.0) + + if (ply is ServerPlayer) { + ShockwaveDamageMobTrigger.trigger(ply as ServerPlayer, entity, source, damage) + } + } + + for ((entity, distanceMultiplier) in entities) { + if (seen.add(entity)) { + val multiplier = (1.0 - distanceMultiplier).pow(1.25) + + // don't hurt items, arrows, etc etc + if (entity is LivingEntity) { + val source = ShockwaveDamageSource(ply) + val damage = multiplier.toFloat() * ServerConfig.Shockwave.DAMAGE.toFloat() + entity.hurt(source, damage) + entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 3.0) + + if (ply is ServerPlayer) { + ShockwaveDamageMobTrigger.trigger(ply as ServerPlayer, entity, source, damage) + } + } else { + entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 6.0) + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index 834bf79d5..49b40832b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -32,11 +32,9 @@ import net.minecraftforge.event.entity.living.LivingDropsEvent import net.minecraftforge.event.entity.living.LivingHurtEvent import net.minecraftforge.event.entity.living.LivingSpawnEvent import net.minecraftforge.event.entity.living.MobEffectEvent -import net.minecraftforge.event.entity.player.EntityItemPickupEvent import net.minecraftforge.event.entity.player.PlayerEvent import net.minecraftforge.eventbus.api.Event import net.minecraftforge.registries.ForgeRegistries -import org.apache.commons.lang3.mutable.MutableInt import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.android.AndroidFeature @@ -51,6 +49,11 @@ import ru.dbotthepony.mc.otm.menu.ExoSuitInventoryMenu import ru.dbotthepony.mc.otm.network.* import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.MRegistry +import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeHumaneTrigger import java.util.* import java.util.stream.Stream import kotlin.collections.ArrayDeque @@ -245,6 +248,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial deathLog.clear() androidEnergy.batteryLevel = ServerConfig.ANDROID_MAX_ENERGY androidEnergy.maxBatteryLevel = ServerConfig.ANDROID_MAX_ENERGY + + if (ply is ServerPlayer) { + BecomeAndroidTrigger.trigger(ply) + } } fun becomeAndroidAndKill() { @@ -265,6 +272,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial androidEnergy.batteryLevel = ImpreciseFraction.ZERO androidEnergy.maxBatteryLevel = ServerConfig.ANDROID_MAX_ENERGY dropBattery() + + if (ply is ServerPlayer) { + BecomeHumaneTrigger.trigger(ply) + } } fun becomeHumaneAndKill() { @@ -524,6 +535,20 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial val instance = AndroidResearch(research, this) instance.deserializeNBT(researchTag) this.research[research] = instance + + if (instance.isResearched && ply is ServerPlayer) { + onceServer(20) { + if (!ply.hasDisconnected()) + AndroidResearchTrigger.trigger(ply, instance.type) + } + } + } + } + + if (isAndroid && ply is ServerPlayer) { + onceServer(20) { + if (!ply.hasDisconnected()) + BecomeAndroidTrigger.trigger(ply) } } } @@ -590,7 +615,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial if (ply.isSleeping && ply.sleepTimer > SLEEP_TICKS_LIMIT) { becomeAndroid() shouldPlaySound = true - (ply as? ServerPlayer)?.displayClientMessage(TranslatableComponent("otm.pill.message_finish").withStyle(ChatFormatting.DARK_RED), false) + + if (ply is ServerPlayer) { + ply.displayClientMessage(TranslatableComponent("otm.pill.message_finish").withStyle(ChatFormatting.DARK_RED), false) + BecomeAndroidSleepTrigger.trigger(ply) + } } } @@ -839,7 +868,13 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial if (original.willBecomeAndroid && event.isWasDeath) { original.becomeAndroid() - (event.entity as? ServerPlayer)?.displayClientMessage(TranslatableComponent("otm.pill.message_finish").withStyle(ChatFormatting.DARK_RED), false) + + val ply = event.entity + + if (ply is ServerPlayer) { + ply.displayClientMessage(TranslatableComponent("otm.pill.message_finish").withStyle(ChatFormatting.DARK_RED), false) + BecomeAndroidDeathTrigger.trigger(ply) + } } it.deserializeNBT(original.serializeNBT()) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/LevelExt.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/LevelExt.kt index 9bc570b21..3342aefe9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/LevelExt.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/LevelExt.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.core import net.minecraft.world.entity.Entity import net.minecraft.world.level.Level import net.minecraft.world.phys.AABB +import java.util.LinkedList import java.util.function.Predicate import kotlin.math.pow @@ -20,7 +21,46 @@ fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, except: Entity pos.z + dimensions.z, ), predicate) - val result = ArrayList>() + val result = LinkedList>() + + for (it in entities) { + val a = (it.position - pos).let { vec -> + vec.x.pow(2.0) / dimensions.x.pow(2.0) + + vec.y.pow(2.0) / dimensions.y.pow(2.0) + + vec.z.pow(2.0) / dimensions.z.pow(2.0) + } + + val b = it.boundingBox.center.let { vec -> + (vec.x - pos.x).pow(2.0) / dimensions.x.pow(2.0) + + (vec.y - pos.y).pow(2.0) / dimensions.y.pow(2.0) + + (vec.z - pos.z).pow(2.0) / dimensions.z.pow(2.0) + } + + val min = a.coerceAtMost(b) + + if (min <= 1.0) { + result.add(it to min) + } + } + + return result +} + +/** + * Pair of entity and distance fraction to center of ellipsoid + */ +fun Level.getEntitiesInEllipsoid(type: Class, pos: Vector, dimensions: Vector, predicate: Predicate): List> { + val entities = getEntitiesOfClass(type, AABB( + pos.x - dimensions.x, + pos.y - dimensions.y, + pos.z - dimensions.z, + + pos.x + dimensions.x, + pos.y + dimensions.y, + pos.z + dimensions.z, + ), predicate) + + val result = LinkedList>() for (it in entities) { val a = (it.position - pos).let { vec -> @@ -65,3 +105,10 @@ fun Level.getEntitiesInSphere(pos: Vector, radius: Double, except: Entity?, pred fun Level.getEntitiesInSphere(pos: Vector, radius: Double, predicate: Predicate): List> { return getEntitiesInEllipsoid(pos, Vector(radius, radius, radius), null, predicate) } + +/** + * Pair of entity and distance fraction to center of ellipsoid + */ +fun Level.getEntitiesInSphere(type: Class, pos: Vector, radius: Double, predicate: Predicate): List> { + return getEntitiesInEllipsoid(type, pos, Vector(radius, radius, radius), predicate) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt index 90a8603c2..7c45ab76b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt @@ -44,7 +44,14 @@ import ru.dbotthepony.mc.otm.registry.objects.ColoredDecorativeBlock import ru.dbotthepony.mc.otm.registry.objects.CrateProperties import ru.dbotthepony.mc.otm.registry.objects.DecorativeBlock import ru.dbotthepony.mc.otm.registry.objects.StripedColoredDecorativeBlock +import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger +import ru.dbotthepony.mc.otm.triggers.BecomeHumaneTrigger import ru.dbotthepony.mc.otm.triggers.BlackHoleTrigger +import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger +import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger import java.util.function.Supplier import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadWriteProperty @@ -261,6 +268,13 @@ object MRegistry { private fun initializeCommon(event: FMLCommonSetupEvent) { event.enqueueWork { CriteriaTriggers.register(BlackHoleTrigger) + CriteriaTriggers.register(BecomeAndroidTrigger) + CriteriaTriggers.register(BecomeAndroidDeathTrigger) + CriteriaTriggers.register(BecomeAndroidSleepTrigger) + CriteriaTriggers.register(BecomeHumaneTrigger) + CriteriaTriggers.register(AndroidResearchTrigger) + CriteriaTriggers.register(ShockwaveDamageMobTrigger) + CriteriaTriggers.register(ShockwaveTrigger) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/AndroidResearchTrigger.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/AndroidResearchTrigger.kt new file mode 100644 index 000000000..2eb8c4634 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/AndroidResearchTrigger.kt @@ -0,0 +1,54 @@ +package ru.dbotthepony.mc.otm.triggers + +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance +import net.minecraft.advancements.critereon.DeserializationContext +import net.minecraft.advancements.critereon.EntityPredicate +import net.minecraft.advancements.critereon.SerializationContext +import net.minecraft.advancements.critereon.SimpleCriterionTrigger +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerPlayer +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.android.AndroidResearchType +import ru.dbotthepony.mc.otm.core.set +import java.util.function.Predicate + +object AndroidResearchTrigger : SimpleCriterionTrigger() { + val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_research") + + override fun getId(): ResourceLocation { + return ID + } + + override fun createInstance( + p_66248_: JsonObject, + p_66249_: EntityPredicate.Composite, + p_66250_: DeserializationContext + ): Instance { + return Instance( + p_66248_["research"]?.asString?.let(::ResourceLocation) + ) + } + + fun trigger(player: ServerPlayer, research: AndroidResearchType) { + trigger(player) { + it.test(research) + } + } + + class Instance(val research: ResourceLocation?) : AbstractCriterionTriggerInstance(ID, EntityPredicate.Composite.ANY), Predicate { + constructor(research: AndroidResearchType) : this(research.id) + + override fun test(t: AndroidResearchType): Boolean { + return research == null || t.id == research + } + + override fun serializeToJson(p_16979_: SerializationContext): JsonObject { + return super.serializeToJson(p_16979_).also { + if (research != null) + it["research"] = JsonPrimitive(research.toString()) + } + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/AndroidStatusTriggers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/AndroidStatusTriggers.kt new file mode 100644 index 000000000..28f186619 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/AndroidStatusTriggers.kt @@ -0,0 +1,98 @@ +package ru.dbotthepony.mc.otm.triggers + +import com.google.gson.JsonObject +import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance +import net.minecraft.advancements.critereon.DeserializationContext +import net.minecraft.advancements.critereon.EntityPredicate +import net.minecraft.advancements.critereon.SimpleCriterionTrigger +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerPlayer +import ru.dbotthepony.mc.otm.OverdriveThatMatters + +object BecomeAndroidTrigger : SimpleCriterionTrigger() { + val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "become_android") + + override fun getId(): ResourceLocation { + return ID + } + + override fun createInstance( + p_66248_: JsonObject, + p_66249_: EntityPredicate.Composite, + p_66250_: DeserializationContext + ): Instance { + return Instance + } + + fun trigger(player: ServerPlayer) { + trigger(player) { true } + } + + object Instance : AbstractCriterionTriggerInstance(ID, EntityPredicate.Composite.ANY) +} + +object BecomeAndroidSleepTrigger : SimpleCriterionTrigger() { + val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "become_android_sleep") + + override fun getId(): ResourceLocation { + return ID + } + + override fun createInstance( + p_66248_: JsonObject, + p_66249_: EntityPredicate.Composite, + p_66250_: DeserializationContext + ): Instance { + return Instance + } + + fun trigger(player: ServerPlayer) { + trigger(player) { true } + } + + object Instance : AbstractCriterionTriggerInstance(ID, EntityPredicate.Composite.ANY) +} + +object BecomeAndroidDeathTrigger : SimpleCriterionTrigger() { + val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "become_android_death") + + override fun getId(): ResourceLocation { + return ID + } + + override fun createInstance( + p_66248_: JsonObject, + p_66249_: EntityPredicate.Composite, + p_66250_: DeserializationContext + ): Instance { + return Instance + } + + fun trigger(player: ServerPlayer) { + trigger(player) { true } + } + + object Instance : AbstractCriterionTriggerInstance(ID, EntityPredicate.Composite.ANY) +} + +object BecomeHumaneTrigger : SimpleCriterionTrigger() { + val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "become_humane") + + override fun getId(): ResourceLocation { + return ID + } + + override fun createInstance( + p_66248_: JsonObject, + p_66249_: EntityPredicate.Composite, + p_66250_: DeserializationContext + ): Instance { + return Instance + } + + fun trigger(player: ServerPlayer) { + trigger(player) { true } + } + + object Instance : AbstractCriterionTriggerInstance(ID, EntityPredicate.Composite.ANY) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/ShockwaveDamageMobTrigger.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/ShockwaveDamageMobTrigger.kt new file mode 100644 index 000000000..a8fe3d1f1 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/ShockwaveDamageMobTrigger.kt @@ -0,0 +1,63 @@ +package ru.dbotthepony.mc.otm.triggers + +import com.google.gson.JsonObject +import com.google.gson.JsonSyntaxException +import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance +import net.minecraft.advancements.critereon.DamagePredicate +import net.minecraft.advancements.critereon.DamageSourcePredicate +import net.minecraft.advancements.critereon.DeserializationContext +import net.minecraft.advancements.critereon.EntityPredicate +import net.minecraft.advancements.critereon.MinMaxBounds +import net.minecraft.advancements.critereon.SerializationContext +import net.minecraft.advancements.critereon.SimpleCriterionTrigger +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.damagesource.DamageSource +import net.minecraft.world.entity.Entity +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.core.set + +object ShockwaveDamageMobTrigger: SimpleCriterionTrigger() { + val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "shockwave_damage_mob") + + override fun getId(): ResourceLocation { + return ID + } + + override fun createInstance( + p_66248_: JsonObject, + p_66249_: EntityPredicate.Composite, + p_66250_: DeserializationContext + ): Instance { + return Instance( + EntityPredicate.Composite.fromJson(p_66248_, "entity_predicate", p_66250_), + (p_66248_["damage"] as? JsonObject)?.let(DamagePredicate::fromJson) ?: DamagePredicate.ANY + ) + } + + fun trigger(player: ServerPlayer, entity: Entity, damageSource: DamageSource, damage: Float) { + val context = EntityPredicate.createContext(player, entity) + + trigger(player) { + it.predicate.matches(context) && it.damagePredicate.matches(player, damageSource, damage, damage, false) + } + } + + class Instance( + val predicate: EntityPredicate.Composite = EntityPredicate.Composite.ANY, + val damagePredicate: DamagePredicate = DamagePredicate( + MinMaxBounds.Doubles.atLeast(1.0), + MinMaxBounds.Doubles.atLeast(1.0), + EntityPredicate.ANY, + null, + DamageSourcePredicate.ANY + ) + ) : AbstractCriterionTriggerInstance(ID, EntityPredicate.Composite.ANY) { + override fun serializeToJson(p_16979_: SerializationContext): JsonObject { + return super.serializeToJson(p_16979_).also { + it["entity_predicate"] = predicate.toJson(p_16979_) + it["damage"] = damagePredicate.serializeToJson() + } + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/ShockwaveTrigger.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/ShockwaveTrigger.kt new file mode 100644 index 000000000..207f27d5b --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/triggers/ShockwaveTrigger.kt @@ -0,0 +1,32 @@ +package ru.dbotthepony.mc.otm.triggers + +import com.google.gson.JsonObject +import net.minecraft.advancements.critereon.AbstractCriterionTriggerInstance +import net.minecraft.advancements.critereon.DeserializationContext +import net.minecraft.advancements.critereon.EntityPredicate.Composite +import net.minecraft.advancements.critereon.SimpleCriterionTrigger +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerPlayer +import ru.dbotthepony.mc.otm.OverdriveThatMatters + +object ShockwaveTrigger : SimpleCriterionTrigger() { + val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "shockwave") + + override fun getId(): ResourceLocation { + return ID + } + + override fun createInstance( + p_66248_: JsonObject, + p_66249_: Composite, + p_66250_: DeserializationContext + ): Instance { + return Instance + } + + fun trigger(player: ServerPlayer) { + trigger(player) { true } + } + + object Instance : AbstractCriterionTriggerInstance(ID, Composite.ANY) +}