Merge remote-tracking branch 'origin/master'

This commit is contained in:
GearShocky 2022-10-27 17:12:28 +06:00
commit 3e291ff340
35 changed files with 580 additions and 523 deletions

View File

@ -0,0 +1,114 @@
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
import net.minecraft.world.level.storage.loot.LootPool
import net.minecraft.world.level.storage.loot.LootTable
import net.minecraft.world.level.storage.loot.entries.LootItem
import net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer
import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction
import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition
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 {
return withPool(LootPool.lootPool().also {
it.item(item, 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) {
add(LootItem.lootTableItem(item).also(configurator))
}
fun LootPool.Builder.setRolls(count: Int): LootPool.Builder = setRolls(ConstantValue.exactly(count.toFloat()))
fun LootPool.Builder.setRolls(count: Float): LootPool.Builder = setRolls(ConstantValue.exactly(count))
fun LootPool.Builder.setRolls(min: Int, max: Int): LootPool.Builder = setRolls(UniformGenerator.between(min.toFloat(), max.toFloat()))
fun LootPool.Builder.setRolls(min: Float, max: Float): LootPool.Builder = setRolls(UniformGenerator.between(min, max))
fun LootPool.Builder.condition(value: LootItemCondition.Builder): LootPool.Builder = `when`(value)
fun LootPool.Builder.chanceCondition(chance: Double): LootPool.Builder = condition(ChanceCondition(chance))
fun <T : LootPoolSingletonContainer.Builder<*>> T.setCount(count: Int, configurator: LootItemConditionalFunction.Builder<*>.() -> Unit = {}): T {
apply(SetItemCountFunction.setCount(ConstantValue.exactly(count.toFloat())).also(configurator))
return this
}
fun <T : LootPoolSingletonContainer.Builder<*>> T.setCount(minimal: Int, maximal: Int, configurator: LootItemConditionalFunction.Builder<*>.() -> Unit = {}): T {
apply(SetItemCountFunction.setCount(UniformGenerator.between(minimal.toFloat(), maximal.toFloat())).also(configurator))
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 {
apply(SetItemCountFunction.setCount(UniformGenerator.between(minimal, maximal)).also(configurator))
return this
}
fun <T : LootPoolSingletonContainer.Builder<*>> T.condition(condition: LootItemCondition.Builder): T {
`when`(condition)
return this
}
fun <T : LootItemConditionalFunction.Builder<*>> T.condition(condition: LootItemCondition.Builder): T {
`when`(condition)
return this
}
inline fun <T : LootPoolSingletonContainer.Builder<*>> T.blockStateCondition(block: Block, configurator: StatePropertiesPredicate.Builder.() -> Unit): T {
condition(
LootItemBlockStatePropertyCondition.hasBlockStateProperties(block)
.setProperties(StatePropertiesPredicate.Builder.properties().also(configurator)))
return this
}
inline fun <T : LootItemConditionalFunction.Builder<*>> T.blockStateCondition(block: Block, configurator: StatePropertiesPredicate.Builder.() -> Unit): T {
condition(
LootItemBlockStatePropertyCondition.hasBlockStateProperties(block)
.setProperties(StatePropertiesPredicate.Builder.properties().also(configurator)))
return this
}
fun <T : LootItemConditionalFunction.Builder<*>> T.chanceCondition(chance: Double): T {
condition(ChanceCondition(chance))
return this
}
operator fun StatePropertiesPredicate.Builder.set(property: Property<*>, value: String): StatePropertiesPredicate.Builder = hasProperty(property, value)
operator fun StatePropertiesPredicate.Builder.set(property: Property<Int>, value: Int): StatePropertiesPredicate.Builder = hasProperty(property, value)
operator fun StatePropertiesPredicate.Builder.set(property: Property<Boolean>, value: Boolean): StatePropertiesPredicate.Builder = hasProperty(property, value)
operator fun <T : Comparable<T>> StatePropertiesPredicate.Builder.set(property: Property<T>, value: T): StatePropertiesPredicate.Builder {
if (value !is StringRepresentable) {
throw ClassCastException("Provided type ${value::class.qualifiedName} is not a subtype of ${StringRepresentable::class.qualifiedName}")
}
return hasProperty(property, value.serializedName)
}

View File

@ -1,8 +1,55 @@
package ru.dbotthepony.mc.otm.datagen.loot package ru.dbotthepony.mc.otm.datagen.loot
import net.minecraft.data.DataGenerator import net.minecraft.data.DataGenerator
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraftforge.common.data.GlobalLootModifierProvider import net.minecraftforge.common.data.GlobalLootModifierProvider
import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender
import ru.dbotthepony.mc.otm.datagen.DataGen import ru.dbotthepony.mc.otm.datagen.DataGen
import java.util.Arrays
import java.util.stream.Stream
@Suppress("FunctionName")
fun BasicLootAppender(
conditions: Array<out LootItemCondition>,
items: Stream<ItemStack>
): LootPoolAppender {
return LootPoolAppender(conditions, items.map {
lootPool {
item(it.item) {
setCount(it.count)
}
}
})
}
@Suppress("FunctionName")
fun BasicLootAppender(
conditions: Array<out LootItemCondition>,
vararg items: ItemStack
) = BasicLootAppender(conditions, Arrays.stream(items))
@Suppress("FunctionName")
fun PlainLootAppender(
conditions: Array<out LootItemCondition>,
items: Stream<Pair<ItemStack, Double>>
): LootPoolAppender {
return LootPoolAppender(conditions, items.map {
lootPool {
item(it.first.item) {
setCount(it.first.count)
}
chanceCondition(it.second)
}
})
}
@Suppress("FunctionName")
fun PlainLootAppender(
conditions: Array<out LootItemCondition>,
vararg items: Pair<ItemStack, Double>
) = PlainLootAppender(conditions, Arrays.stream(items))
class LootModifiers(generator: DataGenerator) : GlobalLootModifierProvider(generator, DataGen.MOD_ID) { class LootModifiers(generator: DataGenerator) : GlobalLootModifierProvider(generator, DataGen.MOD_ID) {
private val lambdas = ArrayList<(LootModifiers) -> Unit>() private val lambdas = ArrayList<(LootModifiers) -> Unit>()

View File

@ -6,27 +6,70 @@ 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.ChanceWithPlaytimeCondition import ru.dbotthepony.mc.otm.data.condition.ChanceWithPlaytimeCondition
import ru.dbotthepony.mc.otm.data.HasExosuitCondition import ru.dbotthepony.mc.otm.data.condition.HasExosuitCondition
import ru.dbotthepony.mc.otm.data.IRandomizableItem import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition
import ru.dbotthepony.mc.otm.data.ItemInInventoryCondition import ru.dbotthepony.mc.otm.data.condition.KilledByRealPlayerOrIndirectly
import ru.dbotthepony.mc.otm.data.KilledByRealPlayer import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender
import ru.dbotthepony.mc.otm.data.BasicLootAppender import ru.dbotthepony.mc.otm.data.loot.RandomizerFunction
import ru.dbotthepony.mc.otm.data.KilledByRealPlayerOrIndirectly
import ru.dbotthepony.mc.otm.data.PlainLootAppender
import ru.dbotthepony.mc.otm.data.RandomizableItemLootAppender
import ru.dbotthepony.mc.otm.registry.MItems import ru.dbotthepony.mc.otm.registry.MItems
@Suppress("FunctionName")
fun LootTableIdCondition(location: String): LootItemCondition { fun LootTableIdCondition(location: String): LootItemCondition {
return LootTableIdCondition.Builder(ResourceLocation("minecraft", location)).build() return LootTableIdCondition.Builder(ResourceLocation("minecraft", location)).build()
} }
@Suppress("FunctionName")
fun LootTableIdCondition(location: ResourceLocation): LootItemCondition { 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,
@ -34,14 +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,14 +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,
@ -70,27 +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,
@ -99,15 +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,
@ -143,12 +145,18 @@ fun addLootModifiers(it: LootModifiers) {
)) ))
it.add("wither_exosuit_upgrades", BasicLootAppender( it.add("wither_exosuit_upgrades", BasicLootAppender(
arrayOf(LootTableIdCondition(EntityType.WITHER.defaultLootTable)), arrayOf(
LootTableIdCondition(EntityType.WITHER.defaultLootTable),
KilledByRealPlayerOrIndirectly,
),
ItemStack(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_WITHER), ItemStack(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_WITHER),
)) ))
it.add("ender_dragon_exosuit_upgrades", BasicLootAppender( it.add("ender_dragon_exosuit_upgrades", BasicLootAppender(
arrayOf(LootTableIdCondition(EntityType.ENDER_DRAGON.defaultLootTable)), arrayOf(
LootTableIdCondition(EntityType.ENDER_DRAGON.defaultLootTable),
KilledByRealPlayerOrIndirectly,
),
ItemStack(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON), ItemStack(MItems.ExosuitUpgrades.INVENTORY_UPGRADE_ENDER_DRAGON),
)) ))
} }

View File

@ -10,11 +10,9 @@ import net.minecraft.advancements.critereon.StatePropertiesPredicate
import net.minecraft.data.DataGenerator import net.minecraft.data.DataGenerator
import net.minecraft.data.loot.LootTableProvider import net.minecraft.data.loot.LootTableProvider
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.util.StringRepresentable
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.SlabBlock import net.minecraft.world.level.block.SlabBlock
import net.minecraft.world.level.block.state.properties.Property
import net.minecraft.world.level.block.state.properties.SlabType import net.minecraft.world.level.block.state.properties.SlabType
import net.minecraft.world.level.storage.loot.LootPool import net.minecraft.world.level.storage.loot.LootPool
import net.minecraft.world.level.storage.loot.LootTable import net.minecraft.world.level.storage.loot.LootTable
@ -22,85 +20,23 @@ import net.minecraft.world.level.storage.loot.ValidationContext
import net.minecraft.world.level.storage.loot.entries.LootItem import net.minecraft.world.level.storage.loot.entries.LootItem
import net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer import net.minecraft.world.level.storage.loot.entries.LootPoolSingletonContainer
import net.minecraft.world.level.storage.loot.functions.CopyNbtFunction import net.minecraft.world.level.storage.loot.functions.CopyNbtFunction
import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction
import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSet import net.minecraft.world.level.storage.loot.parameters.LootContextParamSet
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider import net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProvider
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 ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
import ru.dbotthepony.mc.otm.core.registryName
import java.util.function.BiConsumer import java.util.function.BiConsumer
import java.util.function.Consumer import java.util.function.Consumer
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.reflect.full.isSubclassOf
private typealias LootTableSaver = BiConsumer<ResourceLocation, LootTable.Builder> private typealias LootTableSaver = BiConsumer<ResourceLocation, LootTable.Builder>
private typealias LootTableCallback = Consumer<LootTableSaver> private typealias LootTableCallback = Consumer<LootTableSaver>
private typealias LootTableCallbackProvider = Supplier<LootTableCallback> private typealias LootTableCallbackProvider = Supplier<LootTableCallback>
private typealias LootTuple = Pair<LootTableCallbackProvider, LootContextParamSet> private typealias LootTuple = Pair<LootTableCallbackProvider, LootContextParamSet>
inline fun LootTable.Builder.lootPool(configurator: LootPool.Builder.() -> Unit): LootTable.Builder = withPool(LootPool.lootPool().also(configurator))
inline fun LootPool.Builder.item(item: ItemLike, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit) {
add(LootItem.lootTableItem(item).also(configurator))
}
fun LootPool.Builder.setRolls(count: Int): LootPool.Builder = setRolls(ConstantValue.exactly(count.toFloat()))
fun LootPool.Builder.setRolls(count: Float): LootPool.Builder = setRolls(ConstantValue.exactly(count))
fun LootPool.Builder.setRolls(min: Int, max: Int): LootPool.Builder = setRolls(UniformGenerator.between(min.toFloat(), max.toFloat()))
fun LootPool.Builder.setRolls(min: Float, max: Float): LootPool.Builder = setRolls(UniformGenerator.between(min, max))
fun <T : LootPoolSingletonContainer.Builder<*>> T.setCount(count: Int, configurator: LootItemConditionalFunction.Builder<*>.() -> Unit = {}): T {
apply(SetItemCountFunction.setCount(ConstantValue.exactly(count.toFloat())).also(configurator))
return this
}
fun <T : LootPoolSingletonContainer.Builder<*>> T.setCount(minimal: Int, maximal: Int, configurator: LootItemConditionalFunction.Builder<*>.() -> Unit = {}): T {
apply(SetItemCountFunction.setCount(UniformGenerator.between(minimal.toFloat(), maximal.toFloat())).also(configurator))
return this
}
fun <T : LootPoolSingletonContainer.Builder<*>> T.setCount(minimal: Float, maximal: Float, configurator: LootItemConditionalFunction.Builder<*>.() -> Unit = {}): T {
apply(SetItemCountFunction.setCount(UniformGenerator.between(minimal, maximal)).also(configurator))
return this
}
fun <T : LootPoolSingletonContainer.Builder<*>> T.condition(condition: LootItemCondition.Builder): T {
`when`(condition)
return this
}
fun <T : LootItemConditionalFunction.Builder<*>> T.condition(condition: LootItemCondition.Builder): T {
`when`(condition)
return this
}
inline fun <T : LootPoolSingletonContainer.Builder<*>> T.blockStateCondition(block: Block, configurator: StatePropertiesPredicate.Builder.() -> Unit): T {
condition(LootItemBlockStatePropertyCondition.hasBlockStateProperties(block).setProperties(StatePropertiesPredicate.Builder.properties().also(configurator)))
return this
}
inline fun <T : LootItemConditionalFunction.Builder<*>> T.blockStateCondition(block: Block, configurator: StatePropertiesPredicate.Builder.() -> Unit): T {
condition(LootItemBlockStatePropertyCondition.hasBlockStateProperties(block).setProperties(StatePropertiesPredicate.Builder.properties().also(configurator)))
return this
}
operator fun StatePropertiesPredicate.Builder.set(property: Property<*>, value: String): StatePropertiesPredicate.Builder = hasProperty(property, value)
operator fun StatePropertiesPredicate.Builder.set(property: Property<Int>, value: Int): StatePropertiesPredicate.Builder = hasProperty(property, value)
operator fun StatePropertiesPredicate.Builder.set(property: Property<Boolean>, value: Boolean): StatePropertiesPredicate.Builder = hasProperty(property, value)
operator fun <T : Comparable<T>> StatePropertiesPredicate.Builder.set(property: Property<T>, value: T): StatePropertiesPredicate.Builder {
if (value !is StringRepresentable) {
throw ClassCastException("Provided type ${value::class.qualifiedName} is not a subtype of ${StringRepresentable::class.qualifiedName}")
}
return hasProperty(property, value.serializedName)
}
data class NbtCopy(val source: String, val destination: String, val strategy: CopyNbtFunction.MergeStrategy = CopyNbtFunction.MergeStrategy.REPLACE) data class NbtCopy(val source: String, val destination: String, val strategy: CopyNbtFunction.MergeStrategy = CopyNbtFunction.MergeStrategy.REPLACE)
fun TileNbtCopy(source: String, strategy: CopyNbtFunction.MergeStrategy = CopyNbtFunction.MergeStrategy.REPLACE): NbtCopy { fun TileNbtCopy(source: String, strategy: CopyNbtFunction.MergeStrategy = CopyNbtFunction.MergeStrategy.REPLACE): NbtCopy {
@ -158,7 +94,7 @@ class LootTables(generator: DataGenerator) : LootTableProvider(generator) {
override fun validate(map: MutableMap<ResourceLocation, LootTable>, validationtracker: ValidationContext) {} override fun validate(map: MutableMap<ResourceLocation, LootTable>, validationtracker: ValidationContext) {}
fun createSlabItemTable(block: Block) { fun createSlabItemTable(block: Block, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit = {}) {
builder(LootContextParamSets.BLOCK, block.lootTable) { builder(LootContextParamSets.BLOCK, block.lootTable) {
withPool( withPool(
LootPool.lootPool().setRolls(ConstantValue.exactly(1.0f)).add( LootPool.lootPool().setRolls(ConstantValue.exactly(1.0f)).add(
@ -171,14 +107,16 @@ class LootTables(generator: DataGenerator) : LootTableProvider(generator) {
.hasProperty(SlabBlock.TYPE, SlabType.DOUBLE) .hasProperty(SlabBlock.TYPE, SlabType.DOUBLE)
) )
) )
) ).also(configurator)
) )
) )
} }
} }
fun createSlabItemTable(block: Collection<Block>) { fun createSlabItemTable(blocks: Collection<Block>, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit = {}) {
block.forEach(this::createSlabItemTable) for (block in blocks) {
createSlabItemTable(block, configurator)
}
} }
fun blockProvider(block: Block, provider: () -> LootTable.Builder) { fun blockProvider(block: Block, provider: () -> LootTable.Builder) {
@ -206,13 +144,23 @@ class LootTables(generator: DataGenerator) : LootTableProvider(generator) {
fun dropsSelf(vararg blocks: Block) { fun dropsSelf(vararg blocks: Block) {
for (block in blocks) { for (block in blocks) {
singleLootPool(LootContextParamSets.BLOCK, block.lootTable) { singleLootPool(LootContextParamSets.BLOCK, block.lootTable) {
add(LootItem.lootTableItem(block)) item(block) {}
} }
} }
} }
fun dropsSelf(blocks: Collection<Block>) { fun dropsSelf(block: Block, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit = {}) {
blocks.forEach(this::dropsSelf) singleLootPool(LootContextParamSets.BLOCK, block.lootTable) {
item(block, configurator)
}
}
fun dropsSelf(blocks: Collection<Block>, configurator: LootPoolSingletonContainer.Builder<*>.() -> Unit = {}) {
for (block in blocks) {
singleLootPool(LootContextParamSets.BLOCK, block.lootTable) {
item(block, configurator)
}
}
} }
fun tile(block: Block, f: (CopyNbtFunction.Builder) -> Unit = {}) { fun tile(block: Block, f: (CopyNbtFunction.Builder) -> Unit = {}) {

View File

@ -7,6 +7,7 @@ import net.minecraft.world.level.block.state.properties.BlockStateProperties
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf import net.minecraft.world.level.block.state.properties.DoubleBlockHalf
import net.minecraft.world.level.storage.loot.entries.LootItem import net.minecraft.world.level.storage.loot.entries.LootItem
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition
import ru.dbotthepony.mc.otm.block.entity.ChemicalGeneratorBlockEntity import ru.dbotthepony.mc.otm.block.entity.ChemicalGeneratorBlockEntity
import ru.dbotthepony.mc.otm.block.entity.EnergyCounterBlockEntity import ru.dbotthepony.mc.otm.block.entity.EnergyCounterBlockEntity
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity.Companion.ENERGY_KEY import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity.Companion.ENERGY_KEY
@ -22,45 +23,45 @@ import ru.dbotthepony.mc.otm.registry.MItems
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
fun addLootTables(lootTables: LootTables) { fun addLootTables(lootTables: LootTables) {
lootTables.dropsSelf(MRegistry.DECORATIVE_CRATE.allBlocks.values) lootTables.dropsSelf(MRegistry.DECORATIVE_CRATE.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.CARGO_CRATES.allBlocks.values) lootTables.dropsSelf(MRegistry.CARGO_CRATES.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.INDUSTRIAL_GLASS.allBlocks.values) lootTables.dropsSelf(MRegistry.INDUSTRIAL_GLASS.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.INDUSTRIAL_GLASS_PANE.allBlocks.values) lootTables.dropsSelf(MRegistry.INDUSTRIAL_GLASS_PANE.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.TRITANIUM_BLOCK.allBlocks.values) lootTables.dropsSelf(MRegistry.TRITANIUM_BLOCK.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.TRITANIUM_WALL.allBlocks.values) lootTables.dropsSelf(MRegistry.TRITANIUM_WALL.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.TRITANIUM_STAIRS.allBlocks.values) lootTables.dropsSelf(MRegistry.TRITANIUM_STAIRS.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.createSlabItemTable(MRegistry.TRITANIUM_SLAB.allBlocks.values) lootTables.createSlabItemTable(MRegistry.TRITANIUM_SLAB.allBlocks.values)
lootTables.dropsSelf(MRegistry.VENT.allBlocks.values) lootTables.dropsSelf(MRegistry.VENT.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.VENT_ALTERNATIVE.allBlocks.values) lootTables.dropsSelf(MRegistry.VENT_ALTERNATIVE.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.FLOOR_TILES.blocks.values) lootTables.dropsSelf(MRegistry.FLOOR_TILES.blocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.UNREFINED_FLOOR_TILES.blocks.values) lootTables.dropsSelf(MRegistry.UNREFINED_FLOOR_TILES.blocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.TRITANIUM_STRIPED_BLOCK.flatBlocks) lootTables.dropsSelf(MRegistry.TRITANIUM_STRIPED_BLOCK.flatBlocks) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.TRITANIUM_STRIPED_STAIRS.flatBlocks) lootTables.dropsSelf(MRegistry.TRITANIUM_STRIPED_STAIRS.flatBlocks) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.TRITANIUM_STRIPED_WALL.flatBlocks) lootTables.dropsSelf(MRegistry.TRITANIUM_STRIPED_WALL.flatBlocks) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.createSlabItemTable(MRegistry.TRITANIUM_STRIPED_SLAB.flatBlocks) lootTables.createSlabItemTable(MRegistry.TRITANIUM_STRIPED_SLAB.flatBlocks) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.FLOOR_TILES_STAIRS.blocks.values) lootTables.dropsSelf(MRegistry.FLOOR_TILES_STAIRS.blocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.createSlabItemTable(MRegistry.FLOOR_TILES_SLAB.blocks.values) lootTables.createSlabItemTable(MRegistry.FLOOR_TILES_SLAB.blocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.CARBON_FIBRE_BLOCK) lootTables.dropsSelf(MBlocks.CARBON_FIBRE_BLOCK) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.TRITANIUM_RAW_BLOCK) lootTables.dropsSelf(MBlocks.TRITANIUM_RAW_BLOCK) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.TRITANIUM_STRIPED_BLOCK) lootTables.dropsSelf(MBlocks.TRITANIUM_STRIPED_BLOCK) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.TRITANIUM_STRIPED_WALL) lootTables.dropsSelf(MBlocks.TRITANIUM_STRIPED_WALL) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.TRITANIUM_STRIPED_STAIRS) lootTables.dropsSelf(MBlocks.TRITANIUM_STRIPED_STAIRS) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.createSlabItemTable(MBlocks.TRITANIUM_STRIPED_SLAB) lootTables.createSlabItemTable(MBlocks.TRITANIUM_STRIPED_SLAB) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.MATTER_CABLE) lootTables.dropsSelf(MBlocks.MATTER_CABLE) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.GRAVITATION_STABILIZER) lootTables.dropsSelf(MBlocks.GRAVITATION_STABILIZER)
lootTables.dropsOther(MBlocks.GRAVITATION_STABILIZER_LENS, MBlocks.GRAVITATION_STABILIZER) lootTables.dropsOther(MBlocks.GRAVITATION_STABILIZER_LENS, MBlocks.GRAVITATION_STABILIZER)
lootTables.dropsSelf(MBlocks.LABORATORY_LAMP) lootTables.dropsSelf(MBlocks.LABORATORY_LAMP) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.LABORATORY_LAMP_INVERTED) lootTables.dropsSelf(MBlocks.LABORATORY_LAMP_INVERTED) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.DANGER_STRIPE_BLOCK) lootTables.dropsSelf(MBlocks.DANGER_STRIPE_BLOCK) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.METAL_BEAM) lootTables.dropsSelf(MBlocks.METAL_BEAM) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.TRITANIUM_INGOT_BLOCK) lootTables.dropsSelf(MBlocks.TRITANIUM_INGOT_BLOCK) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MBlocks.TRITANIUM_TRAPDOOR) lootTables.dropsSelf(MBlocks.TRITANIUM_TRAPDOOR) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.dropsSelf(MRegistry.TRITANIUM_PRESSURE_PLATE.allBlocks.values) lootTables.dropsSelf(MRegistry.TRITANIUM_PRESSURE_PLATE.allBlocks.values) { condition(ExplosionCondition.survivesExplosion()) }
lootTables.block(MBlocks.PHANTOM_ATTRACTOR) { lootTables.block(MBlocks.PHANTOM_ATTRACTOR) {
item(MBlocks.PHANTOM_ATTRACTOR) { item(MBlocks.PHANTOM_ATTRACTOR) {
@ -68,6 +69,8 @@ fun addLootTables(lootTables: LootTables) {
this[BlockStateProperties.DOUBLE_BLOCK_HALF] = DoubleBlockHalf.LOWER this[BlockStateProperties.DOUBLE_BLOCK_HALF] = DoubleBlockHalf.LOWER
} }
} }
condition(ExplosionCondition.survivesExplosion())
} }
lootTables.block(MBlocks.TRITANIUM_DOOR) { lootTables.block(MBlocks.TRITANIUM_DOOR) {
@ -76,6 +79,8 @@ fun addLootTables(lootTables: LootTables) {
this[BlockStateProperties.DOUBLE_BLOCK_HALF] = DoubleBlockHalf.LOWER this[BlockStateProperties.DOUBLE_BLOCK_HALF] = DoubleBlockHalf.LOWER
} }
} }
condition(ExplosionCondition.survivesExplosion())
} }
lootTables.builder(LootContextParamSets.ADVANCEMENT_ENTITY, modLocation("research_all_android")) { lootTables.builder(LootContextParamSets.ADVANCEMENT_ENTITY, modLocation("research_all_android")) {

View File

@ -43,6 +43,11 @@ fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
.unlockedBy(MItemTags.TRITANIUM_INGOTS_STORAGE) .unlockedBy(MItemTags.TRITANIUM_INGOTS_STORAGE)
.save(consumer, modLocation("tritanium_ingot_from_storage")) .save(consumer, modLocation("tritanium_ingot_from_storage"))
ShapelessRecipeBuilder(MItems.ENERGY_COUNTER, 1)
.requires(MItems.ENERGY_COUNTER)
.unlockedBy(MItems.ENERGY_COUNTER)
.save(consumer, modLocation("energy_counter_reset"))
MatteryRecipe(MBlocks.PLATE_PRESS) MatteryRecipe(MBlocks.PLATE_PRESS)
.row(MItems.ELECTRIC_PARTS, MItems.ENERGY_BUS, MItems.ELECTRIC_PARTS) .row(MItems.ELECTRIC_PARTS, MItems.ENERGY_BUS, MItems.ELECTRIC_PARTS)
.row(MItemTags.TRITANIUM_INGOTS, Items.BLAST_FURNACE, MItemTags.TRITANIUM_INGOTS) .row(MItemTags.TRITANIUM_INGOTS, Items.BLAST_FURNACE, MItemTags.TRITANIUM_INGOTS)
@ -52,8 +57,7 @@ fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
.build(consumer) .build(consumer)
MatteryRecipe(MBlocks.PLATE_PRESS) MatteryRecipe(MBlocks.PLATE_PRESS)
.rowB(MItemTags.BASIC_CIRCUIT) .rowB(MItems.MACHINE_FRAME)
.row(MItemTags.TRITANIUM_PLATES, MItems.MACHINE_FRAME, MItemTags.TRITANIUM_PLATES)
.rowAC(MItemTags.PISTONS, MItemTags.PISTONS) .rowAC(MItemTags.PISTONS, MItemTags.PISTONS)
.unlockedBy(MItemTags.TRITANIUM_INGOTS) .unlockedBy(MItemTags.TRITANIUM_INGOTS)
.unlockedBy(MItems.ELECTRIC_PARTS) .unlockedBy(MItems.ELECTRIC_PARTS)

View File

@ -208,5 +208,6 @@ fun addTags(tagsProvider: TagsProvider) {
MobEffects.ABSORPTION, MobEffects.ABSORPTION,
MobEffects.SATURATION, MobEffects.SATURATION,
MobEffects.DOLPHINS_GRACE, MobEffects.DOLPHINS_GRACE,
MobEffects.CONFUSION,
) )
} }

