Skip to content

Instantly share code, notes, and snippets.

@eddyb
Created August 8, 2012 19:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save eddyb/3298010 to your computer and use it in GitHub Desktop.
Save eddyb/3298010 to your computer and use it in GitHub Desktop.
SethBling's BanSlimes filter, with two of my fixes.
# Feel free to modify and use this filter however you wish. If you do,
# please give credit to SethBling.
# http://youtube.com/SethBling
#from pymclevel import TAG_Long
# Performs signed overflow and underflow for Java's long.
# NOTE apparently not required.
def jlong(x):
# Signed overflow.
if x >= (1 << 64):
return -(1 << 63) + (x & ((1 << 64)-1))
# Signed underflow.
if x < -(1 << 64):
return (1 << 63) - 1 + (-x-1 & ((1 << 64)-1))
return x
# This mimics some of the functionality from the Java Random class.
# Java Random source code can be found here: http://developer.classpath.org/doc/java/util/Random-source.html
# NOTE not used directly, inlined below.
class Random:
def __init__(self, randseed):
self.setSeed(randseed)
def setSeed(self, randseed):
self.randseed = (randseed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
def next(self, bits):
self.randseed = long(self.randseed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
return int(self.randseed >> (48 - bits))
def nextInt(self, n):
while True:
bits = self.next(31)
val = bits % n
if int(bits - val + (n-1)) >= 0:
break
return val
# Algorithm found here: http://www.minecraftforum.net/topic/397835-find-slime-spawning-chunks-125/
def goodSeed(minx, minz, maxx, maxz, seed):
for x in xrange(minx, maxx):
# Partial seed for the current x.
partial = seed + (x * x * 0x4c1906) + (x * 0x5ac0db)
for z in xrange(minz, maxz):
# Compute the seed passed to the Java Random class.
randSeed = (partial + (z * z * 0x4307a7) + (z * 0x5f24f)) ^ 0x3ad8025f
# Random.setSeed(randSeed)
randSeed = (randSeed ^ 0x5DEECE66D) & ((1 << 48) - 1)
# Random.nextInt(10)
while True:
# bits = Random.next(31)
randSeed = (randSeed * 0x5DEECE66D + 0xB) & ((1 << 48) - 1)
bits = randSeed >> 17 # 17 == (48 - bits) with bits == 31
val = bits % 10
if (bits - val + 9) >= 0: # 9 == (n-1) with n == 10
break
slimeChunk = val == 0
if slimeChunk:
return False
return True
inputs = (
("Max Seed", 100000),
)
def perform(level, box, options):
# Convert block coords to chunk coords
minx = int(box.minx/16)
minz = int(box.minz/16)
maxx = int((box.maxx-1)/16)+1
maxz = int((box.maxz-1)/16)+1
for seed in xrange(options["Max Seed"]):
if goodSeed(minx, minz, maxx, maxz, seed):
#level.root_tag["Data"]["RandomSeed"] = TAG_Long(seed)
print "Found good seed: " + str(seed)
return
print "Didn't find good seed."
# Code for testing the speed of the brute-force.
class TestBox:
minx = 0
minz = 0
maxx = 10*16
maxz = 11*16
perform(False, TestBox(), {'Max Seed': inputs[0][1]})
# Feel free to modify and use this filter however you wish. If you do,
# please give credit to SethBling.
# http://youtube.com/SethBling
#from pymclevel import TAG_Long
# Performs signed overflow and underflow for Java's long.
# NOTE apparently not required.
def jlong(x):
# Signed overflow.
if x >= (1 << 64):
return -(1 << 63) + (x & ((1 << 64)-1))
# Signed underflow.
if x < -(1 << 64):
return (1 << 63) - 1 + (-x-1 & ((1 << 64)-1))
return x
# This mimics some of the functionality from the Java Random class.
# Java Random source code can be found here: http://developer.classpath.org/doc/java/util/Random-source.html
# NOTE not used directly, inlined below.
class Random:
def __init__(self, randseed):
self.setSeed(randseed)
def setSeed(self, randseed):
self.randseed = (randseed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
def next(self, bits):
self.randseed = long(self.randseed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
return int(self.randseed >> (48 - bits))
def nextInt(self, n):
while True:
bits = self.next(31)
val = bits % n
if int(bits - val + (n-1)) >= 0:
break
return val
# Algorithm found here: http://www.minecraftforum.net/topic/397835-find-slime-spawning-chunks-125/
def initChunks(chunks, minx, minz, maxx, maxz):
for x in xrange(minx, maxx):
# Partial seed for the current x.
partial = (x * x * 0x4c1906) + (x * 0x5ac0db)
for z in xrange(minz, maxz):
# Compute per-chunk position-dependent partial seeds.
chunks.append(partial + (z * z * 0x4307a7) + (z * 0x5f24f))
return chunks
def goodSeed(chunks, seed):
for i in chunks:
# Compute the seed passed to the Java Random class.
randSeed = (i + seed) ^ 0x3ad8025f
# Random.setSeed(randSeed)
randSeed = (randSeed ^ 0x5DEECE66D) & ((1 << 48) - 1)
# Random.nextInt(10)
while True:
# bits = Random.next(31)
randSeed = (randSeed * 0x5DEECE66D + 0xB) & ((1 << 48) - 1)
bits = randSeed >> 17 # 17 == (48 - bits) with bits == 31
val = bits % 10
if (bits - val + 9) >= 0: # 9 == (n-1) with n == 10
break
slimeChunk = val == 0
if slimeChunk:
return False
return True
inputs = (
("Max Seed", 100000),
)
def perform(level, box, options):
# Convert block coords to chunk coords
minx = int(box.minx/16)
minz = int(box.minz/16)
maxx = int((box.maxx-1)/16)+1
maxz = int((box.maxz-1)/16)+1
# Initialize per-chunk seeds.
chunks = initChunks([], minx, minz, maxx, maxz)
for seed in xrange(options["Max Seed"]):
if goodSeed(chunks, seed):
#level.root_tag["Data"]["RandomSeed"] = TAG_Long(seed)
print "Found good seed: " + str(seed)
return
print "Didn't find good seed."
# Code for testing the speed of the brute-force.
class TestBox:
minx = 0
minz = 0
maxx = 10*16
maxz = 11*16
perform(False, TestBox(), {'Max Seed': inputs[0][1]})
# Feel free to modify and use this filter however you wish. If you do,
# please give credit to SethBling.
# http://youtube.com/SethBling
#from pymclevel import TAG_Long
# This mimics some of the functionality from the Java Random class.
# Java Random source code can be found here: http://developer.classpath.org/doc/java/util/Random-source.html
class Random:
def __init__(self, randseed):
self.setSeed(randseed)
def setSeed(self, randseed):
self.randseed = (randseed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
def next(self, bits):
self.randseed = long(self.randseed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)
return int(self.randseed >> (48 - bits))
def nextInt(self, n):
while True:
bits = self.next(31)
val = bits % n
if int(bits - val + (n-1)) >= 0:
break
return val
# Algorithm found here: http://www.minecraftforum.net/topic/397835-find-slime-spawning-chunks-125/
def slimeChunk(seed, x, z):
randseed = long(seed) + long(x * x * 0x4c1906) + long(x * 0x5ac0db) + long(z * z) * 0x4307a7L + long(z * 0x5f24f) ^ 0x3ad8025f
r = Random(randseed)
i = r.nextInt(10)
return i == 0
def goodSeed(box, seed):
minx = int(box.minx/16)*16
minz = int(box.minz/16)*16
for x in xrange(minx, box.maxx, 16):
for z in xrange(minz, box.maxz, 16):
if slimeChunk(seed, x/16, z/16):
return False
return True
inputs = (
("Max Seed", 100000),
)
def perform(level, box, options):
for seed in xrange(options["Max Seed"]):
if goodSeed(box, seed):
#level.root_tag["Data"]["RandomSeed"] = TAG_Long(seed)
print "Found good seed: " + str(seed)
return
print "Didn't find good seed."
# Code for testing the speed of the brute-force.
class TestBox:
minx = 0
minz = 0
maxx = 10*16
maxz = 11*16
perform(False, TestBox(), {'Max Seed': inputs[0][1]})
$ time python BanSlimes.original.py; time python BanSlimes.fix1.py; time python BanSlimes.fix2.py
# BanSlimes.original.py
Found good seed: 12949
real 0m1.639s
user 0m1.607s
sys 0m0.016s
# BanSlimes.fix1.py
Found good seed: 12949
real 0m0.634s
user 0m0.608s
sys 0m0.013s
# BanSlimes.fix2.py
Found good seed: 12949
real 0m0.520s
user 0m0.496s
sys 0m0.015s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment