49 Commits

Author SHA1 Message Date
Neil 211ecfe682 Include gui and api inside jar 2020-02-18 12:18:19 +01:00
Neil da35bda7b9 Added a GUI via an item you can get it via /seed gui 2020-02-18 02:33:03 +01:00
Unknown 3baab7fe78 added key binding system 2020-02-05 19:33:18 -05:00
Unknown 5305e870d1 updated commands imports 2020-02-05 19:32:54 -05:00
Unknown de89a6aa3b moved client commands to init 2020-02-05 18:50:58 -05:00
Unknown d99a21ac3d added gui screen 2020-02-05 18:50:39 -05:00
Unknown fcdbd33fa2 encapsulated typeStates 2020-02-05 18:06:07 -05:00
Unknown 02a61a4a68 reorganized finder types and profiles 2020-02-05 17:34:22 -05:00
Unknown a23b2bd9a9 start of finder profiles 2020-02-05 17:08:50 -05:00
Unknown 2f842b5fbe disabled mansion and igloo finders 2020-02-05 17:08:34 -05:00
Unknown d8c4a4f13b removed diamond, infested stone and portal room finders 2020-02-05 16:46:21 -05:00
Unknown 4c7e8034d0 fixed threading issue and non-uniform progress 2020-02-05 16:43:25 -05:00
Unknown 76f73f6b5a Merge remote-tracking branch 'origin/master' 2020-02-04 19:16:02 -05:00
Unknown df47cb9c28 various optimizations, color changes and renderer additions 2020-02-04 19:15:45 -05:00
Unknown 7b83b93cd4 made log threading friendly 2020-02-04 19:14:59 -05:00
Unknown 34214fe17c sped up brute-force 2020-02-04 19:14:42 -05:00
KaptainWutax 38a7337145 Update README.md 2020-01-31 21:45:03 -05:00
Unknown f16063774d matthew proofed underlying logic 2020-01-31 21:38:27 -05:00
Unknown 6fb15ca0c5 added random seed check 2020-01-30 13:25:18 -05:00
Unknown 15b4601e95 clear seed crack input earlier 2020-01-30 13:25:08 -05:00
Unknown aa9df76ee0 update to 1.15.2 2020-01-29 16:55:19 -05:00
Unknown d2467f1a88 re: fixed shipwreck render box 2020-01-29 16:55:11 -05:00
Unknown 8c2738fd6c fixed shipwreck render box 2020-01-29 16:54:52 -05:00
Unknown 85564b9b88 reduced number of emerald ore renderers 2020-01-29 16:49:07 -05:00
Unknown bdc0429e62 added dungeon floor finder 2020-01-29 16:48:44 -05:00
Unknown bb1d241b5a added XOR to PopulationReversal 2020-01-28 19:31:18 -05:00
Unknown 823bb952de added population reversal 2020-01-28 18:26:52 -05:00
Unknown 2329c4098f Merge remote-tracking branch 'origin/master' 2020-01-28 17:59:46 -05:00
Unknown 49b53d60d3 added population seeding 2020-01-28 17:56:53 -05:00
Unknown 9037f27ed8 added spawnpoint data 2020-01-28 17:56:45 -05:00
Unknown fd35c432d8 fixed major bug with chest loot sim 2020-01-28 17:56:38 -05:00
Unknown 405e65049e generalized biome data 2020-01-28 17:56:22 -05:00
KaptainWutax ce0978c37f Create LICENSE.md 2020-01-26 17:20:18 -05:00
KaptainWutax 84da79b767 Update README.md 2020-01-24 11:22:59 -05:00
KaptainWutax 599d27e37d Update README.md 2020-01-24 11:22:34 -05:00
KaptainWutax 1d8131f8db Update README.md 2020-01-24 11:21:31 -05:00
KaptainWutax e40dca96fe Update README.md 2020-01-24 11:10:01 -05:00
KaptainWutax 2a56bc479f Update README.md 2020-01-24 11:08:01 -05:00
Unknown 970d047651 Merge remote-tracking branch 'origin/master' 2020-01-10 16:36:38 -05:00
Unknown dd45e24400 extracted test logic to ISeedData 2020-01-10 16:36:33 -05:00
KaptainWutax bdf53f97e5 Update README.md 2020-01-10 16:21:14 -05:00
Unknown 7a7a53a913 made biome data 3D for 1.16 2020-01-10 16:18:37 -05:00
Unknown b3883149f4 added slime chunk data 2020-01-10 16:18:21 -05:00
Unknown 80f533359a added chest loot data 2020-01-10 16:18:08 -05:00
Unknown d18d38fc85 disable portal room by default 2020-01-01 12:37:29 -05:00
Unknown 7681007184 added portal room finder 2020-01-01 12:34:20 -05:00
Unknown 4b3922c26d made piece size static 2020-01-01 12:34:06 -05:00
Unknown 71f4f8affe added desert well data 2020-01-01 11:27:31 -05:00
Unknown 35fdfaa184 added desert well finder 2019-12-31 23:36:39 -05:00
85 changed files with 2150 additions and 736 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 KaptainWutax
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+65 -14
View File
@@ -2,32 +2,83 @@
## Installation
Download and install the [fabric mod loader](https://fabricmc.net/use/).
### Vanilla Launcher
Then download the lastest [release](https://github.com/KaptainWutax/SeedCracker/releases) of SeedCracker and put the `.jar` file in the `%appdata%/.minecraft/mods/` folder.
Download and install the [fabric mod loader](https://fabricmc.net/use/).
### MultiMC
Add a new minecraft instance and press "Install Fabric" in the instance options.
Then download the lastest [release](https://github.com/KaptainWutax/SeedCracker/releases) of SeedCracker and put the `.jar` file in your mods directory, either `%appdata%/.minecraft/mods/` folder for the vanilla launcher or your own MultiMC instance folder.
## Usage
Launch minercaft with the fabric loader profile.
Run minecraft with the mod installed and run around in the world. Once the mod has collected enough data, it will start the cracking process automatically and output the seed in chat. For the process to start, you are required to locate atleast 5 combined struture and decorator features, 5 biomes and the end pillars.
### Supported Structures(from best to worst)
- Ocean Monument
- End City
- Buried Treasure
- Desert Pyramid
- Jungle Temple
- Swamp Hut
- Shipwreck
### Supported Decorators(from best to worst)
- Dungeon
- End Gateway
- Desert Well
- Emerald Ore
Explore the world you want to crack the seed and find at least 5 structures or decorators (like Monument, Temple, Mansion, Treasure, Dungeon...), in the background while you explore the world, SeedCracker will collect biomes coordinates.
## Commands
Then go on the main End island to load the pillars and the seed cracking process should start and take arround one minute.
## Usefull command
renderer option: `/seed render outlines (ON/OFF/XRAY)`
seed finder option: `/seed finder category (BIOMES/ORES/OTHERS/STRUCTURES) (ON/OFF)`
The command prefix for this mod is /seed.
### Render Command
-`/seed render outlines <ON/OFF/XRAY>`
This command only affects the renderer feedback. The default value is 'XRAY' and highlights data through blocks. You can set the render mod to 'ON' for more standard rendering.
### Finder Command
-`/seed render finder type <FEATURE_TYPE> (ON/OFF)`
-`/seed finder category (BIOMES/ORES/OTHERS/STRUCTURES) (ON/OFF)`
This command is used to disable finders in case you are aware the data is wrong. For example, a map generated in 1.14 has different decorators and would require you to disable them while going through those chunks.
## Video Tutorial
https://youtu.be/1ChmLi9og8Q
## Upcoming Features
A list of features I have on my mind... they won't necessarily be implemented in this order if at all.
- SHA2 brute-forcing, auxiliary to biomes search.
- Dungeon floor cracker, fast lattice reversal.
- Stronghold portal room cracker. (alternative to dungeon floor?)
- Faster brute-forcing by reorganizing located features list.
- End and nether biome finders. (nether would mostly be in preparation for 1.16)
- Chest loot finders. (fun meme, hell to implement)
## Setting up the Workspace
-Clone the repository.
-Run `gradlew genSources <idea|eclipse>`.
## Building the Mod
-Update the version in `build.gradle` and `fabric.mod.json`.
-Run `gradlew build`.
## Contributors
[KaptainWutax](https://github.com/KaptainWutax) - the mod
[KaptainWutax](https://github.com/KaptainWutax) - Author
[neil](https://www.youtube.com/channel/UCbM3acUrR8Ku6pjgRUNPnbQ/featured) - video tutorial
[neil](https://www.youtube.com/channel/UCbM3acUrR8Ku6pjgRUNPnbQ/featured) - Video Tutorial
[Nekzuris](https://github.com/Nekzuris) - readme
[Nekzuris](https://github.com/Nekzuris) - README
+15 -5
View File
@@ -1,5 +1,5 @@
plugins {
id 'fabric-loom' version '0.2.5-SNAPSHOT'
id 'fabric-loom' version '0.2.6-SNAPSHOT'
id 'maven-publish'
}
@@ -12,18 +12,27 @@ group = project.maven_group
minecraft {
}
repositories {
maven {
name = "CottonMC"
url = "http://server.bbkr.space:8081/artifactory/libs-release"
}
}
dependencies {
//to change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}"
modCompile "net.fabricmc:fabric-loader:${project.loader_version}"
// Fabric API. This is technically optional, but you probably want it anyway.
// modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
//modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
// PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
// You may need to force-disable transitiveness on them.
modImplementation "io.github.cottonmc:LibGui:1.6.0"
include "io.github.cottonmc:LibGui:1.6.0"
modImplementation("net.fabricmc.fabric-api:fabric-api:${project.fabric_version}")
include("net.fabricmc.fabric-api:fabric-api:${project.fabric_version}")
}
processResources {
@@ -56,14 +65,15 @@ task sourcesJar(type: Jar, dependsOn: classes) {
jar {
from "LICENSE"
}
}
// configure the maven publication
publishing {
publications {
mavenJava(MavenPublication) {
// add all the jars that should be included when publishing to maven
artifact(remapJar) {
builtBy remapJar
}
artifact(sourcesJar) {
+5 -4
View File
@@ -3,9 +3,9 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/use
minecraft_version=1.15
yarn_mappings=1.15+build.2
loader_version=0.7.2+build.174
minecraft_version=1.15.2
yarn_mappings=1.15.2+build.8
loader_version=0.7.6+build.180
# Mod Properties
mod_version = 0.0.2-alpha
@@ -14,4 +14,5 @@ org.gradle.jvmargs=-Xmx1G
# Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.4.1+build.245-1.14
fabric_version=0.4.32+build.292-1.15
modmenu_version=1.10.1+build.30
@@ -1,199 +1,220 @@
package kaptainwutax.seedcracker;
import io.netty.util.internal.ConcurrentSet;
import kaptainwutax.seedcracker.cracker.*;
import kaptainwutax.seedcracker.cracker.population.DecoratorData;
import kaptainwutax.seedcracker.cracker.structure.StructureData;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.finder.FinderQueue;
import kaptainwutax.seedcracker.gui.GuiItem;
import kaptainwutax.seedcracker.render.RenderQueue;
import kaptainwutax.seedcracker.util.Log;
import kaptainwutax.seedcracker.util.Rand;
import net.fabricmc.api.ModInitializer;
import net.minecraft.world.level.LevelProperties;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.Identifier;
import net.minecraft.util.Rarity;
import net.minecraft.util.registry.Registry;
public class SeedCracker implements ModInitializer {
private static final SeedCracker INSTANCE = new SeedCracker();
public long hashedWorldSeed = -1;
public List<Long> worldSeeds = null;
public Set<Long> structureSeeds = null;
public List<Integer> pillarSeeds = null;
private TimeMachine timeMachine = new TimeMachine();
private List<StructureData> structureCache = new ArrayList<>();
private List<DecoratorData> decoratorCache = new ArrayList<>();
private List<BiomeData> biomeCache = new ArrayList<>();
private DataStorage dataStorage = new DataStorage();
public static Item GUI_ITEM=new GuiItem(new Item.Settings().group(ItemGroup.MISC).rarity(Rarity.EPIC));
@Override
public void onInitialize() {
RenderQueue.get().add("hand", FinderQueue.get()::renderFinders);
DecoratorCache.get().initialize();
Registry.register(Registry.ITEM,new Identifier("seedcracker","gui_item"),GUI_ITEM);
/*
long ss = 5718603440394L;
LCG lcg = Rand.JAVA_LCG.combine(-5);
for(int i = 0; i < 8; i++) {
System.out.println("n");
PopulationReversal.getWorldSeeds(ss, 31 * 16, 19 * 16).forEach(seed -> {
System.out.println("Structure seed: " + seed);
for(int u = 0; u < 1 << 16; u++) {
long worldSeed = ((long)u << 48) | seed;
if(RandomSeed.isRandomSeed(worldSeed)) {
System.out.println("nextLong() equivalent: " + worldSeed);
}
}
});
ss = lcg.nextSeed(ss);
}*/
/*
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(new File("all_mineral.txt")));
StructureData t = new StructureData(new ChunkPos(0, 0), StructureFeatures.BURIED_TREASURE);
StructureData s = new StructureData(new ChunkPos(0, 0), StructureFeatures.SHIPWRECK);
StructureData v = new StructureData(new ChunkPos(1, 1), StructureFeatures.VILLAGE);
BiomeData b1 = new BiomeData(new BlockPos(9, 0, 9), biome -> biome.hasStructureFeature(Feature.BURIED_TREASURE));
BiomeData b2 = new BiomeData(new BlockPos(9, 0, 9), biome -> biome.hasStructureFeature(Feature.SHIPWRECK));
BiomeData b3 = new BiomeData(new BlockPos(9 + 16, 0, 9 + 16), biome -> biome.hasStructureFeature(Feature.VILLAGE));
SpawnPointData spawn = new SpawnPointData(BlockPos.ORIGIN, 50);
ChestLootData loot = new ChestLootData(
MCLootTables.BURIED_TREASURE_CHEST,
new ChestLootData.Stack(Items.EMERALD, Predicates.MORE_OR_EQUAL_TO, 3),
new ChestLootData.Stack(Items.IRON_INGOT, Predicates.MORE_OR_EQUAL_TO, 4),
new ChestLootData.Stack(Items.GOLD_INGOT, Predicates.MORE_OR_EQUAL_TO, 3),
new ChestLootData.Stack(Items.TNT, Predicates.MORE_OR_EQUAL_TO, 1),
new ChestLootData.Stack(Items.DIAMOND, Predicates.MORE_OR_EQUAL_TO, 1)
);
int count = 0;
Rand rand = new Rand(0L, false);
for(long seed = (1L << 48) - 1; seed >= 0; seed--) {
if(!t.test(seed, rand))continue;
if(!s.test(seed, rand))continue;
if(!v.test(seed, rand))continue;
if(!loot.test(seed + 20002L, rand))continue;
for(long u = 0L; u < 1L << 16; u++) {
long worldSeed = (u << 48) | seed;
FakeBiomeSource source = new FakeBiomeSource(worldSeed);
if(!b1.test(source))continue;
if(!b2.test(source))continue;
if(!b3.test(source))continue;
if(!spawn.test(source))continue;
String s2 = "[" + (++count) + "] " + worldSeed + " with structure seed " + seed + "\n";
System.out.print(s2);
writer.write(s2);
writer.flush();
break;
}
}
} catch(Exception e) {
e.printStackTrace();
}*/
/*
long seed = 1_000_000_000_000_000L;
int distance = 80;
Predicate<Biome>[] trees = new Predicate[] {
biome -> biome instanceof ForestBiome || biome instanceof WoodedHillsBiome, //OAK TREE
biome -> biome instanceof SavannaBiome || biome instanceof SavannaPlateauBiome, //ACACIA TREE
biome -> biome instanceof DarkForestHillsBiome || biome instanceof DarkForestBiome, //DARK OAK TREE
biome -> biome instanceof SnowyTaigaBiome || biome instanceof TaigaBiome, //SPRUCE TREE
biome -> biome instanceof JungleBiome || biome instanceof JungleHillsBiome || biome instanceof ModifiedJungleBiome, //JUNGLE TREE
};
Set<Integer> ids = new HashSet<>();
do {
FakeBiomeSource source = new FakeBiomeSource(seed);
BlockPos spawn = SpawnPointData.getSpawnPoint(source);
int x = spawn.getX();
int z = spawn.getZ();
//X direction
for(int s = -1; s != 1; s = 1) {
for(int d = 0; d < distance; d++) {
Biome biome = BiomeData.sampleBiome(source, x + s * d, 0, z);
for(int j = 0; j < trees.length; j++) {
if(!ids.contains(j) && trees[j].test(biome)) {
ids.add(j);
}
}
}
if(ids.size() >= trees.length - 1) {
System.out.println(seed + ", " + ids);
ids.clear();
break;
}
ids.clear();
//Z direction
for(int d = 0; d < distance; d++) {
Biome biome = BiomeData.sampleBiome(source, x, 0, z + s * d);
for(int j = 0; j < trees.length; j++) {
if(!ids.contains(j) && trees[j].test(biome)) {
ids.add(j);
}
}
}
if(ids.size() >= trees.length - 1) {
System.out.println(seed + ", " + ids);
ids.clear();
break;
}
ids.clear();
}
seed++;
} while(seed != 0L);*/
/*
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(new File("season_7_seeds_negative.txt")));
int count = 0;
long seed = 0L;
BiomeData m1 = new BiomeData(new BlockPos(-200, 0, 0), biome -> biome instanceof MushroomFieldsBiome || biome instanceof MushroomFieldShoreBiome);
BiomeData m2 = new BiomeData(new BlockPos(200, 0, 0), biome -> biome instanceof MushroomFieldsBiome || biome instanceof MushroomFieldShoreBiome);
BiomeData m3 = new BiomeData(new BlockPos(0, 0, -200), biome -> biome instanceof MushroomFieldsBiome || biome instanceof MushroomFieldShoreBiome);
BiomeData m4 = new BiomeData(new BlockPos(0, 0, 200), biome -> biome instanceof MushroomFieldsBiome || biome instanceof MushroomFieldShoreBiome);
do {
FakeBiomeSource source = new FakeBiomeSource(seed);
if(m1.test(source) && m2.test(source) && m3.test(source) && m4.test(source)) {
String s = "[" + (++count) + "] " + seed + "\n";
System.out.println(s);
writer.write(s);
writer.flush();
}
seed--;
} while(seed != 0L);
writer.close();
} catch(Exception e) {
;
}*/
/*
long popSeed = 107038380818082L;
for(int x = 0; x < 10000; x++) {
StructureData b = new StructureData(new ChunkPos(x, 0), StructureFeatures.BURIED_TREASURE);
BiomeData b1 = new BiomeData(new BlockPos(16 * x + 9, 0, 9), Biomes.BEACH);
List<Long> worldSeeds = Magic.getSeedFromChunkseed(popSeed, x * 16, 0);
int finalX = x;
worldSeeds.forEach(structureSeed -> {
if(b.test(structureSeed, new Rand(0L))) {
System.out.println("structure seed " + structureSeed + " at x " + (finalX * 16));
for(long u = 0L; u < 1L << 16; u++) {
long worldSeed = (u << 48) | structureSeed;
FakeBiomeSource source = new FakeBiomeSource(worldSeed);
if(!b1.test(source))continue;
System.out.println(worldSeed + " with structure seed " + structureSeed + " at x " + (finalX * 16));
}
}
});
}*/
}
public static SeedCracker get() {
return INSTANCE;
}
public void clear() {
this.hashedWorldSeed = -1;
this.worldSeeds = null;
this.structureSeeds = null;
this.pillarSeeds = null;
this.structureCache.clear();
this.biomeCache.clear();
this.decoratorCache.clear();
}
public synchronized boolean onPillarData(PillarData pillarData) {
if(pillarData != null && (this.pillarSeeds == null || this.pillarSeeds.isEmpty())) {
Log.warn("Looking for pillar seeds...");
this.pillarSeeds = pillarData.getPillarSeeds();
if(this.pillarSeeds.size() > 0) {
Log.warn("Finished search with " + this.pillarSeeds + (this.pillarSeeds.size() == 1 ? " seed." : " seeds."));
} else {
Log.error("Finished search with no seeds.");
}
this.onStructureData(null);
return true;
}
return false;
}
public synchronized boolean onStructureData(StructureData structureData) {
boolean added = false;
if(structureData != null && !this.structureCache.contains(structureData)) {
this.structureCache.add(structureData);
added = true;
}
if(this.structureSeeds == null && this.pillarSeeds != null && this.structureCache.size() + this.decoratorCache.size() >= 5) {
this.structureSeeds = new ConcurrentSet<>();
Log.warn("Looking for structure seeds with " + this.structureCache.size() + " structure features.");
Log.warn("Looking for structure seeds with " + this.decoratorCache.size() + " decorator features.");
this.pillarSeeds.forEach(pillarSeed -> {
timeMachine.buildStructureSeeds(pillarSeed, this.structureCache, this.decoratorCache, this.structureSeeds);
});
if(this.structureSeeds.size() > 0) {
Log.warn("Finished search with " + this.structureSeeds + (this.structureSeeds.size() == 1 ? " seed." : " seeds."));
} else {
Log.error("Finished search with no seeds.");
}
this.structureCache.clear();
this.onDecoratorData(null);
this.onBiomeData(null);
} else if(this.structureSeeds != null && structureData != null) {
this.structureSeeds.removeIf(structureSeed -> {
Rand rand = new Rand(0L);
return !structureData.test(structureSeed, rand);
});
this.onBiomeData(null);
}
return added;
}
public synchronized boolean onDecoratorData(DecoratorData decoratorData) {
boolean added = false;
if(decoratorData != null && !this.decoratorCache.contains(decoratorData)) {
this.decoratorCache.add(decoratorData);
added = true;
}
this.onStructureData(null);
return added;
}
public synchronized boolean onBiomeData(BiomeData biomeData) {
boolean added = false;
if(biomeData != null && !this.biomeCache.contains(biomeData)) {
this.biomeCache.add(biomeData);
added = true;
}
if(this.worldSeeds == null && this.structureSeeds != null && this.biomeCache.size() >= 5) {
this.worldSeeds = new ArrayList<>();
if(this.hashedWorldSeed != -1) {
Log.warn("SHA2 seed was found.");
Log.warn("Looking for world seeds with hash [" + this.hashedWorldSeed + "].");
for(long structureSeed: this.structureSeeds) {
for(long j = 0; j < (1L << 16); j++) {
long worldSeed = (j << 48) | structureSeed;
long hash = LevelProperties.sha256Hash(worldSeed);
if(hash == this.hashedWorldSeed) {
this.worldSeeds.add(worldSeed);
Log.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds."));
return added;
}
}
}
Log.error("Finished search with no seeds, reverting to biomes.");
}
Log.warn("Looking for world seeds with " + this.biomeCache.size() + " biomes.");
this.structureSeeds.forEach(structureSeed -> {
for(long j = 0; j < (1L << 16); j++) {
long worldSeed = (j << 48) | structureSeed;
boolean goodSeed = true;
FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed);
for(BiomeData data : this.biomeCache) {
if(!data.test(fakeBiomeSource)) {
goodSeed = false;
break;
}
}
if(goodSeed) {
this.worldSeeds.add(worldSeed);
}
}
});
if(this.worldSeeds.size() > 0) {
Log.warn("Finished search with " + this.worldSeeds + (this.worldSeeds.size() == 1 ? " seed." : " seeds."));
} else {
Log.error("Finished search with no seeds.");
}
} else if(this.worldSeeds != null && biomeData != null) {
this.worldSeeds.removeIf(worldSeed -> {
FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed);
return !biomeData.test(fakeBiomeSource);
});
} else if(this.worldSeeds != null) {
this.worldSeeds.removeIf(worldSeed -> {
for(BiomeData data: this.biomeCache) {
FakeBiomeSource fakeBiomeSource = new FakeBiomeSource(worldSeed);
if(!data.test(fakeBiomeSource))return true;
}
return false;
});
}
return added;
public DataStorage getDataStorage() {
return this.dataStorage;
}
}
@@ -2,6 +2,7 @@ package kaptainwutax.seedcracker.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import kaptainwutax.seedcracker.init.ClientCommands;
import net.minecraft.client.MinecraftClient;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.LiteralText;
@@ -15,8 +16,8 @@ public abstract class ClientCommand {
public abstract void build(LiteralArgumentBuilder<ServerCommandSource> builder);
protected final void sendFeedback(String message, boolean overlay) {
MinecraftClient.getInstance().player.addChatMessage(new LiteralText(message).formatted(Formatting.AQUA), overlay);
protected final void sendFeedback(String message, Formatting color, boolean overlay) {
MinecraftClient.getInstance().player.addChatMessage(new LiteralText(message).formatted(color), overlay);
}
public final void register(CommandDispatcher<ServerCommandSource> dispatcher) {
@@ -1,9 +1,10 @@
package kaptainwutax.seedcracker.command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import kaptainwutax.seedcracker.finder.FinderConfig;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.finder.FinderQueue;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.Formatting;
import static net.minecraft.server.command.CommandManager.literal;
@@ -16,7 +17,7 @@ public class FinderCommand extends ClientCommand {
@Override
public void build(LiteralArgumentBuilder<ServerCommandSource> builder) {
for(FinderConfig.Type finderType: FinderConfig.Type.values()) {
for(Finder.Type finderType: Finder.Type.values()) {
builder.then(literal("type")
.executes(context -> this.printFinderType(finderType))
.then(literal(finderType.toString())
@@ -25,7 +26,7 @@ public class FinderCommand extends ClientCommand {
);
}
for(FinderConfig.Category finderCategory: FinderConfig.Category.values()) {
for(Finder.Category finderCategory: Finder.Category.values()) {
builder.then(literal("category")
.executes(context -> this.printFinderCategory(finderCategory))
.then(literal(finderCategory.toString())
@@ -35,24 +36,28 @@ public class FinderCommand extends ClientCommand {
}
}
private int printFinderCategory(FinderConfig.Category finderCategory) {
FinderConfig.Type.getForCategory(finderCategory).forEach(this::printFinderType);
private int printFinderCategory(Finder.Category finderCategory) {
Finder.Type.getForCategory(finderCategory).forEach(this::printFinderType);
return 0;
}
private int printFinderType(FinderConfig.Type finderType) {
this.sendFeedback("Finder " + finderType + " is set to [" + String.valueOf(FinderQueue.get().finderConfig.getTypeState(finderType)).toUpperCase() + "].", false);
private int printFinderType(Finder.Type finderType) {
this.sendFeedback("Finder " + finderType + " is set to [" + String.valueOf(FinderQueue.get().finderProfile.getTypeState(finderType)).toUpperCase() + "].", Formatting.AQUA,false);
return 0;
}
private int setFinderCategory(FinderConfig.Category finderCategory, boolean flag) {
FinderConfig.Type.getForCategory(finderCategory).forEach(finderType -> this.setFinderType(finderType, flag));
private int setFinderCategory(Finder.Category finderCategory, boolean flag) {
Finder.Type.getForCategory(finderCategory).forEach(finderType -> this.setFinderType(finderType, flag));
return 0;
}
private int setFinderType(FinderConfig.Type finderType, boolean flag) {
FinderQueue.get().finderConfig.setTypeState(finderType, flag);
this.sendFeedback("Finder " + finderType + " has been set to [" + String.valueOf(flag).toUpperCase() + "].", false);
private int setFinderType(Finder.Type finderType, boolean flag) {
if(FinderQueue.get().finderProfile.setTypeState(finderType, flag)) {
this.sendFeedback("Finder " + finderType + " has been set to [" + String.valueOf(flag).toUpperCase() + "].", Formatting.AQUA, false);
} else {
this.sendFeedback("Your current finder profile is locked and cannot be modified. Please make a copy first.", Formatting.RED, false);
}
return 0;
}
@@ -0,0 +1,42 @@
package kaptainwutax.seedcracker.command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.finder.FinderQueue;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
import static kaptainwutax.seedcracker.SeedCracker.GUI_ITEM;
import static net.minecraft.server.command.CommandManager.literal;
public class GuiCommand extends ClientCommand {
@Override
public String getName() {
return "gui";
}
@Override
public void build(LiteralArgumentBuilder<ServerCommandSource> builder) {
builder.executes(ctx->
{
ServerCommandSource source = ctx.getSource();
ClientPlayerEntity self =(ClientPlayerEntity) source.getEntity();
assert self != null;
if(!self.inventory.insertStack(new ItemStack(GUI_ITEM))){
throw new SimpleCommandExceptionType(new TranslatableText("inventory.isfull")).create();
}
return 1;
});
}
}
@@ -3,6 +3,7 @@ package kaptainwutax.seedcracker.command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import kaptainwutax.seedcracker.finder.FinderQueue;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.Formatting;
import static net.minecraft.server.command.CommandManager.literal;
@@ -27,13 +28,13 @@ public class RenderCommand extends ClientCommand {
}
private int printRenderMode() {
this.sendFeedback("Current render mode is set to [" + FinderQueue.get().renderType + "].", false);
this.sendFeedback("Current render mode is set to [" + FinderQueue.get().renderType + "].", Formatting.AQUA, false);
return 0;
}
private int setRenderMode(FinderQueue.RenderType renderType) {
FinderQueue.get().renderType = renderType;
this.sendFeedback("Set render mode to [" + FinderQueue.get().renderType + "].", false);
this.sendFeedback("Set render mode to [" + FinderQueue.get().renderType + "].", Formatting.AQUA, false);
return 0;
}
@@ -1,46 +1,63 @@
package kaptainwutax.seedcracker.cracker;
import net.minecraft.util.Identifier;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.cracker.storage.ISeedStorage;
import kaptainwutax.seedcracker.cracker.storage.TimeMachine;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.source.VoronoiBiomeAccessType;
public class BiomeData {
import java.util.function.Predicate;
public class BiomeData implements ISeedStorage {
private BlockPos pos;
private int x;
private int z;
private Biome biome;
private Predicate<Biome> biomePredicate;
public BiomeData(int x, int z, Biome biome) {
this.x = x;
this.z = z;
public BiomeData(BlockPos pos, Biome biome) {
this.pos = pos;
this.biome = biome;
}
public BiomeData(int x, int z, String biomeId) {
this(x, z, Registry.BIOME.get(new Identifier(biomeId)));
public BiomeData(BlockPos pos, int biomeId) {
this.pos = pos;
this.biome = Registry.BIOME.get(biomeId);
}
public BiomeData(int x, int z, int biomeId) {
this(x, z, Registry.BIOME.get(biomeId));
public BiomeData(BlockPos pos, Predicate<Biome> biomePredicate) {
this.pos = pos;
this.biomePredicate = biomePredicate;
}
public boolean test(FakeBiomeSource source) {
return VoronoiBiomeAccessType.INSTANCE.getBiome(source.getHashedSeed(), this.x,0, this.z, source) == this.biome;
if(this.biome == null) {
return this.biomePredicate.test(sampleBiome(source, this.pos.getX(), this.pos.getY(), this.pos.getZ()));
}
return sampleBiome(source, this.pos.getX(), this.pos.getY(), this.pos.getZ()) == this.biome;
}
public int getX() {
return this.x;
}
public int getZ() {
return this.z;
public BlockPos getPos() {
return this.pos;
}
public Biome getBiome() {
return this.biome;
}
public static Biome sampleBiome(FakeBiomeSource source, int x, int y, int z) {
return VoronoiBiomeAccessType.INSTANCE.getBiome(source.getHashedSeed(), x, y, z, source);
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.BIOMES);
}
@Override
public boolean equals(Object obj) {
if(obj == this)return true;
@@ -52,4 +69,12 @@ public class BiomeData {
return false;
}
@Override
public int hashCode() {
if(this.biomePredicate == null) {
return this.biome.getName().asFormattedString().hashCode();
}
return super.hashCode();
}
}
@@ -0,0 +1,95 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.loot.LootBuilder;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.context.LootContext;
import net.minecraft.loot.context.LootContextParameters;
import net.minecraft.loot.context.LootContextTypes;
import net.minecraft.util.math.BlockPos;
import java.util.*;
import java.util.function.BiPredicate;
public class ChestLootData {
private LootTable lootTable;
private Map<Item, List<Stack>> stacksMap = new HashMap<>();
public ChestLootData(LootTable lootTable, Stack... stacks) {
this.lootTable = lootTable;
for(Stack stack: stacks) {
Item item = stack.item;
if(!this.stacksMap.containsKey(item)) {
this.stacksMap.put(item, new ArrayList<>());
}
this.stacksMap.get(item).add(stack);
}
}
public boolean test(long lootSeed, Rand rand) {
rand.setSeed(lootSeed, true);
LootContext lootContext = new LootBuilder().setRandom(rand.toRandom())
.put(LootContextParameters.POSITION, new BlockPos(0, 0, 0)).build(LootContextTypes.CHEST);
List<ItemStack> itemStacks = this.lootTable.getDrops(lootContext);
Map<Item, Integer> lootItems = new HashMap<>();
itemStacks.forEach(itemStack -> {
lootItems.put(itemStack.getItem(), lootItems.getOrDefault(itemStack.getItem(), 0) + itemStack.getCount());
});
Set<Item> foundItems = new HashSet<>();
for(Map.Entry<Item, Integer> lootItem: lootItems.entrySet()) {
Item item = lootItem.getKey();
List<Stack> stacks = this.stacksMap.get(item);
if(stacks == null)continue;
boolean matches = true;
for(Stack stack: stacks) {
if(!stack.test(lootItem.getValue())) {
matches = false;
break;
}
}
if(matches) {
foundItems.add(item);
}
}
return foundItems.size() == this.stacksMap.size();
}
public static class Stack {
private Item item;
private BiPredicate<Integer, Integer> predicate;
private int amount;
public Stack(Item item, BiPredicate<Integer, Integer> predicate, int amount) {
this.item = item;
this.predicate = predicate;
this.amount = amount;
}
public boolean test(int count) {
return this.predicate.test(count, this.amount);
}
@Override
public int hashCode() {
return item.hashCode() * 31 + this.amount;
}
}
}
@@ -1,69 +0,0 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.util.Log;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.decorator.Decorator;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.DecoratedFeatureConfig;
import net.minecraft.world.gen.feature.FeatureConfig;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DecoratorCache {
public static int INVALID = -1;
private static DecoratorCache INSTANCE = new DecoratorCache();
private boolean initialized = false;
private Map<Biome, Map<Decorator<?>, Integer>> decoratorSaltMap = new HashMap<>();
public static DecoratorCache get() {
return INSTANCE;
}
public void initialize() {
Registry.BIOME.forEach(biome -> {
this.decoratorSaltMap.put(biome, new HashMap<>());
for(GenerationStep.Feature genStep: GenerationStep.Feature.values()) {
this.initializeBiomeStep(biome, genStep);
}
});
this.initialized = true;
}
private void initializeBiomeStep(Biome biome, GenerationStep.Feature genStep) {
List<ConfiguredFeature<?, ?>> features = biome.getFeaturesForStep(genStep);
for(int i = 0; i < features.size(); i++) {
FeatureConfig config = features.get(i).config;
if(!(config instanceof DecoratedFeatureConfig))continue;
this.decoratorSaltMap.get(biome).put(((DecoratedFeatureConfig)config).decorator.decorator, i + genStep.ordinal() * 10000);
}
}
public int getSalt(Biome biome, Decorator<?> feature, boolean debug) {
if(!this.initialized) {
this.initialize();
}
Integer salt = this.decoratorSaltMap.get(biome).get(feature);
if(salt == null) {
if(debug) {
Log.error(biome.getClass().getSimpleName() + " does not have decorator " + feature + ".");
}
salt = INVALID;
}
return salt;
}
}
@@ -43,7 +43,7 @@ public class FakeBiomeSource extends BiomeSource {
}
static {
BIOMES = ImmutableSet.<Biome>of(Biomes.OCEAN, Biomes.PLAINS, Biomes.DESERT, Biomes.MOUNTAINS, Biomes.FOREST, Biomes.TAIGA, Biomes.SWAMP, Biomes.RIVER, Biomes.FROZEN_OCEAN, Biomes.FROZEN_RIVER, Biomes.SNOWY_TUNDRA, Biomes.SNOWY_MOUNTAINS, Biomes.MUSHROOM_FIELDS, Biomes.MUSHROOM_FIELD_SHORE, Biomes.BEACH, Biomes.DESERT_HILLS, Biomes.WOODED_HILLS, Biomes.TAIGA_HILLS, Biomes.MOUNTAIN_EDGE, Biomes.JUNGLE, Biomes.JUNGLE_HILLS, Biomes.JUNGLE_EDGE, Biomes.DEEP_OCEAN, Biomes.STONE_SHORE, Biomes.SNOWY_BEACH, Biomes.BIRCH_FOREST, Biomes.BIRCH_FOREST_HILLS, Biomes.DARK_FOREST, Biomes.SNOWY_TAIGA, Biomes.SNOWY_TAIGA_HILLS, Biomes.GIANT_TREE_TAIGA, Biomes.GIANT_TREE_TAIGA_HILLS, Biomes.WOODED_MOUNTAINS, Biomes.SAVANNA, Biomes.SAVANNA_PLATEAU, Biomes.BADLANDS, Biomes.WOODED_BADLANDS_PLATEAU, Biomes.BADLANDS_PLATEAU, Biomes.WARM_OCEAN, Biomes.LUKEWARM_OCEAN, Biomes.COLD_OCEAN, Biomes.DEEP_WARM_OCEAN, Biomes.DEEP_LUKEWARM_OCEAN, Biomes.DEEP_COLD_OCEAN, Biomes.DEEP_FROZEN_OCEAN, Biomes.SUNFLOWER_PLAINS, Biomes.DESERT_LAKES, Biomes.GRAVELLY_MOUNTAINS, Biomes.FLOWER_FOREST, Biomes.TAIGA_MOUNTAINS, Biomes.SWAMP_HILLS, Biomes.ICE_SPIKES, Biomes.MODIFIED_JUNGLE, Biomes.MODIFIED_JUNGLE_EDGE, Biomes.TALL_BIRCH_FOREST, Biomes.TALL_BIRCH_HILLS, Biomes.DARK_FOREST_HILLS, Biomes.SNOWY_TAIGA_MOUNTAINS, Biomes.GIANT_SPRUCE_TAIGA, Biomes.GIANT_SPRUCE_TAIGA_HILLS, Biomes.MODIFIED_GRAVELLY_MOUNTAINS, Biomes.SHATTERED_SAVANNA, Biomes.SHATTERED_SAVANNA_PLATEAU, Biomes.ERODED_BADLANDS, Biomes.MODIFIED_WOODED_BADLANDS_PLATEAU, Biomes.MODIFIED_BADLANDS_PLATEAU);
BIOMES = ImmutableSet.of(Biomes.OCEAN, Biomes.PLAINS, Biomes.DESERT, Biomes.MOUNTAINS, Biomes.FOREST, Biomes.TAIGA, new Biome[]{Biomes.SWAMP, Biomes.RIVER, Biomes.FROZEN_OCEAN, Biomes.FROZEN_RIVER, Biomes.SNOWY_TUNDRA, Biomes.SNOWY_MOUNTAINS, Biomes.MUSHROOM_FIELDS, Biomes.MUSHROOM_FIELD_SHORE, Biomes.BEACH, Biomes.DESERT_HILLS, Biomes.WOODED_HILLS, Biomes.TAIGA_HILLS, Biomes.MOUNTAIN_EDGE, Biomes.JUNGLE, Biomes.JUNGLE_HILLS, Biomes.JUNGLE_EDGE, Biomes.DEEP_OCEAN, Biomes.STONE_SHORE, Biomes.SNOWY_BEACH, Biomes.BIRCH_FOREST, Biomes.BIRCH_FOREST_HILLS, Biomes.DARK_FOREST, Biomes.SNOWY_TAIGA, Biomes.SNOWY_TAIGA_HILLS, Biomes.GIANT_TREE_TAIGA, Biomes.GIANT_TREE_TAIGA_HILLS, Biomes.WOODED_MOUNTAINS, Biomes.SAVANNA, Biomes.SAVANNA_PLATEAU, Biomes.BADLANDS, Biomes.WOODED_BADLANDS_PLATEAU, Biomes.BADLANDS_PLATEAU, Biomes.WARM_OCEAN, Biomes.LUKEWARM_OCEAN, Biomes.COLD_OCEAN, Biomes.DEEP_WARM_OCEAN, Biomes.DEEP_LUKEWARM_OCEAN, Biomes.DEEP_COLD_OCEAN, Biomes.DEEP_FROZEN_OCEAN, Biomes.SUNFLOWER_PLAINS, Biomes.DESERT_LAKES, Biomes.GRAVELLY_MOUNTAINS, Biomes.FLOWER_FOREST, Biomes.TAIGA_MOUNTAINS, Biomes.SWAMP_HILLS, Biomes.ICE_SPIKES, Biomes.MODIFIED_JUNGLE, Biomes.MODIFIED_JUNGLE_EDGE, Biomes.TALL_BIRCH_FOREST, Biomes.TALL_BIRCH_HILLS, Biomes.DARK_FOREST_HILLS, Biomes.SNOWY_TAIGA_MOUNTAINS, Biomes.GIANT_SPRUCE_TAIGA, Biomes.GIANT_SPRUCE_TAIGA_HILLS, Biomes.MODIFIED_GRAVELLY_MOUNTAINS, Biomes.SHATTERED_SAVANNA, Biomes.SHATTERED_SAVANNA_PLATEAU, Biomes.ERODED_BADLANDS, Biomes.MODIFIED_WOODED_BADLANDS_PLATEAU, Biomes.MODIFIED_BADLANDS_PLATEAU});
}
}
@@ -1,11 +1,16 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.cracker.storage.SeedData;
import kaptainwutax.seedcracker.cracker.storage.TimeMachine;
import kaptainwutax.seedcracker.util.Rand;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class PillarData {
public class PillarData extends SeedData {
private List<Integer> heights;
@@ -13,25 +18,20 @@ public class PillarData {
this.heights = heights;
}
public List<Integer> getPillarSeeds() {
List<Integer> result = new ArrayList<>();
for(int pillarSeed = 0; pillarSeed < (1 << 16); pillarSeed++) {
List<Integer> h = this.getPillarHeights(pillarSeed);
if(h.equals(this.heights)) result.add(pillarSeed);
}
return result;
@Override
public boolean test(long seed, Rand rand) {
List<Integer> h = this.getPillarHeights((int)seed);
return h.equals(this.heights);
}
public List<Integer> getPillarHeights(int spikeSeed) {
public List<Integer> getPillarHeights(int pillarSeed) {
List<Integer> indices = new ArrayList<>();
for(int i = 0; i < 10; i++) {
indices.add(i);
}
Collections.shuffle(indices, new Random(spikeSeed));
Collections.shuffle(indices, new Random(pillarSeed));
List<Integer> heights = new ArrayList<>();
@@ -42,4 +42,14 @@ public class PillarData {
return heights;
}
@Override
public double getBits() {
return 16;
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.PILLARS);
}
}
@@ -0,0 +1,38 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.cracker.storage.SeedData;
import kaptainwutax.seedcracker.cracker.storage.TimeMachine;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.Seeds;
import net.minecraft.util.math.ChunkPos;
public class SlimeChunkData extends SeedData {
protected static final double BITS = Math.log(10) / Math.log(2);
protected final ChunkPos chunkPos;
protected final boolean isSlimeChunk;
public SlimeChunkData(ChunkPos chunkPos, boolean isSlimeChunk) {
this.chunkPos = chunkPos;
this.isSlimeChunk = isSlimeChunk;
}
@Override
public boolean test(long seed, Rand rand) {
Seeds.setSlimeChunkSeed(rand, seed, this.chunkPos.x, this.chunkPos.z, 987234911L);
return (rand.nextInt(10) == 0) == this.isSlimeChunk;
}
@Override
public double getBits() {
return BITS;
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES);
}
}
@@ -0,0 +1,38 @@
package kaptainwutax.seedcracker.cracker;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
import java.util.List;
import java.util.Random;
public class SpawnPointData {
private BlockPos center;
private int distanceSquared;
public SpawnPointData(BlockPos center, int maxDistance) {
this.center = center;
this.distanceSquared = maxDistance * maxDistance;
}
public boolean test(FakeBiomeSource source) {
BlockPos spawnPos = getSpawnPoint(source);
int distanceX = spawnPos.getX() - this.center.getX();
distanceX *= distanceX;
int distanceZ = spawnPos.getZ() - this.center.getZ();
distanceZ *= distanceZ;
return distanceX + distanceZ <= this.distanceSquared;
}
public static BlockPos getSpawnPoint(FakeBiomeSource source) {
List<Biome> spawnBiomes = source.getSpawnBiomes();
Random random = new Random(source.getSeed());
BlockPos spawnPos = source.locateBiome(0, 63, 0, 256, spawnBiomes, random);
ChunkPos chunkPos = spawnPos == null ? new ChunkPos(0, 0) : new ChunkPos(spawnPos);
return chunkPos.getCenterBlockPos().add(0, 64, 0);
}
}
@@ -1,100 +0,0 @@
package kaptainwutax.seedcracker.cracker;
import kaptainwutax.seedcracker.cracker.population.DecoratorData;
import kaptainwutax.seedcracker.cracker.structure.StructureData;
import kaptainwutax.seedcracker.util.Log;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.math.LCG;
import java.util.ArrayList;
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 {
private LCG inverseLCG = Rand.JAVA_LCG.combine(-2);
public int THREAD_COUNT = 4;
public ExecutorService SERVICE = Executors.newFixedThreadPool(THREAD_COUNT);
private boolean isRunning = false;
public TimeMachine() {
}
public List<Long> bruteforceRegion(int pillarSeed, int region, long size, List<StructureData> structureDataList, List<DecoratorData> decoratorDataList) {
List<Long> result = new ArrayList<>();
Rand rand = new Rand(0L);
long start = region * size;
long end = start + size;
for(long i = start; i < end; i++) {
long structureSeed = this.timeMachine(i, pillarSeed);
boolean goodSeed = true;
for(StructureData structureData: structureDataList) {
if(!goodSeed)break;
if(!structureData.test(structureSeed, rand))goodSeed = false;
}
for(DecoratorData decoratorData : decoratorDataList) {
if(!goodSeed)break;
if(!decoratorData.test(structureSeed))goodSeed = false;
}
if(goodSeed) {
result.add(structureSeed);
}
}
return result;
}
public Set<Long> buildStructureSeeds(int pillarSeed, List<StructureData> structureDataList, List<DecoratorData> decoratorDataList, 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, decoratorDataList));
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;
}
public long timeMachine(long partialWorldSeed, int pillarSeed) {
long currentSeed = 0L;
currentSeed |= (partialWorldSeed & 0xFFFF0000L) << 16;
currentSeed |= (long)pillarSeed << 16;
currentSeed |= partialWorldSeed & 0xFFFFL;
currentSeed = this.inverseLCG.nextSeed(currentSeed);
currentSeed ^= Rand.JAVA_LCG.multiplier;
return currentSeed;
}
public void stop() {
this.isRunning = false;
}
}
@@ -1,56 +1,55 @@
package kaptainwutax.seedcracker.cracker.population;
import kaptainwutax.seedcracker.cracker.DecoratorCache;
import kaptainwutax.seedcracker.cracker.storage.SeedData;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.Seeds;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.decorator.Decorator;
public abstract class DecoratorData {
public abstract class DecoratorData extends SeedData {
private final ChunkPos chunkPos;
private final Decorator<?> decorator;
private final int salt;
private final Biome biome;
public DecoratorData(ChunkPos chunkPos, Decorator<?> decorator, Biome biome) {
public DecoratorData(ChunkPos chunkPos, int salt, Biome biome) {
this.chunkPos = chunkPos;
this.decorator = decorator;
this.salt = salt;
this.biome = biome;
}
public final boolean test(long structureSeed) {
long decoratorSeed = this.getPopulationSeed(structureSeed, this.chunkPos.x << 4, this.chunkPos.z << 4);
int salt = DecoratorCache.get().getSalt(this.biome, this.decorator, true);
if(salt == DecoratorCache.INVALID) {
return false;
}
@Override
public final boolean test(long seed, Rand rand) {
long decoratorSeed = Seeds.setPopulationSeed(null, seed, this.chunkPos.x << 4, this.chunkPos.z << 4);
decoratorSeed += salt;
decoratorSeed ^= Rand.JAVA_LCG.multiplier;
decoratorSeed &= Rand.JAVA_LCG.modulo - 1;
return this.testDecorator(new Rand(decoratorSeed, false));
}
public long getPopulationSeed(long structureSeed, int x, int z) {
Rand rand = new Rand(structureSeed, true);
long a = rand.nextLong() | 1L;
long b = rand.nextLong() | 1L;
return (long)x * a + (long)z * b ^ structureSeed;
rand.setSeed(decoratorSeed, false);
return this.testDecorator(rand);
}
public abstract boolean testDecorator(Rand rand);
public ChunkPos getChunkPos() {
return this.chunkPos;
}
@Override
public boolean equals(Object obj) {
if(obj == this)return true;
if(obj instanceof DecoratorData) {
DecoratorData decoratorData = ((DecoratorData)obj);
return decoratorData.chunkPos.equals(this.chunkPos) && decoratorData.decorator == this.decorator;
return decoratorData.chunkPos.equals(this.chunkPos) && decoratorData.salt == this.salt;
}
return false;
}
@Override
public int hashCode() {
return this.chunkPos.hashCode() * 31 + this.salt;
}
}
@@ -0,0 +1,39 @@
package kaptainwutax.seedcracker.cracker.population;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.cracker.storage.TimeMachine;
import kaptainwutax.seedcracker.util.Rand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
public class DesertWellData extends DecoratorData {
public static final int SALT = 30010;
private static final double BITS = Math.log(1000 * 16 * 16) / Math.log(2);
private BlockPos pos;
public DesertWellData(ChunkPos chunkPos, Biome biome, BlockPos pos) {
super(chunkPos, SALT, biome);
this.pos = new BlockPos(pos.getX() & 15, pos.getY(), pos.getZ() & 15);
}
@Override
public boolean testDecorator(Rand rand) {
if(rand.nextFloat() >= 0.001F)return false;
if(rand.nextInt(16) != this.pos.getX())return false;
if(rand.nextInt(16) != this.pos.getZ())return false;
return true;
}
@Override
public double getBits() {
return BITS;
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES);
}
}
@@ -1,45 +1,44 @@
package kaptainwutax.seedcracker.cracker.population;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.cracker.storage.TimeMachine;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.math.LCG;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.decorator.Decorator;
import java.util.List;
public class DungeonData extends DecoratorData {
public static LCG REVERSE_SKIP = Rand.JAVA_LCG.combine(-1);
public static LCG Y_START_SKIP = Rand.JAVA_LCG.combine(2);
private static final double BITS = Math.log(256 * 16 * 16 * 0.125D) / Math.log(2);
public static final int SALT = 20003;
private static LCG REVERSE_SKIP = Rand.JAVA_LCG.combine(-1);
private static LCG Y_START_SKIP = Rand.JAVA_LCG.combine(2);
public static LCG Y_SKIP = Rand.JAVA_LCG.combine(5);
public static final Integer COBBLESTONE_CALL = 0;
public static final Integer MOSSY_COBBLESTONE_CALL = 1;
private List<BlockPos> starts;
private BlockPos start;
private final List<List<Integer>> floorCallsList;
public DungeonData(ChunkPos chunkPos, Biome biome, List<BlockPos> starts, List<List<Integer>> floorCallsList) {
super(chunkPos, Decorator.DUNGEONS, biome);
this.starts = starts;
public DungeonData(ChunkPos chunkPos, Biome biome, BlockPos start, List<List<Integer>> floorCallsList) {
super(chunkPos, SALT, biome);
this.start = start;
this.floorCallsList = floorCallsList;
}
@Override
public boolean testDecorator(Rand rand) {
if(this.starts.isEmpty())return true;
//TODO: This currently only supports 1 dungeon per chunk.
BlockPos start = this.starts.get(0);
for(int i = 0; i < 8; i++) {
int x = rand.nextInt(16);
int z = rand.nextInt(16);
int y = rand.nextInt(256);
if(y == start.getY() && x == start.getX() && z == start.getZ()) {
if(y == this.start.getY() && x == this.start.getX() && z == this.start.getZ()) {
return true;
}
@@ -50,4 +49,18 @@ public class DungeonData extends DecoratorData {
return false;
}
public BlockPos getStart() {
return this.start;
}
@Override
public double getBits() {
return BITS;
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES);
}
}
@@ -1,18 +1,22 @@
package kaptainwutax.seedcracker.cracker.population;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.cracker.storage.TimeMachine;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.math.LCG;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.decorator.Decorator;
import java.util.List;
import java.util.stream.Collectors;
public class EmeraldOreData extends DecoratorData {
public static final LCG[] SKIP = {
private static final double BITS = Math.log(28 * 16 * 16 * 0.5D) / Math.log(2);
public static final int SALT = 40014;
private static final LCG[] SKIP = {
Rand.JAVA_LCG.combine(0),
Rand.JAVA_LCG.combine(1),
Rand.JAVA_LCG.combine(2),
@@ -22,7 +26,7 @@ public class EmeraldOreData extends DecoratorData {
private List<BlockPos> starts;
public EmeraldOreData(ChunkPos chunkPos, Biome biome, List<BlockPos> ores) {
super(chunkPos, Decorator.EMERALD_ORE, biome);
super(chunkPos, SALT, biome);
this.starts = ores.stream().map(pos ->
new BlockPos(pos.getX() & 15, pos.getY(), pos.getZ() & 15)
@@ -51,4 +55,14 @@ public class EmeraldOreData extends DecoratorData {
return false;
}
@Override
public double getBits() {
return BITS;
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES);
}
}
@@ -1,19 +1,23 @@
package kaptainwutax.seedcracker.cracker.population;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.cracker.storage.TimeMachine;
import kaptainwutax.seedcracker.util.Rand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.decorator.Decorator;
public class EndGatewayData extends DecoratorData {
private static final double BITS = Math.log(700 * 16 * 16 * 7) / Math.log(2);
private static final int SALT = 30000;
private int xOffset;
private int zOffset;
private int height;
public EndGatewayData(ChunkPos chunkPos, Biome biome, BlockPos pos, int height) {
super(chunkPos, Decorator.END_GATEWAY, biome);
super(chunkPos, SALT, biome);
this.xOffset = pos.getX() & 15;
this.zOffset = pos.getZ() & 15;
this.height = height;
@@ -29,4 +33,14 @@ public class EndGatewayData extends DecoratorData {
return true;
}
@Override
public double getBits() {
return BITS;
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES);
}
}
@@ -0,0 +1,122 @@
package kaptainwutax.seedcracker.cracker.storage;
import io.netty.util.internal.ConcurrentSet;
import kaptainwutax.seedcracker.cracker.BiomeData;
import kaptainwutax.seedcracker.cracker.PillarData;
import kaptainwutax.seedcracker.cracker.structure.StructureData;
import kaptainwutax.seedcracker.util.Log;
import java.util.Comparator;
import java.util.Set;
import java.util.function.Consumer;
public class DataStorage {
public static Comparator<SeedData> SEED_DATA_COMPARATOR = (s1, s2) -> {
boolean isStructure1 = s1 instanceof StructureData;
boolean isStructure2 = s2 instanceof StructureData;
if(isStructure1 != isStructure2) {
return isStructure2 ? 1: -1;
}
if(s1.equals(s2)) {
return 0;
}
double diff = s2.getBits() - s1.getBits();
return diff == 0.0D ? 1 : (int)Math.signum(diff);
};
protected TimeMachine timeMachine = new TimeMachine(this);
protected Set<Consumer<DataStorage>> scheduledData = new ConcurrentSet<>();
protected PillarData pillarData = null;
protected ScheduledSet<SeedData> baseSeedData = new ScheduledSet<>(SEED_DATA_COMPARATOR);
protected ScheduledSet<BiomeData> biomeSeedData = new ScheduledSet<>(null);
protected HashedSeedData hashedSeedData = null;
public void tick() {
if(!this.timeMachine.isRunning) {
this.baseSeedData.dump();
this.biomeSeedData.dump();
this.scheduledData.removeIf(c -> {
c.accept(this);
return true;
});
}
}
public synchronized boolean addPillarData(PillarData pillarData) {
boolean isAdded = this.pillarData == null;
if(isAdded && pillarData != null) {
this.pillarData = pillarData;
this.schedule(pillarData::onDataAdded);
}
return isAdded;
}
public synchronized boolean addBaseData(SeedData seedData) {
if(this.baseSeedData.contains(seedData)) {
return false;
}
this.baseSeedData.scheduleAdd(seedData);
this.schedule(seedData::onDataAdded);
return true;
}
public synchronized boolean addBiomeData(BiomeData biomeData) {
if(this.biomeSeedData.contains(biomeData)) {
return false;
}
this.biomeSeedData.scheduleAdd(biomeData);
this.schedule(biomeData::onDataAdded);
return true;
}
public synchronized boolean addHashedSeedData(HashedSeedData hashedSeedData) {
if(this.hashedSeedData == null || this.hashedSeedData.getHashedSeed() != hashedSeedData.getHashedSeed()) {
Log.warn("Fetched hashed world seed [" + hashedSeedData.getHashedSeed() + "].");
this.hashedSeedData = hashedSeedData;
this.schedule(hashedSeedData::onDataAdded);
return true;
}
return false;
}
public void schedule(Consumer<DataStorage> consumer) {
this.scheduledData.add(consumer);
}
public TimeMachine getTimeMachine() {
return this.timeMachine;
}
public double getBaseBits() {
double bits = 0.0D;
for(SeedData baseSeedDatum: this.baseSeedData) {
bits += baseSeedDatum.getBits();
}
return bits;
}
public void clear() {
System.out.println("Clearing data storage.");
this.scheduledData = new ConcurrentSet<>();
this.pillarData = null;
this.baseSeedData = new ScheduledSet<>(SEED_DATA_COMPARATOR);
this.biomeSeedData = new ScheduledSet<>(null);
this.hashedSeedData = null;
this.timeMachine.shouldTerminate = true;
this.timeMachine = new TimeMachine(this);
}
}
@@ -0,0 +1,33 @@
package kaptainwutax.seedcracker.cracker.storage;
import kaptainwutax.seedcracker.util.Rand;
import net.minecraft.world.level.LevelProperties;
public class HashedSeedData extends SeedData {
private final long hashedSeed;
public HashedSeedData(long hashedSeed) {
this.hashedSeed = hashedSeed;
}
@Override
public boolean test(long seed, Rand rand) {
return LevelProperties.sha256Hash(seed) == this.hashedSeed;
}
public long getHashedSeed() {
return this.hashedSeed;
}
@Override
public double getBits() {
return 64;
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.BIOMES);
}
}
@@ -0,0 +1,7 @@
package kaptainwutax.seedcracker.cracker.storage;
public interface ISeedStorage {
void onDataAdded(DataStorage dataStorage);
}
@@ -0,0 +1,27 @@
package kaptainwutax.seedcracker.cracker.storage;
import kaptainwutax.seedcracker.util.Log;
public class ProgressListener {
protected float progress;
protected int count = 0;
public ProgressListener() {
this(0.0F);
}
public ProgressListener(float progress) {
this.progress = progress;
}
public synchronized void addPercent(float percent, boolean debug) {
if((this.count & 3) == 0 && debug) {
Log.debug("Progress: " + this.progress + "%");
}
this.count++;
this.progress += percent;
}
}
@@ -0,0 +1,48 @@
package kaptainwutax.seedcracker.cracker.storage;
import java.util.*;
public class ScheduledSet<T> implements Iterable<T> {
protected final Set<T> baseSet;
protected final Set<T> scheduledSet;
public ScheduledSet(Comparator<T> comparator) {
if(comparator != null) {
this.baseSet = new TreeSet<>(comparator);
} else {
this.baseSet = new HashSet<>();
}
this.scheduledSet = new HashSet<>();
}
public synchronized void scheduleAdd(T e) {
this.scheduledSet.add(e);
}
public synchronized void dump() {
synchronized(this.baseSet) {
this.baseSet.addAll(this.scheduledSet);
this.scheduledSet.clear();
}
}
public synchronized boolean contains(T e) {
return this.baseSet.contains(e) || this.scheduledSet.contains(e);
}
public Set<T> getBaseSet() {
return this.baseSet;
}
@Override
public synchronized Iterator<T> iterator() {
return this.baseSet.iterator();
}
public synchronized int size() {
return this.baseSet.size();
}
}
@@ -0,0 +1,11 @@
package kaptainwutax.seedcracker.cracker.storage;
import kaptainwutax.seedcracker.util.Rand;
public abstract class SeedData implements ISeedStorage {
public abstract boolean test(long seed, Rand rand);
public abstract double getBits();
}
@@ -0,0 +1,251 @@
package kaptainwutax.seedcracker.cracker.storage;
import kaptainwutax.seedcracker.cracker.BiomeData;
import kaptainwutax.seedcracker.cracker.FakeBiomeSource;
import kaptainwutax.seedcracker.util.Log;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.math.LCG;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class TimeMachine {
public static ExecutorService SERVICE = Executors.newFixedThreadPool(5);
private LCG inverseLCG = Rand.JAVA_LCG.combine(-2);
protected DataStorage dataStorage;
public boolean isRunning = false;
public boolean shouldTerminate = false;
protected List<Integer> pillarSeeds = null;
protected List<Long> structureSeeds = null;
protected List<Long> worldSeeds = null;
public TimeMachine(DataStorage dataStorage) {
this.dataStorage = dataStorage;
}
public void poke(Phase phase) {
if(this.isRunning) {
return;
}
this.isRunning = true;
final Phase[] finalPhase = {phase};
SERVICE.submit(() -> {
while(finalPhase[0] != null && !this.shouldTerminate) {
if(finalPhase[0] == Phase.PILLARS) {
if(!this.pokePillars())break;
} else if(finalPhase[0] == Phase.STRUCTURES) {
if(!this.pokeStructures())break;
} else if(finalPhase[0] == Phase.BIOMES) {
if(!this.pokeBiomes())break;
}
finalPhase[0] = finalPhase[0].nextPhase();
}
this.isRunning = false;
});
}
protected boolean pokePillars() {
if(this.pillarSeeds != null || this.dataStorage.pillarData == null)return false;
this.pillarSeeds = new ArrayList<>();
Log.debug("====================================");
Log.warn("Looking for pillar seeds...");
for(int pillarSeed = 0; pillarSeed < 1 << 16 && !this.shouldTerminate; pillarSeed++) {
if(this.dataStorage.pillarData.test(pillarSeed, null)) {
Log.warn("Found pillar seed [" + pillarSeed + "].");
this.pillarSeeds.add(pillarSeed);
}
}
if(!this.pillarSeeds.isEmpty()) {
Log.warn("Finished searching for pillar seeds.");
} else {
Log.error("Finished search with no results.");
}
return true;
}
protected boolean pokeStructures() {
if(this.pillarSeeds == null || this.dataStorage.getBaseBits() < 54.0D)return false;
this.structureSeeds = new ArrayList<>();
SeedData[] cache = new SeedData[this.dataStorage.baseSeedData.size()];
int id = 0;
for(SeedData baseSeedDatum: this.dataStorage.baseSeedData) {
cache[id++] = baseSeedDatum;
}
for(int pillarSeed: this.pillarSeeds) {
Log.debug("====================================");
Log.warn("Looking for structure seeds with pillar seed [" + pillarSeed + "]...");
AtomicInteger completion = new AtomicInteger();
ProgressListener progressListener = new ProgressListener();
for(int threadId = 0; threadId < 4; threadId++) {
int fThreadId = threadId;
SERVICE.submit(() -> {
Rand rand = new Rand(0L, false);
long lower = (long)fThreadId * (1L << 30);
long upper = (long)(fThreadId + 1) * (1L << 30);
for(long partialWorldSeed = lower; partialWorldSeed < upper && !this.shouldTerminate; partialWorldSeed++) {
if((partialWorldSeed & ((1 << 27) - 1)) == 0) {
progressListener.addPercent(3.125F, true);
}
long seed = this.timeMachine(partialWorldSeed, pillarSeed);
boolean matches = true;
for(SeedData baseSeedDatum: cache) {
boolean test = baseSeedDatum.test(seed, rand);
if(!test) {
matches = false;
break;
}
}
if(matches) {
this.structureSeeds.add(seed);
Log.warn("Found structure seed [" + seed + "].");
}
}
completion.getAndIncrement();
});
}
while(completion.get() != 4) {
try {Thread.sleep(50);}
catch(InterruptedException e) {e.printStackTrace();}
if(this.shouldTerminate) {
return false;
}
}
progressListener.addPercent(0.0F, true);
}
if(!this.structureSeeds.isEmpty()) {
Log.warn("Finished searching for structure seeds.");
} else {
Log.error("Finished search with no results.");
}
return true;
}
protected boolean pokeBiomes() {
if(this.structureSeeds == null || this.worldSeeds != null)return false;
if(this.dataStorage.hashedSeedData == null && this.dataStorage.biomeSeedData.size() < 5)return false;
this.worldSeeds = new ArrayList<>();
Log.debug("====================================");
Log.warn("Looking for world seeds...");
if(this.dataStorage.hashedSeedData != null) {
for(long structureSeed: this.structureSeeds) {
for(long upperBits = 0; upperBits < 1 << 16; upperBits++) {
long worldSeed = (upperBits << 48) | structureSeed;
if(!this.dataStorage.hashedSeedData.test(worldSeed, null)) {
continue;
} else {
this.worldSeeds.add(worldSeed);
Log.warn("Found world seed [" + worldSeed + "].");
}
if(this.shouldTerminate) {
return false;
}
}
}
if(!this.worldSeeds.isEmpty()) {
Log.warn("Finished searching for world seeds.");
return true;
} else {
Log.error("Finished search with no results, reverting back to biomes.");
}
}
Log.warn("Looking for world seeds...");
for(long structureSeed: this.structureSeeds) {
for(long upperBits = 0; upperBits < 1 << 16; upperBits++) {
long worldSeed = (upperBits << 48) | structureSeed;
FakeBiomeSource source = new FakeBiomeSource(worldSeed);
boolean matches = true;
for(BiomeData biomeSeedDatum: this.dataStorage.biomeSeedData) {
if(!biomeSeedDatum.test(source)) {
matches = false;
break;
}
}
if(matches) {
this.worldSeeds.add(worldSeed);
Log.warn("Found world seed [" + worldSeed + "].");
}
if(this.shouldTerminate) {
return false;
}
}
}
if(!this.worldSeeds.isEmpty()) {
Log.warn("Finished searching for world seeds.");
} else {
Log.error("Finished search with no results.");
}
return true;
}
public long timeMachine(long partialWorldSeed, int pillarSeed) {
long currentSeed = 0L;
currentSeed |= (partialWorldSeed & 0xFFFF0000L) << 16;
currentSeed |= (long)pillarSeed << 16;
currentSeed |= partialWorldSeed & 0xFFFFL;
currentSeed = this.inverseLCG.nextSeed(currentSeed);
currentSeed ^= Rand.JAVA_LCG.multiplier;
return currentSeed;
}
public enum Phase {
BIOMES(null), STRUCTURES(BIOMES), PILLARS(STRUCTURES);
private final Phase nextPhase;
Phase(Phase nextPhase) {
this.nextPhase = nextPhase;
}
public Phase nextPhase() {
return this.nextPhase;
}
}
}
@@ -1,11 +1,14 @@
package kaptainwutax.seedcracker.cracker.structure;
import kaptainwutax.seedcracker.cracker.storage.DataStorage;
import kaptainwutax.seedcracker.cracker.storage.SeedData;
import kaptainwutax.seedcracker.cracker.storage.TimeMachine;
import kaptainwutax.seedcracker.cracker.structure.type.FeatureType;
import kaptainwutax.seedcracker.util.Seeds;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.Seeds;
import net.minecraft.util.math.ChunkPos;
public class StructureData {
public class StructureData extends SeedData {
public int chunkX;
public int chunkZ;
@@ -22,21 +25,37 @@ public class StructureData {
this.featureType.build(this, chunkPos);
}
@Override
public boolean test(long structureSeed, Rand rand) {
Seeds.setRegionSeed(rand, structureSeed, this.regionX, this.regionZ, this.salt);
return this.featureType.test(rand, this, structureSeed);
}
@Override
public double getBits() {
return this.featureType.getBits();
}
@Override
public void onDataAdded(DataStorage dataStorage) {
dataStorage.getTimeMachine().poke(TimeMachine.Phase.STRUCTURES);
}
@Override
public boolean equals(Object obj) {
if(obj == this)return true;
if(obj instanceof StructureData) {
StructureData structureData = ((StructureData)obj);
return structureData.regionX == this.regionX && structureData.regionZ == this.regionZ && structureData.featureType == this.featureType;
return structureData.featureType == this.featureType && structureData.regionX == this.regionX && structureData.regionZ == this.regionZ;
}
return false;
}
@Override
public int hashCode() {
return this.regionX * 961 + this.regionZ * 31 + this.featureType.salt;
}
}
@@ -41,6 +41,8 @@ public class StructureFeatures {
public static final FeatureType<StructureData> BURIED_TREASURE = new RarityType(10387320, 1, 0.01F);
public static final FeatureType<StructureData> NETHER_FORTRESS = new FeatureType<StructureData>(-1, 1) {
protected final double bits = Math.log(3 * 8 * 8) / Math.log(2);
@Override
public boolean test(Rand rand, StructureData data, long structureSeed) {
Seeds.setWeakSeed(rand, structureSeed, data.chunkX, data.chunkZ);
@@ -49,14 +51,26 @@ public class StructureFeatures {
&& data.chunkX == ((data.chunkX >> 4) << 4) + 4 + rand.nextInt(8)
&& data.chunkZ == ((data.chunkZ >> 4) << 4) + 4 + rand.nextInt(8);
}
@Override
public double getBits() {
return this.bits;
}
};
public static final FeatureType<StructureData> MINESHAFT = new FeatureType<StructureData>(-1, 1) {
protected final double bits = Math.log(1.0D / 0.004D) / Math.log(2);
@Override
public boolean test(Rand rand, StructureData data, long structureSeed) {
Seeds.setStructureStartSeed(rand, structureSeed, data.chunkX, data.chunkZ);
return rand.nextDouble() < 0.004D;
}
@Override
public double getBits() {
return this.bits;
}
};
}
@@ -6,10 +6,12 @@ import kaptainwutax.seedcracker.util.Rand;
public class AbstractTempleType extends FeatureType<StructureData> {
protected final int offset;
protected final double bits;
public AbstractTempleType(int salt, int distance, int offset) {
super(salt, distance);
this.offset = offset;
this.bits = Math.log(this.offset * this.offset) / Math.log(2);
}
@Override
@@ -17,4 +19,9 @@ public class AbstractTempleType extends FeatureType<StructureData> {
return rand.nextInt(this.offset) == data.offsetX && rand.nextInt(this.offset) == data.offsetZ;
}
@Override
public double getBits() {
return this.bits;
}
}
@@ -40,4 +40,6 @@ public abstract class FeatureType<T extends StructureData> {
public abstract boolean test(Rand rand, T data, long structureSeed);
public abstract double getBits();
}
@@ -5,11 +5,13 @@ import kaptainwutax.seedcracker.util.Rand;
public class RarityType extends FeatureType<StructureData> {
private float rarity;
private final float rarity;
private final double bits;
public RarityType(int salt, int distance, float rarity) {
super(salt, distance);
this.rarity = rarity;
this.bits = Math.log(1.0D / this.rarity) / Math.log(2);
}
@Override
@@ -17,4 +19,9 @@ public class RarityType extends FeatureType<StructureData> {
return rand.nextFloat() < this.rarity;
}
@Override
public double getBits() {
return this.bits;
}
}
@@ -7,10 +7,12 @@ import kaptainwutax.seedcracker.util.Rand;
public class TriangularType extends FeatureType<StructureData> {
protected final int peak;
protected final double bits;
public TriangularType(int salt, int distance, int peak) {
super(salt, distance);
this.peak = peak;
this.bits = Math.log(this.peak * this.peak) / Math.log(2);
}
@Override
@@ -19,4 +21,12 @@ public class TriangularType extends FeatureType<StructureData> {
&& (rand.nextInt(this.peak) + rand.nextInt(this.peak)) / 2 == data.offsetZ;
}
/*
* For this type specifically, the bits approximation is bad since the distribution is special.
*/
@Override
public double getBits() {
return this.bits;
}
}
@@ -35,7 +35,7 @@ public class BiomeFinder extends Finder {
continue;
}
if(SeedCracker.get().onBiomeData(new BiomeData(blockPos.getX(), blockPos.getZ(), biome))) {
if(SeedCracker.get().getDataStorage().addBiomeData(new BiomeData(blockPos, biome))) {
blockPos = this.world.getTopPosition(Heightmap.Type.WORLD_SURFACE, blockPos).down();
result.add(blockPos);
}
@@ -1,12 +0,0 @@
package kaptainwutax.seedcracker.finder;
public class DefaultFinderConfig extends FinderConfig {
public DefaultFinderConfig() {
this.typeStates.put(Type.DIAMOND_ORE, false);
this.typeStates.put(Type.INFESTED_STONE_ORE, false);
this.typeStates.put(Type.IGLOO, false);
this.typeStates.put(Type.MANSION, false);
}
}
@@ -1,6 +1,13 @@
package kaptainwutax.seedcracker.finder;
import kaptainwutax.seedcracker.finder.population.DesertWellFinder;
import kaptainwutax.seedcracker.finder.population.DungeonFinder;
import kaptainwutax.seedcracker.finder.population.EndGatewayFinder;
import kaptainwutax.seedcracker.finder.population.EndPillarsFinder;
import kaptainwutax.seedcracker.finder.population.ore.EmeraldOreFinder;
import kaptainwutax.seedcracker.finder.structure.*;
import kaptainwutax.seedcracker.render.Renderer;
import kaptainwutax.seedcracker.util.FinderBuilder;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
@@ -9,8 +16,10 @@ import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public abstract class Finder {
@@ -89,4 +98,42 @@ public abstract class Finder {
return newList;
}
public enum Category {
STRUCTURES,
BIOMES,
ORES,
OTHERS
}
public enum Type {
BURIED_TREASURE(BuriedTreasureFinder::create, Category.STRUCTURES),
DESERT_TEMPLE(DesertTempleFinder::create, Category.STRUCTURES),
END_CITY(EndCityFinder::create, Category.STRUCTURES),
//IGLOO(IglooFinder::create, Category.STRUCTURES),
JUNGLE_TEMPLE(JungleTempleFinder::create, Category.STRUCTURES),
MONUMENT(OceanMonumentFinder::create, Category.STRUCTURES),
SWAMP_HUT(SwampHutFinder::create, Category.STRUCTURES),
//MANSION(MansionFinder::create, Category.STRUCTURES),
SHIPWRECK(ShipwreckFinder::create, Category.STRUCTURES),
END_PILLARS(EndPillarsFinder::create, Category.OTHERS),
END_GATEWAY(EndGatewayFinder::create, Category.OTHERS),
DUNGEON(DungeonFinder::create, Category.OTHERS),
EMERALD_ORE(EmeraldOreFinder::create, Category.ORES),
DESERT_WELL(DesertWellFinder::create, Category.OTHERS),
BIOME(BiomeFinder::create, Category.BIOMES);
public final FinderBuilder finderBuilder;
private final Category category;
Type(FinderBuilder finderBuilder, Category category) {
this.finderBuilder = finderBuilder;
this.category = category;
}
public static List<Type> getForCategory(Category category) {
return Arrays.stream(values()).filter(type -> type.category == category).collect(Collectors.toList());
}
}
}
@@ -1,32 +1,26 @@
package kaptainwutax.seedcracker.finder;
import kaptainwutax.seedcracker.finder.population.DungeonFinder;
import kaptainwutax.seedcracker.finder.population.EndGatewayFinder;
import kaptainwutax.seedcracker.finder.population.EndPillarsFinder;
import kaptainwutax.seedcracker.finder.population.ore.DiamondOreFinder;
import kaptainwutax.seedcracker.finder.population.ore.EmeraldOreFinder;
import kaptainwutax.seedcracker.finder.population.ore.InfestedStoneOreFinder;
import kaptainwutax.seedcracker.finder.structure.*;
import kaptainwutax.seedcracker.util.FinderBuilder;
import kaptainwutax.seedcracker.finder.profile.FinderProfile;
import kaptainwutax.seedcracker.finder.profile.NopeProfile;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;
public class FinderConfig {
protected Map<Type, Boolean> typeStates = new HashMap<>();
protected Map<Type, ConcurrentLinkedQueue<Finder>> activeFinders = new ConcurrentHashMap<>();
protected FinderProfile finderProfile = new NopeProfile();
protected Map<Finder.Type, ConcurrentLinkedQueue<Finder>> activeFinders = new ConcurrentHashMap<>();
public FinderConfig() {
for(Type type: Type.values()) {
this.typeStates.put(type, true);
}
}
public List<Type> getActiveFinderTypes() {
return this.typeStates.entrySet().stream()
public List<Finder.Type> getActiveFinderTypes() {
return this.finderProfile.typeStates.entrySet().stream()
.filter(Map.Entry::getValue)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
@@ -41,7 +35,7 @@ public class FinderConfig {
.flatMap(Queue::stream).collect(Collectors.toList());
}
public void addFinder(Type type, Finder finder) {
public void addFinder(Finder.Type type, Finder finder) {
if(finder.isUseless())return;
if(!this.activeFinders.containsKey(type)) {
@@ -51,52 +45,12 @@ public class FinderConfig {
this.activeFinders.get(type).add(finder);
}
public boolean getTypeState(Type type) {
return this.typeStates.get(type);
public boolean getTypeState(Finder.Type type) {
return this.finderProfile.typeStates.get(type);
}
public void setTypeState(Type type, boolean flag) {
this.typeStates.put(type, flag);
}
public enum Category {
STRUCTURES,
BIOMES,
ORES,
OTHERS
}
public enum Type {
BURIED_TREASURE(BuriedTreasureFinder::create, Category.STRUCTURES),
DESERT_TEMPLE(DesertTempleFinder::create, Category.STRUCTURES),
END_CITY(EndCityFinder::create, Category.STRUCTURES),
IGLOO(IglooFinder::create, Category.STRUCTURES),
JUNGLE_TEMPLE(JungleTempleFinder::create, Category.STRUCTURES),
MONUMENT(OceanMonumentFinder::create, Category.STRUCTURES),
SWAMP_HUT(SwampHutFinder::create, Category.STRUCTURES),
MANSION(MansionFinder::create, Category.STRUCTURES),
SHIPWRECK(ShipwreckFinder::create, Category.STRUCTURES),
END_PILLARS(EndPillarsFinder::create, Category.OTHERS),
END_GATEWAY(EndGatewayFinder::create, Category.OTHERS),
DUNGEON(DungeonFinder::create, Category.OTHERS),
DIAMOND_ORE(DiamondOreFinder::create, Category.ORES),
INFESTED_STONE_ORE(InfestedStoneOreFinder::create, Category.ORES),
EMERALD_ORE(EmeraldOreFinder::create, Category.ORES),
BIOME(BiomeFinder::create, Category.BIOMES);
public final FinderBuilder finderBuilder;
private final Category category;
Type(FinderBuilder finderBuilder, Category category) {
this.finderBuilder = finderBuilder;
this.category = category;
}
public static List<Type> getForCategory(Category category) {
return Arrays.stream(values()).filter(type -> type.category == category).collect(Collectors.toList());
}
public boolean setTypeState(Finder.Type type, boolean flag) {
return this.finderProfile.setTypeState(type, flag);
}
}
@@ -2,6 +2,7 @@ package kaptainwutax.seedcracker.finder;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import kaptainwutax.seedcracker.finder.profile.VanillaProfile;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
@@ -16,7 +17,7 @@ public class FinderQueue {
public static ExecutorService SERVICE = Executors.newFixedThreadPool(5);
public RenderType renderType = RenderType.XRAY;
public FinderConfig finderConfig = new DefaultFinderConfig();
public FinderConfig finderProfile = new FinderConfig();
private FinderQueue() {
this.clear();
@@ -27,17 +28,20 @@ public class FinderQueue {
}
public void onChunkData(World world, ChunkPos chunkPos) {
this.finderConfig.getActiveFinderTypes().forEach(type -> {
SERVICE.submit(() -> {
List<Finder> finders = type.finderBuilder.build(world, chunkPos);
this.finderProfile.getActiveFinderTypes().forEach(type -> {
SERVICE.submit(() -> {
try {
List<Finder> finders = type.finderBuilder.build(world, chunkPos);
finders.forEach(finder -> {
if(finder.isValidDimension(world.dimension.getType())) {
this.finderConfig.addFinder(type, finder);
finder.findInChunk();
this.finderConfig.addFinder(type, finder);
}
});
finders.forEach(finder -> {
if(finder.isValidDimension(world.dimension.getType())) {
finder.findInChunk();
this.finderProfile.addFinder(type, finder);
}
});
} catch(Exception e) {
e.printStackTrace();
}
});
});
}
@@ -55,7 +59,7 @@ public class FinderQueue {
GlStateManager.disableDepthTest();
}
this.finderConfig.getActiveFinders().forEach(finder -> {
this.finderProfile.getActiveFinders().forEach(finder -> {
if(finder.shouldRender()) {
finder.render();
}
@@ -66,7 +70,7 @@ public class FinderQueue {
public void clear() {
this.renderType = RenderType.XRAY;
this.finderConfig = new DefaultFinderConfig();
this.finderProfile = new FinderConfig();
}
public enum RenderType {
@@ -0,0 +1,101 @@
package kaptainwutax.seedcracker.finder.population;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.population.DesertWellData;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.finder.structure.PieceFinder;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.DesertBiome;
import net.minecraft.world.biome.DesertHillsBiome;
import net.minecraft.world.biome.DesertLakesBiome;
import net.minecraft.world.dimension.DimensionType;
import java.util.ArrayList;
import java.util.List;
public class DesertWellFinder extends PieceFinder {
protected static List<BlockPos> SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> {
return false;
});
protected static Vec3i SIZE = new Vec3i(5, 6, 5);
public DesertWellFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos, Direction.NORTH, SIZE);
this.searchPositions = SEARCH_POSITIONS;
this.buildStructure();
}
@Override
public List<BlockPos> findInChunk() {
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(8, 0, 8));
if(!(biome instanceof DesertBiome) && !(biome instanceof DesertHillsBiome) && !(biome instanceof DesertLakesBiome)) {
return new ArrayList<>();
}
List<BlockPos> result = super.findInChunk();
result.forEach(pos -> {
pos = pos.add(2, 1, 2);
if(SeedCracker.get().getDataStorage().addBaseData(new DesertWellData(new ChunkPos(pos), biome, pos))) {
this.renderers.add(new Cuboid(pos.add(-2, -1, -2), SIZE, new Vector4f(0.5f, 0.5f, 1.0f, 1.0f)));
this.renderers.add(new Cube(pos, new Vector4f(0.5f, 0.5f, 1.0f, 1.0f)));
}
});
return result;
}
@Override
public boolean isValidDimension(DimensionType dimension) {
return dimension == DimensionType.OVERWORLD;
}
protected void buildStructure() {
BlockState sandstone = Blocks.SANDSTONE.getDefaultState();
BlockState sandstoneSlab = Blocks.SANDSTONE_SLAB.getDefaultState();
BlockState water = Blocks.WATER.getDefaultState();
this.fillWithOutline(0, 0, 0, 4, 1, 4, sandstone, sandstone, false);
this.fillWithOutline(1, 5, 1, 3, 5, 3, sandstoneSlab, sandstoneSlab, false);
this.addBlock(sandstone, 2, 5, 2);
BlockPos p1 = new BlockPos(2, 1, 2);
this.addBlock(water, p1.getX(), p1.getY(), p1.getZ());
Direction.Type.HORIZONTAL.forEach(facing -> {
BlockPos p2 = p1.offset(facing);
this.addBlock(water, p2.getX(), p2.getY(), p2.getZ());
});
}
public static List<Finder> create(World world, ChunkPos chunkPos) {
List<Finder> finders = new ArrayList<>();
finders.add(new DesertWellFinder(world, chunkPos));
finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z)));
finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x, chunkPos.z - 1)));
finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1)));
finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z)));
finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1)));
finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1)));
finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1)));
finders.add(new DesertWellFinder(world, new ChunkPos(chunkPos.x - 1, chunkPos.z + 1)));
return finders;
}
}
@@ -5,6 +5,7 @@ import kaptainwutax.seedcracker.cracker.population.DungeonData;
import kaptainwutax.seedcracker.finder.BlockFinder;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.render.Cuboid;
import kaptainwutax.seedcracker.util.PosIterator;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
@@ -44,6 +45,8 @@ public class DungeonFinder extends BlockFinder {
//Gets all the positions with a mob spawner in the chunk.
List<BlockPos> result = super.findInChunk();
if(result.size() != 1)return new ArrayList<>();
result.removeIf(pos -> {
BlockEntity blockEntity = this.world.getBlockEntity(pos);
if(!(blockEntity instanceof MobSpawnerBlockEntity))return true;
@@ -69,8 +72,10 @@ public class DungeonFinder extends BlockFinder {
.map(pos -> this.getFloorCalls(this.getDungeonSize(pos), pos)).collect(Collectors.toList());
result.forEach(pos -> {
if(SeedCracker.get().onDecoratorData(new DungeonData(this.chunkPos, biome, starts, floorCallsList))) {
if(SeedCracker.get().getDataStorage().addBaseData(new DungeonData(this.chunkPos, biome, starts.get(0), floorCallsList))) {
this.renderers.add(new Cube(pos, new Vector4f(1.0f, 0.0f, 0.0f, 1.0f)));
Vec3i size = this.getDungeonSize(pos);
this.renderers.add(new Cuboid(pos.subtract(size), pos.add(size).add(1, -1, 1), new Vector4f(1.0f, 0.0f, 0.0f, 1.0f)));
}
});
@@ -81,9 +86,7 @@ public class DungeonFinder extends BlockFinder {
for(int xo = 4; xo >= 3; xo--) {
for(int zo = 4; zo >= 3; zo--) {
Block block = this.world.getBlockState(spawnerPos.add(xo, -1, zo)).getBlock();
if(block != Blocks.MOSSY_COBBLESTONE)continue;
if(block != Blocks.COBBLESTONE)continue;
return new Vec3i(xo, 0, zo);
if(block == Blocks.MOSSY_COBBLESTONE || block == Blocks.COBBLESTONE)return new Vec3i(xo, 0, zo);
}
}
@@ -1,7 +1,6 @@
package kaptainwutax.seedcracker.finder.population;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.DecoratorCache;
import kaptainwutax.seedcracker.cracker.population.EndGatewayData;
import kaptainwutax.seedcracker.finder.BlockFinder;
import kaptainwutax.seedcracker.finder.Finder;
@@ -14,7 +13,6 @@ import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.decorator.Decorator;
import java.util.ArrayList;
import java.util.List;
@@ -35,10 +33,6 @@ public class EndGatewayFinder extends BlockFinder {
//If no end gateway is supposed to populate in this chunk, return.
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(8, 0, 8));
if(DecoratorCache.get().getSalt(biome, Decorator.END_GATEWAY, false) == DecoratorCache.INVALID) {
return new ArrayList<>();
}
List<BlockPos> result = super.findInChunk();
List<BlockPos> newResult = new ArrayList<>();
@@ -48,7 +42,7 @@ public class EndGatewayFinder extends BlockFinder {
if(height >= 3 && height <= 9) {
newResult.add(pos);
if(SeedCracker.get().onDecoratorData(new EndGatewayData(this.chunkPos, biome, pos, height))) {
if(SeedCracker.get().getDataStorage().addBaseData(new EndGatewayData(this.chunkPos, biome, pos, height))) {
this.renderers.add(new Cuboid(pos.add(-1, -2, -1), pos.add(2, 3, 2), new Vector4f(0.4f, 0.4f, 0.82f, 1.0f)));
}
}
@@ -26,7 +26,7 @@ public class EndPillarsFinder extends Finder {
public EndPillarsFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos);
this.alreadyFound = SeedCracker.get().onPillarData(null);
this.alreadyFound = !SeedCracker.get().getDataStorage().addPillarData(null);
if(this.alreadyFound)return;
for(int i = 0; i < this.bedrockMarkers.length; i++) {
@@ -48,7 +48,7 @@ public class EndPillarsFinder extends Finder {
if(result.size() == this.bedrockMarkers.length) {
PillarData pillarData = new PillarData(result.stream().map(Vec3i::getY).collect(Collectors.toList()));
if(SeedCracker.get().onPillarData(pillarData)){
if(SeedCracker.get().getDataStorage().addPillarData(pillarData)) {
result.forEach(pos -> this.renderers.add(new Cube(pos, new Vector4f(0.5f, 0.0f, 0.5f, 1.0f))));
}
@@ -1,42 +0,0 @@
package kaptainwutax.seedcracker.finder.population.ore;
import kaptainwutax.seedcracker.finder.Finder;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.OreFeatureConfig;
import java.util.ArrayList;
import java.util.List;
public class DiamondOreFinder extends SimpleOreFinder {
public static OreFeatureConfig CONFIG = new OreFeatureConfig(OreFeatureConfig.Target.NATURAL_STONE, Blocks.DIAMOND_ORE.getDefaultState(), 8);
protected static List<BlockPos> SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> {
if(pos.getY() > 16 + 4)return true;
return false;
});
public DiamondOreFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos, CONFIG);
this.searchPositions = SEARCH_POSITIONS;
}
@Override
public Vector4f getRenderColor() {
return new Vector4f(0.0f, 1.0f, 1.0f, 1.0f);
}
public static List<Finder> create(World world, ChunkPos chunkPos) {
List<Finder> finders = new ArrayList<>();
finders.add(new DiamondOreFinder(world, chunkPos));
finders.add(new DiamondOreFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z)));
finders.add(new DiamondOreFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1)));
finders.add(new DiamondOreFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1)));
return finders;
}
}
@@ -1,7 +1,6 @@
package kaptainwutax.seedcracker.finder.population.ore;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.DecoratorCache;
import kaptainwutax.seedcracker.cracker.population.EmeraldOreData;
import kaptainwutax.seedcracker.finder.BlockFinder;
import kaptainwutax.seedcracker.finder.Finder;
@@ -13,7 +12,6 @@ import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.decorator.Decorator;
import java.util.ArrayList;
import java.util.List;
@@ -35,16 +33,11 @@ public class EmeraldOreFinder extends BlockFinder {
public List<BlockPos> findInChunk() {
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(8, 0, 8));
if(DecoratorCache.get().getSalt(biome, Decorator.EMERALD_ORE, false) == DecoratorCache.INVALID) {
return new ArrayList<>();
}
List<BlockPos> result = super.findInChunk();
if(!result.isEmpty() && SeedCracker.get().onDecoratorData(new EmeraldOreData(this.chunkPos, biome, result))) {
result.forEach(pos -> {
this.renderers.add(new Cube(pos, new Vector4f(0.0f, 1.0f, 0.0f, 1.0f)));
});
if(!result.isEmpty() && SeedCracker.get().getDataStorage().addBaseData(new EmeraldOreData(this.chunkPos, biome, result))) {
//TODO: support more ores.
this.renderers.add(new Cube(result.get(0), new Vector4f(0.0f, 1.0f, 0.0f, 1.0f)));
}
return result;
@@ -1,42 +0,0 @@
package kaptainwutax.seedcracker.finder.population.ore;
import kaptainwutax.seedcracker.finder.Finder;
import net.minecraft.block.Blocks;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.OreFeatureConfig;
import java.util.ArrayList;
import java.util.List;
public class InfestedStoneOreFinder extends SimpleOreFinder {
public static OreFeatureConfig CONFIG = new OreFeatureConfig(OreFeatureConfig.Target.NATURAL_STONE, Blocks.INFESTED_STONE.getDefaultState(), 9);
protected static List<BlockPos> SEARCH_POSITIONS = Finder.buildSearchPositions(Finder.CHUNK_POSITIONS, pos -> {
if(pos.getY() > 64 + 4)return true;
return false;
});
public InfestedStoneOreFinder(World world, ChunkPos chunkPos) {
super(world, chunkPos, CONFIG);
this.searchPositions = SEARCH_POSITIONS;
}
@Override
public Vector4f getRenderColor() {
return new Vector4f(0.5f, 0.5f, 0.5f, 1.0f);
}
public static List<Finder> create(World world, ChunkPos chunkPos) {
List<Finder> finders = new ArrayList<>();
finders.add(new InfestedStoneOreFinder(world, chunkPos));
finders.add(new InfestedStoneOreFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z)));
finders.add(new InfestedStoneOreFinder(world, new ChunkPos(chunkPos.x, chunkPos.z + 1)));
finders.add(new InfestedStoneOreFinder(world, new ChunkPos(chunkPos.x + 1, chunkPos.z + 1)));
return finders;
}
}
@@ -1,50 +0,0 @@
package kaptainwutax.seedcracker.finder.population.ore;
import kaptainwutax.seedcracker.finder.population.OreFinder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.OreFeatureConfig;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public abstract class SimpleOreFinder extends OreFinder {
public SimpleOreFinder(World world, ChunkPos chunkPos, OreFeatureConfig oreFeatureConfig) {
super(world, chunkPos, oreFeatureConfig);
}
@Override
public void findOreVeins(List<Set<BlockPos>> veins) {
List<BlockPos> starts = new ArrayList<>();
for(Set<BlockPos> vein: veins) {
//This is a semi-accurate estimate.
BlockPos oreStart = new BlockPos(
this.findX(vein, OreFinder.HIGHEST),
this.findY(vein, OreFinder.LOWEST) + 2,
this.findZ(vein, OreFinder.HIGHEST)
);
starts.add(oreStart);
}
//If the start overlaps with another chunk, get rid of it.
starts.removeIf(start -> {
if((start.getX() & 15) == 0 || (start.getX() & 15) == 15)return true;
if((start.getZ() & 15) == 0 || (start.getZ() & 15) == 15)return true;
return false;
});
starts.forEach(start -> {
this.renderers.add(new Cuboid(start.add(-1, -1, -1), start.add(1, 0, 1), this.getRenderColor()));
});
}
public abstract Vector4f getRenderColor();
}
@@ -0,0 +1,19 @@
package kaptainwutax.seedcracker.finder.profile;
public class CustomProfile extends FinderProfile {
public CustomProfile() {
super(false);
this.author = "";
this.locked = false;
}
public void setAuthor(String author) {
this.author = author;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
}
@@ -0,0 +1,34 @@
package kaptainwutax.seedcracker.finder.profile;
import kaptainwutax.seedcracker.finder.Finder;
import java.util.HashMap;
public abstract class FinderProfile {
public final HashMap<Finder.Type, Boolean> typeStates = new HashMap<>();
protected String author;
protected boolean locked;
public FinderProfile(boolean defaultState) {
for(Finder.Type type: Finder.Type.values()) {
this.typeStates.put(type, defaultState);
}
}
public String getAuthor() {
return this.author;
}
public boolean getLocked() {
return this.locked;
}
public boolean setTypeState(Finder.Type type, boolean state) {
if(this.getLocked())return false;
this.typeStates.put(type, state);
return true;
}
}
@@ -0,0 +1,11 @@
package kaptainwutax.seedcracker.finder.profile;
public class NopeProfile extends FinderProfile {
public NopeProfile() {
super(false);
this.author = "KaptainWutax";
this.locked = true;
}
}
@@ -0,0 +1,11 @@
package kaptainwutax.seedcracker.finder.profile;
public class VanillaProfile extends FinderProfile {
public VanillaProfile() {
super(true);
this.author = "KaptainWutax";
this.locked = true;
}
}
@@ -1,6 +1,9 @@
package kaptainwutax.seedcracker.finder.structure;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cube;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.client.util.math.Vector4f;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Direction;
@@ -54,6 +57,12 @@ public abstract class AbstractTempleFinder extends Finder {
protected abstract StructureFeature<?> getStructureFeature();
public void addRenderers(PieceFinder pieceFinder, BlockPos origin, Vector4f color) {
this.renderers.add(new Cuboid(origin, pieceFinder.getLayout(), color));
BlockPos chunkStart = new BlockPos(origin.getX() & -16, origin.getY(), origin.getZ() & -16);
this.renderers.add(new Cube(chunkStart, color));
}
public Map<PieceFinder, List<BlockPos>> findInChunkPieces() {
Map<PieceFinder, List<BlockPos>> result = new HashMap<>();
@@ -72,7 +72,7 @@ public class BuriedTreasureFinder extends BlockFinder {
});
result.forEach(pos -> {
if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.BURIED_TREASURE))) {
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.BURIED_TREASURE))) {
this.renderers.add(new Cube(pos, new Vector4f(1.0f, 1.0f, 0.0f, 1.0f)));
}
});
@@ -4,7 +4,6 @@ import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.structure.StructureData;
import kaptainwutax.seedcracker.cracker.structure.StructureFeatures;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.StairsBlock;
@@ -36,8 +35,8 @@ public class DesertTempleFinder extends AbstractTempleFinder {
combinedResult.addAll(positions);
positions.forEach(pos -> {
if( SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.DESERT_PYRAMID))) {
this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f)));
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.DESERT_PYRAMID))) {
this.addRenderers(pieceFinder, pos, new Vector4f(1.0f, 0.0f, 1.0f, 1.0f));
}
});
});
@@ -14,7 +14,9 @@ import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.feature.Feature;
import java.util.ArrayList;
import java.util.HashMap;
@@ -24,6 +26,7 @@ import java.util.Map;
public class EndCityFinder extends Finder {
protected static List<BlockPos> SEARCH_POSITIONS = buildSearchPositions(CHUNK_POSITIONS, pos -> {
if(pos.getY() > 90)return true;
return false;
});
@@ -74,6 +77,12 @@ public class EndCityFinder extends Finder {
@Override
public List<BlockPos> findInChunk() {
Biome biome = this.world.getBiome(this.chunkPos.getCenterBlockPos().add(9, 0, 9));
if(!biome.hasStructureFeature(Feature.END_CITY)) {
return new ArrayList<>();
}
Map<PieceFinder, List<BlockPos>> result = this.findInChunkPieces();
List<BlockPos> combinedResult = new ArrayList<>();
@@ -86,7 +95,7 @@ public class EndCityFinder extends Finder {
combinedResult.addAll(positions);
positions.forEach(pos -> {
if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.END_CITY))) {
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.END_CITY))) {
this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(0.6f, 0.0f, 0.6f, 1.0f)));
this.renderers.add(new Cube(pos, new Vector4f(0.6f, 0.0f, 0.6f, 1.0f)));
}
@@ -45,7 +45,7 @@ public class IglooFinder extends AbstractTempleFinder {
combinedResult.addAll(positions);
positions.forEach(pos -> {
if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.IGLOO))) {
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.IGLOO))) {
this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(0.0f, 1.0f, 1.0f, 1.0f)));
this.renderers.add(new Cube(pos, new Vector4f(0.0f, 1.0f, 1.0f, 1.0f)));
}
@@ -4,7 +4,6 @@ import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.structure.StructureData;
import kaptainwutax.seedcracker.cracker.structure.StructureFeatures;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.*;
import net.minecraft.block.enums.WallMountLocation;
import net.minecraft.block.enums.WireConnection;
@@ -36,8 +35,8 @@ public class JungleTempleFinder extends AbstractTempleFinder {
combinedResult.addAll(positions);
positions.forEach(pos -> {
if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.JUNGLE_TEMPLE))) {
this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f)));
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.JUNGLE_TEMPLE))) {
this.addRenderers(pieceFinder, pos, new Vector4f(1.0f, 0.0f, 1.0f, 1.0f));
}
});
});
@@ -62,7 +62,7 @@ public class MansionFinder extends Finder {
combinedResult.addAll(positions);
positions.forEach(pos -> {
if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.WOODLAND_MANSION))) {
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.WOODLAND_MANSION))) {
this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(0.4f, 0.26f, 0.13f, 1.0f)));
this.renderers.add(new Cube(this.chunkPos.getCenterBlockPos().add(0, pos.getY(), 0), new Vector4f(0.4f, 0.26f, 0.13f, 1.0f)));
}
@@ -58,7 +58,7 @@ public class OceanMonumentFinder extends Finder {
positions.forEach(pos -> {
ChunkPos monumentStart = new ChunkPos(this.chunkPos.x + 1, this.chunkPos.z + 1);
if(SeedCracker.get().onStructureData(new StructureData(monumentStart, StructureFeatures.OCEAN_MONUMENT))) {
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(monumentStart, StructureFeatures.OCEAN_MONUMENT))) {
this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(0.0f, 0.0f, 1.0f, 1.0f)));
this.renderers.add(new Cube(monumentStart.getCenterBlockPos().add(0, pos.getY(), 0), new Vector4f(0.0f, 0.0f, 1.0f, 1.0f)));
}
@@ -170,14 +170,14 @@ public class ShipwreckFinder extends BlockFinder {
BlockBox box = new BlockBox(
Math.min(pos2.getX(), pos3.getX()), pos2.getY(), Math.min(pos2.getZ(), pos3.getZ()),
Math.max(pos2.getX(), pos3.getX()), pos3.getY(), Math.max(pos2.getZ(), pos3.getZ()));
Math.max(pos2.getX(), pos3.getX()) + 1, pos3.getY() + 1, Math.max(pos2.getZ(), pos3.getZ()) + 1);
mutablePos.setOffset(-4, -chestY, -15);
if((mutablePos.getX() & 0xf) == 0 && (mutablePos.getZ() & 0xf) == 0) {
if(SeedCracker.get().onStructureData(new StructureData(new ChunkPos(mutablePos), StructureFeatures.SHIPWRECK))) {
this.renderers.add(new Cuboid(box, new Vector4f(1.0f, 0.0f, 1.0f, 1.0f)));
this.renderers.add(new Cube(new ChunkPos(mutablePos).getCenterBlockPos().offset(Direction.UP, mutablePos.getY()), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f)));
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(new ChunkPos(mutablePos), StructureFeatures.SHIPWRECK))) {
this.renderers.add(new Cuboid(box, new Vector4f(0.0f, 1.0f, 1.0f, 1.0f)));
this.renderers.add(new Cube(new ChunkPos(mutablePos).getCenterBlockPos().offset(Direction.UP, mutablePos.getY()), new Vector4f(0.0f, 1.0f, 1.0f, 1.0f)));
return true;
}
}
@@ -4,7 +4,6 @@ import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.cracker.structure.StructureData;
import kaptainwutax.seedcracker.cracker.structure.StructureFeatures;
import kaptainwutax.seedcracker.finder.Finder;
import kaptainwutax.seedcracker.render.Cuboid;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.StairsBlock;
@@ -37,8 +36,8 @@ public class SwampHutFinder extends AbstractTempleFinder {
combinedResult.addAll(positions);
positions.forEach(pos -> {
if(SeedCracker.get().onStructureData(new StructureData(this.chunkPos, StructureFeatures.SWAMP_HUT))) {
this.renderers.add(new Cuboid(pos, pieceFinder.getLayout(), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f)));
if(SeedCracker.get().getDataStorage().addBaseData(new StructureData(this.chunkPos, StructureFeatures.SWAMP_HUT))) {
this.addRenderers(pieceFinder, pos, new Vector4f(1.0f, 0.0f, 1.0f, 1.0f));
}
});
});
@@ -0,0 +1,46 @@
package kaptainwutax.seedcracker.gui;
import io.github.cottonmc.cotton.gui.client.BackgroundPainter;
import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription;
import io.github.cottonmc.cotton.gui.widget.WButton;
import io.github.cottonmc.cotton.gui.widget.WGridPanel;
import io.github.cottonmc.cotton.gui.widget.WLabel;
import io.github.cottonmc.cotton.gui.widget.WSprite;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.finder.FinderQueue;
import net.minecraft.text.LiteralText;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Identifier;
public class Gui extends LightweightGuiDescription {
public Gui() {
WGridPanel root = new WGridPanel();
setRootPanel(root);
root.setSize(256, 240);
WSprite icon = new WSprite(new Identifier("minecraft:textures/item/redstone.png"));
root.add(icon, 0, 2, 1, 1);
WButton button = new WButton(new TranslatableText("RESET DATA"));
button.setOnClick(new Runnable() {
@Override
public void run() {
SeedCracker.get().getDataStorage().clear();
FinderQueue.get().clear();
}
}
);
root.add(button, 0, 3, 4, 1);
WLabel label = new WLabel(new LiteralText("Test"), 0xFFFFFF);
root.add(label, 0, 4, 2, 1);
root.validate(this);
}
@Override
public void addPainters() {
getRootPanel().setBackgroundPainter(BackgroundPainter.VANILLA); //This is done automatically though
}
}
@@ -0,0 +1,22 @@
package kaptainwutax.seedcracker.gui;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World;
public class GuiItem extends Item {
public GuiItem(Settings settings) {
super(settings);
}
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
MinecraftClient.getInstance().openScreen(new Screen(new Gui()));
return super.use(world, user, hand);
}
}
@@ -0,0 +1,11 @@
package kaptainwutax.seedcracker.gui;
import io.github.cottonmc.cotton.gui.GuiDescription;
import io.github.cottonmc.cotton.gui.client.CottonClientScreen;
public class Screen extends CottonClientScreen {
public Screen(GuiDescription description) {
super(description);
}
}
@@ -1,8 +1,12 @@
package kaptainwutax.seedcracker.command;
package kaptainwutax.seedcracker.init;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import kaptainwutax.seedcracker.command.ClientCommand;
import kaptainwutax.seedcracker.command.FinderCommand;
import kaptainwutax.seedcracker.command.GuiCommand;
import kaptainwutax.seedcracker.command.RenderCommand;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.command.CommandException;
@@ -20,10 +24,12 @@ public class ClientCommands {
public static RenderCommand RENDER;
public static FinderCommand FINDER;
public static GuiCommand GUI;
static {
COMMANDS.add(RENDER = new RenderCommand());
COMMANDS.add(FINDER = new FinderCommand());
COMMANDS.add(GUI = new GuiCommand());
}
public static void registerCommands(CommandDispatcher<ServerCommandSource> dispatcher) {
@@ -0,0 +1,43 @@
package kaptainwutax.seedcracker.init;
import kaptainwutax.seedcracker.util.Log;
import net.minecraft.client.options.KeyBinding;
import java.util.LinkedHashSet;
public class KeyBindings {
public static LinkedHashSet<KeyBinding> KEY_REGISTRY = new LinkedHashSet<>();
public static LinkedHashSet<String> CATEGORY_REGISTRY = new LinkedHashSet<>();
public static KeyBinding OPEN_MENU = new KeyBinding(getName("open_menu"), 'M', getCategory("seedcracker"));
static {
registerKeyBinding(OPEN_MENU);
}
/*
* Registers keys and their categories. Remember that everything is FIFO.
*/
private static void registerKeyBinding(KeyBinding keyBinding) {
if(keyBinding == null) {
throw new NullPointerException("Cannot register a null key binding!");
} else {
KEY_REGISTRY.add(keyBinding);
CATEGORY_REGISTRY.add(keyBinding.getCategory());
Log.debug("Registering key [" + keyBinding.getName() + ", " + keyBinding.getId() + "] from category [" + keyBinding.getCategory() + "].");
}
}
/*
* Generates the category and key prefixes for the language files.
*/
public static String getCategory(String registryName) {
return "key.categories." + registryName;
}
public static String getName(String registryName) {
return "key." + registryName.toLowerCase();
}
}
@@ -0,0 +1,41 @@
package kaptainwutax.seedcracker.magic;
/**
* Math utility library-- I have no idea how it works, don't ask.
* All credits to Matthew. (The man doesn't have a GitHub, shame!)
* */
public class MagicMath {
public static final long MASK_16 = 0xFFFFL;
public static final long MASK_32 = 0xFFFF_FFFFL;
public static final long MASK_48 = 0xFFFF_FFFF_FFFFL;
public static int countTrailingZeroes(long v) {
int c; // output: c will count v's trailing zero bits,
// so if v is 1101000 (base 2), then c will be 3
v = (v ^ (v - 1)) >> 1; // Set v's trailing 0s to 1s and zero rest
for(c = 0; v != 0; c++) {
v >>>= 1;
}
return c;
}
public static long modInverse(long x, int mod) { //Fast method for modular inverse mod powers of 2
long inv = 0;
long b = 1;
for(int i = 0; i < mod; i++) {
if((b & 1) == 1) {
inv |= 1L << i;
b = (b - x) >> 1;
} else {
b >>= 1;
}
}
return inv;
}
}
@@ -0,0 +1,122 @@
package kaptainwutax.seedcracker.magic;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.Seeds;
import kaptainwutax.seedcracker.util.math.LCG;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class PopulationReversal {
private static final LCG SKIP_2 = Rand.JAVA_LCG.combine(2);
private static final LCG SKIP_4 = Rand.JAVA_LCG.combine(4);
public static ArrayList<Long> getWorldSeeds(long populationSeed, int x, int z) {
populationSeed ^= Rand.JAVA_LCG.multiplier;
ArrayList<Long> worldSeeds = new ArrayList<>();
if (x == 0 && z == 0) {
worldSeeds.add(populationSeed);
return worldSeeds;
}
long c; //a is upper 16 bits, b middle 16 bits, c lower 16 bits of worldseed.
long e = populationSeed & MagicMath.MASK_32; //The algorithm proceeds by solving for worldseed in 16 bit groups
long f = populationSeed & MagicMath.MASK_16; //as such, we need the 16 bit groups of chunkseed for later eqns.
boolean xEven = (x & 1) == 0;
boolean zEven = (z & 1) == 0;
long firstMultiplier = (SKIP_2.multiplier * x + SKIP_4.multiplier * z) & MagicMath.MASK_16;
int multTrailingZeroes = MagicMath.countTrailingZeroes(firstMultiplier); //TODO currently code blows up if this is 16, but you can use it to get bits of seed anyway if it is non zero
long firstMultInv = MagicMath.modInverse(firstMultiplier >> multTrailingZeroes,16);
//TODO We can recover more initial bits when x + z is divisible by a power of 2
if (xEven ^ zEven) { //bottom bit of x*a + z*b is odd so we xor by 1 to get bottom bit of worldseed.
c = (populationSeed & 1) ^ 1;
} else { //bottom bit of x*a + z*b is even so we xor by 0 to get bottom bit of worldseed.
c = (populationSeed & 1);
}
for (; c < (1L << 16); c += 2) { //iterate through all possible lower 16 bits of worldseed.
long target = (c ^ f) & MagicMath.MASK_16; //now that we've guessed 16 bits of worldseed we can undo the mask
//We need to handle the four different cases of the effect the two | 1s have on the seed
long magic = x * ((SKIP_2.multiplier * ((c ^ Rand.JAVA_LCG.multiplier) & MagicMath.MASK_16) + SKIP_2.addend) >>> 16) + z * ((SKIP_4.multiplier * ((c ^ Rand.JAVA_LCG.multiplier) & MagicMath.MASK_16) + SKIP_4.addend) >>> 16);
addWorldSeed(worldSeeds, target - (magic & MagicMath.MASK_16), multTrailingZeroes, firstMultInv, c, e, x, z, populationSeed); //case both nextLongs were odd
addWorldSeed(worldSeeds, target - ((magic + x) & MagicMath.MASK_16), multTrailingZeroes, firstMultInv, c, e, x, z, populationSeed); //case where x nextLong even
addWorldSeed(worldSeeds, target - ((magic + z) & MagicMath.MASK_16), multTrailingZeroes, firstMultInv, c, e, x, z, populationSeed); //case where z nextLong even
addWorldSeed(worldSeeds, target - ((magic + x + z) & MagicMath.MASK_16), multTrailingZeroes, firstMultInv, c, e, x, z, populationSeed); //case where both nextLongs even
}
return worldSeeds;
}
public static long makeSecondAddend(int x, long k, int z) {
return ((x*((((SKIP_2.multiplier * ((k ^ Rand.JAVA_LCG.multiplier) & MagicMath.MASK_32) + SKIP_2.addend) & MagicMath.MASK_48) >>> 16) | 1L) +
z*((((SKIP_4.multiplier * ((k ^ Rand.JAVA_LCG.multiplier) & MagicMath.MASK_32) + SKIP_4.addend) & MagicMath.MASK_48) >>> 16) | 1L)) >>> 16) & MagicMath.MASK_16;
}
public static void addWorldSeed(List<Long> worldSeeds, long firstAddend, int multTrailingZeroes, long firstMultInv, long c, long e, int x, int z, long populationSeed){
if(MagicMath.countTrailingZeroes(firstAddend) >= multTrailingZeroes) { //Does there exist a set of 16 bits which work for bits 17-32
long b = ((((firstMultInv * firstAddend)>>> multTrailingZeroes) ^ (Rand.JAVA_LCG.multiplier >> 16)) & ((1L << (16 - multTrailingZeroes)) - 1));
for(; b < (1L << 16); b += (1L << (16 - multTrailingZeroes))) { //if the previous multiplier had a power of 2 divisor, we get multiple solutions for b
long k = (b << 16) + c;
long target2 = (k ^ e) >> 16; //now that we know b, we can undo more of the mask
long secondAddend = makeSecondAddend(x, k, z);
if (MagicMath.countTrailingZeroes(target2 - secondAddend) >= multTrailingZeroes) { //Does there exist a set of 16 bits which work for bits 33-48
long a = ((((firstMultInv * (target2 - secondAddend)) >>> multTrailingZeroes) ^ (Rand.JAVA_LCG.multiplier >> 32)) & ((1L << (16-multTrailingZeroes)) - 1));
for(; a < (1L << 16); a += (1L << (16 - multTrailingZeroes))) { //if the previous multiplier had a power of 2 divisor, we get multiple solutions for a
if(Seeds.setPopulationSeed(null, (a << 32) + k, x, z) == populationSeed) { //lazy check if the test has succeeded
worldSeeds.add((a << 32) + k);
}
}
}
}
}
}
/*
* Left as reference if I need to test this mess again. :P
* */
public static void main(String[] args) {
long seed;
int x , z;
ArrayList<Long> seeds;
/*long seed = 40820992642153L;
int x = 2;
int z = 4;
ArrayList<Long> seeds = getSeedFromChunkseed(getChunkseed(seed, x, z), x, z);
System.out.println("start");
for (long a : seeds) {
System.out.println(a);
}
System.out.println("done");*/
Random r = new Random();
int failcount = 0;
System.out.println("start");
long start = System.currentTimeMillis();
for(int i = 0; i < 100000; i++){
seed = r.nextLong() & ((1L << 48)-1);
x = r.nextInt(16) - 8;
z = r.nextInt(16) - 8;
seeds = getWorldSeeds(Seeds.setPopulationSeed(null, seed, x, z) ^ Rand.JAVA_LCG.multiplier, x, z);
if (!seeds.contains(seed)) {
System.out.println(seed);
System.out.println(x);
System.out.println(z);
failcount++;
System.out.println();
}
}
System.out.println("End: "+((System.currentTimeMillis()-start)/1000.0));
System.out.println(failcount+" failures.");
}
}
@@ -0,0 +1,23 @@
package kaptainwutax.seedcracker.magic;
import kaptainwutax.seedcracker.util.Rand;
import kaptainwutax.seedcracker.util.math.LCG;
public class RandomSeed {
private static final LCG INVERSE_LCG = Rand.JAVA_LCG.combine(-1);
/**
* Source: https://twitter.com/Geosquare_/status/1169623192153010176
* */
public static boolean isRandomSeed(long worldSeed) {
long upperBits = worldSeed >>> 32;
long lowerBits = worldSeed & MagicMath.MASK_32;
long a = (24667315 * upperBits + 18218081 * lowerBits + 67552711) >> 32;
long b = (-4824621 * upperBits + 7847617 * lowerBits + 7847617) >> 32;
long seed = INVERSE_LCG.nextSeed(7847617 * a - 18218081 * b);
return new Rand(seed, false).nextLong() == worldSeed;
}
}
@@ -3,7 +3,8 @@ package kaptainwutax.seedcracker.mixin;
import com.mojang.authlib.GameProfile;
import com.mojang.brigadier.CommandDispatcher;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.command.ClientCommands;
import kaptainwutax.seedcracker.init.ClientCommands;
import kaptainwutax.seedcracker.cracker.storage.HashedSeedData;
import kaptainwutax.seedcracker.finder.FinderQueue;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
@@ -35,6 +36,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
FinderQueue.get().onChunkData(this.world, new ChunkPos(chunkX, chunkZ));
}
@SuppressWarnings("unchecked")
@Inject(method = "<init>", at = @At("RETURN"))
public void onInit(MinecraftClient mc, Screen screen, ClientConnection connection, GameProfile profile, CallbackInfo ci) {
ClientCommands.registerCommands((CommandDispatcher<ServerCommandSource>)(Object)this.commandDispatcher);
@@ -48,7 +50,7 @@ public abstract class ClientPlayNetworkHandlerMixin {
@Inject(method = "onPlayerRespawn", at = @At("HEAD"))
public void onPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) {
SeedCracker.get().hashedWorldSeed = packet.method_22425();
SeedCracker.get().getDataStorage().addHashedSeedData(new HashedSeedData(packet.method_22425()));
}
}
@@ -1,7 +1,8 @@
package kaptainwutax.seedcracker.mixin;
import com.mojang.brigadier.StringReader;
import kaptainwutax.seedcracker.command.ClientCommands;
import kaptainwutax.seedcracker.SeedCracker;
import kaptainwutax.seedcracker.init.ClientCommands;
import net.minecraft.client.network.ClientPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -13,6 +14,11 @@ import java.util.regex.Pattern;
@Mixin(ClientPlayerEntity.class)
public abstract class ClientPlayerEntityMixin {
@Inject(method = "tick", at = @At("HEAD"))
private void tick(CallbackInfo ci) {
SeedCracker.get().getDataStorage().tick();
}
@Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true)
private void onSendChatMessage(String message, CallbackInfo ci) {
if(message.startsWith("/")) {
@@ -14,9 +14,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ClientWorld.class)
public abstract class ClientWorldMixin {
@Inject(method = "disconnect", at = @At("TAIL"))
@Inject(method = "disconnect", at = @At("HEAD"))
private void disconnect(CallbackInfo ci) {
SeedCracker.get().clear();
SeedCracker.get().getDataStorage().clear();
FinderQueue.get().clear();
}
@@ -0,0 +1,36 @@
package kaptainwutax.seedcracker.mixin;
import kaptainwutax.seedcracker.init.KeyBindings;
import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.KeyBinding;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Iterator;
@Mixin(GameOptions.class)
public class GameOptionsMixin {
@Shadow public KeyBinding[] keysAll;
@Inject(method = "<init>", at = @At("RETURN"))
private void init(CallbackInfo ci) {
KeyBinding[] oldKeys = this.keysAll;
KeyBinding[] newKeys = new KeyBinding[oldKeys.length + KeyBindings.KEY_REGISTRY.size()];
Iterator<KeyBinding> keyBindingIterator = KeyBindings.KEY_REGISTRY.iterator();
for(int i = 0; i < newKeys.length; i++) {
if(i < oldKeys.length) {
newKeys[i] = oldKeys[i];
} else {
newKeys[i] = keyBindingIterator.next();
}
}
this.keysAll = newKeys;
}
}
@@ -0,0 +1,24 @@
package kaptainwutax.seedcracker.mixin;
import kaptainwutax.seedcracker.init.KeyBindings;
import net.minecraft.client.options.KeyBinding;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Map;
@Mixin(KeyBinding.class)
public class KeyBindingMixin {
@Shadow @Final private static Map<String, Integer> categoryOrderMap;
static {
int start = categoryOrderMap.size();
for(String category: KeyBindings.CATEGORY_REGISTRY) {
categoryOrderMap.put(category, start++);
}
}
}
@@ -11,7 +11,7 @@ public class Log {
PlayerEntity player = getPlayer();
if(player != null) {
player.addChatMessage(new LiteralText(message), false);
schedule(() -> player.addChatMessage(new LiteralText(message), false));
}
}
@@ -19,7 +19,7 @@ public class Log {
PlayerEntity player = getPlayer();
if(player != null) {
player.addChatMessage(new LiteralText(TextFormat.YELLOW + message), false);
schedule(() -> player.addChatMessage(new LiteralText(TextFormat.YELLOW + message), false));
}
}
@@ -27,10 +27,14 @@ public class Log {
PlayerEntity player = getPlayer();
if(player != null) {
player.addChatMessage(new LiteralText(TextFormat.RED + message), false);
schedule(() -> player.addChatMessage(new LiteralText(TextFormat.RED + message), false));
}
}
private static void schedule(Runnable runnable) {
MinecraftClient.getInstance().execute(runnable);
}
private static PlayerEntity getPlayer() {
return MinecraftClient.getInstance().player;
}
@@ -4,11 +4,22 @@ public class Seeds {
public static long setRegionSeed(Rand rand, long worldSeed, int regionX, int regionZ, int salt) {
long seed = (long)regionX * 341873128712L + (long)regionZ * 132897987541L + worldSeed + (long)salt;
if(rand != null)rand.setSeed(seed, true);
return seed;
}
public static long setPopulationSeed(Rand rand, long worldSeed, int posX, int posZ) {
if(rand == null)rand = new Rand(0L);
rand.setSeed(worldSeed, true);
long a = rand.nextLong() | 1L;
long b = rand.nextLong() | 1L;
long seed = (long)posX * a + (long)posZ * b ^ worldSeed;
rand.setSeed(seed, true);
return seed;
}
public static long setStructureStartSeed(Rand rand, long worldSeed, int chunkX, int chunkZ) {
if(rand == null)rand = new Rand(0L);
rand.setSeed(worldSeed, true);
long a = rand.nextLong();
long b = rand.nextLong();
@@ -21,8 +32,18 @@ public class Seeds {
int sX = chunkX >> 4;
int sZ = chunkZ >> 4;
long seed = (long)(sX ^ sZ << 4) ^ worldSeed;
rand.setSeed(seed, true);
rand.nextInt();
if(rand != null) {
rand.setSeed(seed, true);
rand.nextInt();
}
return seed;
}
public static long setSlimeChunkSeed(Rand rand, long worldSeed, int chunkX, int chunkZ, long salt) {
long seed = worldSeed + (long)(chunkX * chunkX * 4987142) + (long)(chunkX * 5947611) + (long)(chunkZ * chunkZ) * 4392871L + (long)(chunkZ * 389711) ^ salt;
if(rand != null)rand.setSeed(seed, true);
return seed;
}
@@ -0,0 +1,53 @@
package kaptainwutax.seedcracker.util.loot;
import net.minecraft.client.MinecraftClient;
import net.minecraft.loot.context.LootContext;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.WorldGenerationProgressListener;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.WorldSaveHandler;
import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.level.LevelInfo;
import net.minecraft.world.level.LevelProperties;
import java.io.File;
public class LootBuilder extends LootContext.Builder {
private static final FakeWorld FAKE_WORLD = new FakeWorld();
public LootBuilder() {
super(FAKE_WORLD);
}
private static class FakeWorld extends ServerWorld {
public FakeWorld() {
super(new IntegratedServer(
MinecraftClient.getInstance(), null, null,
new LevelInfo(new LevelProperties(new CompoundTag(), null, 0, null)),
null, null, null, null, null
), Runnable::run, new WorldSaveHandler(new File("foo"), "bar", null, null),
new LevelProperties(new CompoundTag(), null, 0, null),
DimensionType.OVERWORLD, null, new WorldGenerationProgressListener() {
@Override
public void start(ChunkPos var1) {
}
@Override
public void setChunkStatus(ChunkPos var1, ChunkStatus var2) {
}
@Override
public void stop() {
}
});
}
}
}
@@ -0,0 +1,55 @@
package kaptainwutax.seedcracker.util.loot;
import net.minecraft.block.Blocks;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.Items;
import net.minecraft.item.map.MapIcon;
import net.minecraft.loot.ConstantLootTableRange;
import net.minecraft.loot.LootPool;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.UniformLootTableRange;
import net.minecraft.loot.entry.EmptyEntry;
import net.minecraft.loot.entry.ItemEntry;
import net.minecraft.loot.function.*;
public class MCLootTables {
public static LootTable ABANDONED_MINESHAFT_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(1)).withEntry(ItemEntry.builder(Items.GOLDEN_APPLE).setWeight(20)).withEntry(ItemEntry.builder(Items.ENCHANTED_GOLDEN_APPLE)).withEntry(ItemEntry.builder(Items.NAME_TAG).setWeight(30)).withEntry(ItemEntry.builder(Items.BOOK).setWeight(10).withFunction(EnchantRandomlyLootFunction.builder())).withEntry(ItemEntry.builder(Items.IRON_PICKAXE).setWeight(5)).withEntry(EmptyEntry.Serializer().setWeight(5))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 4.0F)).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.REDSTONE).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 9.0F)))).withEntry(ItemEntry.builder(Items.LAPIS_LAZULI).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 9.0F)))).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.MELON_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.PUMPKIN_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BEETROOT_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F))))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(3)).withEntry(ItemEntry.builder(Blocks.RAIL).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 8.0F)))).withEntry(ItemEntry.builder(Blocks.POWERED_RAIL).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Blocks.DETECTOR_RAIL).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Blocks.ACTIVATOR_RAIL).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Blocks.TORCH).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 16.0F))))).create();
public static LootTable BURIED_TREASURE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(1)).withEntry(ItemEntry.builder(Items.HEART_OF_THE_SEA))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(5.0F, 8.0F)).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Blocks.TNT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F))))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 3.0F)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F)))).withEntry(ItemEntry.builder(Items.PRISMARINE_CRYSTALS).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F))))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(0.0F, 1.0F)).withEntry(ItemEntry.builder(Items.LEATHER_CHESTPLATE)).withEntry(ItemEntry.builder(Items.IRON_SWORD))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(2)).withEntry(ItemEntry.builder(Items.COOKED_COD).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.COOKED_SALMON).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F))))).create();
public static LootTable DESERT_PYRAMID_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 4.0F)).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.BONE).setWeight(25).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 6.0F)))).withEntry(ItemEntry.builder(Items.SPIDER_EYE).setWeight(25).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(25).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.SADDLE).setWeight(20)).withEntry(ItemEntry.builder(Items.IRON_HORSE_ARMOR).setWeight(15)).withEntry(ItemEntry.builder(Items.GOLDEN_HORSE_ARMOR).setWeight(10)).withEntry(ItemEntry.builder(Items.DIAMOND_HORSE_ARMOR).setWeight(5)).withEntry(ItemEntry.builder(Items.BOOK).setWeight(20).withFunction(EnchantRandomlyLootFunction.builder())).withEntry(ItemEntry.builder(Items.GOLDEN_APPLE).setWeight(20)).withEntry(ItemEntry.builder(Items.ENCHANTED_GOLDEN_APPLE).setWeight(2)).withEntry(EmptyEntry.Serializer().setWeight(15))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(4)).withEntry(ItemEntry.builder(Items.BONE).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.GUNPOWDER).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.STRING).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Blocks.SAND).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F))))).create();
public static LootTable END_CITY_TREASURE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 6.0F)).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 6.0F)))).withEntry(ItemEntry.builder(Items.BEETROOT_SEEDS).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 10.0F)))).withEntry(ItemEntry.builder(Items.SADDLE).setWeight(3)).withEntry(ItemEntry.builder(Items.IRON_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.GOLDEN_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.DIAMOND_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.DIAMOND_SWORD).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.DIAMOND_BOOTS).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.DIAMOND_CHESTPLATE).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.DIAMOND_LEGGINGS).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.DIAMOND_HELMET).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.DIAMOND_PICKAXE).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.DIAMOND_SHOVEL).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.IRON_SWORD).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.IRON_BOOTS).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.IRON_CHESTPLATE).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.IRON_LEGGINGS).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.IRON_HELMET).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.IRON_PICKAXE).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments())).withEntry(ItemEntry.builder(Items.IRON_SHOVEL).setWeight(3).withFunction(EnchantWithLevelsLootFunction.builder(UniformLootTableRange.between(20.0F, 39.0F)).allowTreasureEnchantments()))).create();
public static LootTable IGLOO_CHEST_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 8.0F)).withEntry(ItemEntry.builder(Items.APPLE).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.GOLD_NUGGET).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.STONE_AXE).setWeight(2)).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(10)).withEntry(ItemEntry.builder(Items.EMERALD)).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 3.0F))))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(1)).withEntry(ItemEntry.builder(Items.GOLDEN_APPLE))).create();
public static LootTable JUNGLE_TEMPLE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 6.0F)).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 7.0F)))).withEntry(ItemEntry.builder(Blocks.BAMBOO).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.BONE).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 6.0F)))).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(16).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.SADDLE).setWeight(3)).withEntry(ItemEntry.builder(Items.IRON_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.GOLDEN_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.DIAMOND_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.BOOK).withFunction(EnchantWithLevelsLootFunction.builder(ConstantLootTableRange.create(30)).allowTreasureEnchantments()))).create();
public static LootTable JUNGLE_TEMPLE_DISPENSER_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 2.0F)).withEntry(ItemEntry.builder(Items.ARROW).setWeight(30).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 7.0F))))).create();
public static LootTable NETHER_BRIDGE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 4.0F)).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.GOLDEN_SWORD).setWeight(5)).withEntry(ItemEntry.builder(Items.GOLDEN_CHESTPLATE).setWeight(5)).withEntry(ItemEntry.builder(Items.FLINT_AND_STEEL).setWeight(5)).withEntry(ItemEntry.builder(Items.NETHER_WART).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.SADDLE).setWeight(10)).withEntry(ItemEntry.builder(Items.GOLDEN_HORSE_ARMOR).setWeight(8)).withEntry(ItemEntry.builder(Items.IRON_HORSE_ARMOR).setWeight(5)).withEntry(ItemEntry.builder(Items.DIAMOND_HORSE_ARMOR).setWeight(3)).withEntry(ItemEntry.builder(Blocks.OBSIDIAN).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F))))).create();
public static LootTable PILLAGER_OUTPOST_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(0.0F, 1.0F)).withEntry(ItemEntry.builder(Items.CROSSBOW))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 3.0F)).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(7).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.POTATO).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.CARROT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 5.0F))))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 3.0F)).withEntry(ItemEntry.builder(Blocks.DARK_OAK_LOG).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 3.0F))))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 3.0F)).withEntry(ItemEntry.builder(Items.EXPERIENCE_BOTTLE).setWeight(7)).withEntry(ItemEntry.builder(Items.STRING).setWeight(4).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 6.0F)))).withEntry(ItemEntry.builder(Items.ARROW).setWeight(4).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.TRIPWIRE_HOOK).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.BOOK).setWeight(1).withFunction(EnchantRandomlyLootFunction.builder()))).create();
public static LootTable SHIPWRECK_MAP_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(1)).withEntry(ItemEntry.builder(Items.MAP).withFunction(ExplorationMapLootFunction.create().withDestination("buried_treasure").withDecoration(MapIcon.Type.RED_X).withZoom((byte)1).withSkipExistingChunks(false)))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(3)).withEntry(ItemEntry.builder(Items.COMPASS)).withEntry(ItemEntry.builder(Items.MAP)).withEntry(ItemEntry.builder(Items.CLOCK)).withEntry(ItemEntry.builder(Items.PAPER).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 10.0F)))).withEntry(ItemEntry.builder(Items.FEATHER).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.BOOK).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F))))).create();
public static LootTable SHIPWRECK_SUPPLY_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 10.0F)).withEntry(ItemEntry.builder(Items.PAPER).setWeight(8).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 12.0F)))).withEntry(ItemEntry.builder(Items.POTATO).setWeight(7).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 6.0F)))).withEntry(ItemEntry.builder(Items.POISONOUS_POTATO).setWeight(7).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 6.0F)))).withEntry(ItemEntry.builder(Items.CARROT).setWeight(7).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(7).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(8.0F, 21.0F)))).withEntry(ItemEntry.builder(Items.SUSPICIOUS_STEW).setWeight(10).withFunction(SetStewEffectLootFunction.builder().withEffect(StatusEffects.NIGHT_VISION, UniformLootTableRange.between(7.0F, 10.0F)).withEffect(StatusEffects.JUMP_BOOST, UniformLootTableRange.between(7.0F, 10.0F)).withEffect(StatusEffects.WEAKNESS, UniformLootTableRange.between(6.0F, 8.0F)).withEffect(StatusEffects.BLINDNESS, UniformLootTableRange.between(5.0F, 7.0F)).withEffect(StatusEffects.POISON, UniformLootTableRange.between(10.0F, 20.0F)).withEffect(StatusEffects.SATURATION, UniformLootTableRange.between(7.0F, 10.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(5.0F, 24.0F)))).withEntry(ItemEntry.builder(Blocks.PUMPKIN).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.BAMBOO).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.GUNPOWDER).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Blocks.TNT).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F)))).withEntry(ItemEntry.builder(Items.LEATHER_HELMET).setWeight(3).withFunction(EnchantRandomlyLootFunction.builder())).withEntry(ItemEntry.builder(Items.LEATHER_CHESTPLATE).setWeight(3).withFunction(EnchantRandomlyLootFunction.builder())).withEntry(ItemEntry.builder(Items.LEATHER_LEGGINGS).setWeight(3).withFunction(EnchantRandomlyLootFunction.builder())).withEntry(ItemEntry.builder(Items.LEATHER_BOOTS).setWeight(3).withFunction(EnchantRandomlyLootFunction.builder()))).create();
public static LootTable SHIPWRECK_TREASURE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 6.0F)).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(90).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(40).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(5)).withEntry(ItemEntry.builder(Items.EXPERIENCE_BOTTLE).setWeight(5))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 5.0F)).withEntry(ItemEntry.builder(Items.IRON_NUGGET).setWeight(50).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 10.0F)))).withEntry(ItemEntry.builder(Items.GOLD_NUGGET).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 10.0F)))).withEntry(ItemEntry.builder(Items.LAPIS_LAZULI).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 10.0F))))).create();
public static LootTable SIMPLE_DUNGEON_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 3.0F)).withEntry(ItemEntry.builder(Items.SADDLE).setWeight(20)).withEntry(ItemEntry.builder(Items.GOLDEN_APPLE).setWeight(15)).withEntry(ItemEntry.builder(Items.ENCHANTED_GOLDEN_APPLE).setWeight(2)).withEntry(ItemEntry.builder(Items.MUSIC_DISC_13).setWeight(15)).withEntry(ItemEntry.builder(Items.MUSIC_DISC_CAT).setWeight(15)).withEntry(ItemEntry.builder(Items.NAME_TAG).setWeight(20)).withEntry(ItemEntry.builder(Items.GOLDEN_HORSE_ARMOR).setWeight(10)).withEntry(ItemEntry.builder(Items.IRON_HORSE_ARMOR).setWeight(15)).withEntry(ItemEntry.builder(Items.DIAMOND_HORSE_ARMOR).setWeight(5)).withEntry(ItemEntry.builder(Items.BOOK).setWeight(10).withFunction(EnchantRandomlyLootFunction.builder()))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 4.0F)).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(20)).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BUCKET).setWeight(10)).withEntry(ItemEntry.builder(Items.REDSTONE).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.MELON_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.PUMPKIN_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BEETROOT_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F))))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(3)).withEntry(ItemEntry.builder(Items.BONE).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.GUNPOWDER).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.STRING).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F))))).create();
public static LootTable SPAWN_BONUS_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(1)).withEntry(ItemEntry.builder(Items.STONE_AXE)).withEntry(ItemEntry.builder(Items.WOODEN_AXE).setWeight(3))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(1)).withEntry(ItemEntry.builder(Items.STONE_PICKAXE)).withEntry(ItemEntry.builder(Items.WOODEN_PICKAXE).setWeight(3))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(3)).withEntry(ItemEntry.builder(Items.APPLE).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F)))).withEntry(ItemEntry.builder(Items.SALMON).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F))))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(4)).withEntry(ItemEntry.builder(Items.STICK).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 12.0F)))).withEntry(ItemEntry.builder(Blocks.OAK_PLANKS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 12.0F)))).withEntry(ItemEntry.builder(Blocks.OAK_LOG).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.SPRUCE_LOG).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.BIRCH_LOG).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.JUNGLE_LOG).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.ACACIA_LOG).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.DARK_OAK_LOG).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F))))).create();
public static LootTable STRONGHOLD_CORRIDOR_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 3.0F)).withEntry(ItemEntry.builder(Items.ENDER_PEARL).setWeight(10)).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.REDSTONE).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 9.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.APPLE).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_PICKAXE).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_SWORD).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_CHESTPLATE).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_HELMET).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_LEGGINGS).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_BOOTS).setWeight(5)).withEntry(ItemEntry.builder(Items.GOLDEN_APPLE)).withEntry(ItemEntry.builder(Items.SADDLE)).withEntry(ItemEntry.builder(Items.IRON_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.GOLDEN_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.DIAMOND_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.BOOK).withFunction(EnchantWithLevelsLootFunction.builder(ConstantLootTableRange.create(30)).allowTreasureEnchantments()))).create();
public static LootTable STRONGHOLD_CROSSING_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 4.0F)).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.REDSTONE).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(4.0F, 9.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.APPLE).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_PICKAXE)).withEntry(ItemEntry.builder(Items.BOOK).withFunction(EnchantWithLevelsLootFunction.builder(ConstantLootTableRange.create(30)).allowTreasureEnchantments()))).create();
public static LootTable STRONGHOLD_LIBRARY_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 10.0F)).withEntry(ItemEntry.builder(Items.BOOK).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.PAPER).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.MAP)).withEntry(ItemEntry.builder(Items.COMPASS)).withEntry(ItemEntry.builder(Items.BOOK).setWeight(10).withFunction(EnchantWithLevelsLootFunction.builder(ConstantLootTableRange.create(30)).allowTreasureEnchantments()))).create();
public static LootTable UNDERWATER_RUIN_BIG_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 8.0F)).withEntry(ItemEntry.builder(Items.COAL).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.GOLD_NUGGET).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.EMERALD)).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 3.0F))))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(1)).withEntry(ItemEntry.builder(Items.GOLDEN_APPLE)).withEntry(ItemEntry.builder(Items.BOOK).setWeight(5).withFunction(EnchantRandomlyLootFunction.builder())).withEntry(ItemEntry.builder(Items.LEATHER_CHESTPLATE)).withEntry(ItemEntry.builder(Items.GOLDEN_HELMET)).withEntry(ItemEntry.builder(Items.FISHING_ROD).setWeight(5).withFunction(EnchantRandomlyLootFunction.builder())).withEntry(ItemEntry.builder(Items.MAP).setWeight(10).withFunction(ExplorationMapLootFunction.create().withDestination("buried_treasure").withDecoration(MapIcon.Type.RED_X).withZoom((byte)1).withSkipExistingChunks(false)))).create();
public static LootTable UNDERWATER_RUIN_SMALL_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(2.0F, 8.0F)).withEntry(ItemEntry.builder(Items.COAL).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.STONE_AXE).setWeight(2)).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(5)).withEntry(ItemEntry.builder(Items.EMERALD)).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 3.0F))))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(1)).withEntry(ItemEntry.builder(Items.LEATHER_CHESTPLATE)).withEntry(ItemEntry.builder(Items.GOLDEN_HELMET)).withEntry(ItemEntry.builder(Items.FISHING_ROD).setWeight(5).withFunction(EnchantRandomlyLootFunction.builder())).withEntry(ItemEntry.builder(Items.MAP).setWeight(5).withFunction(ExplorationMapLootFunction.create().withDestination("buried_treasure").withDecoration(MapIcon.Type.RED_X).withZoom((byte)1).withSkipExistingChunks(false)))).create();
public static LootTable VILLAGE_WEAPONSMITH_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 8.0F)).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.APPLE).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_PICKAXE).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_SWORD).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_CHESTPLATE).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_HELMET).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_LEGGINGS).setWeight(5)).withEntry(ItemEntry.builder(Items.IRON_BOOTS).setWeight(5)).withEntry(ItemEntry.builder(Blocks.OBSIDIAN).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 7.0F)))).withEntry(ItemEntry.builder(Blocks.OAK_SAPLING).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(3.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.SADDLE).setWeight(3)).withEntry(ItemEntry.builder(Items.IRON_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.GOLDEN_HORSE_ARMOR)).withEntry(ItemEntry.builder(Items.DIAMOND_HORSE_ARMOR))).create();
public static LootTable VILLAGE_TOOLSMITH_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 8.0F)).withEntry(ItemEntry.builder(Items.DIAMOND).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_PICKAXE).setWeight(5)).withEntry(ItemEntry.builder(Items.COAL).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.STICK).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.IRON_SHOVEL).setWeight(5))).create();
public static LootTable VILLAGE_CARTOGRAPHER_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 5.0F)).withEntry(ItemEntry.builder(Items.MAP).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.PAPER).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.COMPASS).setWeight(5)).withEntry(ItemEntry.builder(Items.BREAD).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.STICK).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F))))).create();
public static LootTable VILLAGE_MASON_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 5.0F)).withEntry(ItemEntry.builder(Items.CLAY_BALL).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.FLOWER_POT).setWeight(1)).withEntry(ItemEntry.builder(Blocks.STONE).setWeight(2)).withEntry(ItemEntry.builder(Blocks.STONE_BRICKS).setWeight(2)).withEntry(ItemEntry.builder(Items.BREAD).setWeight(4).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.YELLOW_DYE).setWeight(1)).withEntry(ItemEntry.builder(Blocks.SMOOTH_STONE).setWeight(1)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1))).create();
public static LootTable VILLAGE_ARMORER_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 5.0F)).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(4).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.IRON_HELMET).setWeight(1)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1))).create();
public static LootTable VILLAGE_SHEPARD_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 5.0F)).withEntry(ItemEntry.builder(Blocks.WHITE_WOOL).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Blocks.BLACK_WOOL).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.GRAY_WOOL).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.BROWN_WOOL).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Blocks.LIGHT_GRAY_WOOL).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1)).withEntry(ItemEntry.builder(Items.SHEARS).setWeight(1)).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 6.0F))))).create();
public static LootTable VILLAGE_BUTCHER_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 5.0F)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1)).withEntry(ItemEntry.builder(Items.PORKCHOP).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.BEEF).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.MUTTON).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F))))).create();
public static LootTable VILLAGE_FLETCHER_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 5.0F)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1)).withEntry(ItemEntry.builder(Items.ARROW).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.FEATHER).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.EGG).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.FLINT).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.STICK).setWeight(6).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F))))).create();
public static LootTable VILLAGE_FISHER_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 5.0F)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1)).withEntry(ItemEntry.builder(Items.COD).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.SALMON).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.WATER_BUCKET).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.BARREL).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.WHEAT_SEEDS).setWeight(3).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F))))).create();
public static LootTable VILLAGE_TANNERY_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 5.0F)).withEntry(ItemEntry.builder(Items.LEATHER).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.LEATHER_CHESTPLATE).setWeight(2)).withEntry(ItemEntry.builder(Items.LEATHER_BOOTS).setWeight(2)).withEntry(ItemEntry.builder(Items.LEATHER_HELMET).setWeight(2)).withEntry(ItemEntry.builder(Items.BREAD).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.LEATHER_LEGGINGS).setWeight(2)).withEntry(ItemEntry.builder(Items.SADDLE).setWeight(1)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F))))).create();
public static LootTable VILLAGE_TEMPLE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 8.0F)).withEntry(ItemEntry.builder(Items.REDSTONE).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(7).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(7).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.LAPIS_LAZULI).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F))))).create();
public static LootTable VILLAGE_PLAINS_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 8.0F)).withEntry(ItemEntry.builder(Items.GOLD_NUGGET).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.DANDELION).setWeight(2)).withEntry(ItemEntry.builder(Items.POPPY).setWeight(1)).withEntry(ItemEntry.builder(Items.POTATO).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.APPLE).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.BOOK).setWeight(1)).withEntry(ItemEntry.builder(Items.FEATHER).setWeight(1)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Blocks.OAK_SAPLING).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F))))).create();
public static LootTable VILLAGE_TAIGA_HOUSE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 8.0F)).withEntry(ItemEntry.builder(Items.IRON_NUGGET).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.FERN).setWeight(2)).withEntry(ItemEntry.builder(Items.LARGE_FERN).setWeight(2)).withEntry(ItemEntry.builder(Items.POTATO).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.SWEET_BERRIES).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.PUMPKIN_SEEDS).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.PUMPKIN_PIE).setWeight(1)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Blocks.SPRUCE_SAPLING).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.SPRUCE_SIGN).setWeight(1)).withEntry(ItemEntry.builder(Items.SPRUCE_LOG).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F))))).create();
public static LootTable VILLAGE_SAVANNA_HOUSE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 8.0F)).withEntry(ItemEntry.builder(Items.GOLD_NUGGET).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.GRASS).setWeight(5)).withEntry(ItemEntry.builder(Items.TALL_GRASS).setWeight(5)).withEntry(ItemEntry.builder(Items.BREAD).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.WHEAT_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Blocks.ACACIA_SAPLING).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F)))).withEntry(ItemEntry.builder(Items.SADDLE).setWeight(1)).withEntry(ItemEntry.builder(Blocks.TORCH).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 2.0F)))).withEntry(ItemEntry.builder(Items.BUCKET).setWeight(1))).create();
public static LootTable VILLAGE_SNOWY_HOUSE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 8.0F)).withEntry(ItemEntry.builder(Blocks.BLUE_ICE).setWeight(1)).withEntry(ItemEntry.builder(Blocks.SNOW_BLOCK).setWeight(4)).withEntry(ItemEntry.builder(Items.POTATO).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BEETROOT_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 5.0F)))).withEntry(ItemEntry.builder(Items.BEETROOT_SOUP).setWeight(1)).withEntry(ItemEntry.builder(Items.FURNACE).setWeight(1)).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.SNOWBALL).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F))))).create();
public static LootTable VILLAGE_DESERT_HOUSE_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(3.0F, 8.0F)).withEntry(ItemEntry.builder(Items.CLAY_BALL).setWeight(1)).withEntry(ItemEntry.builder(Items.GREEN_DYE).setWeight(1)).withEntry(ItemEntry.builder(Blocks.CACTUS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 7.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BOOK).setWeight(1)).withEntry(ItemEntry.builder(Blocks.DEAD_BUSH).setWeight(2).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F)))).withEntry(ItemEntry.builder(Items.EMERALD).setWeight(1).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 3.0F))))).create();
public static LootTable WOODLAND_MANSION_CHEST = LootTable.builder().withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 3.0F)).withEntry(ItemEntry.builder(Items.LEAD).setWeight(20)).withEntry(ItemEntry.builder(Items.GOLDEN_APPLE).setWeight(15)).withEntry(ItemEntry.builder(Items.ENCHANTED_GOLDEN_APPLE).setWeight(2)).withEntry(ItemEntry.builder(Items.MUSIC_DISC_13).setWeight(15)).withEntry(ItemEntry.builder(Items.MUSIC_DISC_CAT).setWeight(15)).withEntry(ItemEntry.builder(Items.NAME_TAG).setWeight(20)).withEntry(ItemEntry.builder(Items.CHAINMAIL_CHESTPLATE).setWeight(10)).withEntry(ItemEntry.builder(Items.DIAMOND_HOE).setWeight(15)).withEntry(ItemEntry.builder(Items.DIAMOND_CHESTPLATE).setWeight(5)).withEntry(ItemEntry.builder(Items.BOOK).setWeight(10).withFunction(EnchantRandomlyLootFunction.builder()))).withPool(LootPool.builder().withRolls(UniformLootTableRange.between(1.0F, 4.0F)).withEntry(ItemEntry.builder(Items.IRON_INGOT).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.GOLD_INGOT).setWeight(5).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BREAD).setWeight(20)).withEntry(ItemEntry.builder(Items.WHEAT).setWeight(20).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BUCKET).setWeight(10)).withEntry(ItemEntry.builder(Items.REDSTONE).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.COAL).setWeight(15).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.MELON_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.PUMPKIN_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F)))).withEntry(ItemEntry.builder(Items.BEETROOT_SEEDS).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(2.0F, 4.0F))))).withPool(LootPool.builder().withRolls(ConstantLootTableRange.create(3)).withEntry(ItemEntry.builder(Items.BONE).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.GUNPOWDER).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.ROTTEN_FLESH).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F)))).withEntry(ItemEntry.builder(Items.STRING).setWeight(10).withFunction(SetCountLootFunction.builder(UniformLootTableRange.between(1.0F, 8.0F))))).create();
}
@@ -0,0 +1,14 @@
package kaptainwutax.seedcracker.util.math;
import java.util.function.BiPredicate;
public class Predicates {
public static BiPredicate<Integer, Integer> EQUAL_TO = Integer::equals;
public static BiPredicate<Integer, Integer> NOT_EQUAL_TO = (a, b) -> !a.equals(b);
public static BiPredicate<Integer, Integer> LESS_THAN = (a, b) -> a < b;
public static BiPredicate<Integer, Integer> MORE_THAN = (a, b) -> a > b;
public static BiPredicate<Integer, Integer> LESS_OR_EQUAL_TO = (a, b) -> a <= b;
public static BiPredicate<Integer, Integer> MORE_OR_EQUAL_TO = (a, b) -> a >= b;
}
@@ -0,0 +1,4 @@
{
"key.categories.seedcracker": "Seed Cracker",
"key.open_menu": "Open Menu"
}
@@ -0,0 +1,6 @@
{
"parent": "item/handheld",
"textures": {
"layer0": "seedcracker:item/gui_item"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

+7 -1
View File
@@ -27,9 +27,15 @@
],
"depends": {
"fabricloader": ">=0.4.0"
"fabricloader": ">=0.4.0",
"fabric": "*",
"minecraft": ">=1.15"
},
"suggests": {
"flamingo": "*"
},
"custom": {
"modmenu:api": true,
"modmenu:clientsideOnly": true
}
}
+3 -1
View File
@@ -9,7 +9,9 @@
"GameRendererMixin",
"ClientPlayNetworkHandlerMixin",
"ClientWorldMixin",
"ClientPlayerEntityMixin"
"ClientPlayerEntityMixin",
"GameOptionsMixin",
"KeyBindingMixin"
],
"injectors": {
"defaultRequire": 1