Merge branch '1.21' of https://git.dbotthepony.ru/DBot/overdrive_that_matters into world-structures

This commit is contained in:
GearShocky 2025-03-09 19:57:27 +05:00
commit 59af269c00
48 changed files with 652 additions and 310 deletions

View File

@ -22,7 +22,7 @@ mixin_version=0.8.5
neogradle.subsystems.parchment.minecraftVersion=1.21.1 neogradle.subsystems.parchment.minecraftVersion=1.21.1
neogradle.subsystems.parchment.mappingsVersion=2024.11.17 neogradle.subsystems.parchment.mappingsVersion=2024.11.17
kommons_version=3.1.3 kommons_version=3.3.2
caffeine_cache_version=3.1.5 caffeine_cache_version=3.1.5
jei_version=19.16.4.171 jei_version=19.16.4.171

View File

@ -34,6 +34,7 @@ import ru.dbotthepony.mc.otm.datagen.items.MatteryItemModelProvider
import ru.dbotthepony.mc.otm.datagen.lang.AddEnglishLanguage import ru.dbotthepony.mc.otm.datagen.lang.AddEnglishLanguage
import ru.dbotthepony.mc.otm.datagen.models.MatteryBlockModelProvider import ru.dbotthepony.mc.otm.datagen.models.MatteryBlockModelProvider
import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource
import ru.dbotthepony.mc.otm.data.FlywheelMaterialDataProvider import ru.dbotthepony.mc.otm.data.FlywheelMaterialDataProvider
import ru.dbotthepony.mc.otm.datagen.advancements.addAdvancements import ru.dbotthepony.mc.otm.datagen.advancements.addAdvancements
import ru.dbotthepony.mc.otm.datagen.advancements.addAndroidAdvancements import ru.dbotthepony.mc.otm.datagen.advancements.addAndroidAdvancements
@ -68,6 +69,10 @@ internal fun modLootTable(string: String) = ResourceKey.create(Registries.LOOT_T
object DataGen { object DataGen {
const val MOD_ID = OverdriveThatMatters.MOD_ID const val MOD_ID = OverdriveThatMatters.MOD_ID
// for things which need to be random (e.g. UUIDs),
// so builds continue to be reproducible
val random = PCG32RandomSource(822393994030754753L)
var blockModelProvider: MatteryBlockModelProvider by WriteOnce() var blockModelProvider: MatteryBlockModelProvider by WriteOnce()
private set private set
var itemModelProvider: MatteryItemModelProvider by WriteOnce() var itemModelProvider: MatteryItemModelProvider by WriteOnce()

View File

@ -437,4 +437,6 @@ fun addMatterData(provider: MatterDataProvider) {
} }
} }
} }
provider.inherit(MItems.IMPERFECT_BREAD, Items.BREAD, 1.5)
} }

View File

