Get rid of IRandomizableItem, add proper data driven exopack slot upgrades

This commit is contained in:
DBotThePony 2023-05-09 10:24:59 +07:00
parent f71bed5dae
commit eabbd040d2
Signed by: DBot
GPG Key ID: DCC23B5715498507
7 changed files with 97 additions and 157 deletions

View File

@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.datagen.loot
import net.minecraft.advancements.critereon.StatePropertiesPredicate import net.minecraft.advancements.critereon.StatePropertiesPredicate
import net.minecraft.util.StringRepresentable import net.minecraft.util.StringRepresentable
import net.minecraft.world.item.Rarity
import net.minecraft.world.level.ItemLike import net.minecraft.world.level.ItemLike
import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.properties.Property import net.minecraft.world.level.block.state.properties.Property
@ -17,7 +16,6 @@ import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue import net.minecraft.world.level.storage.loot.providers.number.ConstantValue
import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator
import ru.dbotthepony.mc.otm.data.condition.ChanceCondition import ru.dbotthepony.mc.otm.data.condition.ChanceCondition
import ru.dbotthepony.mc.otm.data.loot.RandomizerFunction
inline fun LootTable.Builder.lootPool(configurator: LootPool.Builder.() -> Unit): LootTable.Builder = withPool(LootPool.lootPool().also(configurator)) inline fun LootTable.Builder.lootPool(configurator: LootPool.Builder.() -> Unit): LootTable.Builder = withPool(LootPool.lootPool().also(configurator))
inline fun LootTable.Builder.singleItem(item: ItemLike, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit): LootTable.Builder { inline fun LootTable.Builder.singleItem(item: ItemLike, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit): LootTable.Builder {
@ -29,18 +27,6 @@ inline fun LootTable.Builder.singleItem(item: ItemLike, configurator: LootPoolSi
inline fun lootPool(configurator: LootPool.Builder.() -> Unit): LootPool = LootPool.lootPool().also(configurator).build() inline fun lootPool(configurator: LootPool.Builder.() -> Unit): LootPool = LootPool.lootPool().also(configurator).build()
inline fun singleItem(item: ItemLike, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit): LootPool = lootPool { item(item, configurator) } inline fun singleItem(item: ItemLike, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit): LootPool = lootPool { item(item, configurator) }
fun singleRandomizedItem(item: ItemLike, rarity: Rarity = Rarity.COMMON, chance: Double? = null): LootPool {
return lootPool {
item(item) {
apply(RandomizerFunction.valueOf(rarity))
if (chance != null) {
chanceCondition(chance)
}
}
}
}
inline fun LootPool.Builder.item(item: ItemLike, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit) { inline fun LootPool.Builder.item(item: ItemLike, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit) {
add(LootItem.lootTableItem(item).also(configurator)) add(LootItem.lootTableItem(item).also(configurator))
} }

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.datagen.loot package ru.dbotthepony.mc.otm.datagen.loot
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.util.valueproviders.UniformInt
import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.EntityType
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity import net.minecraft.world.item.Rarity
@ -14,8 +15,8 @@ import ru.dbotthepony.mc.otm.data.condition.HasExoPackCondition
import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition
import ru.dbotthepony.mc.otm.data.condition.KilledByRealPlayerOrIndirectly import ru.dbotthepony.mc.otm.data.condition.KilledByRealPlayerOrIndirectly
import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender
import ru.dbotthepony.mc.otm.data.loot.RandomizerFunction
import ru.dbotthepony.mc.otm.item.ProceduralBatteryItem import ru.dbotthepony.mc.otm.item.ProceduralBatteryItem
import ru.dbotthepony.mc.otm.item.exopack.ProceduralExoPackSlotUpgradeItem
import ru.dbotthepony.mc.otm.registry.MItems import ru.dbotthepony.mc.otm.registry.MItems
@Suppress("FunctionName") @Suppress("FunctionName")
@ -29,24 +30,32 @@ fun LootTableIdCondition(location: ResourceLocation): LootItemCondition {
} }
fun addLootModifiers(it: LootModifiers) { fun addLootModifiers(it: LootModifiers) {
it.add("dungeon_exosuit", LootPoolAppender( it.add("dungeon_exopack", LootPoolAppender(
arrayOf(LootTableIdCondition(BuiltInLootTables.SIMPLE_DUNGEON)), arrayOf(LootTableIdCondition(BuiltInLootTables.SIMPLE_DUNGEON)),
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) { singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.2) chanceCondition(0.2)
apply(RandomizerFunction.COMMON) apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(6, 9)))
}, },
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) { singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.05) chanceCondition(0.05)
apply(RandomizerFunction.UNCOMMON) apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(9, 18)))
}, },
)) ))
it.add("mineshaft_additions", LootPoolAppender( it.add("mineshaft_additions", LootPoolAppender(
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)), arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.1),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.1, rarity = Rarity.UNCOMMON), singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.1)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(4, 8)))
},
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.1)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(4, 10)))
},
singleItem(MItems.PROCEDURAL_BATTERY) { singleItem(MItems.PROCEDURAL_BATTERY) {
chanceCondition(0.15) chanceCondition(0.15)
@ -61,21 +70,49 @@ fun addLootModifiers(it: LootModifiers) {
it.add("desert_pyramid_exosuit", LootPoolAppender( it.add("desert_pyramid_exosuit", LootPoolAppender(
arrayOf(LootTableIdCondition(BuiltInLootTables.DESERT_PYRAMID)), arrayOf(LootTableIdCondition(BuiltInLootTables.DESERT_PYRAMID)),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.15, rarity = Rarity.UNCOMMON),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.25, rarity = Rarity.COMMON) singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.1)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(12, 18)))
},
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.25)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(4, 9)))
},
)) ))
it.add("jungle_temple_exosuit", LootPoolAppender( it.add("jungle_temple_exosuit", LootPoolAppender(
arrayOf(LootTableIdCondition(BuiltInLootTables.JUNGLE_TEMPLE)), arrayOf(LootTableIdCondition(BuiltInLootTables.JUNGLE_TEMPLE)),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.15, rarity = Rarity.UNCOMMON),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.35, rarity = Rarity.RARE) singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.15)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(9, 18)))
},
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.35)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(16, 28), UniformInt.of(2, 6)))
},
)) ))
it.add("end_city_exosuit", LootPoolAppender( it.add("end_city_exosuit", LootPoolAppender(
arrayOf(LootTableIdCondition(BuiltInLootTables.END_CITY_TREASURE)), arrayOf(LootTableIdCondition(BuiltInLootTables.END_CITY_TREASURE)),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.4, rarity = Rarity.UNCOMMON),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.2, rarity = Rarity.RARE), singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.15, rarity = Rarity.EPIC), chanceCondition(0.4)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(9, 18)))
},
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.2)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(14, 27), UniformInt.of(2, 6)))
},
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.1)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(27, 56), UniformInt.of(2, 6)))
},
)) ))
it.add("dungeon_pill", PlainLootAppender( it.add("dungeon_pill", PlainLootAppender(

View File

@ -1,8 +1,10 @@
package ru.dbotthepony.mc.otm.data package ru.dbotthepony.mc.otm.data
import com.mojang.serialization.DataResult import com.mojang.serialization.DataResult
import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.parameters.LootContextParam import net.minecraft.world.level.storage.loot.parameters.LootContextParam
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
operator fun <T> LootContext.get(param: LootContextParam<T>): T? { operator fun <T> LootContext.get(param: LootContextParam<T>): T? {
return getParamOrNull(param) return getParamOrNull(param)
@ -11,3 +13,14 @@ operator fun <T> LootContext.get(param: LootContextParam<T>): T? {
fun <T> DataResult<T>.getOrNull(): T? { fun <T> DataResult<T>.getOrNull(): T? {
return get().left().orElse(null) return get().left().orElse(null)
} }
fun LootContext.findPlayer(): Player? {
return getParamOrNull(LootContextParams.DIRECT_KILLER_ENTITY).let {
if (it != null)
it as? Player
else
getParamOrNull(LootContextParams.KILLER_ENTITY).let {
if (it != null) it as? Player else getParamOrNull(LootContextParams.THIS_ENTITY) as? Player
}
}
}

View File

@ -1,11 +0,0 @@
package ru.dbotthepony.mc.otm.data.loot
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.level.ItemLike
interface IRandomizableItem {
fun randomize(itemStack: ItemStack, random: RandomSource, ply: Player?, rarity: Rarity = Rarity.COMMON)
}

View File

@ -1,82 +0,0 @@
package ru.dbotthepony.mc.otm.data.loot
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.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.Serializer
import net.minecraft.world.level.storage.loot.functions.LootItemFunction
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes
enum class RandomizerFunction(val rarity: Rarity) : LootItemFunction, LootItemFunction.Builder {
COMMON(Rarity.COMMON),
UNCOMMON(Rarity.UNCOMMON),
RARE(Rarity.RARE),
EPIC(Rarity.EPIC);
override fun apply(itemStack: ItemStack, context: LootContext): ItemStack {
val randomizer = itemStack.item as? IRandomizableItem
if (randomizer == null) {
LOGGER.error("${itemStack.item} does not implement ${IRandomizableItem::class.qualifiedName}! Can not randomize $itemStack!")
return itemStack
}
val random = context.random
val player =
context.getParamOrNull(LootContextParams.DIRECT_KILLER_ENTITY).let {
if (it != null)
it as? Player
else
context.getParamOrNull(LootContextParams.KILLER_ENTITY).let {
if (it != null)
it as? Player
else
context.getParamOrNull(LootContextParams.THIS_ENTITY) as? Player
}
}
randomizer.randomize(itemStack, random, player, rarity)
return itemStack
}
override fun getType(): LootItemFunctionType {
return MItemFunctionTypes.RANDOMIZER
}
override fun build(): LootItemFunction {
return this
}
companion object : Serializer<RandomizerFunction> {
fun valueOf(rarity: Rarity): RandomizerFunction {
return when(rarity) {
Rarity.COMMON -> COMMON
Rarity.UNCOMMON -> UNCOMMON
Rarity.RARE -> RARE
Rarity.EPIC -> EPIC
}
}
override fun serialize(p_79325_: JsonObject, p_79326_: RandomizerFunction, p_79327_: JsonSerializationContext) {
p_79325_["rarity"] = JsonPrimitive(p_79326_.rarity.name)
}
override fun deserialize(p_79323_: JsonObject, p_79324_: JsonDeserializationContext): RandomizerFunction {
return valueOf(Rarity.valueOf(p_79323_["rarity"]?.asString ?: throw JsonSyntaxException("Invalid rarity json element")))
}
private val LOGGER = LogManager.getLogger()
}
}

View File

@ -1,27 +1,48 @@
package ru.dbotthepony.mc.otm.item.exopack package ru.dbotthepony.mc.otm.item.exopack
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.util.RandomSource import net.minecraft.util.valueproviders.ConstantInt
import net.minecraft.world.entity.player.Player import net.minecraft.util.valueproviders.IntProvider
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity import net.minecraft.world.item.Rarity
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.functions.LootItemFunction
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.tagNotNull import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.data.loot.IRandomizableItem import ru.dbotthepony.mc.otm.data.Codec2Serializer
import ru.dbotthepony.mc.otm.registry.MItemFunctionTypes
import java.util.* import java.util.*
class ProceduralExoPackSlotUpgradeItem : AbstractExoPackSlotUpgradeItem(defaultProperties()), IRandomizableItem { class ProceduralExoPackSlotUpgradeItem : AbstractExoPackSlotUpgradeItem(defaultProperties()) {
override fun getRarity(itemStack: ItemStack): Rarity { class Randomizer(val slots: IntProvider, val luckBias: IntProvider = ConstantInt.ZERO) : LootItemFunction, LootItemFunction.Builder {
return when (slotCount(itemStack)) { override fun apply(t: ItemStack, u: LootContext): ItemStack {
in 0 .. 9 -> Rarity.COMMON t.tagNotNull[SLOT_COUNT_KEY] = slots.sample(u.random) + (luckBias.sample(u.random) * u.luck / 1024f).coerceAtLeast(0f).toInt()
in 10 .. 18 -> Rarity.UNCOMMON return t
in 19 .. 27 -> Rarity.RARE }
in 28 .. 36 -> Rarity.EPIC
else -> Rarity.EPIC override fun getType(): LootItemFunctionType {
return MItemFunctionTypes.PROCEDURAL_EXOPACK_UPGRADE
}
override fun build(): LootItemFunction {
return this
}
companion object {
val SERIALIZER = Codec2Serializer<Randomizer>(
RecordCodecBuilder.create {
it.group(
IntProvider.CODEC.fieldOf("slots").forGetter(Randomizer::slots),
IntProvider.CODEC.optionalFieldOf("luck_bias", ConstantInt.ZERO).forGetter(Randomizer::luckBias),
).apply(it, ::Randomizer)
}
)
} }
} }
@ -50,30 +71,6 @@ class ProceduralExoPackSlotUpgradeItem : AbstractExoPackSlotUpgradeItem(defaultP
} }
} }
override fun randomize(itemStack: ItemStack, random: RandomSource, ply: Player?, rarity: Rarity) {
var amount = random.nextIntBetweenInclusive(6, 9)
val luck = (ply?.luck ?: 0f) * 0.3f
val finalLuck = (0.5f - (luck / 512f).coerceAtLeast(-0.3f).coerceAtMost(0.3f))
if (random.nextFloat() >= finalLuck && rarity.ordinal >= Rarity.UNCOMMON.ordinal) {
amount += random.nextIntBetweenInclusive(4, 9)
if (random.nextFloat() >= finalLuck && rarity.ordinal >= Rarity.RARE.ordinal) {
amount += random.nextIntBetweenInclusive(6, 9)
if (random.nextFloat() >= finalLuck && rarity.ordinal >= Rarity.EPIC.ordinal) {
amount += random.nextIntBetweenInclusive(8, 12)
if (random.nextFloat() >= finalLuck) {
amount += random.nextIntBetweenInclusive(14, 18)
}
}
}
}
itemStack.tagNotNull[SLOT_COUNT_KEY] = amount
}
companion object { companion object {
const val SLOT_COUNT_KEY = "slotCount" const val SLOT_COUNT_KEY = "slotCount"
const val UUID_KEY = "uuid" const val UUID_KEY = "uuid"

View File

@ -6,15 +6,15 @@ import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.DeferredRegister
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.data.loot.CopyTileNbtFunction import ru.dbotthepony.mc.otm.data.loot.CopyTileNbtFunction
import ru.dbotthepony.mc.otm.data.loot.RandomizerFunction
import ru.dbotthepony.mc.otm.item.ProceduralBatteryItem import ru.dbotthepony.mc.otm.item.ProceduralBatteryItem
import ru.dbotthepony.mc.otm.item.exopack.ProceduralExoPackSlotUpgradeItem
object MItemFunctionTypes { object MItemFunctionTypes {
private val registry = DeferredRegister.create(Registries.LOOT_FUNCTION_TYPE, OverdriveThatMatters.MOD_ID) private val registry = DeferredRegister.create(Registries.LOOT_FUNCTION_TYPE, OverdriveThatMatters.MOD_ID)
val RANDOMIZER: LootItemFunctionType by registry.register("randomizer") { LootItemFunctionType(RandomizerFunction.Companion) }
val COPY_TILE_NBT: LootItemFunctionType by registry.register("copy_tile_nbt") { LootItemFunctionType(CopyTileNbtFunction.Companion) } val COPY_TILE_NBT: LootItemFunctionType by registry.register("copy_tile_nbt") { LootItemFunctionType(CopyTileNbtFunction.Companion) }
val PROCEDURAL_BATTERY: LootItemFunctionType by registry.register(MNames.PROCEDURAL_BATTERY) { LootItemFunctionType(ProceduralBatteryItem.Randomizer.SERIALIZER) } val PROCEDURAL_BATTERY: LootItemFunctionType by registry.register(MNames.PROCEDURAL_BATTERY) { LootItemFunctionType(ProceduralBatteryItem.Randomizer.SERIALIZER) }
val PROCEDURAL_EXOPACK_UPGRADE: LootItemFunctionType by registry.register("exopack_upgrade") { LootItemFunctionType(ProceduralExoPackSlotUpgradeItem.Randomizer.SERIALIZER) }
internal fun register(bus: IEventBus) { internal fun register(bus: IEventBus) {
registry.register(bus) registry.register(bus)