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.mappingsVersion=2024.11.17
kommons_version=3.1.3
kommons_version=3.3.2
caffeine_cache_version=3.1.5
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.models.MatteryBlockModelProvider
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.datagen.advancements.addAdvancements
import ru.dbotthepony.mc.otm.datagen.advancements.addAndroidAdvancements
@ -68,6 +69,10 @@ internal fun modLootTable(string: String) = ResourceKey.create(Registries.LOOT_T
object DataGen {
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()
private set
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_CREATIVE2)
provider.withExistingParent(MItems.GOLD_DISK, MItems.PATTERN_DRIVE_CREATIVE.registryName!!)
provider.generated(MItems.MATTER_DUST)
provider.generated(MItems.TRITANIUM_DOOR.values)

View File

@ -145,6 +145,8 @@ private fun sounds(provider: MatteryLanguageProvider) {
private fun misc(provider: MatteryLanguageProvider) {
with(provider.english) {
misc("misc.inert", "Inert")
misc("misc.yes", "Yes")
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_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, "description1", "Creative-only item")
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) {
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("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) {
with(provider.russian) {
misc("misc.inert", "Инертен")
misc("misc.yes", "Да")
misc("misc.no", "Нет")
@ -878,6 +880,9 @@ private fun items(provider: MatteryLanguageProvider) {
add(MItems.PATTERN_DRIVE_QUAD, "Четырёхуровневый диск шаблонов")
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, "description1", "Предмет режима творчества")
add(MItems.PATTERN_DRIVE_CREATIVE2, "description2", "Содержит в себе шаблоны всех предметов, которые имеют значение материи")
@ -984,6 +989,15 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) {
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("flywheel.current_loss_t", "Текущая потеря энергии в тик:")

View File

@ -1,7 +1,10 @@
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 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
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.world.entity.EntityType
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.LootTable
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.KilledByRealPlayerOrIndirectly
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.item.ProceduralBatteryItem
import ru.dbotthepony.mc.otm.item.exopack.ProceduralExopackSlotUpgradeItem
import ru.dbotthepony.mc.otm.item.matter.GoldDiskItem
import ru.dbotthepony.mc.otm.registry.game.MItems
@Suppress("FunctionName")
@ -66,6 +69,11 @@ fun addLootModifiers(it: LootModifiers) {
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) {
chanceCondition(0.15)
@ -122,6 +130,11 @@ fun addLootModifiers(it: LootModifiers) {
chanceCondition(0.1)
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(

View File

@ -34,7 +34,12 @@ fun addEquipmentTags(tagsProvider: TagsProvider) {
.add(MItems.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.PICKAXES).add(MItems.TRITANIUM_PICKAXE)
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.spongepowered.asm.mixin.Mixin;
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)
public abstract class LevelMixin implements IMatteryLevel {
public final RandomSource otm_random = new Xoshiro256SSRandom();
public final RandomSource otm_random = new PCG32RandomSource();
@Override
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.core.HolderLookup
import net.minecraft.server.MinecraftServer
import net.minecraft.util.RandomSource
import net.minecraft.world.level.Level
import net.neoforged.api.distmarker.Dist
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.IConditionalTickable
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.graph.GraphNodeList
import java.lang.ref.Cleaner
import java.util.*
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 postServerTick = 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.network.chat.Component
import net.minecraft.network.chat.ComponentSerialization
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
@ -83,9 +84,11 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
override fun setLevel(level: Level) {
super.setLevel(level)
level.once {
if (!isRemoved && this.level == level) {
redstoneControl.redstoneSignal = level.getBestNeighborSignal(blockPos)
if (level is ServerLevel) {
level.once(4) {
if (!isRemoved && this.level == level) {
redstoneControl.redstoneSignal = level.getBestNeighborSignal(blockPos)
}
}
}
}

View File

@ -165,7 +165,7 @@ abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockP
if (!SERVER_IS_LIVE) return
val level = level
level?.once {
level?.once(4) {
if (!node.isValid) return@once
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))
val energyConfig = ConfigurableEnergy(energy, modesTop = FlowDirection.NONE)
var chargeAndroids = true
set(value) {
field = value
markDirtyFast()
}
var chargeExopacks = true
set(value) {
field = value
markDirtyFast()
}
init {
savetables.stateful(energyConfig::energy, ENERGY_KEY)
savetablesConfig.bool(::chargeAndroids)
savetablesConfig.bool(::chargeExopacks)
}
override fun tick() {
super.tick()
if (redstoneControl.isBlockedByRedstone) return
if (redstoneControl.isBlockedByRedstone || !chargeAndroids && !chargeExopacks) return
val level = level ?: return
var available = energyConfig.energy.extractEnergy(energyConfig.energy.batteryLevel, true)
if (!available.isPositive) return
@ -49,14 +63,14 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma
for ((ent) in ents) {
val ply = (ent as Player).matteryPlayer
if (ply.isAndroid) {
if (chargeAndroids && ply.isAndroid) {
val received = ply.androidEnergy.receiveEnergyChecked(available, false)
available -= received
energyConfig.energy.extractEnergy(received, false)
if (!available.isPositive) return
}
if (ply.hasExopack) {
if (chargeExopacks && ply.hasExopack && ply.acceptExopackChargeFromWirelessCharger) {
val received = ply.exopackEnergy.receiveEnergyChecked(available, false)
available -= received
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.config.MachinesConfig
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.registry.game.MBlockEntities
class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider {
class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider {
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
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 fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return super.extractEnergy(howMuch, simulate).also {
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)
}
}
@ -41,7 +46,7 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return super.receiveEnergy(howMuch, simulate).also {
if (!simulate && it.isPositive) {
if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) {
if (workerState != WorkerState.WORKING) {
level?.setBlock(blockPos, blockState.setValue(
WorkerState.SEMI_WORKER_STATE,
WorkerState.WORKING
@ -53,9 +58,15 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
})
val energyConfig = ConfigurableEnergy(energy)
var chargeAndroids = true
set(value) {
field = value
markDirtyFast()
}
init {
savetables.stateful(::energy, ENERGY_KEY)
savetablesConfig.bool(::chargeAndroids)
}
private var tickedOnce = false
@ -66,20 +77,20 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
if (!tickedOnce) {
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)
} 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)
}
}
if (redstoneControl.isBlockedByRedstone) return
if (redstoneControl.isBlockedByRedstone || !chargeAndroids) return
val level = level ?: return
val x = blockPos.x.toDouble()
val y = blockPos.y.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)
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 exopackChargeSlots = MatteryContainer(4)
var acceptExopackChargeFromWirelessCharger = true
init {
savetables.int(::ticksIExist)
@ -578,6 +579,7 @@ class MatteryPlayer(val ply: Player) {
savetables.bool(::isExopackVisible, "displayExoSuit")
savetables.bool(::isExopackCraftingUpgraded, "isExoSuitCraftingUpgraded")
savetables.bool(::isExopackEnderAccessInstalled, "isExopackEnderAccessUpgraded")
savetables.bool(::acceptExopackChargeFromWirelessCharger)
savetables.int(::nextDischargeHurt)
savetables.int(::nextHealTick)

View File

@ -1,7 +1,13 @@
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.TooltipContext
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import ru.dbotthepony.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import java.util.*
import java.util.function.Predicate
import java.util.stream.Collectors
@ -72,3 +78,19 @@ fun IPatternStorage.getBarWidth(): Int {
fun IPatternStorage.getBarColor(): Int {
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 STATISTICS_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)

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.translation
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.slot.AbstractSlotPanel
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<*>) {
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 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) }
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 {
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.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.panels.Dock
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.BatterySlotPanel
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.TallHorizontalProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu
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
}
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
}

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.kommons.math.RGBAColor
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.menu.tech.AndroidStationMenu
import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket
@ -717,7 +718,18 @@ class AndroidStationScreen(p_97741_: AndroidStationMenu, p_97742_: Inventory, p_
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
}

View File

@ -76,4 +76,12 @@ object ServerConfig : AbstractConfig("misc") {
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
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
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
get() = positiveDecimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus)
override val energyStorage: Decimal
@ -53,7 +53,7 @@ class UpgradeContainer(
override val energyConsumed: Decimal
get() = anyDecimals(IMatteryUpgrade::energyConsumed, Decimal::plus)
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
get() = positiveDecimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus)
override val energyThroughput: Decimal
@ -62,24 +62,24 @@ class UpgradeContainer(
fun transform(values: EnergyBalanceValues): EnergyBalanceValues {
return object : EnergyBalanceValues {
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
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 {
return object : VerboseEnergyBalanceValues {
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
get() = values.maxEnergyReceive * (energyThroughput + Decimal.ONE) + energyThroughputFlat
get() = if (isEmpty) values.maxEnergyReceive else values.maxEnergyReceive * (energyThroughput + Decimal.ONE) + energyThroughputFlat
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 {
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]
}
fun IntArray.shuffle(random: RandomSource) {
fun IntArray.shuffle(random: RandomSource): IntArray {
for (i in lastIndex downTo 1) {
val j = random.nextInt(i + 1)
val copy = this[i]
this[i] = this[j]
this[j] = copy
}
return this
}
fun <T> MutableList<T>.shuffle(random: RandomSource) {
return Util.shuffle(this, random)
fun <T, L : MutableList<T>> L.shuffle(random: RandomSource): L {
Util.shuffle(this, random)
return this
}
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)
fun RandomSource.nextUUID(): UUID {
return UUID(nextLong(), nextLong())
}
// normal distribution via Marsaglia polar method
fun RandomGenerator.nextNormalDoubles(stddev: Double, mean: Double): DoublePair {
var rand1: Double

View File

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

View File

@ -5,6 +5,7 @@ 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 java.lang.StringBuilder
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.PositionalRandomFactory
import net.minecraft.world.level.levelgen.RandomSupport
import ru.dbotthepony.kommons.random.LCG64Random
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.
@ -19,7 +19,7 @@ import java.util.random.RandomGenerator
* * Always use upper 32 bits instead of implementing BitRandomSource and sampling some upper bits
* * 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)
override fun setSeed(seed: Long) {
@ -27,43 +27,12 @@ class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) :
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 {
return gaussian.nextGaussian()
}
override fun fork(): RandomSource {
return LCG64Random(nextLong())
return LCG64RandomSource(nextLong())
}
override fun forkPositional(): PositionalRandomFactory {
@ -72,24 +41,19 @@ class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) :
class Positional(val seed: Long) : PositionalRandomFactory {
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 {
return LCG64Random(name.hashCode().toLong().xor(seed))
return LCG64RandomSource(name.hashCode().toLong().xor(seed))
}
override fun fromSeed(seed: Long): RandomSource {
return LCG64Random(seed)
return LCG64RandomSource(seed)
}
override fun parityConfigString(builder: StringBuilder) {
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.player.Player
import net.minecraft.world.level.Level
import ru.dbotthepony.mc.otm.registry.game.MEntityTypes
class BreadMonster(type: EntityType<BreadMonster>, level: Level) : Monster(type, level) {
constructor(level: Level) : this(MEntityTypes.BREAD_MONSTER, level)
val idleState = AnimationState()
init {

View File

@ -6,24 +6,28 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.neoforged.bus.api.SubscribeEvent
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
object WitheredSkeletonSpawnHandler {
@SubscribeEvent
fun onEntityJoin(event: EntityJoinLevelEvent) {
val entity = event.entity
if (entity is WitherSkeleton){
val giveHelmet = entity.random.nextFloat() < 0.1f
val giveSword = entity.random.nextFloat() < 0.24f
if (entity is WitherSkeleton) {
val giveHelmet = event.level.otmRandom.nextFloat() < ServerConfig.WITHER_SKELETON_HELMET_CHANCE
val giveSword = event.level.otmRandom.nextFloat() < ServerConfig.WITHER_SKELETON_SWORD_CHANCE
if (giveHelmet) {
entity.setItemSlot(EquipmentSlot.HEAD, ItemStack(Items.NETHERITE_HELMET))
entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD))
} else if (giveSword) {
entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD))
if (!entity.hasItemInSlot(EquipmentSlot.HEAD))
entity.setItemSlot(EquipmentSlot.HEAD, ItemStack(Items.NETHERITE_HELMET))
}
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))
}
}
}

View File

@ -24,6 +24,7 @@ import net.neoforged.neoforge.event.tick.ServerTickEvent
import net.neoforged.neoforge.network.PacketDistributor
import net.neoforged.neoforge.network.handling.IPayloadContext
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.MatteryCapability
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.writeDecimal
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.isClientThread
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 passed: Decimal = Decimal.ZERO
override var received: Decimal = Decimal.ZERO
@ -125,7 +128,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
}
fun values(): Values {
return values(UUID.randomUUID())
return values(THREAD_LOCAL_RANDOM.nextUUID())
}
override fun save(nbt: CompoundTag, registry: HolderLookup.Provider): CompoundTag {
@ -160,7 +163,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc
fun updateValues() {
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()) {
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 net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Rarity
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.PatternInsertUpdated
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.getBarWidth
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.game.MDataComponentTypes
import java.util.stream.Stream
class PatternStorageItem : Item, CapabilitiesRegisterListener {
class PatternStorageItem : MatteryItem, CapabilitiesRegisterListener {
private val _capacity: () -> Int
val capacity get() = _capacity.invoke()
var isCreative: Boolean
constructor(capacity: Int) : super(Properties().stacksTo(1)) {
_capacity = { capacity }
isCreative = false
}
constructor(capacity: () -> Int) : super(Properties().stacksTo(1)) {
_capacity = capacity
isCreative = false
@ -47,29 +43,21 @@ class PatternStorageItem : Item, CapabilitiesRegisterListener {
}
override fun appendHoverText(
p_41421_: ItemStack,
p_339594_: TooltipContext,
list: MutableList<Component>,
p_41424_: TooltipFlag
itemStack: ItemStack,
context: TooltipContext,
components: MutableList<Component>,
tooltipType: TooltipFlag
) {
p_41421_.getCapability(MatteryCapability.PATTERN_ITEM)?.let {
itemStack.getCapability(MatteryCapability.PATTERN_ITEM)?.let {
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
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) {
list.add(
TranslatableComponent(
"otm.item.pattern.line",
state.item.getName(ItemStack(state.item, 1)),
String.format("%.2f", state.researchPercent * 100.0)
).withStyle(ChatFormatting.AQUA)
)
}
it.gatherTooltip(context, components, tooltipType)
}
super.appendHoverText(p_41421_, p_339594_, list, p_41424_)
super.appendHoverText(itemStack, context, components, tooltipType)
}
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 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
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_SPEED, AttributeModifier(BASE_ATTACK_SPEED_ID, -2.4, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND)
attributes = builder.build()
}
override fun getMaxDamage(stack: ItemStack): Int {
return 420
}
override fun isEnchantable(p_41456_: ItemStack): Boolean {
return p_41456_.count == 1
override fun isEnchantable(stack: ItemStack): Boolean {
return stack.count == 1
}
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 {
target.addEffect(MobEffectInstance(MobEffects.WITHER, 100, 0))
return super.hurtEnemy(stack, target, attacker)
val status = super.hurtEnemy(stack, target, attacker)
if (status) target.addEffect(MobEffectInstance(MobEffects.WITHER, 100, 0), attacker)
return status
}
override fun getDefaultAttributeModifiers(stack: ItemStack): ItemAttributeModifiers {
return attributes
}
}

View File

@ -7,7 +7,14 @@ import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.Container
import net.minecraft.world.entity.ExperienceOrb
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.neoforged.neoforge.network.PacketDistributor
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.collect.ConditionalSet
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.network.MatteryStreamCodec
import ru.dbotthepony.mc.otm.network.MenuDataPacket
@ -207,7 +208,8 @@ abstract class MatteryMenu(
var sortInventoryInput: SortInput? = null
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
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.AndroidChargerTopBlockEntity
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.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.game.MMenus
@ -13,6 +14,9 @@ class AndroidChargerMenu : MatteryPoweredMenu {
val energyConfig: EnergyConfigPlayerInput
val profiledEnergy: ProfiledLevelGaugeWidget<*>
val chargeAndroids: BooleanInputWithFeedback?
val chargeExopacks: BooleanInputWithFeedback?
constructor(
p_38852_: Int,
inventory: Inventory,
@ -20,6 +24,8 @@ class AndroidChargerMenu : MatteryPoweredMenu {
) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile) {
energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy, energyWidget)
chargeAndroids = BooleanInputWithFeedback(this, tile?.let { it::chargeAndroids })
chargeExopacks = BooleanInputWithFeedback(this, tile?.let { it::chargeExopacks })
}
constructor(
@ -29,6 +35,8 @@ class AndroidChargerMenu : MatteryPoweredMenu {
) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) {
energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget)
chargeAndroids = null
chargeExopacks = null
}
constructor(
@ -38,6 +46,8 @@ class AndroidChargerMenu : MatteryPoweredMenu {
) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) {
energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget)
chargeAndroids = null
chargeExopacks = null
}
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.menu.MatteryPoweredMenu
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.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.game.MMenus
@ -25,7 +26,7 @@ class AndroidStationMenu @JvmOverloads constructor(
) : MatteryPoweredMenu(MMenus.ANDROID_STATION, containerID, inventory, tile) {
private fun container(target: (MatteryPlayer) -> KMutableProperty0<ItemStack>): Container {
if (player is ServerPlayer)
return PartContainer(target.invoke(player.matteryPlayer ?: throw NullPointerException("OTM player capability is missing")))
return PartContainer(target.invoke(player.matteryPlayer))
else
return SimpleContainer(1)
}
@ -115,6 +116,7 @@ class AndroidStationMenu @JvmOverloads constructor(
val equipment = makeEquipmentSlots()
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
val chargeAndroids = BooleanInputWithFeedback(this, tile?.let { it::chargeAndroids })
init {
addInventorySlots()
@ -122,6 +124,6 @@ class AndroidStationMenu @JvmOverloads constructor(
}
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.IMPERFECT_BREAD)
accept(ItemStack(MItems.IMPERFECT_BREAD).also {
it[MDataComponentTypes.INERT] = true
})
// exo
accept(MItems.EXOPACK_PROBE)

View File

@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList
import com.mojang.serialization.Codec
import net.minecraft.core.UUIDUtil
import net.minecraft.core.component.DataComponentType
import net.minecraft.core.component.DataComponents
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.nbt.CompoundTag
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 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_UPGRADE_ID: DataComponentType<UUID> by registry.register("exopack_upgrade_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.level.block.Block
import net.neoforged.bus.api.IEventBus
import net.neoforged.neoforge.common.DeferredSpawnEggItem
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.MatteryPlayer
import ru.dbotthepony.mc.otm.capability.UpgradeType
import ru.dbotthepony.mc.otm.config.CablesConfig
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.SupplierMap
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.ProceduralExopackSlotUpgradeItem
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.MatterDustItem
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_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(
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_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_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