Procedural exosuit inventory upgrade attempt

This commit is contained in:
DBotThePony 2022-10-10 01:02:36 +07:00
parent 30db39453a
commit eeebda6253
Signed by: DBot
GPG Key ID: DCC23B5715498507
14 changed files with 597 additions and 126 deletions

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.datagen.items
import com.google.common.collect.Streams
import net.minecraft.resources.ResourceLocation
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.datagen.DataGen
@ -52,18 +53,22 @@ fun addItemModels(provider: MatteryItemModelProvider) {
provider.generated(MItems.PILL_HEAL)
provider.generated(MItems.NUTRIENT_PASTE)
for (item in MItems.EXOSUIT_INVENTORY_UPGRADES_CRAFTABLE) {
provider.generated(item, ResourceLocation(DataGen.MOD_ID, "item/exosuit_inventory_upgrade"))
for (item in MItems.ExosuitUpgrades.INVENTORY_UPGRADES) {
provider.generated(item, modLocation("item/exosuit_inventory_upgrade"))
}
for (item in MItems.EXOSUIT_INVENTORY_UPGRADES_UNCRAFTABLE) {
provider.KOT(item)
for (item in listOf(
MItems.ExosuitUpgrades.INVENTORY_UPGRADE_HUGE,
MItems.ExosuitUpgrades.INVENTORY_UPGRADE_BIG,
MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL,
MItems.ExosuitUpgrades.INVENTORY_UPGRADE_WITHER,
MItems.ExosuitUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON,
)) {
provider.generated(item, modLocation("item/exosuit_inventory_upgrade"))
}
provider.generated(MItems.EXOSUIT_INVENTORY_UPGRADE_CREATIVE)
provider.generated(MItems.EXOSUIT_CRAFTING_UPGRADE)
provider.KOT(MItems.EXOSUIT_INVENTORY_UPGRADE_BIG)
provider.KOT(MItems.EXOSUIT_INVENTORY_UPGRADE_HUGE)
provider.generated(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_CREATIVE)
provider.generated(MItems.ExosuitUpgrades.CRAFTING_UPGRADE)
provider.component(MItems.TRITANIUM_INGOT)
provider.resource(MItems.TRITANIUM_ORE_CLUMP)
@ -112,16 +117,6 @@ fun addItemModels(provider: MatteryItemModelProvider) {
provider.block(MItems.STORAGE_IMPORTER)
provider.block(MItems.STORAGE_EXPORTER)
provider.generated(MItems.EXOSUIT_CRAFTING_UPGRADE)
provider.generated(MItems.EXOSUIT_INVENTORY_UPGRADE_CREATIVE)
provider.generatedStrict(MItems.EXOSUIT_INVENTORY_UPGRADE_BIG, "exosuit_inventory_upgrade")
provider.generatedStrict(MItems.EXOSUIT_INVENTORY_UPGRADE_HUGE, "exosuit_inventory_upgrade")
for (item in MItems.EXOSUIT_INVENTORY_UPGRADES) {
provider.generatedStrict(item, "exosuit_inventory_upgrade")
}
for ((color, item) in MItems.CARGO_CRATE_MINECARTS) {
provider.generated(item)
}

View File

@ -415,8 +415,17 @@ private fun blocks(provider: MatteryLanguageProvider) {
private fun items(provider: MatteryLanguageProvider) {
with(provider.english) {
add(MItems.EXOSUIT_PROBE, "Exosuit Probe")
add(MItems.EXOSUIT_INVENTORY_UPGRADE_CREATIVE, "Creative Exosuit Inventory Upgrade")
add(MItems.EXOSUIT_CRAFTING_UPGRADE, "Exosuit Crafting Upgrade")
add(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_CREATIVE, "Creative Exosuit Inventory Upgrade")
add(MItems.ExosuitUpgrades.CRAFTING_UPGRADE, "Exosuit Crafting Upgrade")
add(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_WITHER, "Superdense Packing Upgrade")
add(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_WITHER, "description", "Utilizes similar principle that exhibit Nether Stars")
add(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON, "Ender Link Pocket Dimension Upgrade")
add(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON, "description", "Allows to store items in portative pocket dimension")
add(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, "Indescribable Exosuit Inventory Upgrade")
add(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_PROCEDURAL, "description", "They normally generate in dungeons with appropriate NBT tag attached")
add(MItems.NUTRIENT_PASTE, "Nutrient paste")

View File

@ -1,17 +1,23 @@
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
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.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.IRandomizableItem
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.data.RandomizableItemLootAppender
import ru.dbotthepony.mc.otm.item.ProceduralExoSuitSlotUpgradeItem
import ru.dbotthepony.mc.otm.registry.MItems
fun LootTableIdCondition(location: String): LootItemCondition {
@ -24,53 +30,97 @@ fun LootTableIdCondition(location: ResourceLocation): LootItemCondition {
fun addLootModifiers(it: LootModifiers) {
it.add("dungeon_pill", LootTableSeparatedAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/simple_dungeon")).build()),
arrayOf(LootTableIdCondition(BuiltInLootTables.SIMPLE_DUNGEON)),
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("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", LootTableSeparatedAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/abandoned_mineshaft")).build()),
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
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_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", LootTableSeparatedAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/abandoned_mineshaft")).build()),
arrayOf(LootTableIdCondition(BuiltInLootTables.ABANDONED_MINESHAFT)),
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", LootTableSeparatedAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/abandoned_mineshaft")).build()),
arrayOf(LootTableIdCondition(BuiltInLootTables.DESERT_PYRAMID)),
ItemStack(MItems.PILL_ANDROID, 1) to 0.05,
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", LootTableSeparatedAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/jungle_temple")).build()),
arrayOf(LootTableIdCondition(BuiltInLootTables.JUNGLE_TEMPLE)),
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", LootTableSeparatedAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/end_city_treasure")).build()),
arrayOf(LootTableIdCondition(BuiltInLootTables.END_CITY_TREASURE)),
ItemStack(MItems.PILL_ANDROID, 1) to 0.1,
ItemStack(MItems.PILL_HUMANE, 1) to 0.3,
ItemStack(MItems.PILL_OBLIVION, 1) to 0.5,
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", LootTableSeparatedAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/shipwreck_supply")).build()),
arrayOf(LootTableIdCondition(BuiltInLootTables.SHIPWRECK_SUPPLY)),
ItemStack(MItems.PILL_HUMANE, 1) to 0.4,
ItemStack(MItems.PILL_HEAL, 1) to 0.6,
ItemStack(MItems.PILL_HEAL, 1) to 0.6,
ItemStack(MItems.PILL_HEAL, 1) to 0.6,
ItemStack(MItems.PILL_HEAL, 1) to 0.6,
))
it.add("shipwreck_supply_nutrient_paste", LootTableSeparatedAppender(
arrayOf(LootTableIdCondition.Builder(ResourceLocation("chests/shipwreck_supply")).build()),
arrayOf(LootTableIdCondition(BuiltInLootTables.SHIPWRECK_SUPPLY)),
ItemStack(MItems.NUTRIENT_PASTE, 12) to 0.85,
ItemStack(MItems.NUTRIENT_PASTE, 24) to 0.35,
ItemStack(MItems.NUTRIENT_PASTE, 38) to 0.1,

View File

@ -77,7 +77,7 @@ fun addLootTables(lootTables: LootTables) {
lootTables.provider(LootContextParamSets.ADVANCEMENT_ENTITY) {
it.accept(modLocation("research_all_android"), singleLootPool {
it.add(LootItem.lootTableItem(MItems.EXOSUIT_INVENTORY_UPGRADE_HUGE))
it.add(LootItem.lootTableItem(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_HUGE))
})
it.accept(modLocation("tritanium_block3"), singleLootPool {

View File

@ -280,7 +280,7 @@ fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
.build(consumer)
// апгрейд на сетку крафта
MatteryRecipe(MItems.EXOSUIT_CRAFTING_UPGRADE)
MatteryRecipe(MItems.ExosuitUpgrades.CRAFTING_UPGRADE)
.row(MItemTags.ADVANCED_CIRCUIT, MItemTags.ADVANCED_CIRCUIT, MItemTags.ADVANCED_CIRCUIT)
.row(MItemTags.CRAFTING_TABLES, MItems.QUANTUM_TRANSCEIVER, MItemTags.CRAFTING_TABLES)
.row(MItemTags.TRITANIUM_PLATES, MItemTags.TRITANIUM_PLATES, MItemTags.TRITANIUM_PLATES)

View File

@ -10,6 +10,7 @@ import net.minecraft.nbt.IntTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.LongArrayTag
import net.minecraft.nbt.LongTag
import net.minecraft.nbt.NbtUtils
import net.minecraft.nbt.ShortTag
import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag
@ -101,15 +102,32 @@ fun CompoundTag.getList(key: String): ListTag {
return this[key] as? ListTag ?: ListTag()
}
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getByteList(key: String): MutableList<ByteTag> = getList(key, Tag.TAG_BYTE.toInt()) as MutableList<ByteTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getShortList(key: String): MutableList<ShortTag> = getList(key, Tag.TAG_SHORT.toInt()) as MutableList<ShortTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getIntList(key: String): MutableList<IntTag> = getList(key, Tag.TAG_INT.toInt()) as MutableList<IntTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getLongList(key: String): MutableList<LongTag> = getList(key, Tag.TAG_LONG.toInt()) as MutableList<LongTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getFloatList(key: String): MutableList<FloatTag> = getList(key, Tag.TAG_FLOAT.toInt()) as MutableList<FloatTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getDoubleList(key: String): MutableList<DoubleTag> = getList(key, Tag.TAG_DOUBLE.toInt()) as MutableList<DoubleTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getByteArrayList(key: String): MutableList<ByteArrayTag> = getList(key, Tag.TAG_BYTE_ARRAY.toInt()) as MutableList<ByteArrayTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getStringList(key: String): MutableList<StringTag> = getList(key, Tag.TAG_STRING.toInt()) as MutableList<StringTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getListList(key: String): MutableList<ListTag> = getList(key, Tag.TAG_LIST.toInt()) as MutableList<ListTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getCompoundList(key: String): MutableList<CompoundTag> = getList(key, Tag.TAG_COMPOUND.toInt()) as MutableList<CompoundTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getIntArrayList(key: String): MutableList<IntArrayTag> = getList(key, Tag.TAG_INT_ARRAY.toInt()) as MutableList<IntArrayTag>
@Suppress("unchecked_cast") // type is checked inside getList
fun CompoundTag.getLongArrayList(key: String): MutableList<LongArrayTag> = getList(key, Tag.TAG_LONG_ARRAY.toInt()) as MutableList<LongArrayTag>
fun CompoundTag.getUUIDSafe(key: String): UUID? {
val value = this[key] as? IntArrayTag ?: return null
return NbtUtils.loadUUID(value)
}

View File

@ -29,6 +29,7 @@ import net.minecraftforge.registries.ForgeRegistry
import net.minecraftforge.registries.IForgeRegistry
import java.math.BigInteger
import java.util.Spliterators
import java.util.UUID
import java.util.stream.Stream
import java.util.stream.StreamSupport
import kotlin.reflect.KProperty
@ -396,3 +397,11 @@ fun Entity.genericPositions(): Collection<Vector> {
boundingBox.center
)
}
fun ResourceLocation.toUUID(): UUID {
return toString().toUUID()
}
fun String.toUUID(): UUID {
return UUID.nameUUIDFromBytes(toByteArray(Charsets.UTF_8))
}

View File

@ -0,0 +1,30 @@
package ru.dbotthepony.mc.otm.data
import com.google.common.collect.ImmutableMap
import com.mojang.datafixers.util.Pair
import com.mojang.serialization.Codec
import com.mojang.serialization.DataResult
import com.mojang.serialization.DynamicOps
import kotlin.reflect.KClass
class EnumCodec<E : Enum<E>>(val type: Class<E>) : Codec<E> {
private val values: Map<String, E> by lazy {
val builder = ImmutableMap.Builder<String, E>()
for (value in type.enumConstants) builder.put(value.name, value)
builder.build()
}
override fun <T : Any> encode(input: E, ops: DynamicOps<T>, prefix: T): DataResult<T> {
require(prefix == ops.empty()) { "Non-empty prefix: $prefix" }
return DataResult.success(ops.createString(input.name))
}
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<E, T>> {
return ops.getStringValue(input).flatMap {
DataResult.success(values[it] ?: return@flatMap DataResult.error("No such enum $it (valid ones are: ${values.keys.joinToString(", ")})"))
}.map { Pair.of(it, ops.empty()) }
}
}
fun <E : Enum<E>> Class<E>.codec() = EnumCodec(this)
fun <E : Enum<E>> KClass<E>.codec() = EnumCodec(this.java)

View File

@ -0,0 +1,195 @@
package ru.dbotthepony.mc.otm.data
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.RandomSource
import net.minecraft.util.valueproviders.ConstantInt
import net.minecraft.util.valueproviders.IntProvider
import net.minecraft.util.valueproviders.UniformInt
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.ItemLike
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
interface IRandomizableItem : ItemLike {
fun randomize(itemStack: ItemStack, random: RandomSource, ply: Player?, rarity: Rarity = Rarity.COMMON)
}
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, ::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()))
}
}
}
}
}
}

