From e2195ba809a25a3d65ca65faab178638a882a9d1 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Mon, 24 Feb 2020 14:45:12 +0900 Subject: [PATCH] using proper hashing function --- src/net/torvald/UnsafePtr.kt | 2 +- src/net/torvald/random/XXHash32.java | 79 +++++++++++++++++++ .../terrarum/blockproperties/BlockProp.kt | 6 +- src/net/torvald/terrarum/tests/RNGTest.kt | 26 +++++- 4 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 src/net/torvald/random/XXHash32.java diff --git a/src/net/torvald/UnsafePtr.kt b/src/net/torvald/UnsafePtr.kt index 425a7656b..febd1fb0d 100644 --- a/src/net/torvald/UnsafePtr.kt +++ b/src/net/torvald/UnsafePtr.kt @@ -8,7 +8,7 @@ import sun.misc.Unsafe */ object UnsafeHelper { - internal val unsafe: Unsafe + val unsafe: Unsafe init { val unsafeConstructor = Unsafe::class.java.getDeclaredConstructor() diff --git a/src/net/torvald/random/XXHash32.java b/src/net/torvald/random/XXHash32.java new file mode 100644 index 000000000..ba6a8b1c2 --- /dev/null +++ b/src/net/torvald/random/XXHash32.java @@ -0,0 +1,79 @@ +package net.torvald.random; + +import net.torvald.UnsafeHelper; +import net.torvald.terrarum.AppLoader; + +/** + * Code from https://richardstartin.github.io/posts/xxhash + * https://github.com/richardstartin/xxhash-benchmark + * Created by minjaesong on 2020-02-24 + */ + +public class XXHash32 { + + static final int PRIME1 = 0x9E3779B1; + static final int PRIME2 = 0x85EBCA77; + static final int PRIME3 = 0xC2B2AE3D; + static final int PRIME4 = 0x27D4EB2F; + static final int PRIME5 = 0x165667B1; + + static final int ARRAY_ELEM_OFFSET = (AppLoader.is32BitJVM) ? 8 : 16; + + public static int hash(byte[] data, int seed) { + int end = data.length; + int offset = 0; + int h32; + if (data.length >= 16) { + int limit = end - 16; + int v1 = seed + PRIME1 + PRIME2; + int v2 = seed + PRIME2; + int v3 = seed; + int v4 = seed - PRIME1; + + do { + v1 += getInt(data, offset) * PRIME2; + v1 = Integer.rotateLeft(v1, 13); + v1 *= PRIME1; + offset += 4; + v2 += getInt(data, offset) * PRIME2; + v2 = Integer.rotateLeft(v2, 13); + v2 *= PRIME1; + offset += 4; + v3 += getInt(data, offset) * PRIME2; + v3 = Integer.rotateLeft(v3, 13); + v3 *= PRIME1; + offset += 4; + v4 += getInt(data, offset) * PRIME2; + v4 = Integer.rotateLeft(v4, 13); + v4 *= PRIME1; + offset += 4; + } while(offset <= limit); + + h32 = Integer.rotateLeft(v1, 1) + Integer.rotateLeft(v2, 7) + Integer.rotateLeft(v3, 12) + Integer.rotateLeft(v4, 18); + } else { + h32 = seed + PRIME5; + } + + for(h32 += data.length; offset <= end - 4; offset += 4) { + h32 += getInt(data, offset) * PRIME3; + h32 = Integer.rotateLeft(h32, 17) * PRIME4; + } + + while(offset < end) { + h32 += (data[offset] & 255) * PRIME5; + h32 = Integer.rotateLeft(h32, 11) * PRIME1; + ++offset; + } + + h32 ^= h32 >>> 15; + h32 *= PRIME2; + h32 ^= h32 >>> 13; + h32 *= PRIME3; + h32 ^= h32 >>> 16; + return h32; + } + + protected static int getInt(byte[] data, int offset) { + return UnsafeHelper.INSTANCE.getUnsafe().getInt(data, offset + ARRAY_ELEM_OFFSET); + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/blockproperties/BlockProp.kt b/src/net/torvald/terrarum/blockproperties/BlockProp.kt index 4d564e215..27b710a33 100644 --- a/src/net/torvald/terrarum/blockproperties/BlockProp.kt +++ b/src/net/torvald/terrarum/blockproperties/BlockProp.kt @@ -1,7 +1,9 @@ package net.torvald.terrarum.blockproperties import net.torvald.gdx.graphics.Cvec +import net.torvald.random.XXHash32 import net.torvald.terrarum.gameworld.fmod +import net.torvald.terrarum.serialise.toLittle /** * Created by minjaesong on 2016-02-16. @@ -58,8 +60,8 @@ class BlockProp { fun getLumCol(x: Int, y: Int) = if (dynamicLuminosityFunction == 0) { baseLumCol } else { - val offset = (x * 214013 + 2531011).ushr(16).fmod(BlockCodex.DYNAMIC_RANDOM_CASES) - BlockCodex[BlockCodex.dynamicToVirtualMap[id]!! - offset]._lumCol + val offset = XXHash32.hash(((x and 0xFFFF).shl(16) or (y and 0xFFFF)).toLittle(), 10000) + BlockCodex[BlockCodex.dynamicToVirtualMap[id]!! - offset.fmod(BlockCodex.DYNAMIC_RANDOM_CASES)]._lumCol } /** diff --git a/src/net/torvald/terrarum/tests/RNGTest.kt b/src/net/torvald/terrarum/tests/RNGTest.kt index 51270e707..47d03ea41 100644 --- a/src/net/torvald/terrarum/tests/RNGTest.kt +++ b/src/net/torvald/terrarum/tests/RNGTest.kt @@ -1,6 +1,10 @@ package net.torvald.terrarum.tests import net.torvald.random.HQRNG +import net.torvald.random.XXHash32 +import net.torvald.terrarum.blockproperties.BlockCodex +import net.torvald.terrarum.gameworld.fmod +import net.torvald.terrarum.serialise.toLittle import java.util.* /** @@ -20,7 +24,7 @@ fun main(args: Array) { println() - val rng2 = com.sudoplay.joise.generator.HQRNG() + /*val rng2 = com.sudoplay.joise.generator.HQRNG() repeat(512) { println(rng2.getRange(0, 10)) @@ -29,4 +33,24 @@ fun main(args: Array) { // getTarget: 0..(t-1) (exclusive) // getRange: low..high (inclusive) // get01: 0.0 until 1.0 (exclusive) + + + */ + + + + for (tries in 0 until 16) { + repeat(BlockCodex.DYNAMIC_RANDOM_CASES + 12) { repeats -> + val x = 349 + repeats + val y = 9492 + tries + + + val offset = XXHash32.hash(((x and 0xFFFF).shl(16) or (y and 0xFFFF)).toLittle(), 10000) + + //print("${offset.toString().padStart(2, '0')} ") + print("${offset.fmod(BlockCodex.DYNAMIC_RANDOM_CASES).toString().padStart(2, '0')} ") + } + println() + println() + } }