View File

@ -148,6 +148,26 @@ object ServerConfig {
.comment("If this is disabled, any (technically) excess hunger will be nullified, unless playing on peaceful difficulty.") .comment("If this is disabled, any (technically) excess hunger will be nullified, unless playing on peaceful difficulty.")
.define("regenerateEnergy", true) .define("regenerateEnergy", true)
object NanobotsRegeneration {
val COOLDOWN: List<Int> by specBuilder
.comment("In ticks, time between heal ticks")
.comment("One heal tick restores 1 heart (2 health points) at most")
.comment("If not getting hurt in specified period of ticks, heal tick takes place, tick timer resets to zero and THIS array' index advances by 1")
.comment("Index inside this array can not exceed of one of ability's")
.comment("")
.comment("Wording in pseudocode:")
.comment("if (ticksSinceTakingDamage >= cooldownConfigOption[healTicks /* or config's biggest index, whichever is smaller */]) {")
.comment(" healTicks = min(healTicks + 1, this.level /* ability level */)")
.comment(" ticksSinceTakingDamage = 0")
.comment(" this.ply.heal(...)")
.comment("}")
.defineList("cooldown", { mutableListOf(80, 60, 40, 20) }) { it is Int }
val ENERGY_PER_HITPOINT by specBuilder
.comment("Energy required to regenerate 1 health point (half a heart)")
.defineImpreciseFraction("energyPerHitpoint", ImpreciseFraction(800))
}
val ANDROID_ENERGY_PER_HUNGER_POINT by specBuilder.defineImpreciseFraction("energyPerHunger", ImpreciseFraction(2000), ImpreciseFraction.ZERO) val ANDROID_ENERGY_PER_HUNGER_POINT by specBuilder.defineImpreciseFraction("energyPerHunger", ImpreciseFraction(2000), ImpreciseFraction.ZERO)
val ANDROID_MAX_ENERGY by specBuilder.comment("Internal battery of every android has this much storage").defineImpreciseFraction("capacity", ImpreciseFraction(80_000), ImpreciseFraction.ZERO) val ANDROID_MAX_ENERGY by specBuilder.comment("Internal battery of every android has this much storage").defineImpreciseFraction("capacity", ImpreciseFraction(80_000), ImpreciseFraction.ZERO)
val NIGHT_VISION_POWER_DRAW by specBuilder.defineImpreciseFraction("nightVisionPowerDraw", ImpreciseFraction(8), ImpreciseFraction.ZERO) val NIGHT_VISION_POWER_DRAW by specBuilder.defineImpreciseFraction("nightVisionPowerDraw", ImpreciseFraction(8), ImpreciseFraction.ZERO)
@ -223,6 +243,7 @@ object ServerConfig {
init { init {
// access instances so spec is built // access instances so spec is built
NanobotsRegeneration
EnderTeleporter EnderTeleporter
AndroidJumpBoost AndroidJumpBoost
AndroidItemMagnet AndroidItemMagnet

View File

@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraftforge.event.entity.living.LivingHurtEvent import net.minecraftforge.event.entity.living.LivingHurtEvent
import ru.dbotthepony.mc.otm.ServerConfig
import ru.dbotthepony.mc.otm.android.AndroidFeature import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction
@ -19,16 +20,16 @@ class NanobotsRegenerationFeature(android: MatteryPlayerCapability) : AndroidFea
if (ply.health > 0f && ply.health < ply.maxHealth) { if (ply.health > 0f && ply.health < ply.maxHealth) {
ticksPassed++ ticksPassed++
val waitTime = TICKS_BETWEEN_HEAL.getOrElse(healTicks) { TICKS_BETWEEN_HEAL.last() } val waitTime = ServerConfig.NanobotsRegeneration.COOLDOWN.getOrElse(healTicks) { ServerConfig.NanobotsRegeneration.COOLDOWN.last() }
if (ticksPassed > waitTime) { if (ticksPassed > waitTime) {
val missingHealth = (ply.maxHealth - ply.health).coerceAtMost(2f) val missingHealth = (ply.maxHealth - ply.health).coerceAtMost(2f)
val power = ENERGY_PER_HITPOINT * missingHealth val power = ServerConfig.NanobotsRegeneration.ENERGY_PER_HITPOINT * missingHealth
val extracted = android.androidEnergy.extractEnergyInner(power, false) val extracted = android.androidEnergy.extractEnergyInner(power, false)
if (extracted.isPositive) { if (extracted.isPositive) {
healTicks = (healTicks + 1).coerceAtMost(level) healTicks = (healTicks + 1).coerceAtMost(level)
val healed = (extracted / ENERGY_PER_HITPOINT).toFloat() val healed = (extracted / ServerConfig.NanobotsRegeneration.ENERGY_PER_HITPOINT).toFloat()
ply.heal(healed) ply.heal(healed)
(ply as ServerPlayer?)?.awardStat(StatNames.HEALTH_REGENERATED, (healed * 10f).roundToInt()) (ply as ServerPlayer?)?.awardStat(StatNames.HEALTH_REGENERATED, (healed * 10f).roundToInt())
ticksPassed = 0 ticksPassed = 0
@ -59,15 +60,4 @@ class NanobotsRegenerationFeature(android: MatteryPlayerCapability) : AndroidFea
ticksPassed = nbt.getInt("ticksPassed") ticksPassed = nbt.getInt("ticksPassed")
healTicks = nbt.getInt("healTicks") healTicks = nbt.getInt("healTicks")
} }
companion object {
private val ENERGY_PER_HITPOINT = ImpreciseFraction(800)
private val TICKS_BETWEEN_HEAL = listOf(
100, // 5 seconds
80, // 4 seconds
60, // 3 seconds
40, // 2 seconds
)
}
} }

View File

@ -16,7 +16,6 @@ import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.IEnergyStorage import net.minecraftforge.energy.IEnergyStorage
import net.minecraftforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.block.EnergyCounterBlock import ru.dbotthepony.mc.otm.block.EnergyCounterBlock
import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.capability.*
@ -126,13 +125,13 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
tickOnceServer(this::checkSurroundings) tickOnceServer(this::checkSurroundings)
} }
private inner class EnergyCounterCap(val is_input: Boolean) : IMatteryEnergyStorage { private inner class EnergyCounterCap(val isInput: Boolean) : IMatteryEnergyStorage {
override fun extractEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { override fun extractEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
return extractEnergyInner(howMuch, simulate) return extractEnergyInner(howMuch, simulate)
} }
override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
if (is_input) if (isInput)
return ImpreciseFraction.ZERO return ImpreciseFraction.ZERO
if (inputCapability.isPresent) { if (inputCapability.isPresent) {
@ -164,7 +163,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
} }
override fun receiveEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { override fun receiveEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
if (!is_input) if (!isInput)
return ImpreciseFraction.ZERO return ImpreciseFraction.ZERO
if (outputCapability.isPresent) { if (outputCapability.isPresent) {
@ -193,7 +192,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override val batteryLevel: ImpreciseFraction override val batteryLevel: ImpreciseFraction
get() { get() {
if (is_input) { if (isInput) {
if (outputCapability.isPresent) { if (outputCapability.isPresent) {
val it = outputCapability.resolve().get() val it = outputCapability.resolve().get()
@ -220,7 +219,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override val maxBatteryLevel: ImpreciseFraction override val maxBatteryLevel: ImpreciseFraction
get() { get() {
if (is_input) { if (isInput) {
if (outputCapability.isPresent) { if (outputCapability.isPresent) {
val it = outputCapability.resolve().get() val it = outputCapability.resolve().get()
@ -247,7 +246,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
override val missingPower: ImpreciseFraction override val missingPower: ImpreciseFraction
get() { get() {
if (is_input) { if (isInput) {
if (outputCapability.isPresent) { if (outputCapability.isPresent) {
val it = outputCapability.resolve().get() val it = outputCapability.resolve().get()
@ -272,15 +271,15 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
return ImpreciseFraction.ZERO return ImpreciseFraction.ZERO
} }
override fun canExtract() = !is_input override fun canExtract() = !isInput
override fun canReceive() = is_input override fun canReceive() = isInput
} }
private var resolverInput = LazyOptional.of<IMatteryEnergyStorage> { energyInput } private var resolverInput = LazyOptional.of<IMatteryEnergyStorage> { energyInput }
private var resolverOutput = LazyOptional.of<IMatteryEnergyStorage> { energyOutput } private var resolverOutput = LazyOptional.of<IMatteryEnergyStorage> { energyOutput }
private var resolverInputMekanism = if (isMekanismLoaded) LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) } else null private var resolverInputMekanism = if (isMekanismLoaded) LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) } else null
private var resolverOutputMekanism = if (isMekanismLoaded) LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) } else null private var resolverOutputMekanism = if (isMekanismLoaded) LazyOptional.of { Mattery2MekanismEnergyWrapper(energyOutput) } else null
private var valid = true private var valid = true
@ -301,7 +300,7 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
if (isMekanismLoaded) { if (isMekanismLoaded) {
resolverInputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) } resolverInputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) }
resolverOutputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyInput) } resolverOutputMekanism = LazyOptional.of { Mattery2MekanismEnergyWrapper(energyOutput) }
} }
} }

View File

@ -19,6 +19,7 @@ import net.minecraft.client.renderer.FogRenderer
import net.minecraft.client.renderer.GameRenderer import net.minecraft.client.renderer.GameRenderer
import net.minecraft.core.Vec3i import net.minecraft.core.Vec3i
import net.minecraft.world.level.levelgen.XoroshiroRandomSource import net.minecraft.world.level.levelgen.XoroshiroRandomSource
import net.minecraft.world.level.material.FogType
import org.lwjgl.opengl.GL14 import org.lwjgl.opengl.GL14
import ru.dbotthepony.mc.otm.ClientConfig import ru.dbotthepony.mc.otm.ClientConfig
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
@ -465,7 +466,7 @@ object GlitchRenderer {
makeColorGlitch() makeColorGlitch()
} }
if (!Minecraft.useShaderTransparency()) { if (!Minecraft.useShaderTransparency() && minecraft.gameRenderer.mainCamera.fluidInCamera == FogType.NONE) {
glitchBuffer.bindWrite(true) glitchBuffer.bindWrite(true)
RenderSystem.clearColor(FogRenderer.fogRed, FogRenderer.fogGreen, FogRenderer.fogBlue, 1f) RenderSystem.clearColor(FogRenderer.fogRed, FogRenderer.fogGreen, FogRenderer.fogBlue, 1f)
RenderSystem.clear(GlConst.GL_COLOR_BUFFER_BIT, Minecraft.ON_OSX) RenderSystem.clear(GlConst.GL_COLOR_BUFFER_BIT, Minecraft.ON_OSX)

View File

@ -216,6 +216,7 @@ class MatterPanelScreen(
val input = object : EditBoxPanel<MatterPanelScreen>(this@MatterPanelScreen, rowInput) { val input = object : EditBoxPanel<MatterPanelScreen>(this@MatterPanelScreen, rowInput) {
init { init {
dock = Dock.FILL dock = Dock.FILL
requestFocus()
} }
override fun configureNew(widget: EditBox, recreation: Boolean) { override fun configureNew(widget: EditBox, recreation: Boolean) {

View File

@ -1576,7 +1576,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
open fun tick() { open fun tick() {
tick++ tick++
for (child in Array(childrenInternal.size) { childrenInternal[it] }) { for (child in Array(visibleChildrenInternal.size) { visibleChildrenInternal[it] }) {
child.tick() child.tick()
} }
} }

View File

@ -10,11 +10,28 @@ import java.util.function.Predicate
import kotlin.NoSuchElementException import kotlin.NoSuchElementException
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
/**
* Represents value which can be encoded onto or decoded from stream.
*
* Also provides [copy] and [compare] methods
*/
interface IStreamCodec<V> { interface IStreamCodec<V> {
fun read(stream: DataInputStream): V fun read(stream: DataInputStream): V
fun write(stream: DataOutputStream, value: V) fun write(stream: DataOutputStream, value: V)
/**
* if value is immutable, return it right away
*/
fun copy(value: V): V fun copy(value: V): V
fun compare(a: V, b: V): Boolean
/**
* Optional equality check override. Utilized to determine whenever e.g. network value is different from new value
*
* By default uses [Any.equals]
*/
fun compare(a: V, b: V): Boolean {
return a == b
}
} }
class StreamCodec<V>( class StreamCodec<V>(

View File

@ -1,54 +0,0 @@
package ru.dbotthepony.mc.otm.data
import com.google.common.collect.ImmutableList
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraftforge.common.loot.IGlobalLootModifier
import net.minecraftforge.common.loot.LootModifier
import java.util.Arrays
import java.util.stream.Stream
class BasicLootAppender(
conditions: Array<out LootItemCondition>,
items: Stream<ItemStack>
) : LootModifier(conditions) {
constructor(
conditions: Array<out LootItemCondition>,
items: Collection<ItemStack>
) : this(conditions, items.stream())
constructor(
conditions: Array<out LootItemCondition>,
vararg items: ItemStack
) : this(conditions, Arrays.stream(items))
private val items = items.map { it.copy() }.collect(ImmutableList.toImmutableList())
override fun codec(): Codec<out IGlobalLootModifier> {
return CODEC
}
override fun doApply(
generatedLoot: ObjectArrayList<ItemStack>,
context: LootContext
): ObjectArrayList<ItemStack> {
for (item in items)
generatedLoot.add(item.copy())
return generatedLoot
}
companion object {
val CODEC: Codec<BasicLootAppender> by lazy {
RecordCodecBuilder.create {
codecStart(it)
.and(ItemStackCodec.LIST.fieldOf("items").forGetter(BasicLootAppender::items))
.apply(it, ::BasicLootAppender)
}
}
}
}

View File

@ -1,52 +0,0 @@
package ru.dbotthepony.mc.otm.data
import com.google.common.collect.ImmutableList
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraftforge.common.loot.IGlobalLootModifier
import net.minecraftforge.common.loot.LootModifier
import java.util.*
import java.util.stream.Stream
class PlainLootAppender(conditions: Array<out LootItemCondition>, entries: Stream<Pair<ItemStack, Double>>) : LootModifier(conditions) {
constructor(conditions: Array<out LootItemCondition>, vararg entries: Pair<ItemStack, Double>) : this(conditions, Arrays.stream(entries))
constructor(conditions: Array<out LootItemCondition>, entries: Collection<Pair<ItemStack, Double>>) : this(conditions, entries.stream())
private val entries = entries.map { it.first.copy() to it.second }.collect(ImmutableList.toImmutableList())
override fun doApply(generatedLoot: ObjectArrayList<ItemStack>, context: LootContext): ObjectArrayList<ItemStack> {
for ((item, chance) in entries) {
if (context.random.nextDouble() <= chance) {
generatedLoot.add(item.copy())
}
}
return generatedLoot
}
override fun codec(): Codec<out IGlobalLootModifier> {
return CODEC
}
companion object {
private val paircodec: Codec<Pair<ItemStack, Double>> = RecordCodecBuilder.create {
it.group(
ItemStackCodec.fieldOf("item").forGetter { it.first },
Codec.DOUBLE.fieldOf("chance").forGetter { it.second }
).apply(it, ::Pair)
}
private val pairlistcodec = Codec.list(paircodec)
val CODEC: Codec<PlainLootAppender> =
RecordCodecBuilder.create {
codecStart(it).and(
pairlistcodec.fieldOf("entries").forGetter(PlainLootAppender::entries)
).apply(it, ::PlainLootAppender)
}
}
}

View File

@ -1,195 +0,0 @@
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,44 @@
package ru.dbotthepony.mc.otm.data.condition
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.level.storage.loot.LootContext
import net.minecraft.world.level.storage.loot.Serializer
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.registry.MLootItemConditions
/**
* u serious?
*/
data class ChanceCondition(val chance: Double) : LootItemCondition, LootItemCondition.Builder {
init {
require(chance in 0.0 .. 1.0) { "Invalid chance: $chance" }
}
override fun test(t: LootContext): Boolean {
return t.random.nextDouble() < chance
}
override fun getType(): LootItemConditionType {
return MLootItemConditions.CHANCE
}
override fun build(): LootItemCondition {
return this
}
companion object : Serializer<ChanceCondition> {
override fun serialize(p_79325_: JsonObject, p_79326_: ChanceCondition, p_79327_: JsonSerializationContext) {
p_79325_["chance"] = JsonPrimitive(p_79326_.chance)
}
override fun deserialize(p_79323_: JsonObject, p_79324_: JsonDeserializationContext): ChanceCondition {
return ChanceCondition(p_79323_["chance"]?.asDouble ?: throw JsonSyntaxException("Invalid chance json element"))
}
}
}

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.mc.otm.data package ru.dbotthepony.mc.otm.data.condition
import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject import com.google.gson.JsonObject
@ -11,9 +11,10 @@ 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
class ChanceWithPlaytimeCondition( data class ChanceWithPlaytimeCondition(
val minPlaytime: Int = 0, val minPlaytime: Int = 0,
val maxPlaytime: Int, val maxPlaytime: Int,
val minProbability: Double, val minProbability: Double,

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.mc.otm.data package ru.dbotthepony.mc.otm.data.condition
import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject import com.google.gson.JsonObject
@ -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 {

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.mc.otm.data package ru.dbotthepony.mc.otm.data.condition
import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject import com.google.gson.JsonObject
@ -17,9 +17,10 @@ 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
class ItemInInventoryCondition( data class ItemInInventoryCondition(
val item: ItemStack, val item: ItemStack,
val matchDamage: Boolean = false, val matchDamage: Boolean = false,
val matchNBT: Boolean = false, val matchNBT: Boolean = false,

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.mc.otm.data package ru.dbotthepony.mc.otm.data.condition
import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject import com.google.gson.JsonObject
@ -10,7 +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.capability.matteryPlayer 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 {

View File

@ -1,4 +1,4 @@
package ru.dbotthepony.mc.otm.data package ru.dbotthepony.mc.otm.data.condition
import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonObject import com.google.gson.JsonObject
@ -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 {

View File

@ -0,0 +1,11 @@
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,4 +1,4 @@
package ru.dbotthepony.mc.otm.data package ru.dbotthepony.mc.otm.data.loot
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import com.google.gson.* import com.google.gson.*
@ -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) {
@ -25,7 +28,10 @@ class LootPoolAppender(conditions: Array<out LootItemCondition>, pools: Stream<L
constructor(conditions: Array<out LootItemCondition>, vararg pools: LootPool) : this(conditions, Arrays.stream(pools)) constructor(conditions: Array<out LootItemCondition>, vararg pools: LootPool) : this(conditions, Arrays.stream(pools))
override fun doApply(generatedLoot: ObjectArrayList<ItemStack>, context: LootContext): ObjectArrayList<ItemStack> { override fun doApply(generatedLoot: ObjectArrayList<ItemStack>, context: LootContext): ObjectArrayList<ItemStack> {
pools.forEach { it.addRandomItems(generatedLoot::add, context) } for (pool in pools) {
pool.addRandomItems(generatedLoot::add, context)
}
return generatedLoot return generatedLoot
} }
@ -33,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 {

View File

@ -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()
}
}

View File

@ -11,11 +11,12 @@ import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.tagNotNull import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.data.IRandomizableItem import ru.dbotthepony.mc.otm.data.loot.IRandomizableItem
import java.util.* import java.util.*
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") // .tab(null) is a legal statement because tab field itself is nullable @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 { class ProceduralExoSuitSlotUpgradeItem : AbstractExoSuitSlotUpgradeItem(defaultProperties().tab(null)),
IRandomizableItem {
override fun getRarity(itemStack: ItemStack): Rarity { override fun getRarity(itemStack: ItemStack): Rarity {
return when (slotCount(itemStack)) { return when (slotCount(itemStack)) {
in 0 .. 9 -> Rarity.COMMON in 0 .. 9 -> Rarity.COMMON

View File

@ -34,10 +34,10 @@ private object TritaniumArmorMaterial : ArmorMaterial {
override fun getDefenseForSlot(p_40411_: EquipmentSlot): Int { override fun getDefenseForSlot(p_40411_: EquipmentSlot): Int {
return when (p_40411_) { return when (p_40411_) {
EquipmentSlot.FEET -> 4 EquipmentSlot.FEET -> 3
EquipmentSlot.LEGS -> 7 EquipmentSlot.LEGS -> 6
EquipmentSlot.CHEST -> 12 EquipmentSlot.CHEST -> 8
EquipmentSlot.HEAD -> 5 EquipmentSlot.HEAD -> 3
else -> throw IllegalArgumentException("yo dude what the fuck") else -> throw IllegalArgumentException("yo dude what the fuck")
} }
} }

View File

@ -87,7 +87,12 @@ class ExoSuitInventoryMenu(val capability: MatteryPlayerCapability) : MatteryMen
init { init {
for ((a, b) in curiosSlots) { for ((a, b) in curiosSlots) {
addSlot(a) addSlot(a)
if (b != null) addSlot(b) storage2Inventory(a)
if (b != null) {
addSlot(b)
storage2Inventory(b)
}
} }
} }

View File

@ -94,6 +94,24 @@ enum class MapAction {
CLEAR, ADD, REMOVE CLEAR, ADD, REMOVE
} }
/**
* Universal one-to-many value synchronizer
*
* This class represent collection of synchronizable values (similar to entitydata or menu's dataslots)
*
* Advantages of this class are:
* * It can be freely pooled. You can call [collectNetworkPayload] and [FieldSynchronizer.Endpoint.collectNetworkPayload] as much as you like,
* because they use dirty lists to track which fields need networking. **Warning**: If you attach one or more "observed" values (more on them below),
* each call to above methods will cause scan on observed fields.
* * It is universal. No, seriously, you can use it anywhere, all it needs is you encode [FastByteArrayOutputStream], send it over your
* networking channel, and create [InputStream] to feed to [FieldSynchronizer.Endpoint]
* * Its capabilities at networking are only limited by codecs you provide, see [FieldSynchronizer.Field], [IStreamCodec]
* * Provides not only single values, but also smart [FieldSynchronizer.Map] map synchronization
* * Has network version "conflict" resolver. If source FieldSynchronizer and target FieldSynchronizer have different set of fields, they can figure out how to synchronize
* only known fields. **Keep in mind this only works if you manually specify names on ALL created fields**
* * Directly bytestream embeddable. [FieldSynchronizer.Endpoint] always knows how much bytes to read from incoming stream, you can directly embed it into your data flow
* on network channel.
*/
@Suppress("unused") @Suppress("unused")
class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCallback: Boolean) { class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCallback: Boolean) {
constructor() : this(Runnable {}, false) constructor() : this(Runnable {}, false)

View File

@ -4,19 +4,13 @@ import net.minecraftforge.eventbus.api.IEventBus
import net.minecraftforge.registries.DeferredRegister 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.LootPoolAppender import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender
import ru.dbotthepony.mc.otm.data.BasicLootAppender
import ru.dbotthepony.mc.otm.data.PlainLootAppender
import ru.dbotthepony.mc.otm.data.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("loot_appender_separated") { PlainLootAppender.CODEC }
registry.register("loot_appender_basic") { BasicLootAppender.CODEC }
registry.register("randomizable_item_loot_appender") { RandomizableItemLootAppender.Companion }
} }
internal fun register(bus: IEventBus) { internal fun register(bus: IEventBus) {

View File

@ -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)
}
}
}

View File

@ -3,14 +3,14 @@ package ru.dbotthepony.mc.otm.registry
import net.minecraft.core.Registry import net.minecraft.core.Registry
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
import net.minecraftforge.registries.RegisterEvent import net.minecraftforge.registries.RegisterEvent
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.data.ChanceWithPlaytimeCondition import ru.dbotthepony.mc.otm.data.condition.ChanceWithPlaytimeCondition
import ru.dbotthepony.mc.otm.data.HasExosuitCondition import ru.dbotthepony.mc.otm.data.condition.HasExosuitCondition
import ru.dbotthepony.mc.otm.data.ItemInInventoryCondition import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition
import ru.dbotthepony.mc.otm.data.KilledByRealPlayer import ru.dbotthepony.mc.otm.data.condition.KilledByRealPlayer
import ru.dbotthepony.mc.otm.data.KilledByRealPlayerOrIndirectly import ru.dbotthepony.mc.otm.data.condition.KilledByRealPlayerOrIndirectly
import ru.dbotthepony.mc.otm.data.condition.ChanceCondition
object MLootItemConditions { object MLootItemConditions {
val HAS_EXOSUIT = LootItemConditionType(HasExosuitCondition) val HAS_EXOSUIT = LootItemConditionType(HasExosuitCondition)
@ -18,6 +18,7 @@ object MLootItemConditions {
val KILLED_BY_REAL_PLAYER_OR_INDIRECTLY = LootItemConditionType(KilledByRealPlayerOrIndirectly) val KILLED_BY_REAL_PLAYER_OR_INDIRECTLY = LootItemConditionType(KilledByRealPlayerOrIndirectly)
val CHANCE_WITH_PLAYTIME = LootItemConditionType(ChanceWithPlaytimeCondition) val CHANCE_WITH_PLAYTIME = LootItemConditionType(ChanceWithPlaytimeCondition)
val ITEM_IN_INVENTORY = LootItemConditionType(ItemInInventoryCondition) val ITEM_IN_INVENTORY = LootItemConditionType(ItemInInventoryCondition)
val CHANCE = LootItemConditionType(ChanceCondition.Companion)
internal fun register(event: RegisterEvent) { internal fun register(event: RegisterEvent) {
if (event.getVanillaRegistry<LootItemConditionType>() == Registry.LOOT_CONDITION_TYPE) { if (event.getVanillaRegistry<LootItemConditionType>() == Registry.LOOT_CONDITION_TYPE) {
@ -26,6 +27,7 @@ object MLootItemConditions {
Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "item_in_inventory"), ITEM_IN_INVENTORY) Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "item_in_inventory"), ITEM_IN_INVENTORY)
Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "killed_by_real_player"), KILLED_BY_REAL_PLAYER) Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "killed_by_real_player"), KILLED_BY_REAL_PLAYER)
Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "killed_by_real_player_or_indirectly"), KILLED_BY_REAL_PLAYER_OR_INDIRECTLY) Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "killed_by_real_player_or_indirectly"), KILLED_BY_REAL_PLAYER_OR_INDIRECTLY)
Registry.LOOT_CONDITION_TYPE.register(ResourceLocation(OverdriveThatMatters.MOD_ID, "chance"), CHANCE)
} }
} }
} }

View File

@ -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)

View File

@ -2,7 +2,7 @@
"type": "minecraft:crafting_shaped", "type": "minecraft:crafting_shaped",
"pattern": [ "pattern": [
"GBG", "BGB",
"PEP", "PEP",
"TET" "TET"
], ],
@ -31,6 +31,6 @@
"result": { "result": {
"item": "overdrive_that_matters:machine_frame", "item": "overdrive_that_matters:machine_frame",
"count": 1 "count": 2
} }
} }