From b7b2b8095cc0295d098f9c0adef30e190b935a32 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 15 Mar 2025 10:04:16 +0700 Subject: [PATCH] Revert "Remove otmRandom" This reverts commit 5a016bef The way OTM uses random generator in its code will quickly cause LCG used in Minecraft to show its bias because LCG in minecraft samples its highest 48 bits, which gives us at best 2^16 period in the lowest bit returned by LCG. Which it doesn't sound bad, it quickly causes RNG become biased the quicker/more it is sampled on each tick, especially considering some may use `level.random.nextInt(chance) == 0` to determine chance of something happening, which will get extremely biased on heavy RNG congested environment If we avoid sampling Level's generator this much, we won't suffer from bias in our own code, as well as avoid biasing other mods this much. The "2^16 period" problem is also might be the reason why Entities get their own instance of RandomSource, and Mob Goals use random exactly the way described above (`nextInt(chance)`), which can and will suffer from bias the moment mob exists in world for more than 2^16 ticks (but actual bias will happen sooner because RNG is not sampled only once per tick, obviously) --- .../dbotthepony/mc/otm/mixin/LevelMixin.java | 19 +++++++++++++++++++ .../mixin/MixinAbstractHurtingProjectile.java | 3 ++- .../entity/blackhole/BlackHoleBlockEntity.kt | 4 ++-- .../BlackHoleGeneratorBlockEntity.kt | 6 +++--- .../block/entity/cable/EnergyCableGraph.kt | 4 ++-- .../decorative/CargoCrateBlockEntity.kt | 4 ++-- .../matter/MatterDecomposerBlockEntity.kt | 4 ++-- .../matter/MatterReconstructorBlockEntity.kt | 4 ++-- .../matter/MatterRecyclerBlockEntity.kt | 4 ++-- .../matter/MatterReplicatorBlockEntity.kt | 4 ++-- .../tech/AbstractPoweredFurnaceBlockEntity.kt | 4 ++-- .../entity/tech/AndroidChargerBlockEntity.kt | 3 ++- .../entity/tech/AndroidStationBlockEntity.kt | 3 ++- .../entity/tech/BatteryBankBlockEntity.kt | 4 ++-- .../entity/tech/EnergyInterfaceBlockEntity.kt | 4 ++-- .../entity/tech/EssenceStorageBlockEntity.kt | 6 +++--- .../entity/tech/PlatePressBlockEntity.kt | 4 ++-- .../dbotthepony/mc/otm/core/IMatteryLevel.kt | 17 +++++++++++++++++ .../mc/otm/entity/MinecartCargoCrate.kt | 4 ++-- .../mc/otm/entity/SpawnModifiers.kt | 6 +++--- .../ru/dbotthepony/mc/otm/item/BatteryItem.kt | 4 ++-- .../item/consumables/EssenceCapsuleItem.kt | 3 ++- .../item/consumables/ImperfectBreadItem.kt | 4 ++-- .../mc/otm/item/tool/ExplosiveHammerItem.kt | 4 ++-- .../mc/otm/item/weapon/EnergySwordItem.kt | 9 +++++---- .../mc/otm/item/weapon/FallingSunItem.kt | 9 +++++---- .../mc/otm/network/MatteryPlayerPackets.kt | 3 ++- .../mc/otm/network/SmokeParticlesPacket.kt | 4 ++-- .../mc/otm/player/MatteryPlayer.kt | 4 ++-- .../android/feature/EnderTeleporterFeature.kt | 7 ++++--- .../overdrive_that_matters.mixins.json | 3 ++- 31 files changed, 105 insertions(+), 60 deletions(-) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/IMatteryLevel.kt diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java new file mode 100644 index 000000000..9930b5a28 --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java @@ -0,0 +1,19 @@ +package ru.dbotthepony.mc.otm.mixin; + +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.Level; +import net.neoforged.fml.ModList; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import ru.dbotthepony.mc.otm.core.IMatteryLevel; +import ru.dbotthepony.mc.otm.core.util.GJRAND64RandomSource; + +@Mixin(Level.class) +public abstract class LevelMixin implements IMatteryLevel { + private final RandomSource otm_random = ModList.get().isLoaded("better_random") ? null : new GJRAND64RandomSource(); + + @Override + public @Nullable RandomSource getOtmRandom() { + return otm_random; + } +} diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/MixinAbstractHurtingProjectile.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/MixinAbstractHurtingProjectile.java index 21f131c1b..a91002d1d 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/mixin/MixinAbstractHurtingProjectile.java +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/MixinAbstractHurtingProjectile.java @@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import ru.dbotthepony.mc.otm.player.IMatteryPlayer; +import ru.dbotthepony.mc.otm.core.IMatteryLevel; import ru.dbotthepony.mc.otm.registry.game.MSoundEvents; @Mixin(AbstractHurtingProjectile.class) @@ -24,7 +25,7 @@ public class MixinAbstractHurtingProjectile { AbstractHurtingProjectile proj = (AbstractHurtingProjectile)(Object)this; if (cap.isAndroid() && proj.getOwner() != entity) { - entity.level().playSound(entity, proj.blockPosition(), MSoundEvents.INSTANCE.getANDROID_PROJ_PARRY(), SoundSource.PLAYERS, 1.0f, 0.95f + entity.level().getRandom().nextFloat() * 0.1f); + entity.level().playSound(entity, proj.blockPosition(), MSoundEvents.INSTANCE.getANDROID_PROJ_PARRY(), SoundSource.PLAYERS, 1.0f, 0.95f + ((IMatteryLevel) entity.level()).getOtmRandom().nextFloat() * 0.1f); } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleBlockEntity.kt index 0cc196d20..c94c15b68 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleBlockEntity.kt @@ -44,7 +44,7 @@ import ru.dbotthepony.mc.otm.core.math.getSphericalBlockPositions import ru.dbotthepony.mc.otm.core.math.times import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.set -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.isClient import ru.dbotthepony.mc.otm.matter.MatterManager import ru.dbotthepony.mc.otm.registry.MDamageTypes @@ -271,7 +271,7 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery } // шанс 1% что черная дыра потеряет 0.1 MtU каждую секунду * силу гравитации дыры ^ -1 - if (level.random.nextDouble() < 0.01 * 0.05 * (1 / gravitationStrength)) { + if (level.otmRandom.nextDouble() < 0.01 * 0.05 * (1 / gravitationStrength)) { this.mass += HAWKING_MASS_LOSE_STEP } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleGeneratorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleGeneratorBlockEntity.kt index 5347f3248..84c9bba76 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleGeneratorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/blackhole/BlackHoleGeneratorBlockEntity.kt @@ -34,7 +34,7 @@ import ru.dbotthepony.mc.otm.core.math.times import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag import ru.dbotthepony.mc.otm.core.multiblock.MultiblockStatus import ru.dbotthepony.mc.otm.core.multiblock.shapedMultiblock -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.util.InvalidableLazy import ru.dbotthepony.mc.otm.menu.tech.BlackHoleGeneratorMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities @@ -86,8 +86,8 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) multiblock?.blockEntities(MatterHatchBlockEntity.INPUT_TAG)?.iterator()?.map { it.matter }?.toList() ?: listOf() } - val energy = CombinedProfiledEnergyStorage(FlowDirection.NONE, energyTarget::value, { level?.random }) - val matter = CombinedProfiledMatterStorage(FlowDirection.NONE, matterTarget::value, { level?.random }) + val energy = CombinedProfiledEnergyStorage(FlowDirection.NONE, energyTarget::value, { level?.otmRandom }) + val matter = CombinedProfiledMatterStorage(FlowDirection.NONE, matterTarget::value, { level?.otmRandom }) enum class Mode(val label: Component, val tooltip: Component) { TARGET_MASS(TranslatableComponent("otm.gui.black_hole_generator.sustain.mode"), TranslatableComponent("otm.gui.black_hole_generator.sustain.desc")), diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt index 21ebb4928..8434ce627 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableGraph.kt @@ -14,7 +14,7 @@ import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.reduce import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.RelativeSide -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.shuffle import ru.dbotthepony.mc.otm.graph.GraphNodeList import ru.dbotthepony.mc.otm.onceServer @@ -627,7 +627,7 @@ class EnergyCableGraph : GraphNodeList= failureChance * upgrades.failureMultiplier) + if (failureChance * upgrades.failureMultiplier <= 0.0 || level!!.otmRandom.nextDouble() >= failureChance * upgrades.failureMultiplier) repairProgress += progressPerTick energy.extractEnergy(energyConsumption * (progressPerTick / thisProgressPerTick), false) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt index 87405bf61..d8fe21afe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt @@ -24,7 +24,7 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.item.matter.MatterDustItem import ru.dbotthepony.mc.otm.menu.matter.MatterRecyclerMenu @@ -117,7 +117,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) stack.shrink(1) container.setChanged(0) - val actualMatter = dustMatter.matter * (0.4 + level!!.random.nextDouble() * 0.6) + val actualMatter = dustMatter.matter * (0.4 + level!!.otmRandom.nextDouble() * 0.6) return JobContainer.success( RecyclerJob( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt index 944b3c954..ac9f9c181 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt @@ -28,7 +28,7 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.data.codec.DecimalCodec import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.graph.matter.MatterNode @@ -184,7 +184,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : task = allocation.task.id, matterValue = matter.matter, pattern = Optional.ofNullable(allocation.pattern), - asDust = (level?.random?.nextDouble() ?: 1.0) * upgrades.failureMultiplier > (allocation.pattern?.researchPercent ?: 2.0), + asDust = (level?.otmRandom?.nextDouble() ?: 1.0) * upgrades.failureMultiplier > (allocation.pattern?.researchPercent ?: 2.0), ticks = ticks, )) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index 48e11140b..4ca9c7317 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -35,7 +35,7 @@ import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.maybe import ru.dbotthepony.mc.otm.core.immutableList -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu import ru.dbotthepony.mc.otm.recipe.MatteryCookingRecipe import ru.dbotthepony.mc.otm.recipe.MicrowaveRecipe @@ -153,7 +153,7 @@ sealed class AbstractPoweredFurnaceBlockEntity

