diff --git a/gradle.properties b/gradle.properties
index e0c63b221..face01890 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -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.3.2
+kommons_version=3.5.2
 caffeine_cache_version=3.1.5
 
 jei_version=19.16.4.171
diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/GJRAND64RandomSource.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/GJRAND64RandomSource.kt
new file mode 100644
index 000000000..0f8ac64c8
--- /dev/null
+++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/GJRAND64RandomSource.kt
@@ -0,0 +1,55 @@
+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 ru.dbotthepony.kommons.random.GJRAND64Random
+import java.lang.StringBuilder
+
+class GJRAND64RandomSource : GJRAND64Random, IRandomSourceGenerator {
+	private val gaussian = MarsagliaPolarGaussian(this)
+
+	constructor(seed: Long) : super(seed)
+	constructor(seed0: Long, seed1: Long) : super(seed0, seed1)
+
+	override fun nextInt(): Int {
+		return nextLong().ushr(32).toInt()
+	}
+
+	override fun nextGaussian(): Double {
+		return gaussian.nextGaussian()
+	}
+
+	override fun fork(): RandomSource {
+		return GJRAND64RandomSource(nextLong(), nextLong())
+	}
+
+	override fun forkPositional(): PositionalRandomFactory {
+		return Positional(nextLong(), nextLong())
+	}
+
+	override fun setSeed(seed: Long) {
+		reinitialize(seed)
+		gaussian.reset()
+	}
+
+	class Positional(private val seed0: Long, private val seed1: Long) : PositionalRandomFactory {
+		override fun at(x: Int, y: Int, z: Int): RandomSource {
+			val seed = Mth.getSeed(x, y, z)
+			return GJRAND64RandomSource(seed0.xor(seed.rotateLeft(32)), seed1.xor(seed))
+		}
+
+		override fun fromHashOf(name: String): RandomSource {
+			return GJRAND64RandomSource(name.hashCode().toLong().xor(seed0), seed1)
+		}
+
+		override fun fromSeed(seed: Long): RandomSource {
+			return GJRAND64RandomSource(seed)
+		}
+
+		override fun parityConfigString(builder: StringBuilder) {
+			throw UnsupportedOperationException()
+		}
+	}
+}