Random numbers through player generated entropy
Minecraft's built-in java.util.Random is a Linear Congruential Generator (LCG); fast, but predictable. Given its seed, every value it will ever produce is known in advance. PlayerEntropy replaces that with a live entropy pool fed by real player behaviour: movement, clicks, block interactions, chat; anything a player does contributes unpredictable, high-quality randomness that no one can game or predict.
PlayerEntropy collects entropy from player events as they happen on the server and mixes them into a shared pool. The pool is designed to fill quickly under normal server activity — with five active players, a 16KB pool fills in roughly two seconds. From that pool you can draw raw entropy bytes, or use it to seed a CSPRNG for unlimited high-quality random output.
The library is platform-agnostic at its core. Adapters provide the platform-specific event wiring.
| Module | Description |
|---|---|
PlayerEntropy-core |
Platform-independent entropy pool and API |
PlayerEntropy-spigot |
Spigot/Paper adapter — wires player events into the pool |
PlayerEntropyLab |
Companion plugin: in-world visualizations and statistical tests |
Add the Spigot adapter as a dependency (it includes core transitively):
<dependency>
<groupId>dev.siea.playerentropy</groupId>
<artifactId>PlayerEntropy-spigot</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>PlayerEntropy is not currently published to a public Maven repository. Install it locally with
mvn installfrom the repo root before depending on it.
public class MyPlugin extends JavaPlugin {
private PlayerEntropy entropy;
@Override
public void onEnable() {
this.entropy = PlayerEntropy.of(new SpigotServer(this));
}
}byte[] bytes = entropy.nextBytes(32); // 32 bytes of true entropy
int i = entropy.netInt(100); // random number below 100
...Use this for seeding your own systems, one-off cryptographic seeds, or anywhere you need a small amount of true randomness.
Random random = entropy.random();
// draw as many values as you need
double value = random.nextDouble();
int roll = random.nextInt(20);The CSPRNG is seeded from the pool and reseeds itself automatically as the pool refills. Use this wherever you need large volumes of high-quality random output.
java.util.Random is a Linear Congruential Generator. That means its entire future output is determined by a single 48-bit seed, usually derived from the system clock at startup. In practice this means:
- It's predictable. Anyone who knows or can guess the seed knows every value the RNG will ever produce. On a Minecraft server seeded at startup, the seed space is small enough to brute-force.
- Low-bit bias. LCGs are notoriously weak in their lower bits.
nextInt(n)for smallndraws from the weakest part of the output. Loot rolls, mob decisions, and spawn logic all use small ranges. - Structural patterns. Plot enough LCG output in 3D and you'll see diagonal hyperplanes — the values are not independently distributed, they follow a lattice. PlayerEntropyLab can show you this in the world with blocks.
- Identical across servers. Two servers started at the same millisecond produce the same sequence. PlayerEntropy's pool is fed by real player behaviour — no two servers will ever produce the same output.
PlayerEntropy doesn't just reseed java.util.Random with a better seed. It replaces the generator entirely with one that is continuously refreshed by entropy no one can predict or replay.
| Platform | Status |
|---|---|
| Spigot / Paper | ✅ Supported |
| Fabric | 🚧 Planned |
# From repo root — builds core and all adapters
mvn install
# PlayerEntropyLab is a separate project
cd PlayerEntropyLab
mvn packageRequires Java 21 and Maven 3.9+.