From 38334ec9e70de3157aece54e17176668d7976399 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 15 Sep 2022 20:29:51 +0700 Subject: [PATCH] Exosuit Probe drops! --- .../mc/otm/datagen/loot/LootModifiersData.kt | 52 +++++++++-- .../ru/dbotthepony/mc/otm/capability/Ext.kt | 13 +++ .../otm/data/ChanceWithPlaytimeCondition.kt | 77 ++++++++++++++++ .../kotlin/ru/dbotthepony/mc/otm/data/Ext.kt | 13 +++ .../mc/otm/data/HasExosuitCondition.kt | 40 ++++++++ .../mc/otm/data/ItemInInventoryCondition.kt | 91 +++++++++++++++++++ .../dbotthepony/mc/otm/data/ItemStackCodec.kt | 39 ++++++++ .../mc/otm/data/KilledByRealPlayer.kt | 37 ++++++++ .../mc/otm/data/LootTableAppender.kt | 6 +- .../mc/otm/data/LootTableBasicAppender.kt | 38 ++++++++ .../mc/otm/registry/LootModifiers.kt | 3 +- .../mc/otm/registry/MLootItemConditions.kt | 28 ++++++ .../dbotthepony/mc/otm/registry/MRegistry.kt | 1 + 13 files changed, 426 insertions(+), 12 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/ChanceWithPlaytimeCondition.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/Ext.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/HasExosuitCondition.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/ItemInInventoryCondition.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/ItemStackCodec.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/KilledByRealPlayer.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/LootTableBasicAppender.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/registry/MLootItemConditions.kt diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootModifiersData.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootModifiersData.kt index eb9bfb77e..aa0114199 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootModifiersData.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootModifiersData.kt @@ -1,45 +1,61 @@ package ru.dbotthepony.mc.otm.datagen.loot import net.minecraft.resources.ResourceLocation +import net.minecraft.world.entity.EntityType import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition +import net.minecraft.world.level.storage.loot.predicates.LootItemKilledByPlayerCondition import net.minecraftforge.common.loot.LootTableIdCondition +import ru.dbotthepony.mc.otm.data.ChanceWithPlaytimeCondition +import ru.dbotthepony.mc.otm.data.HasExosuitCondition +import ru.dbotthepony.mc.otm.data.ItemInInventoryCondition +import ru.dbotthepony.mc.otm.data.KilledByRealPlayer import ru.dbotthepony.mc.otm.data.LootTableBasicAppender +import ru.dbotthepony.mc.otm.data.LootTableSeparatedAppender import ru.dbotthepony.mc.otm.registry.MItems +fun LootTableIdCondition(location: String): LootItemCondition { + return LootTableIdCondition.Builder(ResourceLocation("minecraft", location)).build() +} + +fun LootTableIdCondition(location: ResourceLocation): LootItemCondition { + return LootTableIdCondition.Builder(location).build() +} + fun addLootModifiers(it: LootModifiers) { - it.add("dungeon_pill", LootTableBasicAppender( + it.add("dungeon_pill", LootTableSeparatedAppender( arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/simple_dungeon")).build()), ItemStack(MItems.PILL_ANDROID, 1) to 0.4, ItemStack(MItems.PILL_HEAL, 2) to 0.5, ItemStack(MItems.PILL_HEAL, 1) to 0.75, )) - it.add("mineshaft_pill", LootTableBasicAppender( + it.add("mineshaft_pill", LootTableSeparatedAppender( arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/abandoned_mineshaft")).build()), ItemStack(MItems.PILL_ANDROID, 1) to 0.075, ItemStack(MItems.PILL_HEAL, 2) to 0.1, ItemStack(MItems.PILL_HEAL, 1) to 0.4, )) - it.add("mineshaft_nutrient_paste", LootTableBasicAppender( + it.add("mineshaft_nutrient_paste", LootTableSeparatedAppender( arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/abandoned_mineshaft")).build()), ItemStack(MItems.NUTRIENT_PASTE, 6) to 0.5, ItemStack(MItems.NUTRIENT_PASTE, 8) to 0.35, ItemStack(MItems.NUTRIENT_PASTE, 12) to 0.15, )) - it.add("desert_pyramid_pill", LootTableBasicAppender( + it.add("desert_pyramid_pill", LootTableSeparatedAppender( arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/abandoned_mineshaft")).build()), ItemStack(MItems.PILL_ANDROID, 1) to 0.05, ItemStack(MItems.PILL_HEAL, 1) to 0.3, )) - it.add("jungle_temple_pill", LootTableBasicAppender( + it.add("jungle_temple_pill", LootTableSeparatedAppender( arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/jungle_temple")).build()), ItemStack(MItems.PILL_ANDROID, 1) to 0.5 )) - it.add("end_city_modifications", LootTableBasicAppender( + it.add("end_city_modifications", LootTableSeparatedAppender( arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/end_city_treasure")).build()), ItemStack(MItems.PILL_ANDROID, 1) to 0.1, ItemStack(MItems.PILL_HUMANE, 1) to 0.3, @@ -47,16 +63,36 @@ fun addLootModifiers(it: LootModifiers) { ItemStack(MItems.ZPM_BATTERY, 1) to 0.005, )) - it.add("shipwreck_supply_pill", LootTableBasicAppender( + it.add("shipwreck_supply_pill", LootTableSeparatedAppender( arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/shipwreck_supply")).build()), ItemStack(MItems.PILL_HUMANE, 1) to 0.4, ItemStack(MItems.PILL_HEAL, 1) to 0.6, )) - it.add("shipwreck_supply_nutrient_paste", LootTableBasicAppender( + it.add("shipwreck_supply_nutrient_paste", LootTableSeparatedAppender( arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/shipwreck_supply")).build()), ItemStack(MItems.NUTRIENT_PASTE, 12) to 0.85, ItemStack(MItems.NUTRIENT_PASTE, 24) to 0.35, ItemStack(MItems.NUTRIENT_PASTE, 38) to 0.1, )) + + it.add("exosuit_probe_enderman_drop", LootTableBasicAppender( + arrayOf( + LootTableIdCondition(EntityType.ENDERMAN.defaultLootTable), + HasExosuitCondition.INVERTED, + KilledByRealPlayer, + ChanceWithPlaytimeCondition( + minPlaytime = 20 * 60 * 10, + maxPlaytime = 20 * 60 * 120, + minProbability = 0.1, + maxProbability = 0.5, + ), + ItemInInventoryCondition( + ItemStack(MItems.EXOSUIT_PROBE) + ).invert().build() + ), + listOf( + ItemStack(MItems.EXOSUIT_PROBE) + ) + )) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt index 23ef14317..6e0ba62d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.capability +import com.google.common.collect.Streams import net.minecraft.core.Direction import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack @@ -11,9 +12,11 @@ import net.minecraftforge.fml.ModList import ru.dbotthepony.mc.otm.compat.mekanism.getMekanismEnergySided import ru.dbotthepony.mc.otm.compat.mekanism.mekanismEnergy import ru.dbotthepony.mc.otm.container.iterator +import ru.dbotthepony.mc.otm.container.stream import ru.dbotthepony.mc.otm.core.iterator import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.orNull +import java.util.stream.Stream val ICapabilityProvider.matteryPlayer: MatteryPlayerCapability? get() = getCapability(MatteryCapability.MATTERY_PLAYER).orNull() @@ -145,6 +148,16 @@ fun ICapabilityProvider.getMatteryEnergySided(side: Direction? = null): LazyOpti return LazyOptional.empty() } +fun Player.itemStream(): Stream { + matteryPlayer?.let { + if (it.hasExoSuit) { + return Streams.concat(inventory.stream(), it.exoSuitContainer.stream()) + } + } + + return inventory.stream() +} + fun Player.extendedItemIterator(): MutableIterator { return object : MutableIterator { private val regular = this@extendedItemIterator.inventory.iterator() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/ChanceWithPlaytimeCondition.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/ChanceWithPlaytimeCondition.kt new file mode 100644 index 000000000..4922085f4 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/ChanceWithPlaytimeCondition.kt @@ -0,0 +1,77 @@ +package ru.dbotthepony.mc.otm.data + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import com.google.gson.JsonSerializationContext +import net.minecraft.world.level.storage.loot.LootContext +import net.minecraft.world.level.storage.loot.Serializer +import net.minecraft.world.level.storage.loot.parameters.LootContextParams +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType +import ru.dbotthepony.mc.otm.capability.matteryPlayer +import ru.dbotthepony.mc.otm.core.set +import ru.dbotthepony.mc.otm.registry.MLootItemConditions + +class ChanceWithPlaytimeCondition( + val minPlaytime: Int = 0, + val maxPlaytime: Int, + val minProbability: Double, + val maxProbability: Double +) : LootItemCondition, LootItemCondition.Builder { + init { + require(minPlaytime <= maxPlaytime) { "Invalid playtime range: min $minPlaytime, max $maxPlaytime" } + require(minProbability <= maxProbability) { "Invalid probability range: min $minProbability, max $maxProbability" } + + require(maxProbability <= 1.0) { "Excessive max probability: $maxProbability" } + } + + override fun test(t: LootContext): Boolean { + return t[LootContextParams.LAST_DAMAGE_PLAYER]?.matteryPlayer?.let { + val chance: Double + + if (it.ticksIExist < minPlaytime) { + chance = minProbability + } else if (it.ticksIExist >= maxPlaytime) { + chance = maxProbability + } else { + chance = minProbability + (maxProbability - minProbability) * (it.ticksIExist - minPlaytime).toDouble() / (maxPlaytime - minPlaytime).toDouble() + } + + return t.random.nextDouble() <= chance + } ?: (t.random.nextDouble() <= minProbability) + } + + override fun getType(): LootItemConditionType { + return MLootItemConditions.CHANCE_WITH_PLAYTIME + } + + override fun build(): LootItemCondition { + return this + } + + companion object : Serializer { + override fun serialize( + p_79325_: JsonObject, + p_79326_: ChanceWithPlaytimeCondition, + p_79327_: JsonSerializationContext + ) { + p_79325_["minPlaytime"] = JsonPrimitive(p_79326_.minPlaytime) + p_79325_["maxPlaytime"] = JsonPrimitive(p_79326_.maxPlaytime) + p_79325_["minProbability"] = JsonPrimitive(p_79326_.minProbability) + p_79325_["maxProbability"] = JsonPrimitive(p_79326_.maxProbability) + } + + override fun deserialize( + p_79323_: JsonObject, + p_79324_: JsonDeserializationContext + ): ChanceWithPlaytimeCondition { + return ChanceWithPlaytimeCondition( + minPlaytime = p_79323_["minPlaytime"].asInt, + maxPlaytime = p_79323_["maxPlaytime"].asInt, + minProbability = p_79323_["minProbability"].asDouble, + maxProbability = p_79323_["maxProbability"].asDouble, + ) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/Ext.kt new file mode 100644 index 000000000..bd3f096c1 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/Ext.kt @@ -0,0 +1,13 @@ +package ru.dbotthepony.mc.otm.data + +import com.mojang.serialization.DataResult +import net.minecraft.world.level.storage.loot.LootContext +import net.minecraft.world.level.storage.loot.parameters.LootContextParam + +operator fun LootContext.get(param: LootContextParam): T? { + return getParamOrNull(param) +} + +fun DataResult.getOrNull(): T? { + return get().left().orElse(null) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/HasExosuitCondition.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/HasExosuitCondition.kt new file mode 100644 index 000000000..3f866f7e6 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/HasExosuitCondition.kt @@ -0,0 +1,40 @@ +package ru.dbotthepony.mc.otm.data + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonObject +import com.google.gson.JsonSerializationContext +import net.minecraft.world.level.storage.loot.LootContext +import net.minecraft.world.level.storage.loot.Serializer +import net.minecraft.world.level.storage.loot.parameters.LootContextParams +import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType +import ru.dbotthepony.mc.otm.capability.matteryPlayer +import ru.dbotthepony.mc.otm.registry.MLootItemConditions + +object HasExosuitCondition : LootItemCondition, Serializer, LootItemCondition.Builder { + override fun test(t: LootContext): Boolean { + t[LootContextParams.LAST_DAMAGE_PLAYER]?.matteryPlayer?.let { + return it.hasExoSuit + } + + return false + } + + override fun getType(): LootItemConditionType { + return MLootItemConditions.HAS_EXOSUIT + } + + override fun serialize(p_79325_: JsonObject, p_79326_: HasExosuitCondition, p_79327_: JsonSerializationContext) { + } + + override fun deserialize(p_79323_: JsonObject, p_79324_: JsonDeserializationContext): HasExosuitCondition { + return this + } + + override fun build(): LootItemCondition { + return this + } + + val INVERTED: LootItemCondition = InvertedLootItemCondition.invert(this).build() +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/ItemInInventoryCondition.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/ItemInInventoryCondition.kt new file mode 100644 index 000000000..e53e47492 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/ItemInInventoryCondition.kt @@ -0,0 +1,91 @@ +package ru.dbotthepony.mc.otm.data + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import com.google.gson.JsonSerializationContext +import com.google.gson.JsonSyntaxException +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.level.storage.loot.LootContext +import net.minecraft.world.level.storage.loot.Serializer +import net.minecraft.world.level.storage.loot.parameters.LootContextParams +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType +import net.minecraftforge.registries.ForgeRegistries +import ru.dbotthepony.mc.otm.capability.itemStream +import ru.dbotthepony.mc.otm.core.registryName +import ru.dbotthepony.mc.otm.core.set +import ru.dbotthepony.mc.otm.registry.MLootItemConditions + +class ItemInInventoryCondition( + val item: ItemStack, + val matchDamage: Boolean = false, + val matchNBT: Boolean = false +) : LootItemCondition, LootItemCondition.Builder { + override fun test(t: LootContext): Boolean { + val matches = t[LootContextParams.LAST_DAMAGE_PLAYER]?.itemStream()?.filter { + if (matchDamage && matchNBT) { + it.item == item.item && it.tag == item.tag && it.damageValue == item.damageValue + } else if (matchDamage) { + it.item == item.item && it.damageValue == item.damageValue + } else if (matchNBT) { + it.item == item.item && it.tag == item.tag + } else { + it.item == item.item + } + } ?: return false + + var count = 0 + + for (match in matches) { + count += match.count + + if (count >= item.count) { + return true + } + } + + return false + } + + override fun getType(): LootItemConditionType { + return MLootItemConditions.ITEM_IN_INVENTORY + } + + override fun build(): LootItemCondition { + return this + } + + companion object : Serializer { + override fun serialize( + p_79325_: JsonObject, + p_79326_: ItemInInventoryCondition, + p_79327_: JsonSerializationContext + ) { + p_79325_["item"] = JsonPrimitive(p_79326_.item.item.registryName!!.toString()) + p_79325_["itemCount"] = JsonPrimitive(p_79326_.item.count) + p_79325_["matchDamage"] = JsonPrimitive(p_79326_.matchDamage) + p_79325_["matchNBT"] = JsonPrimitive(p_79326_.matchNBT) + } + + override fun deserialize(p_79323_: JsonObject, p_79324_: JsonDeserializationContext): ItemInInventoryCondition { + val item = p_79323_["item"]?.asString ?: throw JsonSyntaxException("Missing item") + val itemCount = p_79323_["itemCount"]?.asInt ?: throw JsonSyntaxException("Missing itemCount") + val matchDamage = p_79323_["matchDamage"]?.asBoolean ?: throw JsonSyntaxException("Missing matchDamage") + val matchNBT = p_79323_["matchNBT"]?.asBoolean ?: throw JsonSyntaxException("Missing matchNBT") + + val getItem = ForgeRegistries.ITEMS.getValue(ResourceLocation(item)) + + if (getItem == null || getItem == Items.AIR) { + throw JsonSyntaxException("Invalid item $item") + } + + return ItemInInventoryCondition( + ItemStack(getItem, itemCount), + matchDamage, matchNBT + ) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/ItemStackCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/ItemStackCodec.kt new file mode 100644 index 000000000..df087bd9a --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/ItemStackCodec.kt @@ -0,0 +1,39 @@ +package ru.dbotthepony.mc.otm.data + +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import com.mojang.serialization.codecs.ListCodec +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraftforge.registries.ForgeRegistries + +object ItemStackCodec : Codec { + override fun encode(input: ItemStack, ops: DynamicOps, prefix: T): DataResult { + require(prefix == ops.empty()) { "Non-empty prefix: $prefix" } + + return ForgeRegistries.ITEMS.codec.encode(input.item, ops, ops.empty()).map { + ops.createMap(mapOf( + ops.createString("id") to it, + ops.createString("count") to ops.createInt(input.count) + )) + } + } + + override fun decode(ops: DynamicOps, input: T): DataResult> { + return ops.getMap(input).flatMap { + val item = it["id"]?.let { ForgeRegistries.ITEMS.codec.decode(ops, it) }?.result()?.orElse(null)?.first + val count = it["count"]?.let(ops::getNumberValue)?.result()?.orElse(null)?.toInt() ?: return@flatMap DataResult.error("Invalid item count") + + if (item == null || item == Items.AIR) { + return@flatMap DataResult.error("Unknown item type $item") + } + + DataResult.success(ItemStack(item, count)) + }.map { Pair.of(it, ops.empty()) } + } + + val LIST = ListCodec(this) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/KilledByRealPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/KilledByRealPlayer.kt new file mode 100644 index 000000000..8f7c7fbe6 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/KilledByRealPlayer.kt @@ -0,0 +1,37 @@ +package ru.dbotthepony.mc.otm.data + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonObject +import com.google.gson.JsonSerializationContext +import net.minecraft.world.level.storage.loot.LootContext +import net.minecraft.world.level.storage.loot.Serializer +import net.minecraft.world.level.storage.loot.parameters.LootContextParams +import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemCondition +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType +import net.minecraftforge.common.util.FakePlayer +import ru.dbotthepony.mc.otm.capability.matteryPlayer +import ru.dbotthepony.mc.otm.registry.MLootItemConditions + +object KilledByRealPlayer : LootItemCondition, Serializer, LootItemCondition.Builder { + override fun test(t: LootContext): Boolean { + return t.hasParam(LootContextParams.LAST_DAMAGE_PLAYER) && t[LootContextParams.LAST_DAMAGE_PLAYER] !is FakePlayer + } + + override fun getType(): LootItemConditionType { + return MLootItemConditions.HAS_EXOSUIT + } + + override fun serialize(p_79325_: JsonObject, p_79326_: KilledByRealPlayer, p_79327_: JsonSerializationContext) { + } + + override fun deserialize(p_79323_: JsonObject, p_79324_: JsonDeserializationContext): KilledByRealPlayer { + return this + } + + override fun build(): LootItemCondition { + return this + } + + val INVERTED: LootItemCondition = InvertedLootItemCondition.invert(this).build() +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/LootTableAppender.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/LootTableAppender.kt index 47a4e6b68..4fbf16fca 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/data/LootTableAppender.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/LootTableAppender.kt @@ -64,7 +64,7 @@ class LootTableAppender(conditions: Array, private vararg } } -class LootTableBasicAppender(conditions: Array, entries: List>) : LootModifier(conditions) { +class LootTableSeparatedAppender(conditions: Array, entries: List>) : LootModifier(conditions) { constructor(conditions: Array, vararg entries: Pair) : this(conditions, entries.toList()) private val entries = ImmutableList.copyOf(entries) @@ -135,11 +135,11 @@ class LootTableBasicAppender(conditions: Array, entries: }) } - val CODEC: Codec by lazy { + val CODEC: Codec by lazy { RecordCodecBuilder.create { codecStart(it).and( ItemPairListCodec.fieldOf("entries").forGetter { appender -> appender.entries } - ).apply(it, ::LootTableBasicAppender) + ).apply(it, ::LootTableSeparatedAppender) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/LootTableBasicAppender.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/LootTableBasicAppender.kt new file mode 100644 index 000000000..63b45ea17 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/LootTableBasicAppender.kt @@ -0,0 +1,38 @@ +package ru.dbotthepony.mc.otm.data + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.storage.loot.LootContext +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition +import net.minecraftforge.common.loot.IGlobalLootModifier +import net.minecraftforge.common.loot.LootModifier +import ru.dbotthepony.mc.otm.core.ImmutableList + +class LootTableBasicAppender( + conditions: Array, + items: List +) : LootModifier(conditions) { + private val items = ImmutableList(items.size) { items[it].copy() } + + override fun codec(): Codec { + return CODEC + } + + override fun doApply( + generatedLoot: ObjectArrayList, + context: LootContext + ): ObjectArrayList { + generatedLoot.addAll(items) + return generatedLoot + } + + companion object { + val CODEC: Codec by lazy { + RecordCodecBuilder.create { + codecStart(it).and(ItemStackCodec.LIST.fieldOf("items").forGetter { it.items }).apply(it, ::LootTableBasicAppender) + } + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LootModifiers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LootModifiers.kt index e85211d21..7307b42d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LootModifiers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LootModifiers.kt @@ -1,18 +1,19 @@ package ru.dbotthepony.mc.otm.registry import net.minecraftforge.eventbus.api.IEventBus -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.ForgeRegistries import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.data.LootTableAppender import ru.dbotthepony.mc.otm.data.LootTableBasicAppender +import ru.dbotthepony.mc.otm.data.LootTableSeparatedAppender object LootModifiers { private val registry = DeferredRegister.create(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, OverdriveThatMatters.MOD_ID) init { registry.register("loot_appender") { LootTableAppender.CODEC } + registry.register("loot_appender_separated") { LootTableSeparatedAppender.CODEC } registry.register("loot_appender_basic") { LootTableBasicAppender.CODEC } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MLootItemConditions.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MLootItemConditions.kt new file mode 100644 index 000000000..0c63f1de8 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MLootItemConditions.kt @@ -0,0 +1,28 @@ +package ru.dbotthepony.mc.otm.registry + +import net.minecraft.core.Registry +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent +import net.minecraftforge.registries.RegisterEvent +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.data.ChanceWithPlaytimeCondition +import ru.dbotthepony.mc.otm.data.HasExosuitCondition +import ru.dbotthepony.mc.otm.data.ItemInInventoryCondition +import ru.dbotthepony.mc.otm.data.KilledByRealPlayer + +object MLootItemConditions { + val HAS_EXOSUIT = LootItemConditionType(HasExosuitCondition) + val KILLED_BY_REAL_PLAYER = LootItemConditionType(KilledByRealPlayer) + val CHANCE_WITH_PLAYTIME = LootItemConditionType(ChanceWithPlaytimeCondition) + val ITEM_IN_INVENTORY = LootItemConditionType(ItemInInventoryCondition) + + internal fun register(event: RegisterEvent) { + if (event.getVanillaRegistry() == Registry.LOOT_CONDITION_TYPE) { + Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "has_exosuit"), HAS_EXOSUIT) + Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "chance_with_playtime"), CHANCE_WITH_PLAYTIME) + Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "item_in_inventory"), ITEM_IN_INVENTORY) + Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "killed_by_real_player"), KILLED_BY_REAL_PLAYER) + } + } +} 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 0cda2d2ae..b30427c48 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt @@ -223,6 +223,7 @@ object MRegistry { fun initialize(bus: IEventBus) { bus.addListener(this::register) bus.addListener(MStats::registerVanilla) + bus.addListener(MLootItemConditions::register) MBlocks.register(bus) MBlockEntities.register(bus)