parent
228cc3eab5
commit
4dc132a8ec
@ -2,6 +2,7 @@ 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
|
||||||
@ -16,10 +17,28 @@ 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 {
|
||||||
|
return withPool(LootPool.lootPool().also {
|
||||||
|
it.item(item, configurator)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
inline fun lootPool(configurator: LootPool.Builder.() -> Unit): LootPool.Builder = LootPool.lootPool().also(configurator)
|
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) {
|
inline fun LootPool.Builder.item(item: ItemLike, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit) {
|
||||||
add(LootItem.lootTableItem(item).also(configurator))
|
add(LootItem.lootTableItem(item).also(configurator))
|
||||||
@ -43,6 +62,11 @@ fun <T : LootPoolSingletonContainer.Builder<*>> T.setCount(minimal: Int, maximal
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T : LootPoolSingletonContainer.Builder<*>> T.chanceCondition(chance: Double): T {
|
||||||
|
condition(ChanceCondition(chance))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun <T : LootPoolSingletonContainer.Builder<*>> T.setCount(minimal: Float, maximal: Float, configurator: LootItemConditionalFunction.Builder<*>.() -> Unit = {}): T {
|
fun <T : LootPoolSingletonContainer.Builder<*>> T.setCount(minimal: Float, maximal: Float, configurator: LootItemConditionalFunction.Builder<*>.() -> Unit = {}): T {
|
||||||
apply(SetItemCountFunction.setCount(UniformGenerator.between(minimal, maximal)).also(configurator))
|
apply(SetItemCountFunction.setCount(UniformGenerator.between(minimal, maximal)).also(configurator))
|
||||||
return this
|
return this
|
||||||
|
@ -19,7 +19,7 @@ fun BasicLootAppender(
|
|||||||
item(it.item) {
|
item(it.item) {
|
||||||
setCount(it.count)
|
setCount(it.count)
|
||||||
}
|
}
|
||||||
}.build()
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ fun PlainLootAppender(
|
|||||||
}
|
}
|
||||||
|
|
||||||
chanceCondition(it.second)
|
chanceCondition(it.second)
|
||||||
}.build()
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,13 +6,14 @@ import net.minecraft.world.item.ItemStack
|
|||||||
import net.minecraft.world.item.Rarity
|
import net.minecraft.world.item.Rarity
|
||||||
import net.minecraft.world.level.storage.loot.BuiltInLootTables
|
import net.minecraft.world.level.storage.loot.BuiltInLootTables
|
||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
||||||
|
import net.minecraftforge.common.loot.LootModifier
|
||||||
import net.minecraftforge.common.loot.LootTableIdCondition
|
import net.minecraftforge.common.loot.LootTableIdCondition
|
||||||
import ru.dbotthepony.mc.otm.data.condition.ChanceWithPlaytimeCondition
|
import ru.dbotthepony.mc.otm.data.condition.ChanceWithPlaytimeCondition
|
||||||
import ru.dbotthepony.mc.otm.data.condition.HasExosuitCondition
|
import ru.dbotthepony.mc.otm.data.condition.HasExosuitCondition
|
||||||
import ru.dbotthepony.mc.otm.data.loot.IRandomizableItem
|
|
||||||
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.RandomizableItemLootAppender
|
import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender
|
||||||
|
import ru.dbotthepony.mc.otm.data.loot.RandomizerFunction
|
||||||
import ru.dbotthepony.mc.otm.registry.MItems
|
import ru.dbotthepony.mc.otm.registry.MItems
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
@ -25,7 +26,50 @@ fun LootTableIdCondition(location: ResourceLocation): LootItemCondition {
|
|||||||
return LootTableIdCondition.Builder(location).build()
|
return LootTableIdCondition.Builder(location).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun exosuitModifiers(it: LootModifiers) {
|
||||||
|
it.add("dungeon_exosuit", LootPoolAppender(
|
||||||
|
arrayOf(LootTableIdCondition(BuiltInLootTables.SIMPLE_DUNGEON)),
|
||||||
|
|
||||||
|
singleItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
|
||||||
|
chanceCondition(0.2)
|
||||||
|
apply(RandomizerFunction.COMMON)
|
||||||
|
},
|
||||||
|
|
||||||
|
singleItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL) {
|
||||||
|
chanceCondition(0.05)
|
||||||
|
apply(RandomizerFunction.UNCOMMON)
|
||||||
|
},
|
||||||
|
))
|
||||||
|
|
||||||
|
it.add("mineshaft_exosuit", LootPoolAppender(
|
||||||
|
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.1),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.1, rarity = Rarity.UNCOMMON)
|
||||||
|
))
|
||||||
|
|
||||||
|
it.add("desert_pyramid_exosuit", LootPoolAppender(
|
||||||
|
arrayOf(LootTableIdCondition(BuiltInLootTables.DESERT_PYRAMID)),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.15, rarity = Rarity.UNCOMMON),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.25, rarity = Rarity.COMMON)
|
||||||
|
))
|
||||||
|
|
||||||
|
it.add("jungle_temple_exosuit", LootPoolAppender(
|
||||||
|
arrayOf(LootTableIdCondition(BuiltInLootTables.JUNGLE_TEMPLE)),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.15, rarity = Rarity.UNCOMMON),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.35, rarity = Rarity.RARE)
|
||||||
|
))
|
||||||
|
|
||||||
|
it.add("end_city_exosuit", LootPoolAppender(
|
||||||
|
arrayOf(LootTableIdCondition(BuiltInLootTables.END_CITY_TREASURE)),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.4, rarity = Rarity.UNCOMMON),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.2, rarity = Rarity.RARE),
|
||||||
|
singleRandomizedItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, chance = 0.15, rarity = Rarity.EPIC),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fun addLootModifiers(it: LootModifiers) {
|
fun addLootModifiers(it: LootModifiers) {
|
||||||
|
exosuitModifiers(it)
|
||||||
|
|
||||||
it.add("dungeon_pill", PlainLootAppender(
|
it.add("dungeon_pill", PlainLootAppender(
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.SIMPLE_DUNGEON)),
|
arrayOf(LootTableIdCondition(BuiltInLootTables.SIMPLE_DUNGEON)),
|
||||||
ItemStack(MItems.PILL_ANDROID, 1) to 0.4,
|
ItemStack(MItems.PILL_ANDROID, 1) to 0.4,
|
||||||
@ -33,15 +77,6 @@ fun addLootModifiers(it: LootModifiers) {
|
|||||||
ItemStack(MItems.PILL_HEAL, 1) to 0.75,
|
ItemStack(MItems.PILL_HEAL, 1) to 0.75,
|
||||||
))
|
))
|
||||||
|
|
||||||
it.add("dungeon_exosuit", RandomizableItemLootAppender(
|
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.SIMPLE_DUNGEON)),
|
|
||||||
listOf(
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.2),
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.05, rarity = Rarity.UNCOMMON)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
it.add("mineshaft_pill", PlainLootAppender(
|
it.add("mineshaft_pill", PlainLootAppender(
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
|
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
|
||||||
ItemStack(MItems.PILL_ANDROID, 1) to 0.075,
|
ItemStack(MItems.PILL_ANDROID, 1) to 0.075,
|
||||||
@ -49,15 +84,6 @@ fun addLootModifiers(it: LootModifiers) {
|
|||||||
ItemStack(MItems.PILL_HEAL, 1) to 0.4,
|
ItemStack(MItems.PILL_HEAL, 1) to 0.4,
|
||||||
))
|
))
|
||||||
|
|
||||||
it.add("mineshaft_exosuit", RandomizableItemLootAppender(
|
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
|
|
||||||
listOf(
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.1),
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.01, rarity = Rarity.UNCOMMON)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
it.add("mineshaft_nutrient_paste", PlainLootAppender(
|
it.add("mineshaft_nutrient_paste", PlainLootAppender(
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
|
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
|
||||||
ItemStack(MItems.NUTRIENT_PASTE, 6) to 0.5,
|
ItemStack(MItems.NUTRIENT_PASTE, 6) to 0.5,
|
||||||
@ -71,29 +97,11 @@ fun addLootModifiers(it: LootModifiers) {
|
|||||||
ItemStack(MItems.PILL_HEAL, 1) to 0.3,
|
ItemStack(MItems.PILL_HEAL, 1) to 0.3,
|
||||||
))
|
))
|
||||||
|
|
||||||
it.add("desert_pyramid_exosuit", RandomizableItemLootAppender(
|
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.DESERT_PYRAMID)),
|
|
||||||
listOf(
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.15, rarity = Rarity.UNCOMMON),
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.25, rarity = Rarity.COMMON),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
it.add("jungle_temple_pill", PlainLootAppender(
|
it.add("jungle_temple_pill", PlainLootAppender(
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.JUNGLE_TEMPLE)),
|
arrayOf(LootTableIdCondition(BuiltInLootTables.JUNGLE_TEMPLE)),
|
||||||
ItemStack(MItems.PILL_ANDROID, 1) to 0.5
|
ItemStack(MItems.PILL_ANDROID, 1) to 0.5
|
||||||
))
|
))
|
||||||
|
|
||||||
it.add("jungle_temple_exosuit", RandomizableItemLootAppender(
|
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.JUNGLE_TEMPLE)),
|
|
||||||
listOf(
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.15, rarity = Rarity.UNCOMMON),
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.35, rarity = Rarity.RARE)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
it.add("end_city_modifications", PlainLootAppender(
|
it.add("end_city_modifications", PlainLootAppender(
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.END_CITY_TREASURE)),
|
arrayOf(LootTableIdCondition(BuiltInLootTables.END_CITY_TREASURE)),
|
||||||
ItemStack(MItems.PILL_ANDROID, 1) to 0.1,
|
ItemStack(MItems.PILL_ANDROID, 1) to 0.1,
|
||||||
@ -102,16 +110,6 @@ fun addLootModifiers(it: LootModifiers) {
|
|||||||
ItemStack(MItems.ZPM_BATTERY, 1) to 0.005,
|
ItemStack(MItems.ZPM_BATTERY, 1) to 0.005,
|
||||||
))
|
))
|
||||||
|
|
||||||
it.add("end_city_exosuit", RandomizableItemLootAppender(
|
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.END_CITY_TREASURE)),
|
|
||||||
listOf(
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.4, rarity = Rarity.UNCOMMON),
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.2, rarity = Rarity.RARE),
|
|
||||||
RandomizableItemLootAppender.Entry(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL as IRandomizableItem, chance = 0.15, rarity = Rarity.EPIC),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
it.add("shipwreck_supply_pill", PlainLootAppender(
|
it.add("shipwreck_supply_pill", PlainLootAppender(
|
||||||
arrayOf(LootTableIdCondition(BuiltInLootTables.SHIPWRECK_SUPPLY)),
|
arrayOf(LootTableIdCondition(BuiltInLootTables.SHIPWRECK_SUPPLY)),
|
||||||
ItemStack(MItems.PILL_HUMANE, 1) to 0.4,
|
ItemStack(MItems.PILL_HUMANE, 1) to 0.4,
|
||||||
|
@ -11,6 +11,7 @@ import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
|||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
||||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||||
import ru.dbotthepony.mc.otm.core.set
|
import ru.dbotthepony.mc.otm.core.set
|
||||||
|
import ru.dbotthepony.mc.otm.data.get
|
||||||
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
||||||
|
|
||||||
data class ChanceWithPlaytimeCondition(
|
data class ChanceWithPlaytimeCondition(
|
||||||
|
@ -10,6 +10,7 @@ import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemConditi
|
|||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
||||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||||
|
import ru.dbotthepony.mc.otm.data.get
|
||||||
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
||||||
|
|
||||||
object HasExosuitCondition : LootItemCondition, Serializer<HasExosuitCondition>, LootItemCondition.Builder {
|
object HasExosuitCondition : LootItemCondition, Serializer<HasExosuitCondition>, LootItemCondition.Builder {
|
||||||
|
@ -17,6 +17,7 @@ import net.minecraftforge.registries.ForgeRegistries
|
|||||||
import ru.dbotthepony.mc.otm.capability.itemsStream
|
import ru.dbotthepony.mc.otm.capability.itemsStream
|
||||||
import ru.dbotthepony.mc.otm.core.registryName
|
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.data.get
|
||||||
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
||||||
|
|
||||||
data class ItemInInventoryCondition(
|
data class ItemInInventoryCondition(
|
||||||
|
@ -10,6 +10,7 @@ import net.minecraft.world.level.storage.loot.predicates.InvertedLootItemConditi
|
|||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
||||||
import net.minecraftforge.common.util.FakePlayer
|
import net.minecraftforge.common.util.FakePlayer
|
||||||
|
import ru.dbotthepony.mc.otm.data.get
|
||||||
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
||||||
|
|
||||||
object KilledByRealPlayer : LootItemCondition, Serializer<KilledByRealPlayer>, LootItemCondition.Builder {
|
object KilledByRealPlayer : LootItemCondition, Serializer<KilledByRealPlayer>, LootItemCondition.Builder {
|
||||||
|
@ -12,6 +12,7 @@ import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
|||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
||||||
import net.minecraftforge.common.util.FakePlayer
|
import net.minecraftforge.common.util.FakePlayer
|
||||||
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
|
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
|
||||||
|
import ru.dbotthepony.mc.otm.data.get
|
||||||
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
|
||||||
|
|
||||||
object KilledByRealPlayerOrIndirectly : LootItemCondition, Serializer<KilledByRealPlayerOrIndirectly>, LootItemCondition.Builder {
|
object KilledByRealPlayerOrIndirectly : LootItemCondition, Serializer<KilledByRealPlayerOrIndirectly>, LootItemCondition.Builder {
|
||||||
|
@ -6,6 +6,6 @@ import net.minecraft.world.item.ItemStack
|
|||||||
import net.minecraft.world.item.Rarity
|
import net.minecraft.world.item.Rarity
|
||||||
import net.minecraft.world.level.ItemLike
|
import net.minecraft.world.level.ItemLike
|
||||||
|
|
||||||
interface IRandomizableItem : ItemLike {
|
interface IRandomizableItem {
|
||||||
fun randomize(itemStack: ItemStack, random: RandomSource, ply: Player?, rarity: Rarity = Rarity.COMMON)
|
fun randomize(itemStack: ItemStack, random: RandomSource, ply: Player?, rarity: Rarity = Rarity.COMMON)
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,17 @@ import com.mojang.serialization.Dynamic
|
|||||||
import com.mojang.serialization.JsonOps
|
import com.mojang.serialization.JsonOps
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.level.storage.loot.Deserializers
|
import net.minecraft.world.level.storage.loot.Deserializers
|
||||||
import net.minecraft.world.level.storage.loot.LootContext
|
import net.minecraft.world.level.storage.loot.LootContext
|
||||||
import net.minecraft.world.level.storage.loot.LootPool
|
import net.minecraft.world.level.storage.loot.LootPool
|
||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
||||||
|
import net.minecraftforge.common.ForgeHooks
|
||||||
import net.minecraftforge.common.loot.IGlobalLootModifier
|
import net.minecraftforge.common.loot.IGlobalLootModifier
|
||||||
import net.minecraftforge.common.loot.LootModifier
|
import net.minecraftforge.common.loot.LootModifier
|
||||||
import java.util.Arrays
|
import java.util.Arrays
|
||||||
|
import java.util.Deque
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
class LootPoolAppender(conditions: Array<out LootItemCondition>, pools: Stream<LootPool>) : LootModifier(conditions) {
|
class LootPoolAppender(conditions: Array<out LootItemCondition>, pools: Stream<LootPool>) : LootModifier(conditions) {
|
||||||
@ -36,23 +39,39 @@ class LootPoolAppender(conditions: Array<out LootItemCondition>, pools: Stream<L
|
|||||||
return CODEC
|
return CODEC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove reflection once Forge implement a way to provide lootpool deserialization context in non-reflective way
|
||||||
companion object {
|
companion object {
|
||||||
// same bro
|
private val lootPoolCodec: Codec<List<LootPool>>
|
||||||
private fun getJson(it: Dynamic<Any?>): JsonElement {
|
|
||||||
val value = it.value ?: throw NullPointerException("value was null")
|
private val forgeHooksLootContext by lazy {
|
||||||
return value as? JsonElement ?: it.ops.convertTo(JsonOps.INSTANCE, it)
|
val field = ForgeHooks::class.java.getDeclaredField("lootContext")
|
||||||
|
field.isAccessible = true
|
||||||
|
field
|
||||||
}
|
}
|
||||||
|
|
||||||
private val lootPoolCodec: Codec<List<LootPool>>
|
private val lootTableContextConstructor by lazy {
|
||||||
|
val clazz = ForgeHooks::class.java.declaredClasses.firstOrNull { it.name.contains("LootTableContext") } ?: throw NoSuchElementException("Unable to find ForgeHooks\$LootTableContext!")
|
||||||
|
val constructor = clazz.getDeclaredConstructor(ResourceLocation::class.java, Boolean::class.java)
|
||||||
|
constructor.isAccessible = true
|
||||||
|
constructor
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val serializer = Deserializers.createLootTableSerializer().create()
|
val serializer = Deserializers.createLootTableSerializer().create()
|
||||||
|
val notExistingLocation = ResourceLocation("null", "null")
|
||||||
|
|
||||||
lootPoolCodec = Codec.list(Codec.PASSTHROUGH.flatXmap({
|
lootPoolCodec = Codec.list(Codec.PASSTHROUGH.flatXmap({
|
||||||
|
val dequeueHolder = forgeHooksLootContext.get(null) as ThreadLocal<Deque<Any>>
|
||||||
|
val deque = dequeueHolder.get() ?: java.util.ArrayDeque()
|
||||||
|
dequeueHolder.set(deque)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DataResult.success(serializer.fromJson(getJson(it as Dynamic<Any?>), LootPool::class.java))
|
deque.push(lootTableContextConstructor.newInstance(notExistingLocation, true))
|
||||||
|
DataResult.success(serializer.fromJson(it.convert(JsonOps.INSTANCE).value, LootPool::class.java))
|
||||||
} catch(err: JsonSyntaxException) {
|
} catch(err: JsonSyntaxException) {
|
||||||
DataResult.error(err.message)
|
DataResult.error(err.message)
|
||||||
|
} finally {
|
||||||
|
deque.pop()
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
try {
|
try {
|
||||||
|
@ -1,189 +0,0 @@
|
|||||||
package ru.dbotthepony.mc.otm.data.loot
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
|
||||||
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.RecordCodecBuilder
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList
|
|
||||||
import net.minecraft.util.valueproviders.ConstantInt
|
|
||||||
import net.minecraft.util.valueproviders.IntProvider
|
|
||||||
import net.minecraft.world.entity.player.Player
|
|
||||||
import net.minecraft.world.item.Item
|
|
||||||
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.parameters.LootContextParams
|
|
||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
|
|
||||||
import net.minecraftforge.common.loot.LootModifier
|
|
||||||
import net.minecraftforge.registries.ForgeRegistries
|
|
||||||
import ru.dbotthepony.mc.otm.data.codec
|
|
||||||
|
|
||||||
class RandomizableItemLootAppender(
|
|
||||||
conditions: Array<out LootItemCondition>,
|
|
||||||
entries: Collection<Entry>
|
|
||||||
) : LootModifier(conditions) {
|
|
||||||
data class Entry(
|
|
||||||
val item: IRandomizableItem,
|
|
||||||
val chance: Double,
|
|
||||||
val count: IntProvider = ConstantInt.of(1),
|
|
||||||
val rarity: Rarity = Rarity.COMMON,
|
|
||||||
val distinct: Boolean = true,
|
|
||||||
) {
|
|
||||||
constructor(
|
|
||||||
item: IRandomizableItem,
|
|
||||||
chance: Double,
|
|
||||||
count: Int,
|
|
||||||
rarity: Rarity = Rarity.COMMON,
|
|
||||||
distinct: Boolean = true,
|
|
||||||
) : this(item, chance, ConstantInt.of(count), rarity, distinct)
|
|
||||||
|
|
||||||
private constructor(
|
|
||||||
item: Item,
|
|
||||||
chance: Double,
|
|
||||||
count: IntProvider,
|
|
||||||
rarity: Rarity = Rarity.COMMON,
|
|
||||||
distinct: Boolean = true,
|
|
||||||
) : this(item as? IRandomizableItem ?: throw ClassCastException("$item is not a subtype of IRandomizableItem"), chance, count, rarity, distinct)
|
|
||||||
|
|
||||||
init {
|
|
||||||
require(count.minValue >= 0) { "Invalid min value ${count.minValue}" }
|
|
||||||
require(count.maxValue >= 0) { "Invalid max value ${count.maxValue}" }
|
|
||||||
require(count.maxValue >= count.minValue) { "Invalid bounds, they must be ${count.maxValue} >= ${count.minValue}!" }
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val CODEC: Codec<Entry> by lazy {
|
|
||||||
RecordCodecBuilder.create {
|
|
||||||
it.group(
|
|
||||||
ForgeRegistries.ITEMS.codec.fieldOf("item").forGetter { it.item.asItem() },
|
|
||||||
Codec.DOUBLE.fieldOf("chance").forGetter(Entry::chance),
|
|
||||||
IntProvider.CODEC.fieldOf("count").forGetter(Entry::count),
|
|
||||||
Rarity::class.codec().fieldOf("rarity").forGetter(Entry::rarity),
|
|
||||||
Codec.BOOL.fieldOf("distinct").forGetter(Entry::distinct),
|
|
||||||
).apply(it, RandomizableItemLootAppender::Entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val entries: List<Entry> = ImmutableList.copyOf(entries)
|
|
||||||
|
|
||||||
override fun codec(): Codec<RandomizableItemLootAppender> {
|
|
||||||
return Companion
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun doApply(
|
|
||||||
generatedLoot: ObjectArrayList<ItemStack>,
|
|
||||||
context: LootContext
|
|
||||||
): ObjectArrayList<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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for ((item, chance, count, rarity, distinct) in entries) {
|
|
||||||
if (random.nextDouble() <= chance) {
|
|
||||||
if (distinct) {
|
|
||||||
val items = ArrayList<ItemStack>()
|
|
||||||
|
|
||||||
for (i in 0 until count.sample(random)) {
|
|
||||||
val stack = ItemStack(item.asItem(), 1)
|
|
||||||
item.randomize(stack, random, player, rarity)
|
|
||||||
|
|
||||||
for (existing in items) {
|
|
||||||
if (ItemStack.isSameItemSameTags(existing, stack)) {
|
|
||||||
existing.count += stack.count
|
|
||||||
stack.count = 0
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stack.count > 0) {
|
|
||||||
items.add(stack)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (stack in items) {
|
|
||||||
while (stack.count > stack.maxStackSize && stack.maxStackSize > 0) {
|
|
||||||
val split = stack.split(stack.maxStackSize)
|
|
||||||
generatedLoot.add(split)
|
|
||||||
}
|
|
||||||
|
|
||||||
generatedLoot.add(stack)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val stack = ItemStack(item.asItem(), count.sample(random))
|
|
||||||
item.randomize(stack, random, player, rarity)
|
|
||||||
|
|
||||||
while (stack.count > stack.maxStackSize && stack.maxStackSize > 0) {
|
|
||||||
val split = stack.split(stack.maxStackSize)
|
|
||||||
generatedLoot.add(split)
|
|
||||||
}
|
|
||||||
|
|
||||||
generatedLoot.add(stack)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return generatedLoot
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object : Codec<RandomizableItemLootAppender> {
|
|
||||||
override fun <T : Any> encode(
|
|
||||||
input: RandomizableItemLootAppender,
|
|
||||||
ops: DynamicOps<T>,
|
|
||||||
prefix: T
|
|
||||||
): DataResult<T> {
|
|
||||||
require(prefix == ops.empty()) { "Non-empty prefix: $prefix" }
|
|
||||||
|
|
||||||
return LOOT_CONDITIONS_CODEC.encode(input.conditions, ops, prefix).flatMap map@{
|
|
||||||
val encodedEntries = input.entries.map { Entry.CODEC.encode(it, ops, prefix) }
|
|
||||||
val firstError = encodedEntries.firstOrNull { !it.result().isPresent }
|
|
||||||
|
|
||||||
if (firstError != null) {
|
|
||||||
return@map firstError
|
|
||||||
}
|
|
||||||
|
|
||||||
return@map DataResult.success(ops.createMap(linkedMapOf(
|
|
||||||
ops.createString("conditions") to it,
|
|
||||||
ops.createString("entries") to ops.createList(encodedEntries.stream().map { it.result().get() })
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : Any> decode(
|
|
||||||
ops: DynamicOps<T>,
|
|
||||||
input: T
|
|
||||||
): DataResult<Pair<RandomizableItemLootAppender, T>> {
|
|
||||||
return ops.getMap(input).flatMap { map ->
|
|
||||||
LOOT_CONDITIONS_CODEC.decode(ops, map["conditions"]).flatMap {
|
|
||||||
val conditions = it.first
|
|
||||||
|
|
||||||
ops.getStream(map["entries"]).flatMap {
|
|
||||||
val collected = it.map { Entry.CODEC.decode(ops, it) }.toList()
|
|
||||||
|
|
||||||
for ((i, element) in collected.withIndex()) {
|
|
||||||
if (element.result().isEmpty) {
|
|
||||||
return@flatMap DataResult.error("Invalid entry at $i: ${element.error().get().message()}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return@flatMap DataResult.success(Pair.of(RandomizableItemLootAppender(conditions, collected.map { it.result().get().first }), ops.empty()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,81 @@
|
|||||||
|
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.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()
|
||||||
|
}
|
||||||
|
}
|
@ -5,14 +5,12 @@ import net.minecraftforge.registries.DeferredRegister
|
|||||||
import net.minecraftforge.registries.ForgeRegistries
|
import net.minecraftforge.registries.ForgeRegistries
|
||||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender
|
import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender
|
||||||
import ru.dbotthepony.mc.otm.data.loot.RandomizableItemLootAppender
|
|
||||||
|
|
||||||
object LootModifiers {
|
object LootModifiers {
|
||||||
private val registry = DeferredRegister.create(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, OverdriveThatMatters.MOD_ID)
|
private val registry = DeferredRegister.create(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, OverdriveThatMatters.MOD_ID)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
registry.register("loot_appender") { LootPoolAppender.CODEC }
|
registry.register("loot_appender") { LootPoolAppender.CODEC }
|
||||||
registry.register("randomized_appender") { RandomizableItemLootAppender.Companion }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun register(bus: IEventBus) {
|
internal fun register(bus: IEventBus) {
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.registry
|
||||||
|
|
||||||
|
import net.minecraft.core.Registry
|
||||||
|
import net.minecraft.resources.ResourceLocation
|
||||||
|
import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType
|
||||||
|
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
|
||||||
|
import net.minecraftforge.registries.RegisterEvent
|
||||||
|
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||||
|
import ru.dbotthepony.mc.otm.data.loot.RandomizerFunction
|
||||||
|
|
||||||
|
object MItemFunctionTypes {
|
||||||
|
val RANDOMIZER = LootItemFunctionType(RandomizerFunction.Companion)
|
||||||
|
|
||||||
|
internal fun register(event: RegisterEvent) {
|
||||||
|
if (event.getVanillaRegistry<LootItemConditionType>() == Registry.LOOT_FUNCTION_TYPE) {
|
||||||
|
Registry.LOOT_FUNCTION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "randomizer"), RANDOMIZER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -262,6 +262,7 @@ object MRegistry {
|
|||||||
bus.addListener(this::initializeCommon)
|
bus.addListener(this::initializeCommon)
|
||||||
bus.addListener(MStats::registerVanilla)
|
bus.addListener(MStats::registerVanilla)
|
||||||
bus.addListener(MLootItemConditions::register)
|
bus.addListener(MLootItemConditions::register)
|
||||||
|
bus.addListener(MItemFunctionTypes::register)
|
||||||
|
|
||||||
MBlocks.register(bus)
|
MBlocks.register(bus)
|
||||||
MBlockEntities.register(bus)
|
MBlockEntities.register(bus)
|
||||||
|
Loading…
Reference in New Issue
Block a user