View File

@ -0,0 +1,120 @@
package ru.dbotthepony.mc.otm.item
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResultHolder
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.LivingEntity
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.item.TooltipFlag
import net.minecraft.world.item.UseAnim
import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.ServerConfig
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.toUUID
import ru.dbotthepony.mc.otm.runIfClient
import java.util.UUID
abstract class AbstractExoSuitSlotUpgradeItem(properties: Properties = defaultProperties()) : Item(properties) {
abstract fun hasDescription(itemStack: ItemStack): Boolean
abstract fun slotCount(itemStack: ItemStack): Int
abstract fun uuid(itemStack: ItemStack): UUID?
override fun canBeHurtBy(p_41387_: DamageSource): Boolean {
return super.canBeHurtBy(p_41387_) && !p_41387_.isExplosion && !p_41387_.isFire
}
override fun getUseDuration(p_41454_: ItemStack): Int {
return 30
}
override fun appendHoverText(p_41421_: ItemStack, p_41422_: Level?, tooltip: MutableList<Component>, p_41424_: TooltipFlag) {
super.appendHoverText(p_41421_, p_41422_, tooltip, p_41424_)
val alreadyHasExosuit = runIfClient(true) {
minecraft.player?.matteryPlayer?.hasExoSuit == true
}
if (!alreadyHasExosuit) {
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.no_exosuit").withStyle(ChatFormatting.GRAY))
if (runIfClient(false) { minecraft.player?.isCreative != true }) {
return
}
}
val uuid = uuid(p_41421_)
val alreadyHas = (uuid != null && !ServerConfig.INFINITE_EXOSUIT_UPGRADES) && runIfClient(false) {
minecraft.player?.matteryPlayer?.exoSuitSlotCountModifiers?.contains(uuid) == true
}
if (alreadyHas) {
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.already_activated").withStyle(ChatFormatting.DARK_RED))
}
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.slots_upgrade", slotCount(p_41421_)).withStyle(ChatFormatting.DARK_GREEN))
if (hasDescription(p_41421_)) {
tooltip.add(TranslatableComponent("$descriptionId.description").withStyle(ChatFormatting.DARK_GRAY))
}
}
override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
val matteryPlayer = player.matteryPlayer ?: return super.use(p_41432_, player, hand)
val uuid = uuid(player.getItemInHand(hand))
if (matteryPlayer.hasExoSuit && ((uuid == null || ServerConfig.INFINITE_EXOSUIT_UPGRADES) || uuid !in matteryPlayer.exoSuitSlotCountModifiers)) {
player.startUsingItem(hand)
return InteractionResultHolder.consume(player.getItemInHand(hand))
}
return super.use(p_41432_, player, hand)
}
override fun finishUsingItem(itemStack: ItemStack, level: Level, player: LivingEntity): ItemStack {
if (player !is Player) return super.finishUsingItem(itemStack, level, player)
val matteryPlayer = player.matteryPlayer ?: return super.finishUsingItem(itemStack, level, player)
val uuid = uuid(itemStack)
val slotCount = slotCount(itemStack)
if (slotCount <= 0 || !matteryPlayer.hasExoSuit || (!ServerConfig.INFINITE_EXOSUIT_UPGRADES && uuid != null && uuid in matteryPlayer.exoSuitSlotCountModifiers)) {
return super.finishUsingItem(itemStack, level, player)
}
if (!player.abilities.instabuild)
itemStack.shrink(1)
if (player is ServerPlayer) {
if (uuid != null) {
if (ServerConfig.INFINITE_EXOSUIT_UPGRADES && uuid in matteryPlayer.exoSuitSlotCountModifiers) {
matteryPlayer.exoSuitSlotCountModifiers[UUID.randomUUID()] = slotCount
} else {
matteryPlayer.exoSuitSlotCountModifiers[uuid] = slotCount
}
} else {
matteryPlayer.exoSuitSlotCountModifiers[UUID.randomUUID()] = slotCount
}
player.displayClientMessage(TranslatableComponent("otm.exosuit_upgrades.slots_upgraded", slotCount).withStyle(ChatFormatting.DARK_GREEN), false)
}
return itemStack
}
override fun getUseAnimation(p_41452_: ItemStack): UseAnim = UseAnim.BOW
companion object {
fun defaultProperties(rarity: Rarity = Rarity.UNCOMMON) = Properties().stacksTo(8).rarity(Rarity.UNCOMMON).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB).fireResistant()
}
}