@ -195,6 +195,8 @@ fun addItemModels(provider: MatteryItemModelProvider) {
provider.generated(MItems.PATTERN_DRIVE_CREATIVE) provider.generated(MItems.PATTERN_DRIVE_CREATIVE)
provider.generated(MItems.PATTERN_DRIVE_CREATIVE2) provider.generated(MItems.PATTERN_DRIVE_CREATIVE2)
provider.withExistingParent(MItems.GOLD_DISK, MItems.PATTERN_DRIVE_CREATIVE.registryName!!)
provider.generated(MItems.MATTER_DUST) provider.generated(MItems.MATTER_DUST)
provider.generated(MItems.TRITANIUM_DOOR.values) provider.generated(MItems.TRITANIUM_DOOR.values)

View File

@ -145,6 +145,8 @@ private fun sounds(provider: MatteryLanguageProvider) {
private fun misc(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) {
with(provider.english) { with(provider.english) {
misc("misc.inert", "Inert")
misc("misc.yes", "Yes") misc("misc.yes", "Yes")
misc("misc.no", "No") misc("misc.no", "No")
@ -885,6 +887,9 @@ private fun items(provider: MatteryLanguageProvider) {
add(MItems.PATTERN_DRIVE_QUAD, "Quad-Level Pattern Drive") add(MItems.PATTERN_DRIVE_QUAD, "Quad-Level Pattern Drive")
add(MItems.PATTERN_DRIVE_CREATIVE, "Creative Pattern Drive") add(MItems.PATTERN_DRIVE_CREATIVE, "Creative Pattern Drive")
add(MItems.GOLD_DISK, "Gold Disk")
add(MItems.GOLD_DISK, "single_item", "Gold Disk (%s)")
add(MItems.PATTERN_DRIVE_CREATIVE2, "Omni-Present Pattern Drive") add(MItems.PATTERN_DRIVE_CREATIVE2, "Omni-Present Pattern Drive")
add(MItems.PATTERN_DRIVE_CREATIVE2, "description1", "Creative-only item") add(MItems.PATTERN_DRIVE_CREATIVE2, "description1", "Creative-only item")
add(MItems.PATTERN_DRIVE_CREATIVE2, "description2", "Holds pattern for every item that have matter value") add(MItems.PATTERN_DRIVE_CREATIVE2, "description2", "Holds pattern for every item that have matter value")
@ -991,6 +996,15 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) {
with(provider.english) { with(provider.english) {
gui("exopack.accept_wireless_charge", "Accept wireless charging")
gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging")
gui("charge_androids", "Charge Androids")
gui("dont_charge_androids", "Do not charge Androids")
gui("charge_exopacks", "Charge Exopacks")
gui("dont_charge_exopacks", "Do not charge Exopacks")
gui("multiblock.formed", "Multiblock is formed: %s") gui("multiblock.formed", "Multiblock is formed: %s")
gui("flywheel.current_loss_t", "Current energy loss per tick:") gui("flywheel.current_loss_t", "Current energy loss per tick:")

View File

@ -159,6 +159,8 @@ private fun sounds(provider: MatteryLanguageProvider) {
private fun misc(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) {
with(provider.russian) { with(provider.russian) {
misc("misc.inert", "Инертен")
misc("misc.yes", "Да") misc("misc.yes", "Да")
misc("misc.no", "Нет") misc("misc.no", "Нет")
@ -878,6 +880,9 @@ private fun items(provider: MatteryLanguageProvider) {
add(MItems.PATTERN_DRIVE_QUAD, "Четырёхуровневый диск шаблонов") add(MItems.PATTERN_DRIVE_QUAD, "Четырёхуровневый диск шаблонов")
add(MItems.PATTERN_DRIVE_CREATIVE, "Творческий диск шаблонов") add(MItems.PATTERN_DRIVE_CREATIVE, "Творческий диск шаблонов")
add(MItems.GOLD_DISK, "Золотой диск")
add(MItems.GOLD_DISK, "single_item", "Золотой диск (%s)")
add(MItems.PATTERN_DRIVE_CREATIVE2, "Вездесущий диск шаблонов") add(MItems.PATTERN_DRIVE_CREATIVE2, "Вездесущий диск шаблонов")
add(MItems.PATTERN_DRIVE_CREATIVE2, "description1", "Предмет режима творчества") add(MItems.PATTERN_DRIVE_CREATIVE2, "description1", "Предмет режима творчества")
add(MItems.PATTERN_DRIVE_CREATIVE2, "description2", "Содержит в себе шаблоны всех предметов, которые имеют значение материи") add(MItems.PATTERN_DRIVE_CREATIVE2, "description2", "Содержит в себе шаблоны всех предметов, которые имеют значение материи")
@ -984,6 +989,15 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) {
with(provider.russian) { with(provider.russian) {
gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников")
gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников")
gui("charge_androids", "Заряжать андроидов")
gui("dont_charge_androids", "Не заряжать андроидов")
gui("charge_exopacks", "Заряжать экзопаки")
gui("dont_charge_exopacks", "Не заряжать экзопаки")
gui("multiblock.formed", "Мультиблок сформирован: %s") gui("multiblock.formed", "Мультиблок сформирован: %s")
gui("flywheel.current_loss_t", "Текущая потеря энергии в тик:") gui("flywheel.current_loss_t", "Текущая потеря энергии в тик:")

View File

@ -1,7 +1,10 @@
package ru.dbotthepony.mc.otm.datagen.loot package ru.dbotthepony.mc.otm.datagen.loot
import net.minecraft.world.level.storage.loot.functions.SetComponentsFunction
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import ru.dbotthepony.mc.otm.datagen.modLootTable import ru.dbotthepony.mc.otm.datagen.modLootTable
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
import ru.dbotthepony.mc.otm.registry.game.MEntityTypes
import ru.dbotthepony.mc.otm.registry.game.MItems import ru.dbotthepony.mc.otm.registry.game.MItems
fun addEntityLoot(loot: LootTables) { fun addEntityLoot(loot: LootTables) {
@ -31,4 +34,12 @@ fun addEntityLoot(loot: LootTables) {
} }
} }
} }
loot.builder(LootContextParamSets.ENTITY, MEntityTypes.BREAD_MONSTER.defaultLootTable) {
lootPool {
item(MItems.IMPERFECT_BREAD) {
apply(SetComponentsFunction.setComponent(MDataComponentTypes.INERT, true))
}
}
}
} }

View File

@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation
import net.minecraft.util.valueproviders.UniformInt import net.minecraft.util.valueproviders.UniformInt
import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.EntityType
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.level.storage.loot.BuiltInLootTables import net.minecraft.world.level.storage.loot.BuiltInLootTables
import net.minecraft.world.level.storage.loot.LootTable import net.minecraft.world.level.storage.loot.LootTable
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition import net.minecraft.world.level.storage.loot.predicates.LootItemCondition
@ -18,9 +19,11 @@ import ru.dbotthepony.mc.otm.data.condition.HasExoPackCondition
import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition
import ru.dbotthepony.mc.otm.data.condition.KilledByRealPlayerOrIndirectly import ru.dbotthepony.mc.otm.data.condition.KilledByRealPlayerOrIndirectly
import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender
import ru.dbotthepony.mc.otm.datagen.DataGen
import ru.dbotthepony.mc.otm.datagen.modLootTable import ru.dbotthepony.mc.otm.datagen.modLootTable
import ru.dbotthepony.mc.otm.item.ProceduralBatteryItem import ru.dbotthepony.mc.otm.item.ProceduralBatteryItem
import ru.dbotthepony.mc.otm.item.exopack.ProceduralExopackSlotUpgradeItem import ru.dbotthepony.mc.otm.item.exopack.ProceduralExopackSlotUpgradeItem
import ru.dbotthepony.mc.otm.item.matter.GoldDiskItem
import ru.dbotthepony.mc.otm.registry.game.MItems import ru.dbotthepony.mc.otm.registry.game.MItems
@Suppress("FunctionName") @Suppress("FunctionName")
@ -66,6 +69,11 @@ fun addLootModifiers(it: LootModifiers) {
apply(ProceduralExopackSlotUpgradeItem.Randomizer(UniformInt.of(4, 10))) apply(ProceduralExopackSlotUpgradeItem.Randomizer(UniformInt.of(4, 10)))
}, },
singleItem(MItems.GOLD_DISK) {
chanceCondition(0.1)
apply(GoldDiskItem.patterns(DataGen.random, MItems.IMPERFECT_BREAD))
},
singleItem(MItems.PROCEDURAL_BATTERY) { singleItem(MItems.PROCEDURAL_BATTERY) {
chanceCondition(0.15) chanceCondition(0.15)
@ -122,6 +130,11 @@ fun addLootModifiers(it: LootModifiers) {
chanceCondition(0.1) chanceCondition(0.1)
apply(ProceduralExopackSlotUpgradeItem.Randomizer(UniformInt.of(27, 56), UniformInt.of(2, 6))) apply(ProceduralExopackSlotUpgradeItem.Randomizer(UniformInt.of(27, 56), UniformInt.of(2, 6)))
}, },
singleItem(MItems.GOLD_DISK) {
chanceCondition(0.15)
apply(GoldDiskItem.patterns(DataGen.random, Items.ENDER_PEARL))
},
)) ))
it.add("dungeon_pill", PlainLootAppender( it.add("dungeon_pill", PlainLootAppender(

View File

@ -34,7 +34,12 @@ fun addEquipmentTags(tagsProvider: TagsProvider) {
.add(MItems.TRITANIUM_BOOTS) .add(MItems.TRITANIUM_BOOTS)
.add(MItems.SIMPLE_TRITANIUM_BOOTS) .add(MItems.SIMPLE_TRITANIUM_BOOTS)
tagsProvider.items.Appender(ItemTags.SWORDS).add(MItems.TRITANIUM_SWORD).add(MItems.ENERGY_SWORD) tagsProvider.items.Appender(ItemTags.SWORDS)
.add(MItems.TRITANIUM_SWORD)
.add(MItems.ENERGY_SWORD)
.add(MItems.FALLING_SUN)
.add(MItems.WITHERED_STEEL_SWORD)
tagsProvider.items.Appender(ItemTags.AXES).add(MItems.TRITANIUM_AXE) tagsProvider.items.Appender(ItemTags.AXES).add(MItems.TRITANIUM_AXE)
tagsProvider.items.Appender(ItemTags.PICKAXES).add(MItems.TRITANIUM_PICKAXE) tagsProvider.items.Appender(ItemTags.PICKAXES).add(MItems.TRITANIUM_PICKAXE)
tagsProvider.items.Appender(ItemTags.SHOVELS).add(MItems.TRITANIUM_SHOVEL) tagsProvider.items.Appender(ItemTags.SHOVELS).add(MItems.TRITANIUM_SHOVEL)

View File

@ -5,11 +5,11 @@ import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import ru.dbotthepony.mc.otm.core.IMatteryLevel; import ru.dbotthepony.mc.otm.core.IMatteryLevel;
import ru.dbotthepony.mc.otm.core.util.Xoshiro256SSRandom; import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource;
@Mixin(Level.class) @Mixin(Level.class)
public abstract class LevelMixin implements IMatteryLevel { public abstract class LevelMixin implements IMatteryLevel {
public final RandomSource otm_random = new Xoshiro256SSRandom(); public final RandomSource otm_random = new PCG32RandomSource();
@Override @Override
public @NotNull RandomSource getOtmRandom() { public @NotNull RandomSource getOtmRandom() {

View File

@ -7,6 +7,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder
import net.minecraft.client.server.IntegratedServer import net.minecraft.client.server.IntegratedServer
import net.minecraft.core.HolderLookup import net.minecraft.core.HolderLookup
import net.minecraft.server.MinecraftServer import net.minecraft.server.MinecraftServer
import net.minecraft.util.RandomSource
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.neoforged.api.distmarker.Dist import net.neoforged.api.distmarker.Dist
import net.neoforged.fml.loading.FMLLoader import net.neoforged.fml.loading.FMLLoader
@ -22,12 +23,17 @@ import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
import ru.dbotthepony.mc.otm.core.util.AtomicallyInvalidatedLazy import ru.dbotthepony.mc.otm.core.util.AtomicallyInvalidatedLazy
import ru.dbotthepony.mc.otm.core.util.IConditionalTickable import ru.dbotthepony.mc.otm.core.util.IConditionalTickable
import ru.dbotthepony.mc.otm.core.util.ITickable import ru.dbotthepony.mc.otm.core.util.ITickable
import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource
import ru.dbotthepony.mc.otm.core.util.TickList import ru.dbotthepony.mc.otm.core.util.TickList
import ru.dbotthepony.mc.otm.graph.GraphNodeList import ru.dbotthepony.mc.otm.graph.GraphNodeList
import java.lang.ref.Cleaner import java.lang.ref.Cleaner
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
private val threadLocalRandom = ThreadLocal.withInitial { PCG32RandomSource() }
internal val THREAD_LOCAL_RANDOM: RandomSource
get() = threadLocalRandom.get()
private val preServerTick = TickList() private val preServerTick = TickList()
private val postServerTick = TickList() private val postServerTick = TickList()
private val preWorldTick = WeakHashMap<Level, TickList>() private val preWorldTick = WeakHashMap<Level, TickList>()

View File

@ -7,6 +7,7 @@ import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtOps import net.minecraft.nbt.NbtOps
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.chat.ComponentSerialization import net.minecraft.network.chat.ComponentSerialization
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.MenuProvider import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
@ -83,12 +84,14 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
super.setLevel(level) super.setLevel(level)
level.once { if (level is ServerLevel) {
level.once(4) {
if (!isRemoved && this.level == level) { if (!isRemoved && this.level == level) {
redstoneControl.redstoneSignal = level.getBestNeighborSignal(blockPos) redstoneControl.redstoneSignal = level.getBestNeighborSignal(blockPos)
} }
} }
} }
}
inner class ConfigurableFluidHandler<T : IFluidHandler>( inner class ConfigurableFluidHandler<T : IFluidHandler>(
val capability: T, val capability: T,

View File

@ -165,7 +165,7 @@ abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockP
if (!SERVER_IS_LIVE) return if (!SERVER_IS_LIVE) return
val level = level val level = level
level?.once { level?.once(4) {
if (!node.isValid) return@once if (!node.isValid) return@once
val newState = blockState val newState = blockState

View File

@ -30,14 +30,28 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.ANDROID_CHARGER)) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.ANDROID_CHARGER))
val energyConfig = ConfigurableEnergy(energy, modesTop = FlowDirection.NONE) val energyConfig = ConfigurableEnergy(energy, modesTop = FlowDirection.NONE)
var chargeAndroids = true
set(value) {
field = value
markDirtyFast()
}
var chargeExopacks = true
set(value) {
field = value
markDirtyFast()
}
init { init {
savetables.stateful(energyConfig::energy, ENERGY_KEY) savetables.stateful(energyConfig::energy, ENERGY_KEY)
savetablesConfig.bool(::chargeAndroids)
savetablesConfig.bool(::chargeExopacks)
} }
override fun tick() { override fun tick() {
super.tick() super.tick()
if (redstoneControl.isBlockedByRedstone) return if (redstoneControl.isBlockedByRedstone || !chargeAndroids && !chargeExopacks) return
val level = level ?: return val level = level ?: return
var available = energyConfig.energy.extractEnergy(energyConfig.energy.batteryLevel, true) var available = energyConfig.energy.extractEnergy(energyConfig.energy.batteryLevel, true)
if (!available.isPositive) return if (!available.isPositive) return
@ -49,14 +63,14 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
for ((ent) in ents) { for ((ent) in ents) {
val ply = (ent as Player).matteryPlayer val ply = (ent as Player).matteryPlayer
if (ply.isAndroid) { if (chargeAndroids && ply.isAndroid) {
val received = ply.androidEnergy.receiveEnergyChecked(available, false) val received = ply.androidEnergy.receiveEnergyChecked(available, false)
available -= received available -= received
energyConfig.energy.extractEnergy(received, false) energyConfig.energy.extractEnergy(received, false)
if (!available.isPositive) return if (!available.isPositive) return
} }
if (ply.hasExopack) { if (chargeExopacks && ply.hasExopack && ply.acceptExopackChargeFromWirelessCharger) {
val received = ply.exopackEnergy.receiveEnergyChecked(available, false) val received = ply.exopackEnergy.receiveEnergyChecked(available, false)
available -= received available -= received
energyConfig.energy.extractEnergy(received, false) energyConfig.energy.extractEnergy(received, false)

View File

@ -17,21 +17,26 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.capability.moveEnergy
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.otmRandom
import ru.dbotthepony.mc.otm.core.shuffle
import ru.dbotthepony.mc.otm.core.util.countingLazy
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider {
MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider {
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return AndroidStationMenu(containerID, inventory, this) return AndroidStationMenu(containerID, inventory, this)
} }
private val workerState by countingLazy(blockStateChangesCounter) {
blockState.getValue(WorkerState.SEMI_WORKER_STATE)
}
override val energy: ProfiledEnergyStorage<WorkerEnergyStorage> = ProfiledEnergyStorage(object : WorkerEnergyStorage(::markDirtyFast, MachinesConfig.AndroidStation.VALUES) { override val energy: ProfiledEnergyStorage<WorkerEnergyStorage> = ProfiledEnergyStorage(object : WorkerEnergyStorage(::markDirtyFast, MachinesConfig.AndroidStation.VALUES) {
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal { override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return super.extractEnergy(howMuch, simulate).also { return super.extractEnergy(howMuch, simulate).also {
if (!simulate && this.batteryLevel.isZero) { if (!simulate && this.batteryLevel.isZero) {
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) { if (workerState != WorkerState.IDLE) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
} }
} }
@ -41,7 +46,7 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal { override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return super.receiveEnergy(howMuch, simulate).also { return super.receiveEnergy(howMuch, simulate).also {
if (!simulate && it.isPositive) { if (!simulate && it.isPositive) {
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) { if (workerState != WorkerState.WORKING) {
level?.setBlock(blockPos, blockState.setValue( level?.setBlock(blockPos, blockState.setValue(
WorkerState.SEMI_WORKER_STATE, WorkerState.SEMI_WORKER_STATE,
WorkerState.WORKING WorkerState.WORKING
@ -53,9 +58,15 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
}) })
val energyConfig = ConfigurableEnergy(energy) val energyConfig = ConfigurableEnergy(energy)
var chargeAndroids = true
set(value) {
field = value
markDirtyFast()
}
init { init {
savetables.stateful(::energy, ENERGY_KEY) savetables.stateful(::energy, ENERGY_KEY)
savetablesConfig.bool(::chargeAndroids)
} }
private var tickedOnce = false private var tickedOnce = false
@ -66,20 +77,20 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
if (!tickedOnce) { if (!tickedOnce) {
tickedOnce = true tickedOnce = true
if (energy.batteryLevel.isPositive && blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) { if (energy.batteryLevel.isPositive && workerState != WorkerState.WORKING) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS) level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS)
} else if (energy.batteryLevel.isZero && blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) { } else if (!energy.batteryLevel.isPositive && workerState != WorkerState.IDLE) {
level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS)
} }
} }
if (redstoneControl.isBlockedByRedstone) return if (redstoneControl.isBlockedByRedstone || !chargeAndroids) return
val level = level ?: return val level = level ?: return
val x = blockPos.x.toDouble() val x = blockPos.x.toDouble()
val y = blockPos.y.toDouble() val y = blockPos.y.toDouble()
val z = blockPos.z.toDouble() val z = blockPos.z.toDouble()
for (ent in level.getEntitiesOfClass(ServerPlayer::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0))) { for (ent in level.getEntitiesOfClass(ServerPlayer::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0)).shuffle(level.otmRandom)) {
if (ent.matteryPlayer.isAndroid) if (ent.matteryPlayer.isAndroid)
moveEnergy(energy, ent.matteryPlayer.androidEnergy, amount = energy.batteryLevel, simulate = false, ignoreFlowRestrictions = true) moveEnergy(energy, ent.matteryPlayer.androidEnergy, amount = energy.batteryLevel, simulate = false, ignoreFlowRestrictions = true)
} }

View File

@ -565,6 +565,7 @@ class MatteryPlayer(val ply: Player) {
val exopackEnergy = ProfiledEnergyStorage(BatteryBackedEnergyStorage(ply, syncher, Decimal.ZERO, ExopackConfig.ENERGY_CAPACITY, false, onChange = { for (v in smelters) v.notify(MachineJobEventLoop.IdleReason.POWER) })) val exopackEnergy = ProfiledEnergyStorage(BatteryBackedEnergyStorage(ply, syncher, Decimal.ZERO, ExopackConfig.ENERGY_CAPACITY, false, onChange = { for (v in smelters) v.notify(MachineJobEventLoop.IdleReason.POWER) }))
val exopackChargeSlots = MatteryContainer(4) val exopackChargeSlots = MatteryContainer(4)
var acceptExopackChargeFromWirelessCharger = true
init { init {
savetables.int(::ticksIExist) savetables.int(::ticksIExist)
@ -578,6 +579,7 @@ class MatteryPlayer(val ply: Player) {
savetables.bool(::isExopackVisible, "displayExoSuit") savetables.bool(::isExopackVisible, "displayExoSuit")
savetables.bool(::isExopackCraftingUpgraded, "isExoSuitCraftingUpgraded") savetables.bool(::isExopackCraftingUpgraded, "isExoSuitCraftingUpgraded")
savetables.bool(::isExopackEnderAccessInstalled, "isExopackEnderAccessUpgraded") savetables.bool(::isExopackEnderAccessInstalled, "isExopackEnderAccessUpgraded")
savetables.bool(::acceptExopackChargeFromWirelessCharger)
savetables.int(::nextDischargeHurt) savetables.int(::nextDischargeHurt)
savetables.int(::nextHealTick) savetables.int(::nextHealTick)

View File

@ -1,7 +1,13 @@
package ru.dbotthepony.mc.otm.capability.matter package ru.dbotthepony.mc.otm.capability.matter
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item import net.minecraft.world.item.Item
import net.minecraft.world.item.Item.TooltipContext
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import java.util.* import java.util.*
import java.util.function.Predicate import java.util.function.Predicate
import java.util.stream.Collectors import java.util.stream.Collectors
@ -72,3 +78,19 @@ fun IPatternStorage.getBarWidth(): Int {
fun IPatternStorage.getBarColor(): Int { fun IPatternStorage.getBarColor(): Int {
return RGBAColor.LOW_PATTERNS.linearInterpolation((storedPatterns / patternCapacity).toFloat(), RGBAColor.FULL_PATTERNS).toBGR() return RGBAColor.LOW_PATTERNS.linearInterpolation((storedPatterns / patternCapacity).toFloat(), RGBAColor.FULL_PATTERNS).toBGR()
} }
fun IPatternStorage.gatherTooltip(
context: TooltipContext,
components: MutableList<Component>,
tooltipType: TooltipFlag
) {
for (state in patterns) {
components.add(
TranslatableComponent(
"otm.item.pattern.line",
state.item.getName(ItemStack(state.item, 1)),
String.format("%.2f", state.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)
)
}
}

View File

@ -43,6 +43,10 @@ object Widgets18 {
val CURIOS_INVENTORY = miscGrid.next() val CURIOS_INVENTORY = miscGrid.next()
val STATISTICS_TAB = miscGrid.next() val STATISTICS_TAB = miscGrid.next()
val SETTINGS_TAB = miscGrid.next() val SETTINGS_TAB = miscGrid.next()
val WIRELESS_CHARGING_ENABLED = miscGrid.next()
val WIRELESS_CHARGING_DISABLED = miscGrid.next()
val WIRELESS_CHARGING_ANDROIDS_ENABLED = miscGrid.next()
val WIRELESS_CHARGING_ANDROIDS_DISABLED = miscGrid.next()
private val slotBgGrid = WidgetLocation.SLOT_BACKGROUNDS.grid(4, 4) private val slotBgGrid = WidgetLocation.SLOT_BACKGROUNDS.grid(4, 4)

View File

@ -24,6 +24,7 @@ import ru.dbotthepony.mc.otm.client.render.WidgetLocation
import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.render.translation import ru.dbotthepony.mc.otm.client.render.translation
import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
@ -172,13 +173,25 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
} }
protected fun makeChargePanels(frame: EditablePanel<*>) { protected fun makeChargePanels(frame: EditablePanel<*>) {
val chargeWidth = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width + AbstractSlotPanel.SIZE + 6f + ProgressGaugePanel.GAUGE_BACKGROUND.width * 2f val chargeWidth = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width + AbstractSlotPanel.SIZE * 2 + 8f + ProgressGaugePanel.GAUGE_BACKGROUND.width * 2f
val chargeStrip = BackgroundPanel.paddedCenter(this, frame, frame.width - chargeWidth - 6f, frame.height + 2f, chargeWidth, AbstractSlotPanel.SIZE) val chargeStrip = BackgroundPanel.paddedCenter(this, frame, frame.width - chargeWidth - 6f, frame.height + 2f, chargeWidth, AbstractSlotPanel.SIZE)
val chargeStrip2 = BackgroundPanel.paddedCenter(this, frame, frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f, AbstractSlotPanel.SIZE, AbstractSlotPanel.SIZE * 4f) val chargeStrip2 = BackgroundPanel.paddedCenter(this, frame, frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f, AbstractSlotPanel.SIZE, AbstractSlotPanel.SIZE * 4f)
chargeStrip.customDock { chargeStrip.setPos(frame.width - chargeWidth - 6f, frame.height + 2f) } chargeStrip.customDock { chargeStrip.setPos(frame.width - chargeWidth - 6f, frame.height + 2f) }
chargeStrip2.customDock { chargeStrip2.setPos(frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f) } chargeStrip2.customDock { chargeStrip2.setPos(frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f) }
BooleanButtonPanel.square18(
this, chargeStrip,
prop = menu.acceptExopackChargeFromWirelessCharger,
iconActive = Widgets18.WIRELESS_CHARGING_ENABLED,
iconInactive = Widgets18.WIRELESS_CHARGING_DISABLED,
tooltipActive = TranslatableComponent("otm.gui.exopack.accept_wireless_charge"),
tooltipInactive = TranslatableComponent("otm.gui.exopack.dont_accept_wireless_charge"),
).also {
it.dock = Dock.LEFT
it.dockRight = 2f
}
BatterySlotPanel(this, chargeStrip, menu.exopackChargeSlots[0]).also { BatterySlotPanel(this, chargeStrip, menu.exopackChargeSlots[0]).also {
it.dock = Dock.LEFT it.dock = Dock.LEFT
} }

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen.tech
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.Dock import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
@ -10,8 +11,10 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu
class AndroidChargerScreen(menu: AndroidChargerMenu, inventory: Inventory, title: Component) : MatteryScreen<AndroidChargerMenu>(menu, inventory, title) { class AndroidChargerScreen(menu: AndroidChargerMenu, inventory: Inventory, title: Component) : MatteryScreen<AndroidChargerMenu>(menu, inventory, title) {
@ -40,7 +43,33 @@ class AndroidChargerScreen(menu: AndroidChargerMenu, inventory: Inventory, title
it.dockRight = 2f it.dockRight = 2f
} }
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig)
if (menu.chargeExopacks != null) {
controls.addButton(
BooleanButtonPanel.square18(
this, frame,
prop = menu.chargeExopacks!!,
iconActive = Widgets18.WIRELESS_CHARGING_ENABLED,
iconInactive = Widgets18.WIRELESS_CHARGING_DISABLED,
tooltipActive = TranslatableComponent("otm.gui.charge_exopacks"),
tooltipInactive = TranslatableComponent("otm.gui.dont_charge_exopacks"),
)
)
}
if (menu.chargeAndroids != null) {
controls.addButton(
BooleanButtonPanel.square18(
this, frame,
prop = menu.chargeAndroids!!,
iconActive = Widgets18.WIRELESS_CHARGING_ANDROIDS_ENABLED,
iconInactive = Widgets18.WIRELESS_CHARGING_ANDROIDS_DISABLED,
tooltipActive = TranslatableComponent("otm.gui.charge_androids"),
tooltipInactive = TranslatableComponent("otm.gui.dont_charge_androids"),
)
)
}
return frame return frame
} }

View File

@ -34,6 +34,7 @@ import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel
import ru.dbotthepony.mc.otm.core.RandomSource2Generator import ru.dbotthepony.mc.otm.core.RandomSource2Generator
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket
@ -717,7 +718,18 @@ class AndroidStationScreen(p_97741_: AndroidStationMenu, p_97742_: Inventory, p_
this.playerStrip = playerStrip this.playerStrip = playerStrip
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig)
controls.addButton(
BooleanButtonPanel.square18(
this, frame,
prop = menu.chargeAndroids,
iconActive = Widgets18.WIRELESS_CHARGING_ANDROIDS_ENABLED,
iconInactive = Widgets18.WIRELESS_CHARGING_ANDROIDS_DISABLED,
tooltipActive = TranslatableComponent("otm.gui.charge_androids"),
tooltipInactive = TranslatableComponent("otm.gui.dont_charge_androids"),
)
)
return frame return frame
} }

View File

@ -76,4 +76,12 @@ object ServerConfig : AbstractConfig("misc") {
builder.pop() builder.pop()
} }
} }
val WITHER_SKELETON_HELMET_CHANCE: Double by builder
.comment("Chance of Wither Skeleton spawning with Netherite Helmet AND Withered Steel sword")
.defineInRange("WITHER_SKELETON_HELMET_CHANCE", 0.1, 0.0, 1.0)
val WITHER_SKELETON_SWORD_CHANCE: Double by builder
.comment("Chance of Wither Skeleton spawning with Withered Steel sword")
.defineInRange("WITHER_SKELETON_HELMET_CHANCE", 0.24, 0.0, 1.0)
} }

View File

@ -39,9 +39,9 @@ class UpgradeContainer(
} }
override val speedBonus: Double override val speedBonus: Double
get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b } get() = if (isEmpty) 0.0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b }
override val processingItems: Int override val processingItems: Int
get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } get() = if (isEmpty) 0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b }
override val energyStorageFlat: Decimal override val energyStorageFlat: Decimal
get() = positiveDecimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus) get() = positiveDecimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus)
override val energyStorage: Decimal override val energyStorage: Decimal
@ -53,7 +53,7 @@ class UpgradeContainer(
override val energyConsumed: Decimal override val energyConsumed: Decimal
get() = anyDecimals(IMatteryUpgrade::energyConsumed, Decimal::plus) get() = anyDecimals(IMatteryUpgrade::energyConsumed, Decimal::plus)
override val failureMultiplier: Double override val failureMultiplier: Double
get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } get() = if (isEmpty) 1.0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b }
override val energyThroughputFlat: Decimal override val energyThroughputFlat: Decimal
get() = positiveDecimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus) get() = positiveDecimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus)
override val energyThroughput: Decimal override val energyThroughput: Decimal
@ -62,24 +62,24 @@ class UpgradeContainer(
fun transform(values: EnergyBalanceValues): EnergyBalanceValues { fun transform(values: EnergyBalanceValues): EnergyBalanceValues {
return object : EnergyBalanceValues { return object : EnergyBalanceValues {
override val energyCapacity: Decimal override val energyCapacity: Decimal
get() = values.energyCapacity * (energyStorage + Decimal.ONE) + energyStorageFlat get() = if (isEmpty) values.energyCapacity else values.energyCapacity * (energyStorage + Decimal.ONE) + energyStorageFlat
override val energyThroughput: Decimal override val energyThroughput: Decimal
get() = values.energyThroughput * (this@UpgradeContainer.energyThroughput + Decimal.ONE) + energyThroughputFlat get() = if (isEmpty) values.energyThroughput else values.energyThroughput * (this@UpgradeContainer.energyThroughput + Decimal.ONE) + energyThroughputFlat
} }
} }
fun transform(values: VerboseEnergyBalanceValues): VerboseEnergyBalanceValues { fun transform(values: VerboseEnergyBalanceValues): VerboseEnergyBalanceValues {
return object : VerboseEnergyBalanceValues { return object : VerboseEnergyBalanceValues {
override val energyCapacity: Decimal override val energyCapacity: Decimal
get() = values.energyCapacity * (energyStorage + Decimal.ONE) + energyStorageFlat get() = if (isEmpty) values.energyCapacity else values.energyCapacity * (energyStorage + Decimal.ONE) + energyStorageFlat
override val maxEnergyReceive: Decimal override val maxEnergyReceive: Decimal
get() = values.maxEnergyReceive * (energyThroughput + Decimal.ONE) + energyThroughputFlat get() = if (isEmpty) values.maxEnergyReceive else values.maxEnergyReceive * (energyThroughput + Decimal.ONE) + energyThroughputFlat
override val maxEnergyExtract: Decimal override val maxEnergyExtract: Decimal
get() = values.maxEnergyExtract * (energyThroughput + Decimal.ONE) + energyThroughputFlat get() =if (isEmpty) values.maxEnergyExtract else values.maxEnergyExtract * (energyThroughput + Decimal.ONE) + energyThroughputFlat
} }
} }
fun matterCapacity(value: () -> Decimal): () -> Decimal { fun matterCapacity(value: () -> Decimal): () -> Decimal {
return { value.invoke() * (matterStorage + Decimal.ONE) + matterStorageFlat } return { if (isEmpty) value.invoke() else value.invoke() * (matterStorage + Decimal.ONE) + matterStorageFlat }
} }
} }

View File

@ -188,17 +188,20 @@ fun <T : Enum<T>> T.prev(values: Array<out T>): T {
return values[next] return values[next]
} }
fun IntArray.shuffle(random: RandomSource) { fun IntArray.shuffle(random: RandomSource): IntArray {
for (i in lastIndex downTo 1) { for (i in lastIndex downTo 1) {
val j = random.nextInt(i + 1) val j = random.nextInt(i + 1)
val copy = this[i] val copy = this[i]
this[i] = this[j] this[i] = this[j]
this[j] = copy this[j] = copy
} }
return this
} }
fun <T> MutableList<T>.shuffle(random: RandomSource) { fun <T, L : MutableList<T>> L.shuffle(random: RandomSource): L {
return Util.shuffle(this, random) Util.shuffle(this, random)
return this
} }
fun <T> List<T>.random(random: RandomGenerator): T { fun <T> List<T>.random(random: RandomGenerator): T {
@ -624,6 +627,10 @@ infix fun FluidStack.isNotSameAs(other: FluidStack): Boolean {
data class DoublePair(val first: Double, val second: Double) data class DoublePair(val first: Double, val second: Double)
fun RandomSource.nextUUID(): UUID {
return UUID(nextLong(), nextLong())
}
// normal distribution via Marsaglia polar method // normal distribution via Marsaglia polar method
fun RandomGenerator.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { fun RandomGenerator.nextNormalDoubles(stddev: Double, mean: Double): DoublePair {
var rand1: Double var rand1: Double

View File

@ -240,18 +240,31 @@ sealed class Decimal : Number(), Comparable<Decimal> {
return mag.signum() return mag.signum()
} }
private var intCache = 0
private var intComputed = false
override fun toInt(): Int { override fun toInt(): Int {
return if (whole > BI_INT_MAX) { if (!intComputed) {
intCache = if (whole > BI_INT_MAX) {
Int.MAX_VALUE Int.MAX_VALUE
} else if (whole < BI_INT_MIN) { } else if (whole < BI_INT_MIN) {
Int.MIN_VALUE Int.MIN_VALUE
} else { } else {
whole.toInt() whole.toInt()
} }
intComputed = true
} }
return intCache
}
private var longCache = 0L
private var longComputed = false
override fun toLong(): Long { override fun toLong(): Long {
return if (whole > BI_LONG_MAX) { if (!longComputed) {
longCache = if (whole > BI_LONG_MAX) {
Long.MAX_VALUE Long.MAX_VALUE
} else if (whole < BI_LONG_MIN) { } else if (whole < BI_LONG_MIN) {
Long.MIN_VALUE Long.MIN_VALUE
@ -260,6 +273,9 @@ sealed class Decimal : Number(), Comparable<Decimal> {
} }
} }
return longCache
}
override fun compareTo(other: Decimal): Int { override fun compareTo(other: Decimal): Int {
return if (other === Zero) return if (other === Zero)
signum() signum()

View File

@ -5,6 +5,7 @@ import net.minecraft.util.RandomSource
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
import net.minecraft.world.level.levelgen.PositionalRandomFactory import net.minecraft.world.level.levelgen.PositionalRandomFactory
import net.minecraft.world.level.levelgen.RandomSupport import net.minecraft.world.level.levelgen.RandomSupport
import ru.dbotthepony.kommons.random.LCG64Random
import java.lang.StringBuilder import java.lang.StringBuilder
import java.util.random.RandomGenerator import java.util.random.RandomGenerator

View File

@ -0,0 +1,30 @@
package ru.dbotthepony.mc.otm.core.util
import net.minecraft.util.RandomSource
import java.util.random.RandomGenerator
interface IRandomSourceGenerator : RandomSource, RandomGenerator {
override fun nextInt(): Int
override fun nextInt(bound: Int): Int {
return super<RandomGenerator>.nextInt(bound)
}
override fun nextInt(origin: Int, bound: Int): Int {
return super<RandomGenerator>.nextInt(origin, bound)
}
override fun nextBoolean(): Boolean {
return super.nextBoolean()
}
override fun nextFloat(): Float {
return super.nextFloat()
}
override fun nextDouble(): Double {
return super.nextDouble()
}
override fun nextGaussian(): Double
}

View File

@ -6,8 +6,8 @@ import net.minecraft.world.level.levelgen.LegacyRandomSource
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
import net.minecraft.world.level.levelgen.PositionalRandomFactory import net.minecraft.world.level.levelgen.PositionalRandomFactory
import net.minecraft.world.level.levelgen.RandomSupport import net.minecraft.world.level.levelgen.RandomSupport
import ru.dbotthepony.kommons.random.LCG64Random
import java.lang.StringBuilder import java.lang.StringBuilder
import java.util.random.RandomGenerator
/** /**
* Simple and insanely fast random number generator, which can be used for seeding (initializing internal state) of other number generators. * Simple and insanely fast random number generator, which can be used for seeding (initializing internal state) of other number generators.
@ -19,7 +19,7 @@ import java.util.random.RandomGenerator
* * Always use upper 32 bits instead of implementing BitRandomSource and sampling some upper bits * * Always use upper 32 bits instead of implementing BitRandomSource and sampling some upper bits
* * Uses all bits from provided seed * * Uses all bits from provided seed
*/ */
class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) : RandomGenerator, RandomSource { class LCG64RandomSource(seed: Long = RandomSupport.generateUniqueSeed()) : LCG64Random(seed), IRandomSourceGenerator {
private val gaussian = MarsagliaPolarGaussian(this) private val gaussian = MarsagliaPolarGaussian(this)
override fun setSeed(seed: Long) { override fun setSeed(seed: Long) {
@ -27,43 +27,12 @@ class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) :
gaussian.reset() gaussian.reset()
} }
override fun nextInt(): Int {
this.seed = MULTIPLIER * this.seed + INCREMENT
return this.seed.ushr(32).toInt()
}
override fun nextLong(): Long {
val a = nextInt().toLong() and 0xFFFFFFFFL
val b = nextInt().toLong() and 0xFFFFFFFFL
return a.shl(32) or b
}
override fun nextInt(bound: Int): Int {
return super<RandomGenerator>.nextInt(bound)
}
override fun nextInt(origin: Int, bound: Int): Int {
return super<RandomGenerator>.nextInt(origin, bound)
}
override fun nextBoolean(): Boolean {
return super.nextBoolean()
}
override fun nextFloat(): Float {
return super.nextFloat()
}
override fun nextDouble(): Double {
return super.nextDouble()
}
override fun nextGaussian(): Double { override fun nextGaussian(): Double {
return gaussian.nextGaussian() return gaussian.nextGaussian()
} }
override fun fork(): RandomSource { override fun fork(): RandomSource {
return LCG64Random(nextLong()) return LCG64RandomSource(nextLong())
} }
override fun forkPositional(): PositionalRandomFactory { override fun forkPositional(): PositionalRandomFactory {
@ -72,24 +41,19 @@ class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) :
class Positional(val seed: Long) : PositionalRandomFactory { class Positional(val seed: Long) : PositionalRandomFactory {
override fun at(x: Int, y: Int, z: Int): RandomSource { override fun at(x: Int, y: Int, z: Int): RandomSource {
return LCG64Random(Mth.getSeed(x, y, z).xor(seed)) return LCG64RandomSource(Mth.getSeed(x, y, z).xor(seed))
} }
override fun fromHashOf(name: String): RandomSource { override fun fromHashOf(name: String): RandomSource {
return LCG64Random(name.hashCode().toLong().xor(seed)) return LCG64RandomSource(name.hashCode().toLong().xor(seed))
} }
override fun fromSeed(seed: Long): RandomSource { override fun fromSeed(seed: Long): RandomSource {
return LCG64Random(seed) return LCG64RandomSource(seed)
} }
override fun parityConfigString(builder: StringBuilder) { override fun parityConfigString(builder: StringBuilder) {
throw UnsupportedOperationException() throw UnsupportedOperationException()
} }
} }
companion object {
const val MULTIPLIER = 6364136223846793005
const val INCREMENT = 1442695040888963407
}
} }

View File

@ -0,0 +1,51 @@
package ru.dbotthepony.mc.otm.core.util
import net.minecraft.util.Mth
import net.minecraft.util.RandomSource
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
import net.minecraft.world.level.levelgen.PositionalRandomFactory
import net.minecraft.world.level.levelgen.RandomSupport
import ru.dbotthepony.kommons.random.PCG32Random
import java.lang.StringBuilder
/**
* @see PCG32Random
*/
class PCG32RandomSource(seed: Long = RandomSupport.generateUniqueSeed()) : PCG32Random(seed), IRandomSourceGenerator {
private val gaussian = MarsagliaPolarGaussian(this)
override fun setSeed(seed: Long) {
this.seed = seed
gaussian.reset()
}
override fun nextGaussian(): Double {
return gaussian.nextGaussian()
}
override fun fork(): RandomSource {
return PCG32RandomSource(nextLong())
}
override fun forkPositional(): PositionalRandomFactory {
return Positional(nextLong())
}
class Positional(val seed: Long) : PositionalRandomFactory {
override fun at(x: Int, y: Int, z: Int): RandomSource {
return PCG32RandomSource(Mth.getSeed(x, y, z).xor(seed))
}
override fun fromHashOf(name: String): RandomSource {
return PCG32RandomSource(name.hashCode().toLong().xor(seed))
}
override fun fromSeed(seed: Long): RandomSource {
return PCG32RandomSource(seed)
}
override fun parityConfigString(builder: StringBuilder) {
throw UnsupportedOperationException()
}
}
}

View File

@ -0,0 +1,93 @@
package ru.dbotthepony.mc.otm.core.util
import it.unimi.dsi.fastutil.HashCommon
import net.minecraft.util.Mth
import net.minecraft.util.RandomSource
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
import net.minecraft.world.level.levelgen.PositionalRandomFactory
import net.minecraft.world.level.levelgen.RandomSupport
import ru.dbotthepony.kommons.random.LCG64Random
import ru.dbotthepony.kommons.random.Xoshiro256StarStarRandom
/**
* Excellent number generator with guaranteed period of 2^255
*/
class Xoshiro256Random : Xoshiro256StarStarRandom, IRandomSourceGenerator {
private val gaussian = MarsagliaPolarGaussian(this)
// raw
private constructor(s0: Long, s1: Long, s2: Long, s3: Long, marker: Nothing?): super(s0, s1, s2, s3, null)
// normal
constructor(s0: Long, s1: Long, s2: Long, s3: Long) : super(s0, s1, s2, s3)
// 64-bit seeded
constructor(seed: Long) : super(1L, 2L, 3L, 4L, null) {
setSeed(seed)
}
// completely random
constructor() : super(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), null)
override fun setSeed(seed: Long) {
val rng = LCG64Random(seed)
s0 = rng.nextLong()
s1 = rng.nextLong()
s2 = rng.nextLong()
s3 = rng.nextLong()
gaussian.reset()
}
override fun nextInt(): Int {
// sample upper bits
return nextLong().ushr(32).toInt()
}
override fun nextGaussian(): Double {
return gaussian.nextGaussian()
}
override fun fork(): RandomSource {
return Xoshiro256Random(nextLong(), nextLong(), nextLong(), nextLong(), null)
}
override fun forkPositional(): PositionalRandomFactory {
return Positional(nextLong(), nextLong(), nextLong(), nextLong())
}
class Positional(
val s0: Long,
val s1: Long,
val s2: Long,
val s3: Long,
) : PositionalRandomFactory {
override fun at(x: Int, y: Int, z: Int): RandomSource {
val rng = LCG64RandomSource(Mth.getSeed(x, y, z))
return Xoshiro256Random(
s0.rotateLeft(11).xor(rng.nextLong()),
s1.rotateLeft(22).xor(rng.nextLong()),
s2.rotateLeft(33).xor(rng.nextLong()),
s3.rotateLeft(44).xor(rng.nextLong()),
)
}
override fun fromHashOf(name: String): RandomSource {
return Xoshiro256Random(s0, HashCommon.murmurHash3(name.hashCode().toLong()).xor(s1), s2, s3)
}
override fun fromSeed(seed: Long): RandomSource {
return Xoshiro256Random(seed)
}
override fun parityConfigString(builder: StringBuilder) {
throw UnsupportedOperationException()
}
}
companion object {
@JvmStatic
fun raw(s0: Long, s1: Long, s2: Long, s3: Long): Xoshiro256Random {
return Xoshiro256Random(s0, s1, s2, s3, null)
}
}
}

View File

@ -1,138 +0,0 @@
package ru.dbotthepony.mc.otm.core.util
import it.unimi.dsi.fastutil.HashCommon
import net.minecraft.util.Mth
import net.minecraft.util.RandomSource
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
import net.minecraft.world.level.levelgen.PositionalRandomFactory
import net.minecraft.world.level.levelgen.RandomSupport
import java.util.random.RandomGenerator
/**
* Excellent number generator with guaranteed period of 2^255
*/
class Xoshiro256SSRandom private constructor(
private var s0: Long,
private var s1: Long,
private var s2: Long,
private var s3: Long,
marker: Nothing?
) : RandomGenerator, RandomSource {
private val gaussian = MarsagliaPolarGaussian(this)
init {
if (s0 or s1 or s2 or s3 == 0L) {
s0 = 0x73CF3D83FFF44FF3L
s1 = 0x6412312B70F3CD37L
s2 = -0X6BB4C4E1327BFDCFL
s3 = -0X4BE0F5BB5F3F5240L
}
}
constructor(s0: Long, s1: Long, s2: Long, s3: Long) : this(s0, s1, s2, s3, null) {
// discard some values so generator can get going if provided seed was "weak"
for (i in 0 until 32)
nextLong()
}
constructor(seed: Long) : this(1L, 2L, 3L, 4L, null) {
setSeed(seed)
}
constructor() : this(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), null)
override fun setSeed(seed: Long) {
val rng = LCG64Random(seed)
s0 = rng.nextLong()
s1 = rng.nextLong()
s2 = rng.nextLong()
s3 = rng.nextLong()
gaussian.reset()
}
override fun nextInt(): Int {
// sample upper bits
return nextLong().ushr(32).toInt()
}
override fun nextLong(): Long {
val result = (s1 * 5).rotateLeft(7) * 9
val t = s1.shl(17)
s2 = s2.xor(s0)
s3 = s3.xor(s1)
s1 = s1.xor(s2)
s0 = s0.xor(s3)
s2 = s2.xor(t)
s3 = s3.rotateLeft(45)
return result
}
override fun nextInt(bound: Int): Int {
return super<RandomGenerator>.nextInt(bound)
}
override fun nextInt(origin: Int, bound: Int): Int {
return super<RandomGenerator>.nextInt(origin, bound)
}
override fun nextBoolean(): Boolean {
return super.nextBoolean()
}
override fun nextFloat(): Float {
return super.nextFloat()
}
override fun nextDouble(): Double {
return super.nextDouble()
}
override fun nextGaussian(): Double {
return gaussian.nextGaussian()
}
override fun fork(): RandomSource {
return Xoshiro256SSRandom(nextLong(), nextLong(), nextLong(), nextLong())
}
override fun forkPositional(): PositionalRandomFactory {
return Positional(nextLong(), nextLong(), nextLong(), nextLong())
}
class Positional(
val s0: Long,
val s1: Long,
val s2: Long,
val s3: Long,
) : PositionalRandomFactory {
override fun at(x: Int, y: Int, z: Int): RandomSource {
val rng = LCG64Random(Mth.getSeed(x, y, z))
return Xoshiro256SSRandom(
s0.rotateLeft(11).xor(rng.nextLong()),
s1.rotateLeft(22).xor(rng.nextLong()),
s2.rotateLeft(33).xor(rng.nextLong()),
s3.rotateLeft(44).xor(rng.nextLong()),
)
}
override fun fromHashOf(name: String): RandomSource {
return Xoshiro256SSRandom(s0, HashCommon.murmurHash3(name.hashCode().toLong()).xor(s1), s2, s3)
}
override fun fromSeed(seed: Long): RandomSource {
return Xoshiro256SSRandom(seed)
}
override fun parityConfigString(builder: StringBuilder) {
throw UnsupportedOperationException()
}
}
companion object {
@JvmStatic
fun raw(s0: Long, s1: Long, s2: Long, s3: Long): Xoshiro256SSRandom {
return Xoshiro256SSRandom(s0, s1, s2, s3, null)
}
}
}

View File

@ -21,8 +21,11 @@ import net.minecraft.world.entity.monster.Zombie
import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.registry.game.MEntityTypes
class BreadMonster(type: EntityType<BreadMonster>, level: Level) : Monster(type, level) { class BreadMonster(type: EntityType<BreadMonster>, level: Level) : Monster(type, level) {
constructor(level: Level) : this(MEntityTypes.BREAD_MONSTER, level)
val idleState = AnimationState() val idleState = AnimationState()
init { init {

View File

@ -6,23 +6,27 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items import net.minecraft.world.item.Items
import net.neoforged.bus.api.SubscribeEvent import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent
import ru.dbotthepony.mc.otm.config.ServerConfig
import ru.dbotthepony.mc.otm.core.otmRandom
import ru.dbotthepony.mc.otm.registry.game.MItems import ru.dbotthepony.mc.otm.registry.game.MItems
object WitheredSkeletonSpawnHandler { object WitheredSkeletonSpawnHandler {
@SubscribeEvent @SubscribeEvent
fun onEntityJoin(event: EntityJoinLevelEvent) { fun onEntityJoin(event: EntityJoinLevelEvent) {
val entity = event.entity val entity = event.entity
if (entity is WitherSkeleton){
val giveHelmet = entity.random.nextFloat() < 0.1f if (entity is WitherSkeleton) {
val giveSword = entity.random.nextFloat() < 0.24f val giveHelmet = event.level.otmRandom.nextFloat() < ServerConfig.WITHER_SKELETON_HELMET_CHANCE
val giveSword = event.level.otmRandom.nextFloat() < ServerConfig.WITHER_SKELETON_SWORD_CHANCE
if (giveHelmet) { if (giveHelmet) {
if (!entity.hasItemInSlot(EquipmentSlot.HEAD))
entity.setItemSlot(EquipmentSlot.HEAD, ItemStack(Items.NETHERITE_HELMET)) entity.setItemSlot(EquipmentSlot.HEAD, ItemStack(Items.NETHERITE_HELMET))
entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD)) }
} else if (giveSword) {
if (giveSword || giveHelmet) {
if (!entity.hasItemInSlot(EquipmentSlot.MAINHAND) || entity.getItemBySlot(EquipmentSlot.MAINHAND).item == Items.STONE_SWORD)
entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD)) entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD))
} }
} }

View File

@ -24,6 +24,7 @@ import net.neoforged.neoforge.event.tick.ServerTickEvent
import net.neoforged.neoforge.network.PacketDistributor import net.neoforged.neoforge.network.PacketDistributor
import net.neoforged.neoforge.network.handling.IPayloadContext import net.neoforged.neoforge.network.handling.IPayloadContext
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.THREAD_LOCAL_RANDOM
import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.trackedItems import ru.dbotthepony.mc.otm.capability.trackedItems
@ -42,6 +43,8 @@ import ru.dbotthepony.mc.otm.core.math.readDecimal
import ru.dbotthepony.mc.otm.core.math.set import ru.dbotthepony.mc.otm.core.math.set
import ru.dbotthepony.mc.otm.core.math.writeDecimal import ru.dbotthepony.mc.otm.core.math.writeDecimal
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.nextUUID
import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource
import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.core.util.formatPower
import ru.dbotthepony.mc.otm.isClientThread import ru.dbotthepony.mc.otm.isClientThread
import ru.dbotthepony.mc.otm.isServerThread import ru.dbotthepony.mc.otm.isServerThread
@ -82,7 +85,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
} }
} }
class UnboundValues(override val uuid: UUID = UUID.randomUUID()) : IValues { class UnboundValues(override val uuid: UUID = THREAD_LOCAL_RANDOM.nextUUID()) : IValues {
override var energy: Decimal = Decimal.ZERO override var energy: Decimal = Decimal.ZERO
override var passed: Decimal = Decimal.ZERO override var passed: Decimal = Decimal.ZERO
override var received: Decimal = Decimal.ZERO override var received: Decimal = Decimal.ZERO
@ -125,7 +128,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
} }
fun values(): Values { fun values(): Values {
return values(UUID.randomUUID()) return values(THREAD_LOCAL_RANDOM.nextUUID())
} }
override fun save(nbt: CompoundTag, registry: HolderLookup.Provider): CompoundTag { override fun save(nbt: CompoundTag, registry: HolderLookup.Provider): CompoundTag {
@ -160,7 +163,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
fun updateValues() { fun updateValues() {
if (!values.isServer && isServerThread()) { if (!values.isServer && isServerThread()) {
values = serverData.values(stack[MDataComponentTypes.QUANTUM_LINK_ID] ?: UUID.randomUUID().also { stack[MDataComponentTypes.QUANTUM_LINK_ID] = it }) values = serverData.values(stack[MDataComponentTypes.QUANTUM_LINK_ID] ?: THREAD_LOCAL_RANDOM.nextUUID().also { stack[MDataComponentTypes.QUANTUM_LINK_ID] = it })
} else if (isClientThread()) { } else if (isClientThread()) {
val id = stack[MDataComponentTypes.QUANTUM_LINK_ID] ?: return val id = stack[MDataComponentTypes.QUANTUM_LINK_ID] ?: return

View File

@ -1,25 +0,0 @@
package ru.dbotthepony.mc.otm.item.consumables
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.level.Level
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.food.FoodProperties
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
class ImperfectBread(properties: Item.Properties) : Item(properties) {
override fun finishUsingItem(stack: ItemStack, level: Level, entity: LivingEntity): ItemStack {
if (entity is Player) {
entity.addEffect(MobEffectInstance(MobEffects.POISON, 80, 0))
}
return super.finishUsingItem(stack, level, entity)
}
}
val IMPERFECT_BREAD_FOOD: FoodProperties = FoodProperties.Builder()
.nutrition(5)
.saturationModifier(0.6f)
.build()

View File

@ -0,0 +1,52 @@
package ru.dbotthepony.mc.otm.item.consumables
import net.minecraft.ChatFormatting
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.otmRandom
import ru.dbotthepony.mc.otm.core.position
import ru.dbotthepony.mc.otm.entity.BreadMonster
import ru.dbotthepony.mc.otm.item.MatteryItem
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
class ImperfectBreadItem(properties: Properties) : MatteryItem(properties) {
override fun finishUsingItem(stack: ItemStack, level: Level, entity: LivingEntity): ItemStack {
if (entity is ServerPlayer) {
entity.addEffect(MobEffectInstance(MobEffects.POISON, 80, 2))
}
return super.finishUsingItem(stack, level, entity)
}
init {
tooltips.addNormal { itemStack, context, acceptor ->
if (itemStack[MDataComponentTypes.INERT] == true) {
acceptor(TranslatableComponent("otm.misc.inert").withStyle(ChatFormatting.DARK_GRAY))
}
}
}
override fun onEntityItemUpdate(stack: ItemStack, entity: ItemEntity): Boolean {
if (stack[MDataComponentTypes.INERT] == true)
return super.onEntityItemUpdate(stack, entity)
// roll multiple times so multiple bread monsters can spawn on tick
// and also chance be less biased
for (i in 0 until stack.count.coerceAtMost(16)) {
if (entity.level().otmRandom.nextFloat() < 0.001f) {
val ent = BreadMonster(entity.level())
ent.position = entity.position
entity.level().addFreshEntity(ent)
stack.shrink(1)
}
}
return super.onEntityItemUpdate(stack, entity)
}
}

View File

@ -0,0 +1,84 @@
package ru.dbotthepony.mc.otm.item.matter
import com.google.common.collect.ImmutableList
import net.minecraft.network.chat.Component
import net.minecraft.util.RandomSource
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction
import net.minecraft.world.level.storage.loot.functions.SetComponentsFunction
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertFailure
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus
import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.capability.matter.gatherTooltip
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.stream
import ru.dbotthepony.mc.otm.item.MatteryItem
import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
import java.util.*
import java.util.stream.Stream
class GoldDiskItem(parameters: Properties) : MatteryItem(parameters), CapabilitiesRegisterListener {
override fun registerCapabilities(event: RegisterCapabilitiesEvent) {
event.registerItem(MatteryCapability.PATTERN_ITEM, { o, _ -> ItemPatternStorageCapability(o) }, this)
}
override fun getName(stack: ItemStack): Component {
val data = stack[MDataComponentTypes.PATTERNS]
if (data == null || data.size > 1) {
return super.getName(stack)
} else if (data.size == 0 || data[0].item == Items.AIR) {
return TranslatableComponent("$descriptionId.single_item", TextComponent("???"))
} else {
return TranslatableComponent("$descriptionId.single_item", data[0].item.getName(ItemStack(data[0].item)))
}
}
override fun appendHoverText(
itemStack: ItemStack,
context: TooltipContext,
components: MutableList<Component>,
tooltipType: TooltipFlag
) {
itemStack.getCapability(MatteryCapability.PATTERN_ITEM)?.gatherTooltip(context, components, tooltipType)
super.appendHoverText(itemStack, context, components, tooltipType)
}
class ItemPatternStorageCapability(val stack: ItemStack) : IPatternStorage {
override val patternCapacity: Int get() {
return stack[MDataComponentTypes.PATTERNS]?.size ?: 0
}
override val storedPatterns: Int get() {
return patternCapacity
}
override val patterns: Stream<PatternState> get() {
return stack[MDataComponentTypes.PATTERNS]?.stream() ?: Stream.empty()
}
override fun insertPattern(pattern: PatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus {
return PatternInsertFailure
}
}
companion object {
fun patterns(random: RandomSource, vararg items: Item): LootItemConditionalFunction.Builder<*> {
return SetComponentsFunction.setComponent(
MDataComponentTypes.PATTERNS,
items
.stream()
.map { PatternState(UUID(random.nextLong(), random.nextLong()), it, 1.0) }
.collect(ImmutableList.toImmutableList()))
}
}
}

View File

@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.item.matter
import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableList
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity import net.minecraft.world.item.Rarity
import net.minecraft.world.item.TooltipFlag import net.minecraft.world.item.TooltipFlag
@ -15,23 +14,20 @@ import ru.dbotthepony.mc.otm.capability.matter.PatternInsertInserted
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus
import ru.dbotthepony.mc.otm.capability.matter.PatternInsertUpdated import ru.dbotthepony.mc.otm.capability.matter.PatternInsertUpdated
import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.capability.matter.PatternState
import ru.dbotthepony.mc.otm.capability.matter.gatherTooltip
import ru.dbotthepony.mc.otm.capability.matter.getBarColor import ru.dbotthepony.mc.otm.capability.matter.getBarColor
import ru.dbotthepony.mc.otm.capability.matter.getBarWidth import ru.dbotthepony.mc.otm.capability.matter.getBarWidth
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.item.MatteryItem
import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener
import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes
import java.util.stream.Stream import java.util.stream.Stream
class PatternStorageItem : Item, CapabilitiesRegisterListener { class PatternStorageItem : MatteryItem, CapabilitiesRegisterListener {
private val _capacity: () -> Int private val _capacity: () -> Int
val capacity get() = _capacity.invoke() val capacity get() = _capacity.invoke()
var isCreative: Boolean var isCreative: Boolean
constructor(capacity: Int) : super(Properties().stacksTo(1)) {
_capacity = { capacity }
isCreative = false
}
constructor(capacity: () -> Int) : super(Properties().stacksTo(1)) { constructor(capacity: () -> Int) : super(Properties().stacksTo(1)) {
_capacity = capacity _capacity = capacity
isCreative = false isCreative = false
@ -47,29 +43,21 @@ class PatternStorageItem : Item, CapabilitiesRegisterListener {
} }
override fun appendHoverText( override fun appendHoverText(
p_41421_: ItemStack, itemStack: ItemStack,
p_339594_: TooltipContext, context: TooltipContext,
list: MutableList<Component>, components: MutableList<Component>,
p_41424_: TooltipFlag tooltipType: TooltipFlag
) { ) {
p_41421_.getCapability(MatteryCapability.PATTERN_ITEM)?.let { itemStack.getCapability(MatteryCapability.PATTERN_ITEM)?.let {
if (isCreative) if (isCreative)
list.add(TranslatableComponent("otm.item.pattern.infinite.stored", it.storedPatterns).withStyle(ChatFormatting.GRAY)) components.add(TranslatableComponent("otm.item.pattern.infinite.stored", it.storedPatterns).withStyle(ChatFormatting.GRAY))
else else
list.add(TranslatableComponent("otm.item.pattern.stored", it.storedPatterns, it.patternCapacity).withStyle(ChatFormatting.GRAY)) components.add(TranslatableComponent("otm.item.pattern.stored", it.storedPatterns, it.patternCapacity).withStyle(ChatFormatting.GRAY))
for (state in it.patterns) { it.gatherTooltip(context, components, tooltipType)
list.add(
TranslatableComponent(
"otm.item.pattern.line",
state.item.getName(ItemStack(state.item, 1)),
String.format("%.2f", state.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)
)
}
} }
super.appendHoverText(p_41421_, p_339594_, list, p_41424_) super.appendHoverText(itemStack, context, components, tooltipType)
} }
override fun isBarVisible(p_150899_: ItemStack): Boolean { override fun isBarVisible(p_150899_: ItemStack): Boolean {

View File

@ -13,23 +13,19 @@ import net.minecraft.world.item.Tiers
import net.minecraft.world.item.component.ItemAttributeModifiers import net.minecraft.world.item.component.ItemAttributeModifiers
import ru.dbotthepony.mc.otm.registry.game.MItems import ru.dbotthepony.mc.otm.registry.game.MItems
class WitheredSteelSwordItem(properties: Item.Properties) : SwordItem(Tiers.IRON, properties){ class WitheredSteelSwordItem(properties: Properties) : SwordItem(Tiers.IRON, properties) {
private val attributes: ItemAttributeModifiers private val attributes: ItemAttributeModifiers
init { init {
var builder = ItemAttributeModifiers.builder() val builder = ItemAttributeModifiers.builder()
builder.add(Attributes.ATTACK_DAMAGE, AttributeModifier(BASE_ATTACK_DAMAGE_ID, 4.5, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND) builder.add(Attributes.ATTACK_DAMAGE, AttributeModifier(BASE_ATTACK_DAMAGE_ID, 4.5, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND)
builder.add(Attributes.ATTACK_SPEED, AttributeModifier(BASE_ATTACK_SPEED_ID, -2.4, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND) builder.add(Attributes.ATTACK_SPEED, AttributeModifier(BASE_ATTACK_SPEED_ID, -2.4, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND)
attributes = builder.build() attributes = builder.build()
} }
override fun getMaxDamage(stack: ItemStack): Int { override fun isEnchantable(stack: ItemStack): Boolean {
return 420 return stack.count == 1
}
override fun isEnchantable(p_41456_: ItemStack): Boolean {
return p_41456_.count == 1
} }
override fun getEnchantmentValue(stack: ItemStack): Int { override fun getEnchantmentValue(stack: ItemStack): Int {
@ -41,13 +37,12 @@ class WitheredSteelSwordItem(properties: Item.Properties) : SwordItem(Tiers.IRON
} }
override fun hurtEnemy(stack: ItemStack, target: LivingEntity, attacker: LivingEntity): Boolean { override fun hurtEnemy(stack: ItemStack, target: LivingEntity, attacker: LivingEntity): Boolean {
target.addEffect(MobEffectInstance(MobEffects.WITHER, 100, 0)) val status = super.hurtEnemy(stack, target, attacker)
return super.hurtEnemy(stack, target, attacker) if (status) target.addEffect(MobEffectInstance(MobEffects.WITHER, 100, 0), attacker)
return status
} }
override fun getDefaultAttributeModifiers(stack: ItemStack): ItemAttributeModifiers { override fun getDefaultAttributeModifiers(stack: ItemStack): ItemAttributeModifiers {
return attributes return attributes
} }
} }

View File

@ -7,7 +7,14 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.entity.ExperienceOrb import net.minecraft.world.entity.ExperienceOrb
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.* import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.inventory.ContainerSynchronizer
import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.inventory.CraftingMenu
import net.minecraft.world.inventory.ResultContainer
import net.minecraft.world.inventory.ResultSlot
import net.minecraft.world.inventory.Slot
import net.minecraft.world.inventory.TransientCraftingContainer
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.neoforged.neoforge.network.PacketDistributor import net.neoforged.neoforge.network.PacketDistributor
import ru.dbotthepony.mc.otm.capability.MatteryPlayer import ru.dbotthepony.mc.otm.capability.MatteryPlayer

View File

@ -44,6 +44,7 @@ import ru.dbotthepony.mc.otm.container.sortWithIndices
import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.ResourceLocation
import ru.dbotthepony.mc.otm.core.collect.ConditionalSet import ru.dbotthepony.mc.otm.core.collect.ConditionalSet
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.network.MatteryStreamCodec import ru.dbotthepony.mc.otm.network.MatteryStreamCodec
import ru.dbotthepony.mc.otm.network.MenuDataPacket import ru.dbotthepony.mc.otm.network.MenuDataPacket
@ -207,7 +208,8 @@ abstract class MatteryMenu(
var sortInventoryInput: SortInput? = null var sortInventoryInput: SortInput? = null
private set private set
val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings) val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer.sortingSettings)
val acceptExopackChargeFromWirelessCharger = BooleanInputWithFeedback(this, true, player.matteryPlayer::acceptExopackChargeFromWirelessCharger)
var offhandSlot: InventorySlot? = null var offhandSlot: InventorySlot? = null
protected set protected set

View File

@ -5,6 +5,7 @@ import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerMiddleBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerMiddleBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerTopBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerTopBlockEntity
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.game.MMenus import ru.dbotthepony.mc.otm.registry.game.MMenus
@ -13,6 +14,9 @@ class AndroidChargerMenu : MatteryPoweredMenu {
val energyConfig: EnergyConfigPlayerInput val energyConfig: EnergyConfigPlayerInput
val profiledEnergy: ProfiledLevelGaugeWidget<*> val profiledEnergy: ProfiledLevelGaugeWidget<*>
val chargeAndroids: BooleanInputWithFeedback?
val chargeExopacks: BooleanInputWithFeedback?
constructor( constructor(
p_38852_: Int, p_38852_: Int,
inventory: Inventory, inventory: Inventory,
@ -20,6 +24,8 @@ class AndroidChargerMenu : MatteryPoweredMenu {
) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile) { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile) {
energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy, energyWidget) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy, energyWidget)
chargeAndroids = BooleanInputWithFeedback(this, tile?.let { it::chargeAndroids })
chargeExopacks = BooleanInputWithFeedback(this, tile?.let { it::chargeExopacks })
} }
constructor( constructor(
@ -29,6 +35,8 @@ class AndroidChargerMenu : MatteryPoweredMenu {
) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) {
energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget)
chargeAndroids = null
chargeExopacks = null
} }
constructor( constructor(
@ -38,6 +46,8 @@ class AndroidChargerMenu : MatteryPoweredMenu {
) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) {
energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget)
chargeAndroids = null
chargeExopacks = null
} }
init { init {

View File

@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.game.MMenus import ru.dbotthepony.mc.otm.registry.game.MMenus
@ -25,7 +26,7 @@ class AndroidStationMenu @JvmOverloads constructor(
) : MatteryPoweredMenu(MMenus.ANDROID_STATION, containerID, inventory, tile) { ) : MatteryPoweredMenu(MMenus.ANDROID_STATION, containerID, inventory, tile) {
private fun container(target: (MatteryPlayer) -> KMutableProperty0<ItemStack>): Container { private fun container(target: (MatteryPlayer) -> KMutableProperty0<ItemStack>): Container {
if (player is ServerPlayer) if (player is ServerPlayer)
return PartContainer(target.invoke(player.matteryPlayer ?: throw NullPointerException("OTM player capability is missing"))) return PartContainer(target.invoke(player.matteryPlayer))
else else
return SimpleContainer(1) return SimpleContainer(1)
} }
@ -115,6 +116,7 @@ class AndroidStationMenu @JvmOverloads constructor(
val equipment = makeEquipmentSlots() val equipment = makeEquipmentSlots()
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
val chargeAndroids = BooleanInputWithFeedback(this, tile?.let { it::chargeAndroids })
init { init {
addInventorySlots() addInventorySlots()
@ -122,6 +124,6 @@ class AndroidStationMenu @JvmOverloads constructor(
} }
override fun stillValid(player: Player): Boolean { override fun stillValid(player: Player): Boolean {
return super.stillValid(player) && player.matteryPlayer?.isAndroid == true return super.stillValid(player) && player.matteryPlayer.isAndroid
} }
} }

View File

@ -288,6 +288,9 @@ private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
accept(MItems.NUTRIENT_PASTE) accept(MItems.NUTRIENT_PASTE)
accept(MItems.IMPERFECT_BREAD) accept(MItems.IMPERFECT_BREAD)
accept(ItemStack(MItems.IMPERFECT_BREAD).also {
it[MDataComponentTypes.INERT] = true
})
// exo // exo
accept(MItems.EXOPACK_PROBE) accept(MItems.EXOPACK_PROBE)

View File

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList
import com.mojang.serialization.Codec import com.mojang.serialization.Codec
import net.minecraft.core.UUIDUtil import net.minecraft.core.UUIDUtil
import net.minecraft.core.component.DataComponentType import net.minecraft.core.component.DataComponentType
import net.minecraft.core.component.DataComponents
import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.RegistryFriendlyByteBuf import net.minecraft.network.RegistryFriendlyByteBuf
@ -69,6 +70,8 @@ object MDataComponentTypes {
val MAX_BATTERY_OUTPUT: DataComponentType<Decimal> by registry.register("max_battery_output") { DecimalComponent() } val MAX_BATTERY_OUTPUT: DataComponentType<Decimal> by registry.register("max_battery_output") { DecimalComponent() }
val MATTER_LEVEL: DataComponentType<Decimal> by registry.register("matter_level") { DecimalComponent() } val MATTER_LEVEL: DataComponentType<Decimal> by registry.register("matter_level") { DecimalComponent() }
val INERT: DataComponentType<Boolean> by registry.register("inert") { DataComponentType.builder<Boolean>().persistent(Codec.BOOL).build() }
val EXOPACK_SLOT_COUNT: DataComponentType<Int> by registry.register("exopack_slot_count") { DataComponentType.builder<Int>().persistent(Codec.INT).networkSynchronized(StreamCodecs.INT).build() } val EXOPACK_SLOT_COUNT: DataComponentType<Int> by registry.register("exopack_slot_count") { DataComponentType.builder<Int>().persistent(Codec.INT).networkSynchronized(StreamCodecs.INT).build() }
val EXOPACK_UPGRADE_ID: DataComponentType<UUID> by registry.register("exopack_upgrade_id") { uuid() } val EXOPACK_UPGRADE_ID: DataComponentType<UUID> by registry.register("exopack_upgrade_id") { uuid() }
val QUANTUM_LINK_ID: DataComponentType<UUID> by registry.register("quantum_link_id") { uuid() } val QUANTUM_LINK_ID: DataComponentType<UUID> by registry.register("quantum_link_id") { uuid() }

View File

@ -26,18 +26,12 @@ import net.minecraft.world.item.Tiers
import net.minecraft.world.item.crafting.Ingredient import net.minecraft.world.item.crafting.Ingredient
import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.Block
import net.neoforged.bus.api.IEventBus import net.neoforged.bus.api.IEventBus
import net.neoforged.neoforge.common.DeferredSpawnEggItem
import net.neoforged.neoforge.common.SimpleTier import net.neoforged.neoforge.common.SimpleTier
import ru.dbotthepony.mc.otm.block.MatteryBlock
import ru.dbotthepony.mc.otm.block.addSimpleDescription
import ru.dbotthepony.mc.otm.block.tech.FlywheelBatteryBlock
import ru.dbotthepony.mc.otm.capability.ITieredUpgradeSet import ru.dbotthepony.mc.otm.capability.ITieredUpgradeSet
import ru.dbotthepony.mc.otm.capability.MatteryPlayer import ru.dbotthepony.mc.otm.capability.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.UpgradeType
import ru.dbotthepony.mc.otm.config.CablesConfig import ru.dbotthepony.mc.otm.config.CablesConfig
import ru.dbotthepony.mc.otm.config.ItemsConfig import ru.dbotthepony.mc.otm.config.ItemsConfig
import ru.dbotthepony.mc.otm.core.addAll
import ru.dbotthepony.mc.otm.core.asSupplierArray
import ru.dbotthepony.mc.otm.core.collect.SupplierList import ru.dbotthepony.mc.otm.core.collect.SupplierList
import ru.dbotthepony.mc.otm.core.collect.SupplierMap import ru.dbotthepony.mc.otm.core.collect.SupplierMap
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
@ -66,6 +60,7 @@ import ru.dbotthepony.mc.otm.item.exopack.ExopackSlotUpgradeItem
import ru.dbotthepony.mc.otm.item.exopack.ExopackUpgradeItem import ru.dbotthepony.mc.otm.item.exopack.ExopackUpgradeItem
import ru.dbotthepony.mc.otm.item.exopack.ProceduralExopackSlotUpgradeItem import ru.dbotthepony.mc.otm.item.exopack.ProceduralExopackSlotUpgradeItem
import ru.dbotthepony.mc.otm.item.matter.CreativePatternItem import ru.dbotthepony.mc.otm.item.matter.CreativePatternItem
import ru.dbotthepony.mc.otm.item.matter.GoldDiskItem
import ru.dbotthepony.mc.otm.item.matter.MatterCapacitorItem import ru.dbotthepony.mc.otm.item.matter.MatterCapacitorItem
import ru.dbotthepony.mc.otm.item.matter.MatterDustItem import ru.dbotthepony.mc.otm.item.matter.MatterDustItem
import ru.dbotthepony.mc.otm.item.matter.PatternStorageItem import ru.dbotthepony.mc.otm.item.matter.PatternStorageItem
@ -429,7 +424,7 @@ object MItems {
val PILL_HEAL: Item by registry.register(MNames.PILL_HEAL) { HealPillItem() } val PILL_HEAL: Item by registry.register(MNames.PILL_HEAL) { HealPillItem() }
val PILL_NOT_NORMAL: Item by registry.register(MNames.PILL_NOT_NORMAL) { NotNormalPill() } val PILL_NOT_NORMAL: Item by registry.register(MNames.PILL_NOT_NORMAL) { NotNormalPill() }
val IMPERFECT_BREAD: Item by registry.register(MNames.IMPERFECT_BREAD) { ImperfectBread(Item.Properties().food(IMPERFECT_BREAD_FOOD)) } val IMPERFECT_BREAD: Item by registry.register(MNames.IMPERFECT_BREAD) { ImperfectBreadItem(Item.Properties().food(FoodProperties.Builder().nutrition(5).saturationModifier(0.6f).build())) }
val PILLS = SupplierList( val PILLS = SupplierList(
MItems::PILL_ANDROID, MItems::PILL_ANDROID,
@ -503,6 +498,8 @@ object MItems {
val PATTERN_DRIVE_CREATIVE: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE) { PatternStorageItem() } val PATTERN_DRIVE_CREATIVE: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE) { PatternStorageItem() }
val PATTERN_DRIVE_CREATIVE2: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE2) { CreativePatternItem() } val PATTERN_DRIVE_CREATIVE2: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE2) { CreativePatternItem() }
val GOLD_DISK: Item by registry.register("gold_disk") { GoldDiskItem(Properties().stacksTo(16).rarity(Rarity.RARE)) }
val PORTABLE_CONDENSATION_DRIVE: Item by registry.register(MNames.PORTABLE_CONDENSATION_DRIVE) { PortableCondensationDriveItem(4000) } val PORTABLE_CONDENSATION_DRIVE: Item by registry.register(MNames.PORTABLE_CONDENSATION_DRIVE) { PortableCondensationDriveItem(4000) }
val PORTABLE_DENSE_CONDENSATION_DRIVE: Item by registry.register(MNames.PORTABLE_DENSE_CONDENSATION_DRIVE) { PortableCondensationDriveItem(25000) } val PORTABLE_DENSE_CONDENSATION_DRIVE: Item by registry.register(MNames.PORTABLE_DENSE_CONDENSATION_DRIVE) { PortableCondensationDriveItem(25000) }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB