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.util.StringRepresentable
import net.minecraft.world.item.Rarity
import net.minecraft.world.level.ItemLike
import net.minecraft.world.level.block.Block
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.UniformGenerator
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.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 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) {
add(LootItem.lootTableItem(item).also(configurator))
}

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.datagen.loot
import net.minecraft.resources.ResourceLocation
import net.minecraft.util.valueproviders.UniformInt
import net.minecraft.world.entity.EntityType
import net.minecraft.world.item.ItemStack
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.KilledByRealPlayerOrIndirectly
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.exopack.ProceduralExoPackSlotUpgradeItem
import ru.dbotthepony.mc.otm.registry.MItems
@Suppress("FunctionName")
@ -29,24 +30,32 @@ fun LootTableIdCondition(location: ResourceLocation): LootItemCondition {
}
fun addLootModifiers(it: LootModifiers) {
it.add("dungeon_exosuit", LootPoolAppender(
it.add("dungeon_exopack", LootPoolAppender(
arrayOf(LootTableIdCondition(BuiltInLootTables.SIMPLE_DUNGEON)),
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.2)
apply(RandomizerFunction.COMMON)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(6, 9)))
},
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
chanceCondition(0.05)
apply(RandomizerFunction.UNCOMMON)
apply(ProceduralExoPackSlotUpgradeItem.Randomizer(UniformInt.of(9, 18)))
},
))
it.add("mineshaft_additions", LootPoolAppender(
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) {
chanceCondition(0.15)
@ -61,21 +70,49 @@ fun addLootModifiers(it: LootModifiers) {
it.add("desert_pyramid_exosuit", LootPoolAppender(
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(
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(
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),
singleRandomizedItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.15, rarity = Rarity.EPIC),
singleItem(MItems.ExopackUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
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(

View File

@ -1,8 +1,10 @@
package ru.dbotthepony.mc.otm.data
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.parameters.LootContextParam
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
operator fun <T> LootContext.get(param: LootContextParam<T>): T? {
return getParamOrNull(param)
@ -11,3 +13,14 @@ operator fun <T> LootContext.get(param: LootContextParam<T>): T? {
fun <T> DataResult<T>.getOrNull(): T? {
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
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.util.RandomSource
import net.minecraft.world.entity.player.Player
import net.minecraft.util.valueproviders.ConstantInt
import net.minecraft.util.valueproviders.IntProvider
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.item.TooltipFlag
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.nbt.set
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.*
class ProceduralExoPackSlotUpgradeItem : AbstractExoPackSlotUpgradeItem(defaultProperties()), IRandomizableItem {
override fun getRarity(itemStack: ItemStack): Rarity {
return when (slotCount(itemStack)) {
in 0 .. 9 -> Rarity.COMMON
in 10 .. 18 -> Rarity.UNCOMMON
in 19 .. 27 -> Rarity.RARE
in 28 .. 36 -> Rarity.EPIC
else -> Rarity.EPIC
class ProceduralExoPackSlotUpgradeItem : AbstractExoPackSlotUpgradeItem(defaultProperties()) {
class Randomizer(val slots: IntProvider, val luckBias: IntProvider = ConstantInt.ZERO) : LootItemFunction, LootItemFunction.Builder {
override fun apply(t: ItemStack, u: LootContext): ItemStack {
t.tagNotNull[SLOT_COUNT_KEY] = slots.sample(u.random) + (luckBias.sample(u.random) * u.luck / 1024f).coerceAtLeast(0f).toInt()
return t
}
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 {
const val SLOT_COUNT_KEY = "slotCount"
const val UUID_KEY = "uuid"

View File

@ -6,15 +6,15 @@ import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.registries.DeferredRegister
import ru.dbotthepony.mc.otm.OverdriveThatMatters
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.exopack.ProceduralExoPackSlotUpgradeItem
object MItemFunctionTypes {
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 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) {
registry.register(bus)