View File

@ -5,6 +5,7 @@ import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResultHolder
import net.minecraft.world.damagesource.DamageSource
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.Item
@ -18,84 +19,55 @@ import ru.dbotthepony.mc.otm.ServerConfig
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.toUUID
import ru.dbotthepony.mc.otm.runIfClient
import java.util.UUID
class ExoSuitSlotUpgradeItem(
val id: UUID?,
val slotCount: Int,
properties: Properties = Properties().stacksTo(8).rarity(Rarity.UNCOMMON).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)
) : Item(properties) {
val isCreative: Boolean get() = id == null
class ExoSuitSlotUpgradeItem : AbstractExoSuitSlotUpgradeItem {
val hasDescription: Boolean
val slotCount: Int
val isCreative: Boolean
override fun getUseDuration(p_41454_: ItemStack): Int {
return 30
private val uuidProvider: () -> UUID?
override fun uuid(itemStack: ItemStack): UUID? {
return uuidProvider.invoke()
}
override fun appendHoverText(p_41421_: ItemStack, p_41422_: Level?, tooltip: MutableList<Component>, p_41424_: TooltipFlag) {
super.appendHoverText(p_41421_, p_41422_, tooltip, p_41424_)
val alreadyHasExosuit = runIfClient(true) {
minecraft.player?.matteryPlayer?.hasExoSuit == true
}
if (!alreadyHasExosuit) {
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.no_exosuit").withStyle(ChatFormatting.GRAY))
if (runIfClient(false) { minecraft.player?.isCreative != true }) {
return
}
}
val alreadyHas = (id != null && !ServerConfig.INFINITE_EXOSUIT_UPGRADES) && runIfClient(false) {
minecraft.player?.matteryPlayer?.exoSuitSlotCountModifiers?.contains(id) == true
}
if (alreadyHas) {
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.already_activated").withStyle(ChatFormatting.DARK_RED))
}
tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.slots_upgrade", slotCount).withStyle(ChatFormatting.DARK_GREEN))
override fun hasDescription(itemStack: ItemStack): Boolean {
return hasDescription
}
override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder<ItemStack> {
val matteryPlayer = player.matteryPlayer ?: return super.use(p_41432_, player, hand)
if (matteryPlayer.hasExoSuit && ((id == null || ServerConfig.INFINITE_EXOSUIT_UPGRADES) || id !in matteryPlayer.exoSuitSlotCountModifiers)) {
player.startUsingItem(hand)
return InteractionResultHolder.consume(player.getItemInHand(hand))
}
return super.use(p_41432_, player, hand)
override fun slotCount(itemStack: ItemStack): Int {
return slotCount
}
override fun finishUsingItem(itemStack: ItemStack, level: Level, player: LivingEntity): ItemStack {
if (player !is Player) return super.finishUsingItem(itemStack, level, player)
val matteryPlayer = player.matteryPlayer ?: return super.finishUsingItem(itemStack, level, player)
if (!matteryPlayer.hasExoSuit || (!ServerConfig.INFINITE_EXOSUIT_UPGRADES && id != null && id in matteryPlayer.exoSuitSlotCountModifiers)) {
return super.finishUsingItem(itemStack, level, player)
}
if (!player.abilities.instabuild)
itemStack.shrink(1)
if (player is ServerPlayer) {
if (id != null) {
if (ServerConfig.INFINITE_EXOSUIT_UPGRADES && id in matteryPlayer.exoSuitSlotCountModifiers) {
matteryPlayer.exoSuitSlotCountModifiers[UUID.randomUUID()] = slotCount
} else {
matteryPlayer.exoSuitSlotCountModifiers[id] = slotCount
}
} else {
matteryPlayer.exoSuitSlotCountModifiers[UUID.randomUUID()] = slotCount
}
player.displayClientMessage(TranslatableComponent("otm.exosuit_upgrades.slots_upgraded", slotCount).withStyle(ChatFormatting.DARK_GREEN), false)
}
return itemStack
constructor(slotCount: Int, properties: Properties = defaultProperties(), hasDescription: Boolean = false) : super(properties) {
isCreative = false
this.slotCount = slotCount
this.uuidProvider = lazy { registryName!!.toUUID() }::value
this.hasDescription = hasDescription
}
override fun getUseAnimation(p_41452_: ItemStack): UseAnim = UseAnim.BOW
constructor(uuid: UUID?, slotCount: Int, properties: Properties = defaultProperties(), hasDescription: Boolean = false) : super(properties) {
isCreative = uuid == null
this.slotCount = slotCount
this.uuidProvider = { UUID(0L, 0L) }
this.hasDescription = hasDescription
}
constructor(slotCount: Int, rarity: Rarity, hasDescription: Boolean = false) : super(defaultProperties(rarity)) {
isCreative = false
this.slotCount = slotCount
this.uuidProvider = lazy { registryName!!.toUUID() }::value
this.hasDescription = hasDescription
}
constructor(uuid: UUID?, slotCount: Int, rarity: Rarity, hasDescription: Boolean = false) : super(defaultProperties(rarity)) {
isCreative = uuid == null
this.slotCount = slotCount
this.uuidProvider = { UUID(0L, 0L) }
this.hasDescription = hasDescription
}
}

View File

@ -0,0 +1,82 @@
package ru.dbotthepony.mc.otm.item
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.world.item.ItemStack
import net.minecraft.world.item.Rarity
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.data.IRandomizableItem
import java.util.*
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") // .tab(null) is a legal statement because tab field itself is nullable
class ProceduralExoSuitSlotUpgradeItem : AbstractExoSuitSlotUpgradeItem(defaultProperties().tab(null)), 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
}
}
override fun hasDescription(itemStack: ItemStack): Boolean {
return false
}
override fun slotCount(itemStack: ItemStack): Int {
return itemStack.tag?.getInt(SLOT_COUNT_KEY) ?: 0
}
override fun uuid(itemStack: ItemStack): UUID? {
return null
}
override fun appendHoverText(
p_41421_: ItemStack,
p_41422_: Level?,
tooltip: MutableList<Component>,
p_41424_: TooltipFlag
) {
super.appendHoverText(p_41421_, p_41422_, tooltip, p_41424_)
if (p_41421_.tag?.get(SLOT_COUNT_KEY) == null) {
tooltip.add(TranslatableComponent("$descriptionId.description").withStyle(ChatFormatting.GRAY))
}
}
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

@ -7,6 +7,7 @@ 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
import ru.dbotthepony.mc.otm.data.RandomizableItemLootAppender
object LootModifiers {
private val registry = DeferredRegister.create(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, OverdriveThatMatters.MOD_ID)
@ -15,6 +16,7 @@ object LootModifiers {
registry.register("loot_appender") { LootTableAppender.CODEC }
registry.register("loot_appender_separated") { LootTableSeparatedAppender.CODEC }
registry.register("loot_appender_basic") { LootTableBasicAppender.CODEC }
registry.register("randomizable_item_loot_appender") { RandomizableItemLootAppender.Companion }
}
internal fun register(bus: IEventBus) {

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.registry
import com.google.common.collect.Streams
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.tags.BlockTags
@ -17,9 +18,11 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.ServerConfig
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.toUUID
import ru.dbotthepony.mc.otm.item.*
import ru.dbotthepony.mc.otm.item.weapon.PlasmaRifleItem
import java.util.*
import java.util.stream.Stream
import kotlin.collections.ArrayList
object MItems {
@ -297,42 +300,28 @@ object MItems {
val CARGO_CRATE_MINECARTS = registry.allColored(MNames.MINECART_CARGO_CRATE) { color, _ -> MinecartCargoCrateItem(color) }
val EXOSUIT_PROBE: Item by registry.register(MNames.EXOSUIT_PROBE, ::ExoSuitProbeItem)
val EXOSUIT_INVENTORY_UPGRADE_CREATIVE: Item by registry.register("exosuit_inventory_upgrade_creative") { ExoSuitSlotUpgradeItem(null, 9, Item.Properties().stacksTo(8).rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) }
val EXOSUIT_CRAFTING_UPGRADE: Item by registry.register("exosuit_crafting_upgrade", ::ExoSuitCraftingUpgradeItem)
val EXOSUIT_INVENTORY_UPGRADES: List<Item>
val EXOSUIT_INVENTORY_UPGRADES_CRAFTABLE: List<Item>
val EXOSUIT_INVENTORY_UPGRADES_UNCRAFTABLE: List<Item>
object ExosuitUpgrades {
val INVENTORY_UPGRADE_CREATIVE: Item by registry.register("exosuit_inventory_upgrade_creative") { ExoSuitSlotUpgradeItem(null, 27, Rarity.EPIC) }
val CRAFTING_UPGRADE: Item by registry.register("exosuit_crafting_upgrade", ::ExoSuitCraftingUpgradeItem)
init {
val upgrades = ArrayList<() -> Item>()
val upgradesCraftable = ArrayList<() -> Item>()
val upgradesUncraftable = ArrayList<() -> Item>()
val baseSignificant = 7344348239534784L
var baseInsignificant = 848473865769484L
for (i in 1 .. 4) {
val obj = registry.register("exosuit_inventory_upgrade_$i") { ExoSuitSlotUpgradeItem(UUID(baseSignificant, baseInsignificant++), 9) }
upgrades.add(obj::get)
upgradesCraftable.add(obj::get)
val INVENTORY_UPGRADES = LazyList(8) {
registry.register("exosuit_inventory_upgrade_$it") { ExoSuitSlotUpgradeItem(18, Rarity.COMMON) }::get
}
for (i in 1 .. 16) {
val obj = registry.register("exosuit_inventory_upgrade_uncraftable_$i") { ExoSuitSlotUpgradeItem(UUID(baseSignificant, baseInsignificant++), 9 + (i / 5) * 9) }
upgrades.add(obj::get)
upgradesUncraftable.add(obj::get)
}
val INVENTORY_UPGRADE_PROCEDURAL: Item by registry.register("exosuit_inventory_upgrade_procedural") { ProceduralExoSuitSlotUpgradeItem() }
EXOSUIT_INVENTORY_UPGRADES = LazyList(upgrades)
EXOSUIT_INVENTORY_UPGRADES_CRAFTABLE = LazyList(upgradesCraftable)
EXOSUIT_INVENTORY_UPGRADES_UNCRAFTABLE = LazyList(upgradesUncraftable)
val INVENTORY_UPGRADE_BIG: Item by registry.register("exosuit_inventory_upgrade_big") { ExoSuitSlotUpgradeItem(60, Rarity.RARE) }
val INVENTORY_UPGRADE_HUGE: Item by registry.register("exosuit_inventory_upgrade_huge") { ExoSuitSlotUpgradeItem(135, Rarity.RARE) }
val INVENTORY_UPGRADE_WITHER: Item by registry.register("exosuit_inventory_upgrade_wither") { ExoSuitSlotUpgradeItem(90, Rarity.RARE, hasDescription = true) }
val INVENTORY_UPGRADE_ENDER_DRAGON: Item by registry.register("exosuit_inventory_upgrade_ender_dragon") { ExoSuitSlotUpgradeItem(180, Rarity.EPIC, hasDescription = true) }
}
val EXOSUIT_INVENTORY_UPGRADE_BIG: Item by registry.register("exosuit_inventory_upgrade_big") { ExoSuitSlotUpgradeItem(UUID.fromString("121a17a5-533c-9ac0-ff02-03aea75ed20c"), 45, Item.Properties().stacksTo(8).rarity(Rarity.RARE).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) }
val EXOSUIT_INVENTORY_UPGRADE_HUGE: Item by registry.register("exosuit_inventory_upgrade_huge") { ExoSuitSlotUpgradeItem(UUID.fromString("121a17a5-533c-9ac0-ff02-03aea75ed20d"), 90, Item.Properties().stacksTo(8).rarity(Rarity.RARE).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) }
init {
// call static initializer
ExosuitUpgrades
MRegistry.CARGO_CRATES.registerItems(registry)
MRegistry.TRITANIUM_BLOCK.registerItems(registry)
MRegistry.TRITANIUM_STAIRS.registerItems(registry)