0f) { - repairPoints += if ((level?.random?.nextFloat() ?: 1f) <= diff) 1 else 0 + repairPoints += if ((level?.otmRandom?.nextFloat() ?: 1f) <= diff) 1 else 0 } experienceStored -= 1 @@ -202,7 +202,7 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma level!!.playSound(null, ent.x, ent.y, ent.z, SoundEvents.EXPERIENCE_ORB_PICKUP, SoundSource.BLOCKS, - 0.1F, 0.5F + level!!.random.nextFloat() * 0.25F + 0.1F, 0.5F + level!!.otmRandom.nextFloat() * 0.25F ) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index 1db3ae35b..bc8c6e1aa 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -21,7 +21,7 @@ import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.maybe -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MRecipes @@ -90,7 +90,7 @@ class PlatePressBlockEntity( recipe.getResultItem(level.registryAccess()).copyWithCount(toProcess), recipe.workTime * MachinesConfig.PLATE_PRESS.workTimeMultiplier, MachinesConfig.PLATE_PRESS.energyConsumption * toProcess, - experience = recipe.experience.sample(level.random) * toProcess)) + experience = recipe.experience.sample(level.otmRandom) * toProcess)) } override fun tick() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/IMatteryLevel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/IMatteryLevel.kt new file mode 100644 index 000000000..583febb3c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/IMatteryLevel.kt @@ -0,0 +1,17 @@ +package ru.dbotthepony.mc.otm.core + +import net.minecraft.util.RandomSource +import net.minecraft.world.level.Level +import net.neoforged.fml.ModList + +interface IMatteryLevel { + /** + * OTM provided [RandomSource], which has better statistical parameters + * + * Original Minecraft use LCG, which may show bad behavior when repeatedly sampled *a lot*, + * which is what [Level]'s random is used for. OTM provided PRNG should behave better in this scenario. + */ + val otmRandom: RandomSource? +} + +val Level.otmRandom: RandomSource get() = (this as IMatteryLevel).otmRandom ?: random diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/MinecartCargoCrate.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/MinecartCargoCrate.kt index 5c66894fb..ee09e29ff 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/MinecartCargoCrate.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/MinecartCargoCrate.kt @@ -19,7 +19,7 @@ import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.gameevent.GameEvent import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.position import ru.dbotthepony.mc.otm.menu.decorative.MinecartCargoCrateMenu import ru.dbotthepony.mc.otm.registry.game.MItems @@ -90,7 +90,7 @@ class MinecartCargoCrate( if (interactingPlayers++ == 0) { if (!isRemoved) { - level().playSound(null, this, MSoundEvents.CARGO_CRATE_OPEN, SoundSource.BLOCKS, 1f, 0.8f + level().random.nextFloat() * 0.2f) + level().playSound(null, this, MSoundEvents.CARGO_CRATE_OPEN, SoundSource.BLOCKS, 1f, 0.8f + level().otmRandom.nextFloat() * 0.2f) this.gameEvent(GameEvent.CONTAINER_OPEN, player) PiglinAi.angerNearbyPiglins(player, true) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt index 386c0bb06..d7d1bb5d4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt @@ -7,7 +7,7 @@ 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.random +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.registry.game.MItems @@ -17,8 +17,8 @@ object WitheredSkeletonSpawnHandler { val entity = event.entity if (entity is WitherSkeleton) { - val giveHelmet = event.level.random.nextFloat() < ServerConfig.WITHER_SKELETON_HELMET_CHANCE - val giveSword = event.level.random.nextFloat() < ServerConfig.WITHER_SKELETON_SWORD_CHANCE + 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 (!entity.hasItemInSlot(EquipmentSlot.HEAD)) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/BatteryItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/BatteryItem.kt index a4f9651b0..281cdc63f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/BatteryItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/BatteryItem.kt @@ -185,7 +185,7 @@ class CrudeBatteryItem : BatteryItem(ItemsConfig.Batteries.CRUDE) { if (player is ServerPlayer) { if (!mattery.androidEnergy.item.isEmpty) { mattery.androidEnergy.item.getCapability(Capabilities.EnergyStorage.ITEM)?.let { - it.extractEnergy((it.maxEnergyStored * level.random.nextFloat() * .2f).roundToInt(), false) + it.extractEnergy((it.maxEnergyStored * level.otmRandom.nextFloat() * .2f).roundToInt(), false) } mattery.dropBattery() @@ -195,7 +195,7 @@ class CrudeBatteryItem : BatteryItem(ItemsConfig.Batteries.CRUDE) { copyStack.count = 1 mattery.androidEnergy.item = copyStack - val extraDamageMult = level.random.nextFloat() + val extraDamageMult = level.otmRandom.nextFloat() player.hurt(MatteryDamageSource(level.registryAccess().damageType(MDamageTypes.EMP), inflictor = itemStack), 1.5f + extraDamageMult * 3.5f) val debuffDuration = 100 + (100 * (1f - extraDamageMult)).roundToInt() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/EssenceCapsuleItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/EssenceCapsuleItem.kt index df8008a1c..9d7ddbbdd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/EssenceCapsuleItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/EssenceCapsuleItem.kt @@ -17,6 +17,7 @@ import ru.dbotthepony.mc.otm.player.matteryPlayer import ru.dbotthepony.mc.otm.client.isShiftDown import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.util.getLevelFromXp import ru.dbotthepony.mc.otm.item.MatteryItem import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes @@ -80,7 +81,7 @@ class EssenceCapsuleItem(private val digital: Boolean) : MatteryItem(Properties( } else { if (level is ServerLevel) { level.levelEvent(2002, player.blockPosition(), PotionContents.getColor(Potions.WATER)) - ExperienceOrb.award(level, player.position(), (exp * (.5 + level.random.nextFloat() * .25)).toInt()) + ExperienceOrb.award(level, player.position(), (exp * (.5 + level.otmRandom.nextFloat() * .25)).toInt()) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt index 9a3022448..089de13fc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt @@ -9,7 +9,7 @@ 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.random +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 @@ -39,7 +39,7 @@ class ImperfectBreadItem(properties: Properties) : MatteryItem(properties) { // 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().random.nextFloat() < 0.001f) { + if (entity.level().otmRandom.nextFloat() < 0.001f) { val ent = BreadMonster(entity.level()) ent.position = entity.position entity.level().addFreshEntity(ent) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/tool/ExplosiveHammerItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/tool/ExplosiveHammerItem.kt index a79ab1ead..018d1d474 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/tool/ExplosiveHammerItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/tool/ExplosiveHammerItem.kt @@ -84,7 +84,7 @@ class ExplosiveHammerItem(durability: Int = 512) : Item(Properties().stacksTo(1) itemStack.hurtAndBreak(8, level, player) {} if (isPrimed(itemStack)) { - itemStack.hurtAndBreak(level.random.nextInt(1, 20), level, player) {} + itemStack.hurtAndBreak(level.otmRandom.nextInt(1, 20), level, player) {} unprime(itemStack) val (ex, ey, ez) = Vector.atCenterOf(player.blockPosition()) @@ -226,7 +226,7 @@ class ExplosiveHammerItem(durability: Int = 512) : Item(Properties().stacksTo(1) val copy = itemStack.copy() - itemStack.hurtAndBreak(level.random.nextInt(1, 20), attacker, EquipmentSlot.MAINHAND) + itemStack.hurtAndBreak(level.otmRandom.nextInt(1, 20), attacker, EquipmentSlot.MAINHAND) if (!itemStack.isEmpty && attacker.random.nextDouble() <= ToolsConfig.ExplosiveHammer.FLY_OFF_CHANCE) { attacker.setItemInHand(hand, ItemStack.EMPTY) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt index bd42bfb5f..666ffbac2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt @@ -32,6 +32,7 @@ import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.core.math.nextVariance +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.util.WriteOnce import ru.dbotthepony.mc.otm.item.MatteryItem import ru.dbotthepony.mc.otm.item.addSimpleDescription @@ -96,10 +97,10 @@ class EnergySwordItem : MatteryItem(Properties().stacksTo(1).rarity(Rarity.RARE) itemStack.getCapability(MatteryCapability.ITEM_ENERGY)?.let { if (it.extractEnergyExact(ENERGY_PER_SWING, false)) { - it.extractEnergy(attacker.level().random.nextVariance(ENERGY_PER_SWING_VARIANCE), false) + it.extractEnergy(attacker.level().otmRandom.nextVariance(ENERGY_PER_SWING_VARIANCE), false) victim.matteryPlayer?.let { if (it.isAndroid && it.androidEnergy.extractEnergyExact(ENERGY_ZAP, false)) { - it.androidEnergy.extractEnergy(attacker.level().random.nextVariance(ENERGY_ZAP_VARIANCE), false) + it.androidEnergy.extractEnergy(attacker.level().otmRandom.nextVariance(ENERGY_ZAP_VARIANCE), false) victim.hurt(MatteryDamageSource(attacker.level().registryAccess().damageType(MDamageTypes.EMP), attacker, itemStack), 8f) } } @@ -142,12 +143,12 @@ class EnergySwordItem : MatteryItem(Properties().stacksTo(1).rarity(Rarity.RARE) if (blockState.`is`(BlockTags.SWORD_EFFICIENT)) { if (energy?.extractEnergyExact(PLANT_POWER_COST, false) == true) - energy.extractEnergyExact(user.level().random.nextVariance(PLANT_POWER_COST_VARIANCE), false) + energy.extractEnergyExact(user.level().otmRandom.nextVariance(PLANT_POWER_COST_VARIANCE), false) } if (blockState.`is`(Blocks.COBWEB)) { if (energy?.extractEnergyExact(COBWEB_POWER_COST, false) == true) - energy.extractEnergyExact(user.level().random.nextVariance(COBWEB_POWER_COST_VARIANCE), false) + energy.extractEnergyExact(user.level().otmRandom.nextVariance(COBWEB_POWER_COST_VARIANCE), false) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt index c5ce968ff..d4f636c9e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt @@ -32,6 +32,7 @@ import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.core.math.nextVariance +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.util.WriteOnce import ru.dbotthepony.mc.otm.item.MatteryItem import ru.dbotthepony.mc.otm.item.addSimpleDescription @@ -96,10 +97,10 @@ class FallingSunItem : MatteryItem(Properties().stacksTo(1).rarity(Rarity.EPIC)) itemStack.getCapability(MatteryCapability.ITEM_ENERGY)?.let { if (it.extractEnergyExact(ENERGY_PER_SWING, false)) { - it.extractEnergy(attacker.level().random.nextVariance(ENERGY_PER_SWING_VARIANCE), false) + it.extractEnergy(attacker.level().otmRandom.nextVariance(ENERGY_PER_SWING_VARIANCE), false) victim.matteryPlayer?.let { if (it.isAndroid && it.androidEnergy.extractEnergyExact(ENERGY_ZAP, false)) { - it.androidEnergy.extractEnergy(attacker.level().random.nextVariance(ENERGY_ZAP_VARIANCE), false) + it.androidEnergy.extractEnergy(attacker.level().otmRandom.nextVariance(ENERGY_ZAP_VARIANCE), false) victim.hurt(MatteryDamageSource(attacker.level().registryAccess().damageType(MDamageTypes.EMP), attacker, itemStack), 8f) } } @@ -142,12 +143,12 @@ class FallingSunItem : MatteryItem(Properties().stacksTo(1).rarity(Rarity.EPIC)) if (blockState.`is`(BlockTags.SWORD_EFFICIENT)) { if (energy?.extractEnergyExact(PLANT_POWER_COST, false) == true) - energy.extractEnergyExact(user.level().random.nextVariance(PLANT_POWER_COST_VARIANCE), false) + energy.extractEnergyExact(user.level().otmRandom.nextVariance(PLANT_POWER_COST_VARIANCE), false) } if (blockState.`is`(Blocks.COBWEB)) { if (energy?.extractEnergyExact(COBWEB_POWER_COST, false) == true) - energy.extractEnergyExact(user.level().random.nextVariance(COBWEB_POWER_COST_VARIANCE), false) + energy.extractEnergyExact(user.level().otmRandom.nextVariance(COBWEB_POWER_COST_VARIANCE), false) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt index fbc7c2cb9..72b92aaf2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt @@ -24,6 +24,7 @@ import ru.dbotthepony.mc.otm.core.math.component1 import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.component3 import ru.dbotthepony.mc.otm.core.math.toRadians +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.position import ru.dbotthepony.mc.otm.core.readItem import ru.dbotthepony.mc.otm.core.writeItem @@ -445,7 +446,7 @@ class ExopackSmokePacket(val player: UUID) : CustomPacketPayload { z += kotlin.math.sin(deg) * -0.4 val level = ply.level() - val random = level.random + val random = level.otmRandom for (i in 0 .. random.nextInt(2, 4)) level.addParticle( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/SmokeParticlesPacket.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/SmokeParticlesPacket.kt index 5ab9cc173..5d87e004a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/SmokeParticlesPacket.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/SmokeParticlesPacket.kt @@ -13,7 +13,7 @@ import net.neoforged.neoforge.network.handling.IPayloadContext import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.core.ResourceLocation -import ru.dbotthepony.mc.otm.core.random +import ru.dbotthepony.mc.otm.core.otmRandom class SmokeParticlesPacket(val x: Double, val y: Double, val z: Double) : CustomPacketPayload { fun write(buff: FriendlyByteBuf) { @@ -24,7 +24,7 @@ class SmokeParticlesPacket(val x: Double, val y: Double, val z: Double) : Custom fun play(context: IPayloadContext) { minecraft.player?.level()?.let { - makeSmoke(x, y, z, it.random, it) + makeSmoke(x, y, z, it.otmRandom, it) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index a8a906d5f..99e72ad24 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -528,7 +528,7 @@ class MatteryPlayer(val ply: Player) { override fun onJobTick(status: JobStatus) { super.onJobTick(status) - if (isExopackVisible && ply.level().random.nextFloat() <= 0.05f) { + if (isExopackVisible && ply.level().otmRandom.nextFloat() <= 0.05f) { PacketDistributor.sendToPlayersTrackingEntityAndSelf(ply, ExopackSmokePacket(ply.uuid)) } } @@ -1319,7 +1319,7 @@ class MatteryPlayer(val ply: Player) { pos.mul(RenderSystem.getProjectionMatrix()) pos.mul(poseStack.last().pose()) - makeSmoke(cam.x + pos.x, cam.y + pos.y, cam.z + pos.z, ply.level().random, ply.level()) + makeSmoke(cam.x + pos.x, cam.y + pos.y, cam.z + pos.z, ply.level().otmRandom, ply.level()) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/android/feature/EnderTeleporterFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/android/feature/EnderTeleporterFeature.kt index 807d461b1..2f0bd1cbf 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/android/feature/EnderTeleporterFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/android/feature/EnderTeleporterFeature.kt @@ -49,6 +49,7 @@ import ru.dbotthepony.mc.otm.core.math.rotateXDegrees import ru.dbotthepony.mc.otm.core.math.rotateYDegrees import ru.dbotthepony.mc.otm.core.math.shortestDistanceBetween import ru.dbotthepony.mc.otm.core.math.times +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.milliTime import ru.dbotthepony.mc.otm.registry.game.AndroidFeatures import ru.dbotthepony.mc.otm.triggers.EnderTeleporterFallDeathTrigger @@ -302,7 +303,7 @@ class EnderTeleporterFeature(capability: MatteryPlayer) : AndroidActiveFeature(A val event = EventHooks.onEnderTeleport(ply, blockPos.x + 0.5, blockPos.y.toDouble(), blockPos.z + 0.5) if (event.isCanceled) { - (ply as ServerPlayer).connection.send(ClientboundSoundEntityPacket(SoundEvents.ITEM_BREAK.holder, SoundSource.PLAYERS, ply, 0.3f, 0.5f, ply.level().random.nextLong())) + (ply as ServerPlayer).connection.send(ClientboundSoundEntityPacket(SoundEvents.ITEM_BREAK.holder, SoundSource.PLAYERS, ply, 0.3f, 0.5f, ply.level().otmRandom.nextLong())) return false } @@ -310,9 +311,9 @@ class EnderTeleporterFeature(capability: MatteryPlayer) : AndroidActiveFeature(A lastTeleport = ply.server!!.tickCount android.androidEnergy.extractEnergy(PlayerConfig.EnderTeleporter.ENERGY_COST, false) - ply.level().playSound(null, ply, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 0.3f, 0.8f + ply.level().random.nextFloat() * 0.4f) + ply.level().playSound(null, ply, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 0.3f, 0.8f + ply.level().otmRandom.nextFloat() * 0.4f) ply.teleportTo(event.targetX, event.targetY, event.targetZ) - ply.level().playSound(null, ply, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1f, 0.8f + ply.level().random.nextFloat() * 0.4f) + ply.level().playSound(null, ply, SoundEvents.ENDERMAN_TELEPORT, SoundSource.PLAYERS, 1f, 0.8f + ply.level().otmRandom.nextFloat() * 0.4f) ply.deltaMovement = Vector(0.0, 0.0, 0.0) ply.resetFallDistance() diff --git a/src/main/resources/overdrive_that_matters.mixins.json b/src/main/resources/overdrive_that_matters.mixins.json index 5a114f337..9fafe0491 100644 --- a/src/main/resources/overdrive_that_matters.mixins.json +++ b/src/main/resources/overdrive_that_matters.mixins.json @@ -17,7 +17,8 @@ "HopperBlockEntityMixin", "DispenserBlockEntityMixin", "GuiGraphicsMixin", - "BlockStateBaseMixin" + "BlockStateBaseMixin", + "LevelMixin" ], "client": [ "MixinGameRenderer",