Advancements!

This commit is contained in:
DBotThePony 2022-10-02 13:00:47 +07:00
parent 6e78972ea1
commit 1a468f9817
Signed by: DBot
GPG Key ID: DCC23B5715498507
16 changed files with 664 additions and 14 deletions

View File

@ -30,6 +30,7 @@ import ru.dbotthepony.mc.otm.registry.*
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.advancements.AdvancementProvider import ru.dbotthepony.mc.otm.datagen.advancements.AdvancementProvider
import ru.dbotthepony.mc.otm.datagen.advancements.addAdvancements 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.addBlockStates
import ru.dbotthepony.mc.otm.datagen.blocks.addComplexBlockStates import ru.dbotthepony.mc.otm.datagen.blocks.addComplexBlockStates
import ru.dbotthepony.mc.otm.datagen.items.addItemModels import ru.dbotthepony.mc.otm.datagen.items.addItemModels
@ -69,6 +70,8 @@ object DataGen {
private set private set
var languageProvider: MatteryLanguageProvider by WriteOnce() var languageProvider: MatteryLanguageProvider by WriteOnce()
private set private set
var researchProvider: AndroidResearchDataProvider by WriteOnce()
private set
fun decorativeCubeAll(vararg blocks: Block) { fun decorativeCubeAll(vararg blocks: Block) {
blockModelProvider.decorativeCubeAll(*blocks) blockModelProvider.decorativeCubeAll(*blocks)
@ -300,6 +303,7 @@ object DataGen {
val recipeProvider = MatteryRecipeProvider(event.generator) val recipeProvider = MatteryRecipeProvider(event.generator)
val lootModifier = LootModifiers(event.generator) val lootModifier = LootModifiers(event.generator)
val languageProvider = MatteryLanguageProvider(event.generator) val languageProvider = MatteryLanguageProvider(event.generator)
val researchProvider = AndroidResearchDataProvider(event.generator).also { it.exec { addResearchData(it, languageProvider) } }
this.blockModelProvider = blockModelProvider this.blockModelProvider = blockModelProvider
this.blockStateProvider = blockStateProvider this.blockStateProvider = blockStateProvider
@ -308,6 +312,7 @@ object DataGen {
this.recipeProvider = recipeProvider this.recipeProvider = recipeProvider
this.lootModifier = lootModifier this.lootModifier = lootModifier
this.languageProvider = languageProvider this.languageProvider = languageProvider
this.researchProvider = researchProvider
val tagsProvider = TagsProvider(event) val tagsProvider = TagsProvider(event)
val advancementProvider = AdvancementProvider(event) val advancementProvider = AdvancementProvider(event)
@ -323,7 +328,7 @@ object DataGen {
event.generator.addProvider(true, lootTableProvider) event.generator.addProvider(true, lootTableProvider)
event.generator.addProvider(true, lootModifier) event.generator.addProvider(true, lootModifier)
event.generator.addProvider(true, SoundDataProvider(event)) 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) event.generator.addProvider(true, advancementProvider)
AddEnglishLanguage(languageProvider) AddEnglishLanguage(languageProvider)
@ -348,6 +353,7 @@ object DataGen {
advancementProvider.exec { it, files -> advancementProvider.exec { it, files ->
addAdvancements(it, files, languageProvider) addAdvancements(it, files, languageProvider)
addAndroidAdvancements(it, files, languageProvider)
} }
addPlatePressRecipes(recipeProvider) addPlatePressRecipes(recipeProvider)

View File

@ -458,6 +458,9 @@ fun addResearchData(serializer: Consumer<AndroidResearchType>, lang: MatteryLang
add(ENDER_TELEPORTER, "Ender Teleporter") add(ENDER_TELEPORTER, "Ender Teleporter")
add(ENDER_TELEPORTER, "description", "Allows unit to perform instant, short distance teleports without damage to internal systems") 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], "Attack Boost %s")
add(attackBoostList[0], "description", "Increases total melee attack strength by %s%%") add(attackBoostList[0], "description", "Increases total melee attack strength by %s%%")
} }

View File

@ -40,4 +40,50 @@ fun addAdvancements(serializer: Consumer<Advancement>, existingFileHelper: Exist
) )
.addCriterion("pulled_by_black_hole", BlackHoleTrigger.Instance) .addCriterion("pulled_by_black_hole", BlackHoleTrigger.Instance)
.save(serializer, modLocation("regular/black_hole"), existingFileHelper) .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)
} }

