More achievements!
Travel underwater without Air Bags, fixes #209 Kill Elder Guardian without Air Bags, fixes #210 Kill the Wither as Android, fixes #206
This commit is contained in:
parent
9924711f31
commit
5b4c68b201
@ -20,17 +20,20 @@ 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.AndroidFeatures
|
||||
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.AndroidBatteryTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.AndroidTravelUnderwater
|
||||
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.EnderTeleporterFallDeathTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.FallDampenersSaveTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.NanobotsArmorTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.PhantomSpawnDeniedTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.ShockwaveDamageMobTrigger
|
||||
@ -46,8 +49,8 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
|
||||
title = translation.add("root", "Androids and Humans") {
|
||||
russian("Андроиды и Люди")
|
||||
},
|
||||
description = translation.add("root.desc", "Can you make out who is cruel machine and who care about others?") {
|
||||
russian("Сможете ли вы отличить бездушную машину от того, кому другие не безразличны?")
|
||||
description = translation.add("root.desc", "Can you make out who is cruel machine and who shows empathy?") {
|
||||
russian("Сможете ли вы отличить бездушную машину от того, кто показывает сочувствие?")
|
||||
},
|
||||
showToast = false,
|
||||
announceChat = false,
|
||||
@ -381,4 +384,73 @@ fun addAndroidAdvancements(serializer: Consumer<Advancement>, existingFileHelper
|
||||
)
|
||||
.addCriterion("shockwave_warden", ShockwaveDamageMobTrigger.Instance(EntityPredicate.Builder.entity().of(EntityType.WARDEN).build().wrap()))
|
||||
.save(serializer, modLocation("android/shockwave_warden"), existingFileHelper)
|
||||
|
||||
AdvancementBuilder()
|
||||
.parent(root)
|
||||
.display(
|
||||
itemStack = ItemStack(Items.WITHER_SKELETON_SKULL),
|
||||
title = translation.add("wither", "Not Quite Alive, Not Quite Undead") {
|
||||
russian("Ни Живой, Ни Мёртвый")
|
||||
},
|
||||
description = translation.add("wither.desc", "Defeat The Wither as Android. The Wither was surely confused over kind of thing you are") {
|
||||
russian("Победите Иссушителя будучи Андроидом. Наверняка Иссушитель был ошеломлён таким раскладом дел")
|
||||
},
|
||||
frameType = FrameType.GOAL,
|
||||
hidden = true
|
||||
)
|
||||
.addCriterion("kill_wither", KillAsAndroidTrigger.Instance(
|
||||
predicate = EntityPredicate.Builder.entity().of(EntityType.WITHER).build().wrap(),
|
||||
))
|
||||
.save(serializer, modLocation("android/wither"), existingFileHelper)
|
||||
|
||||
val underwater = AdvancementBuilder()
|
||||
.parent(root)
|
||||
.display(
|
||||
itemStack = ItemStack(Items.TURTLE_SPAWN_EGG),
|
||||
title = translation.add("travel_underwater", "Underwater Walk") {
|
||||
russian("Подводная Прогулка")
|
||||
},
|
||||
description = translation.add("travel_underwater.desc", "Travel at least 200 meters underwater as Android without Air Bags research. This reminds us of someone...") {
|
||||
russian("Преодолейте как минимум 200 метров под водой будучи Андроидом без исследования Воздушных Мешков. Кого-то это нам напоминает...")
|
||||
},
|
||||
frameType = FrameType.GOAL,
|
||||
hidden = true
|
||||
)
|
||||
.addCriterion("travel", AndroidTravelUnderwater.Instance(200.0))
|
||||
.save(serializer, modLocation("android/underwater"), existingFileHelper)
|
||||
|
||||
AdvancementBuilder()
|
||||
.parent(underwater)
|
||||
.display(
|
||||
itemStack = ItemStack(Items.TURTLE_SPAWN_EGG),
|
||||
title = translation.add("travel_underwater2", "Underwater Travel") {
|
||||
russian("Подводная Прогулка")
|
||||
},
|
||||
description = translation.add("travel_underwater2.desc", "Travel at least 1046 meters underwater as Android without Air Bags research, like someone else did so") {
|
||||
russian("Преодолейте как минимум 1046 метров под водой будучи Андроидом без исследования Воздушных Мешков, прям как тот, кто так однажды так и сделал")
|
||||
},
|
||||
frameType = FrameType.CHALLENGE,
|
||||
hidden = true
|
||||
)
|
||||
.addCriterion("travel", AndroidTravelUnderwater.Instance(1046.0))
|
||||
.save(serializer, modLocation("android/underwater2"), existingFileHelper)
|
||||
|
||||
AdvancementBuilder()
|
||||
.parent(root)
|
||||
.display(
|
||||
itemStack = ItemStack(Items.PRISMARINE_CRYSTALS),
|
||||
title = translation.add("elder_guardian", "Drowned, but Still Determined") {
|
||||
russian("Затонувший, но Всё Ещё Целеустремлённый")
|
||||
},
|
||||
description = translation.add("elder_guardian.desc", "Slay Elder Guardian as Android without Air Bags researched") {
|
||||
russian("Победите Древнего Стража будучи Андроидом без исследования Воздушных Мешков")
|
||||
},
|
||||
frameType = FrameType.CHALLENGE,
|
||||
hidden = true
|
||||
)
|
||||
.addCriterion("kill_elder_guardian", KillAsAndroidTrigger.Instance(
|
||||
predicate = EntityPredicate.Builder.entity().of(EntityType.ELDER_GUARDIAN).build().wrap(),
|
||||
featurePredicate = KillAsAndroidTrigger.Not(KillAsAndroidTrigger.Has(AndroidFeatures.AIR_BAGS.registryName!!))
|
||||
))
|
||||
.save(serializer, modLocation("android/elder_guardian"), existingFileHelper)
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ import ru.dbotthepony.mc.otm.matter.MatterManager;
|
||||
import ru.dbotthepony.mc.otm.network.*;
|
||||
import ru.dbotthepony.mc.otm.registry.*;
|
||||
import ru.dbotthepony.mc.otm.storage.*;
|
||||
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger;
|
||||
|
||||
import static net.minecraftforge.common.MinecraftForge.EVENT_BUS;
|
||||
|
||||
@ -177,6 +178,8 @@ public final class OverdriveThatMatters {
|
||||
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryBlockEntity.Companion::playerDisconnected);
|
||||
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryBlockEntity.Companion::postLevelTick);
|
||||
|
||||
EVENT_BUS.addListener(EventPriority.LOWEST, KillAsAndroidTrigger.INSTANCE::onKill);
|
||||
|
||||
EVENT_BUS.addListener(EventPriority.NORMAL, EnderTeleporterFeature.Companion::onEntityDeath);
|
||||
EVENT_BUS.addListener(EventPriority.HIGH, ItemTritaniumArmor.Companion::onHurt);
|
||||
|
||||
|
@ -21,6 +21,7 @@ import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.ProjectileWeaponItem
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraftforge.common.ForgeHooks
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
||||
@ -53,16 +54,19 @@ import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.core.collect.UUIDIntModifiersMap
|
||||
import ru.dbotthepony.mc.otm.core.collect.nonEmpty
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.minus
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.util.IntValueCodec
|
||||
import ru.dbotthepony.mc.otm.core.util.Savetables
|
||||
import ru.dbotthepony.mc.otm.core.util.UUIDValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.ExoPackInventoryMenu
|
||||
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.AndroidTravelUnderwater
|
||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger
|
||||
@ -98,6 +102,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
*/
|
||||
val synchronizer = FieldSynchronizer()
|
||||
|
||||
/**
|
||||
* For data to be stored and loaded from NBT automatically
|
||||
*/
|
||||
val savetables = Savetables()
|
||||
|
||||
/**
|
||||
* For fields that need to be synchronized to everyone
|
||||
*
|
||||
@ -251,6 +260,19 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
var ticksIExist = 0
|
||||
private set
|
||||
|
||||
private var lastOutsideLiquid = Vec3(0.0, 0.0, 0.0)
|
||||
private var wasInLiquid = false
|
||||
private var lastDimension = ResourceLocation("overworld")
|
||||
|
||||
init {
|
||||
savetables.int(::ticksIExist)
|
||||
savetables.int(::iteration)
|
||||
savetables.bool(::shouldSendIteration)
|
||||
savetables.bool(::wasInLiquid)
|
||||
savetables.vector(::lastOutsideLiquid)
|
||||
savetables.location(::lastDimension)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whenever player should become an Android once transformation conditions are met (e.g. player dies or sleeps in bed)
|
||||
*/
|
||||
@ -326,6 +348,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
androidEnergy.batteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
||||
androidEnergy.maxBatteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
||||
|
||||
lastOutsideLiquid = ply.position()
|
||||
wasInLiquid = false
|
||||
|
||||
if (ply is ServerPlayer) {
|
||||
BecomeAndroidTrigger.trigger(ply)
|
||||
}
|
||||
@ -374,6 +399,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
androidEnergy.maxBatteryLevel = AndroidConfig.ANDROID_MAX_ENERGY
|
||||
dropBattery()
|
||||
|
||||
lastOutsideLiquid = ply.position()
|
||||
wasInLiquid = false
|
||||
|
||||
if (ply is ServerPlayer) {
|
||||
BecomeHumaneTrigger.trigger(ply)
|
||||
}
|
||||
@ -574,14 +602,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
val tag = CompoundTag()
|
||||
|
||||
tag["ticksIExist"] = ticksIExist
|
||||
val tag = savetables.serializeNBT()
|
||||
|
||||
// iteration
|
||||
tag["iteration"] = iteration
|
||||
tag["shouldSendIteration"] = shouldSendIteration
|
||||
|
||||
tag["deathLog"] = ListTag().also {
|
||||
for ((ticks, component) in deathLog) {
|
||||
it.add(CompoundTag().also {
|
||||
@ -626,12 +649,9 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
}
|
||||
|
||||
override fun deserializeNBT(tag: CompoundTag) {
|
||||
ticksIExist = tag.getInt("ticksIExist")
|
||||
savetables.deserializeNBT(tag)
|
||||
|
||||
// iterations
|
||||
iteration = tag.getInt("iteration")
|
||||
shouldSendIteration = tag.getBoolean("shouldSendIteration")
|
||||
|
||||
deathLog.clear()
|
||||
|
||||
for (value in tag.getCompoundList("deathLog")) {
|
||||
@ -773,18 +793,38 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
||||
}
|
||||
|
||||
if (isAndroid) {
|
||||
if (!ply.isSpectator && ply.airSupply < ply.maxAirSupply)
|
||||
ply.airSupply = ply.maxAirSupply
|
||||
|
||||
// TODO: Maybe passive drain?
|
||||
// extractEnergyInner(BigDecimal.valueOf(new Random().nextDouble()), false);
|
||||
if (!ply.isSpectator && ply.isSwimming && !hasFeature(AndroidFeatures.AIR_BAGS)) {
|
||||
ply.isSwimming = false
|
||||
}
|
||||
|
||||
androidEnergy.tick()
|
||||
|
||||
if (!ply.isSpectator) {
|
||||
if (ply.airSupply < ply.maxAirSupply)
|
||||
ply.airSupply = ply.maxAirSupply
|
||||
|
||||
if (ply.isSwimming && !hasFeature(AndroidFeatures.AIR_BAGS))
|
||||
ply.isSwimming = false
|
||||
|
||||
if (ply is ServerPlayer) {
|
||||
if (ply.level.dimension().location() != lastDimension) {
|
||||
lastDimension = ply.level.dimension().location()
|
||||
wasInLiquid = false
|
||||
lastOutsideLiquid = ply.position
|
||||
}
|
||||
|
||||
if (ply.isUnderWater) {
|
||||
if (!wasInLiquid) {
|
||||
wasInLiquid = true
|
||||
lastOutsideLiquid = ply.position
|
||||
}
|
||||
} else {
|
||||
if (wasInLiquid) {
|
||||
wasInLiquid = false
|
||||
val distance = (lastOutsideLiquid - ply.position).length()
|
||||
AndroidTravelUnderwater.trigger(ply, distance)
|
||||
}
|
||||
|
||||
lastOutsideLiquid = ply.position
|
||||
}
|
||||
}
|
||||
|
||||
val stats = ply.foodData
|
||||
|
||||
while (stats.foodLevel < 18 && androidEnergy.extractEnergy(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT, true) >= AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT) {
|
||||
|
@ -298,3 +298,11 @@ fun <T : Comparable<T>> BlockState.getValueNullable(prop: Property<T>): T? {
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun <T> Stream<T>.asIterable(): Iterable<T> {
|
||||
return object : Iterable<T> {
|
||||
override fun iterator(): Iterator<T> {
|
||||
return this@asIterable.iterator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,9 @@ 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.AndroidBatteryTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.KillAsAndroidTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.AndroidResearchTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.AndroidTravelUnderwater
|
||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidDeathTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidSleepTrigger
|
||||
import ru.dbotthepony.mc.otm.triggers.BecomeAndroidTrigger
|
||||
@ -265,6 +267,8 @@ object MRegistry {
|
||||
CriteriaTriggers.register(NanobotsArmorTrigger)
|
||||
CriteriaTriggers.register(FallDampenersSaveTrigger)
|
||||
CriteriaTriggers.register(EnderTeleporterFallDeathTrigger)
|
||||
CriteriaTriggers.register(KillAsAndroidTrigger)
|
||||
CriteriaTriggers.register(AndroidTravelUnderwater)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,40 @@
|
||||
package ru.dbotthepony.mc.otm.triggers
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParseException
|
||||
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.core.set
|
||||
|
||||
object AndroidTravelUnderwater : SimpleCriterionTrigger<AndroidTravelUnderwater.Instance>() {
|
||||
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "android_walk_underwater")
|
||||
|
||||
override fun getId(): ResourceLocation {
|
||||
return ID
|
||||
}
|
||||
|
||||
override fun createInstance(pJson: JsonObject, pPlayer: EntityPredicate.Composite, pContext: DeserializationContext): Instance {
|
||||
return Instance((pJson["distance_to_travel"] as? JsonPrimitive)?.asDouble ?: throw JsonParseException("Invalid 'distance_to_travel' value"))
|
||||
}
|
||||
|
||||
fun trigger(player: ServerPlayer, travelled: Double) {
|
||||
trigger(player) {
|
||||
it.distanceToTravel <= travelled
|
||||
}
|
||||
}
|
||||
|
||||
class Instance(val distanceToTravel: Double) : AbstractCriterionTriggerInstance(ID, EntityPredicate.Composite.ANY) {
|
||||
override fun serializeToJson(pConditions: SerializationContext): JsonObject {
|
||||
return super.serializeToJson(pConditions).also {
|
||||
it["distance_to_travel"] = JsonPrimitive(distanceToTravel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
package ru.dbotthepony.mc.otm.triggers
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonSyntaxException
|
||||
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 net.minecraft.world.entity.monster.ElderGuardian
|
||||
import net.minecraftforge.event.entity.living.LivingDeathEvent
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
|
||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||
import ru.dbotthepony.mc.otm.core.asIterable
|
||||
import ru.dbotthepony.mc.otm.core.set
|
||||
import ru.dbotthepony.mc.otm.core.stream
|
||||
import ru.dbotthepony.mc.otm.registry.MRegistry
|
||||
import java.util.function.Predicate
|
||||
|
||||
object KillAsAndroidTrigger : SimpleCriterionTrigger<KillAsAndroidTrigger.Instance>() {
|
||||
val ID = ResourceLocation(OverdriveThatMatters.MOD_ID, "kill_as_android")
|
||||
|
||||
override fun getId(): ResourceLocation {
|
||||
return ID
|
||||
}
|
||||
|
||||
override fun createInstance(pJson: JsonObject, pPlayer: EntityPredicate.Composite, pContext: DeserializationContext): Instance {
|
||||
return Instance(
|
||||
predicate = EntityPredicate.Composite.fromJson(pJson, "predicate", pContext),
|
||||
playerPredicate = pPlayer,
|
||||
featurePredicate = (pJson["feature_predicate"] as? JsonObject)?.let(PredicateType::from) ?: throw JsonSyntaxException("Invalid 'feature_predicate': ${pJson["feature_predicate"]}")
|
||||
)
|
||||
}
|
||||
|
||||
enum class PredicateType(val factory: (JsonObject) -> FeaturePredicate) {
|
||||
ALWAYS({ Always }),
|
||||
HAS(::Has),
|
||||
NOT(::Not),
|
||||
AND(::And),
|
||||
OR(::OrPredicate);
|
||||
|
||||
companion object {
|
||||
fun from(json: JsonObject): FeaturePredicate {
|
||||
return when (val type = json["type"]?.asString?.lowercase()) {
|
||||
null -> throw JsonSyntaxException("Missing feature predicate 'type'")
|
||||
"has" -> HAS.factory(json)
|
||||
"and" -> AND.factory(json)
|
||||
"not" -> NOT.factory(json)
|
||||
"or" -> OR.factory(json)
|
||||
"always" -> ALWAYS.factory(json)
|
||||
else -> throw JsonSyntaxException("Unknown feature predicate $type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class FeaturePredicate : Predicate<MatteryPlayerCapability> {
|
||||
abstract val type: PredicateType
|
||||
|
||||
open fun toJson(): JsonObject {
|
||||
return JsonObject().also {
|
||||
it["type"] = type.name.lowercase()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Always : FeaturePredicate() {
|
||||
override val type: PredicateType
|
||||
get() = PredicateType.ALWAYS
|
||||
|
||||
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class Has : FeaturePredicate {
|
||||
private val resolved by lazy { MRegistry.ANDROID_FEATURES.getValue(name) }
|
||||
val name: ResourceLocation
|
||||
|
||||
constructor(name: ResourceLocation) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
constructor(value: JsonObject) {
|
||||
this.name = ResourceLocation.tryParse(value["name"]?.asString ?: throw JsonSyntaxException("Invalid android feature name: ${value["name"]}")) ?: throw JsonSyntaxException("Invalid android feature name ${value["name"]}")
|
||||
}
|
||||
|
||||
override val type: PredicateType
|
||||
get() = PredicateType.HAS
|
||||
|
||||
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||
return t.hasFeature(resolved ?: return false)
|
||||
}
|
||||
|
||||
override fun toJson(): JsonObject {
|
||||
return super.toJson().also {
|
||||
it["name"] = name.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Not(val parent: FeaturePredicate) : FeaturePredicate() {
|
||||
constructor(input: JsonObject) : this(PredicateType.from(input["parent"] as? JsonObject ?: throw JsonSyntaxException("Invalid parent")))
|
||||
|
||||
override val type: PredicateType
|
||||
get() = PredicateType.NOT
|
||||
|
||||
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||
return !parent.test(t)
|
||||
}
|
||||
|
||||
override fun toJson(): JsonObject {
|
||||
return super.toJson().also {
|
||||
it["parent"] = parent.toJson()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class And(children: Iterable<FeaturePredicate>) : FeaturePredicate() {
|
||||
constructor(input: JsonObject) : this((input["children"] as? JsonArray)?.stream()?.map { PredicateType.from(it as? JsonObject ?: throw JsonSyntaxException("Invalid element in children list: $it")) }?.asIterable() ?: throw JsonSyntaxException("Invalid children list"))
|
||||
|
||||
val children: ImmutableList<FeaturePredicate> = ImmutableList.copyOf(children)
|
||||
|
||||
override val type: PredicateType
|
||||
get() = PredicateType.AND
|
||||
|
||||
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||
return children.all { it.test(t) }
|
||||
}
|
||||
|
||||
override fun toJson(): JsonObject {
|
||||
return super.toJson().also {
|
||||
it["children"] = JsonArray().also {
|
||||
for (child in children) {
|
||||
it.add(child.toJson())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OrPredicate(children: Iterable<FeaturePredicate>) : FeaturePredicate() {
|
||||
constructor(input: JsonObject) : this((input["children"] as? JsonArray)?.stream()?.map { PredicateType.from(it as? JsonObject ?: throw JsonSyntaxException("Invalid element in children list: $it")) }?.asIterable() ?: throw JsonSyntaxException("Invalid children list"))
|
||||
|
||||
val children: ImmutableList<FeaturePredicate> = ImmutableList.copyOf(children)
|
||||
|
||||
override val type: PredicateType
|
||||
get() = PredicateType.OR
|
||||
|
||||
override fun test(t: MatteryPlayerCapability): Boolean {
|
||||
return children.any { it.test(t) }
|
||||
}
|
||||
|
||||
override fun toJson(): JsonObject {
|
||||
return super.toJson().also {
|
||||
it["children"] = JsonArray().also {
|
||||
for (child in children) {
|
||||
it.add(child.toJson())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Instance(
|
||||
val predicate: EntityPredicate.Composite = EntityPredicate.Composite.ANY,
|
||||
val featurePredicate: FeaturePredicate = Always,
|
||||
playerPredicate: EntityPredicate.Composite = EntityPredicate.Composite.ANY,
|
||||
) : AbstractCriterionTriggerInstance(ID, playerPredicate) {
|
||||
override fun serializeToJson(pConditions: SerializationContext): JsonObject {
|
||||
return super.serializeToJson(pConditions).also {
|
||||
it["predicate"] = predicate.toJson(pConditions)
|
||||
it["feature_predicate"] = featurePredicate.toJson()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onKill(event: LivingDeathEvent) {
|
||||
if (event.entity is ElderGuardian) {
|
||||
val killer = event.entity.combatTracker.killer
|
||||
|
||||
if (killer is ServerPlayer) {
|
||||
val data = killer.matteryPlayer ?: return
|
||||
|
||||
if (data.isAndroid) {
|
||||
val context = EntityPredicate.createContext(killer, event.entity)
|
||||
|
||||
trigger(killer) {
|
||||
it.predicate.matches(context) &&
|
||||
it.featurePredicate.test(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user