multi-threaded structure seed bruteforcing
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
package kaptainwutax.seedcracker;
|
package kaptainwutax.seedcracker;
|
||||||
|
|
||||||
|
import io.netty.util.internal.ConcurrentSet;
|
||||||
import kaptainwutax.seedcracker.cracker.*;
|
import kaptainwutax.seedcracker.cracker.*;
|
||||||
import kaptainwutax.seedcracker.cracker.population.PopulationData;
|
import kaptainwutax.seedcracker.cracker.population.PopulationData;
|
||||||
import kaptainwutax.seedcracker.finder.FinderQueue;
|
import kaptainwutax.seedcracker.finder.FinderQueue;
|
||||||
@@ -18,6 +19,7 @@ import org.apache.logging.log4j.Logger;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class SeedCracker implements ModInitializer {
|
public class SeedCracker implements ModInitializer {
|
||||||
|
|
||||||
@@ -27,7 +29,7 @@ public class SeedCracker implements ModInitializer {
|
|||||||
public static final OverworldChunkGeneratorConfig CHUNK_GEN_CONFIG = new OverworldChunkGeneratorConfig();
|
public static final OverworldChunkGeneratorConfig CHUNK_GEN_CONFIG = new OverworldChunkGeneratorConfig();
|
||||||
|
|
||||||
public List<Long> worldSeeds = null;
|
public List<Long> worldSeeds = null;
|
||||||
public List<Long> structureSeeds = null;
|
public Set<Long> structureSeeds = null;
|
||||||
public List<Integer> pillarSeeds = null;
|
public List<Integer> pillarSeeds = null;
|
||||||
|
|
||||||
private TimeMachine timeMachine = new TimeMachine();
|
private TimeMachine timeMachine = new TimeMachine();
|
||||||
@@ -130,7 +132,7 @@ public class SeedCracker implements ModInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() + this.populationCache.size() >= 5) {
|
if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() + this.populationCache.size() >= 5) {
|
||||||
this.structureSeeds = new ArrayList<>();
|
this.structureSeeds = new ConcurrentSet<>();
|
||||||
LOG.warn("Looking for structure seeds with " + this.structureCache.size() + " structure features.");
|
LOG.warn("Looking for structure seeds with " + this.structureCache.size() + " structure features.");
|
||||||
LOG.warn("Looking for structure seeds with " + this.populationCache.size() + " population features.");
|
LOG.warn("Looking for structure seeds with " + this.populationCache.size() + " population features.");
|
||||||
|
|
||||||
@@ -186,11 +188,7 @@ public class SeedCracker implements ModInitializer {
|
|||||||
this.worldSeeds = new ArrayList<>();
|
this.worldSeeds = new ArrayList<>();
|
||||||
LOG.warn("Looking for world seeds with " + this.biomeCache.size() + " biomes.");
|
LOG.warn("Looking for world seeds with " + this.biomeCache.size() + " biomes.");
|
||||||
|
|
||||||
for(int i = 0; i < this.structureSeeds.size(); i++) {
|
this.structureSeeds.forEach(structureSeed -> {
|
||||||
SeedCracker.LOG.warn("Progress " + (i * 100.0f) / this.structureSeeds.size() + "%...");
|
|
||||||
|
|
||||||
long structureSeed = this.structureSeeds.get(i);
|
|
||||||
|
|
||||||
for (long j = 0; j < (1L << 16); j++) {
|
for (long j = 0; j < (1L << 16); j++) {
|
||||||
long worldSeed = (j << 48) | structureSeed;
|
long worldSeed = (j << 48) | structureSeed;
|
||||||
boolean goodSeed = true;
|
boolean goodSeed = true;
|
||||||
@@ -208,7 +206,7 @@ public class SeedCracker implements ModInitializer {
|
|||||||
this.worldSeeds.add(worldSeed);
|
this.worldSeeds.add(worldSeed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if(this.worldSeeds.size() > 0) {
|
if(this.worldSeeds.size() > 0) {
|
||||||
LOG.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds."));
|
LOG.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds."));
|
||||||
|
|||||||
@@ -6,24 +6,33 @@ import kaptainwutax.seedcracker.util.Rand;
|
|||||||
import kaptainwutax.seedcracker.util.math.LCG;
|
import kaptainwutax.seedcracker.util.math.LCG;
|
||||||
import net.minecraft.world.gen.ChunkRandom;
|
import net.minecraft.world.gen.ChunkRandom;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class TimeMachine {
|
public class TimeMachine {
|
||||||
|
|
||||||
|
public int THREAD_COUNT = 8;
|
||||||
|
public ExecutorService SERVICE = Executors.newFixedThreadPool(THREAD_COUNT);
|
||||||
|
|
||||||
private LCG inverseLCG = Rand.JAVA_LCG.combine(-2);
|
private LCG inverseLCG = Rand.JAVA_LCG.combine(-2);
|
||||||
|
private boolean isRunning = false;
|
||||||
|
|
||||||
public TimeMachine() {
|
public TimeMachine() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> buildStructureSeeds(int pillarSeed, List<StructureData> structureDataList, List<PopulationData> populationDataList, List<Long> structureSeeds) {
|
public List<Long> bruteforceRegion(int pillarSeed, int region, long size, List<StructureData> structureDataList, List<PopulationData> populationDataList) {
|
||||||
|
List<Long> result = new ArrayList<>();
|
||||||
ChunkRandom chunkRandom = new ChunkRandom();
|
ChunkRandom chunkRandom = new ChunkRandom();
|
||||||
|
|
||||||
for(long i = 0; i < (1L << 32); i++) {
|
long start = region * size;
|
||||||
if((i & ((1L << 28) - 1)) == 0) {
|
long end = start + size;
|
||||||
SeedCracker.LOG.warn("Progress " + (i * 100.0f) / (1L << 32) + "%...");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for(long i = start; i < end; i++) {
|
||||||
long structureSeed = this.timeMachine(i, pillarSeed);
|
long structureSeed = this.timeMachine(i, pillarSeed);
|
||||||
boolean goodSeed = true;
|
boolean goodSeed = true;
|
||||||
|
|
||||||
@@ -40,10 +49,39 @@ public class TimeMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(goodSeed) {
|
if(goodSeed) {
|
||||||
structureSeeds.add(structureSeed);
|
result.add(structureSeed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Long> buildStructureSeeds(int pillarSeed, List<StructureData> structureDataList, List<PopulationData> populationDataList, Set<Long> structureSeeds) {
|
||||||
|
if(this.isRunning) {
|
||||||
|
throw new IllegalStateException("Time Machine is already running");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRunning = true;
|
||||||
|
|
||||||
|
long size = (long)Math.ceil((double)(1L << 32) / THREAD_COUNT);
|
||||||
|
AtomicInteger progress = new AtomicInteger();
|
||||||
|
|
||||||
|
for(int i = 0; i < THREAD_COUNT; i++) {
|
||||||
|
int finalI = i;
|
||||||
|
|
||||||
|
SERVICE.submit(() -> {
|
||||||
|
structureSeeds.addAll(this.bruteforceRegion(pillarSeed, finalI, size, structureDataList, populationDataList));
|
||||||
|
SeedCracker.LOG.warn("Completed thread " + finalI + "!");
|
||||||
|
progress.getAndIncrement();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
while(progress.get() < THREAD_COUNT) {
|
||||||
|
try {Thread.sleep(20);}
|
||||||
|
catch(InterruptedException e) {e.printStackTrace();}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isRunning = false;
|
||||||
return structureSeeds;
|
return structureSeeds;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,4 +96,8 @@ public class TimeMachine {
|
|||||||
return currentSeed;
|
return currentSeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
this.isRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
package kaptainwutax.seedcracker.mixin;
|
package kaptainwutax.seedcracker.mixin;
|
||||||
|
|
||||||
import kaptainwutax.seedcracker.finder.FinderQueue;
|
|
||||||
import kaptainwutax.seedcracker.SeedCracker;
|
import kaptainwutax.seedcracker.SeedCracker;
|
||||||
|
import kaptainwutax.seedcracker.finder.FinderQueue;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
@Mixin(ClientWorld.class)
|
@Mixin(ClientWorld.class)
|
||||||
public abstract class ClientWorldMixin {
|
public abstract class ClientWorldMixin {
|
||||||
|
|
||||||
@@ -17,8 +15,6 @@ public abstract class ClientWorldMixin {
|
|||||||
private void disconnect(CallbackInfo ci) {
|
private void disconnect(CallbackInfo ci) {
|
||||||
SeedCracker.get().clear();
|
SeedCracker.get().clear();
|
||||||
FinderQueue.get().clear();
|
FinderQueue.get().clear();
|
||||||
FinderQueue.SERVICE.shutdown();
|
|
||||||
FinderQueue.SERVICE = Executors.newFixedThreadPool(5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user