View File

@ -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<Advancement>, 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)
}

View File

@ -4,6 +4,7 @@ import net.minecraft.advancements.Advancement
import net.minecraft.advancements.CriterionTriggerInstance import net.minecraft.advancements.CriterionTriggerInstance
import net.minecraft.advancements.DisplayInfo import net.minecraft.advancements.DisplayInfo
import net.minecraft.advancements.FrameType import net.minecraft.advancements.FrameType
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.InventoryChangeTrigger import net.minecraft.advancements.critereon.InventoryChangeTrigger
import net.minecraft.advancements.critereon.ItemPredicate import net.minecraft.advancements.critereon.ItemPredicate
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
@ -11,6 +12,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.tags.TagKey import net.minecraft.tags.TagKey
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.ItemLike
import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TextComponent
fun AdvancementBuilder(): Advancement.Builder = Advancement.Builder.advancement() fun AdvancementBuilder(): Advancement.Builder = Advancement.Builder.advancement()
@ -57,3 +59,13 @@ fun predicate(tag: TagKey<Item>): ItemPredicate {
fun criterion(tag: TagKey<Item>): CriterionTriggerInstance { fun criterion(tag: TagKey<Item>): CriterionTriggerInstance {
return InventoryChangeTrigger.TriggerInstance.hasItems(predicate(tag)) 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)

View File

@ -200,8 +200,13 @@ object ServerConfig {
val COOLDOWN: Int by specBuilder.comment("In ticks").defineInRange("cooldown", 30, 1) 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_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_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 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 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) val ENERGY_COST by specBuilder.defineImpreciseFraction("energyCost", ImpreciseFraction(2048), ImpreciseFraction.ZERO)
init { init {

View File

@ -7,6 +7,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag import net.minecraft.nbt.ListTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.util.INBTSerializable 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.core.set
import ru.dbotthepony.mc.otm.network.FieldSynchronizer import ru.dbotthepony.mc.otm.network.FieldSynchronizer
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
import java.io.DataInputStream import java.io.DataInputStream
import java.io.InputStream import java.io.InputStream
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
@ -273,6 +275,11 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay
if (force || canResearch && consumeResearchCost(false)) { if (force || canResearch && consumeResearchCost(false)) {
onResearched() onResearched()
isResearched = true isResearched = true
if (ply is ServerPlayer) {
AndroidResearchTrigger.trigger(ply as ServerPlayer, this.type)
}
return true return true
} }

View File

@ -5,6 +5,7 @@ import net.minecraft.data.CachedOutput
import net.minecraft.data.DataGenerator import net.minecraft.data.DataGenerator
import net.minecraft.data.DataProvider import net.minecraft.data.DataProvider
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import java.util.Collections
import java.util.LinkedList import java.util.LinkedList
import java.util.function.Consumer import java.util.function.Consumer
@ -14,6 +15,9 @@ open class AndroidResearchDataProvider(protected val dataGenerator: DataGenerato
protected val callbacks = LinkedList<(Consumer<AndroidResearchType>) -> Unit>() protected val callbacks = LinkedList<(Consumer<AndroidResearchType>) -> Unit>()
private val generated = LinkedList<AndroidResearchType>()
val generatedView: List<AndroidResearchType> = Collections.unmodifiableList(generated)
/** /**
* override this * override this
*/ */
@ -49,6 +53,7 @@ open class AndroidResearchDataProvider(protected val dataGenerator: DataGenerato
for (value in added) { for (value in added) {
value.validate() value.validate()
generated.add(value)
} }
} }

View File

@ -2,10 +2,14 @@ package ru.dbotthepony.mc.otm.android.feature
import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.systems.RenderSystem
import com.mojang.blaze3d.vertex.PoseStack import com.mojang.blaze3d.vertex.PoseStack
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation 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.LivingEntity
import net.minecraft.world.entity.monster.warden.Warden
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.NetworkEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.ServerConfig 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.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.registry.ShockwaveDamageSource 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 java.util.function.Supplier
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -77,6 +83,10 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF
cooldown = ServerConfig.Shockwave.COOLDOWN cooldown = ServerConfig.Shockwave.COOLDOWN
if (ply is ServerPlayer) {
ShockwaveTrigger.trigger(ply as ServerPlayer)
}
// TODO: raycasting // TODO: raycasting
val entities = ply.level.getEntitiesInEllipsoid( val entities = ply.level.getEntitiesInEllipsoid(
ply.position, ply.position,
@ -84,17 +94,47 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF
except = ply, except = ply,
) { (it !is LivingEntity || !it.isSpectator && it.isAlive) } ) { (it !is LivingEntity || !it.isSpectator && it.isAlive) }
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 }
val seen = ReferenceArraySet<Entity>()
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) { for ((entity, distanceMultiplier) in entities) {
if (seen.add(entity)) {
val multiplier = (1.0 - distanceMultiplier).pow(1.25) val multiplier = (1.0 - distanceMultiplier).pow(1.25)
// don't hurt items, arrows, etc etc // don't hurt items, arrows, etc etc
if (entity is LivingEntity) { if (entity is LivingEntity) {
entity.hurt(ShockwaveDamageSource(ply), multiplier.toFloat() * ServerConfig.Shockwave.DAMAGE.toFloat()) 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) entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 3.0)
if (ply is ServerPlayer) {
ShockwaveDamageMobTrigger.trigger(ply as ServerPlayer, entity, source, damage)
}
} else { } else {
entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 6.0) entity.deltaMovement += (entity.position - ply.position).normalize() * (multiplier * 6.0)
} }
} }
}
if (ServerConfig.Shockwave.BREAK_BLOCKS) { if (ServerConfig.Shockwave.BREAK_BLOCKS) {
val rounded = ply.position.roundToIntVector() val rounded = ply.position.roundToIntVector()

View File

@ -32,11 +32,9 @@ import net.minecraftforge.event.entity.living.LivingDropsEvent
import net.minecraftforge.event.entity.living.LivingHurtEvent import net.minecraftforge.event.entity.living.LivingHurtEvent
import net.minecraftforge.event.entity.living.LivingSpawnEvent import net.minecraftforge.event.entity.living.LivingSpawnEvent
import net.minecraftforge.event.entity.living.MobEffectEvent import net.minecraftforge.event.entity.living.MobEffectEvent
import net.minecraftforge.event.entity.player.EntityItemPickupEvent
import net.minecraftforge.event.entity.player.PlayerEvent import net.minecraftforge.event.entity.player.PlayerEvent
import net.minecraftforge.eventbus.api.Event import net.minecraftforge.eventbus.api.Event
import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.ForgeRegistries
import org.apache.commons.lang3.mutable.MutableInt
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.android.AndroidFeature 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.network.*
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MRegistry 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.*
import java.util.stream.Stream import java.util.stream.Stream
import kotlin.collections.ArrayDeque import kotlin.collections.ArrayDeque
@ -245,6 +248,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
deathLog.clear() deathLog.clear()
androidEnergy.batteryLevel = ServerConfig.ANDROID_MAX_ENERGY androidEnergy.batteryLevel = ServerConfig.ANDROID_MAX_ENERGY
androidEnergy.maxBatteryLevel = ServerConfig.ANDROID_MAX_ENERGY androidEnergy.maxBatteryLevel = ServerConfig.ANDROID_MAX_ENERGY
if (ply is ServerPlayer) {
BecomeAndroidTrigger.trigger(ply)
}
} }
fun becomeAndroidAndKill() { fun becomeAndroidAndKill() {
@ -265,6 +272,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
androidEnergy.batteryLevel = ImpreciseFraction.ZERO androidEnergy.batteryLevel = ImpreciseFraction.ZERO
androidEnergy.maxBatteryLevel = ServerConfig.ANDROID_MAX_ENERGY androidEnergy.maxBatteryLevel = ServerConfig.ANDROID_MAX_ENERGY
dropBattery() dropBattery()
if (ply is ServerPlayer) {
BecomeHumaneTrigger.trigger(ply)
}
} }
fun becomeHumaneAndKill() { fun becomeHumaneAndKill() {
@ -524,6 +535,20 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
val instance = AndroidResearch(research, this) val instance = AndroidResearch(research, this)
instance.deserializeNBT(researchTag) instance.deserializeNBT(researchTag)
this.research[research] = instance 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) { if (ply.isSleeping && ply.sleepTimer > SLEEP_TICKS_LIMIT) {
becomeAndroid() becomeAndroid()
shouldPlaySound = true 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) { if (original.willBecomeAndroid && event.isWasDeath) {
original.becomeAndroid() 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()) it.deserializeNBT(original.serializeNBT())

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.core
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.phys.AABB import net.minecraft.world.phys.AABB
import java.util.LinkedList
import java.util.function.Predicate import java.util.function.Predicate
import kotlin.math.pow import kotlin.math.pow
@ -20,7 +21,46 @@ fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, except: Entity
pos.z + dimensions.z, pos.z + dimensions.z,
), predicate) ), predicate)
val result = ArrayList<Pair<Entity, Double>>() val result = LinkedList<Pair<Entity, Double>>()
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 <T : Entity> Level.getEntitiesInEllipsoid(type: Class<out T>, pos: Vector, dimensions: Vector, predicate: Predicate<in Entity>): List<Pair<T, Double>> {
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<Pair<T, Double>>()
for (it in entities) { for (it in entities) {
val a = (it.position - pos).let { vec -> 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<in Entity>): List<Pair<Entity, Double>> { fun Level.getEntitiesInSphere(pos: Vector, radius: Double, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
return getEntitiesInEllipsoid(pos, Vector(radius, radius, radius), null, predicate) return getEntitiesInEllipsoid(pos, Vector(radius, radius, radius), null, predicate)
} }
/**
* Pair of entity and distance fraction to center of ellipsoid
*/
fun Level.getEntitiesInSphere(type: Class<out Entity>, pos: Vector, radius: Double, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
return getEntitiesInEllipsoid(type, pos, Vector(radius, radius, radius), predicate)
}

View File

@ -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.CrateProperties
import ru.dbotthepony.mc.otm.registry.objects.DecorativeBlock import ru.dbotthepony.mc.otm.registry.objects.DecorativeBlock
import ru.dbotthepony.mc.otm.registry.objects.StripedColoredDecorativeBlock 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.BlackHoleTrigger
import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger
import ru.dbotthepony.mc.otm.triggers.ShockwaveTrigger
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
@ -261,6 +268,13 @@ object MRegistry {
private fun initializeCommon(event: FMLCommonSetupEvent) { private fun initializeCommon(event: FMLCommonSetupEvent) {
event.enqueueWork { event.enqueueWork {
CriteriaTriggers.register(BlackHoleTrigger) CriteriaTriggers.register(BlackHoleTrigger)
CriteriaTriggers.register(BecomeAndroidTrigger)
CriteriaTriggers.register(BecomeAndroidDeathTrigger)
CriteriaTriggers.register(BecomeAndroidSleepTrigger)
CriteriaTriggers.register(BecomeHumaneTrigger)
CriteriaTriggers.register(AndroidResearchTrigger)
CriteriaTriggers.register(ShockwaveDamageMobTrigger)
CriteriaTriggers.register(ShockwaveTrigger)
} }
} }

View File

@ -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<AndroidResearchTrigger.Instance>() {
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<AndroidResearchType> {
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())
}
}
}
}

View File

@ -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<BecomeAndroidTrigger.Instance>() {
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<BecomeAndroidSleepTrigger.Instance>() {
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<BecomeAndroidDeathTrigger.Instance>() {
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<BecomeHumaneTrigger.Instance>() {
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)
}

View File

@ -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<ShockwaveDamageMobTrigger.Instance>() {
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()
}
}
}
}

View File

@ -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<ShockwaveTrigger.Instance>() {
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)
}