mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-02 07:55:28 +00:00
Initial commit
This commit is contained in:
commit
65b52e76ec
3
common/addons/config-structure/README.md
Normal file
3
common/addons/config-structure/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# config-structure
|
||||||
|
|
||||||
|
Registers the default configuration for Terra Structures, `STRUCTURE`.
|
3
common/addons/config-structure/build.gradle.kts
Normal file
3
common/addons/config-structure/build.gradle.kts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dependencies {
|
||||||
|
"shadedApi"("com.googlecode.json-simple:json-simple:1.1.1")
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.dfsek.terra.addons.structure;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.properties.Properties;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
|
||||||
|
|
||||||
|
public class BiomeStructures implements Properties {
|
||||||
|
private final Set<ConfiguredStructure> structures;
|
||||||
|
|
||||||
|
public BiomeStructures(Set<ConfiguredStructure> structures) {
|
||||||
|
this.structures = structures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ConfiguredStructure> getStructures() {
|
||||||
|
return structures;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.dfsek.terra.addons.structure;
|
||||||
|
|
||||||
|
import com.dfsek.tectonic.annotations.Default;
|
||||||
|
import com.dfsek.tectonic.annotations.Value;
|
||||||
|
import com.dfsek.tectonic.loading.object.ObjectTemplate;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.config.meta.Meta;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
|
||||||
|
|
||||||
|
public class BiomeStructuresTemplate implements ObjectTemplate<BiomeStructures> {
|
||||||
|
@Value("structures")
|
||||||
|
@Default
|
||||||
|
private @Meta Set<@Meta ConfiguredStructure> structures = Collections.emptySet();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BiomeStructures get() {
|
||||||
|
return new BiomeStructures(structures);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.dfsek.terra.addons.structure;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.addon.TerraAddon;
|
||||||
|
import com.dfsek.terra.api.addon.annotations.Addon;
|
||||||
|
import com.dfsek.terra.api.addon.annotations.Author;
|
||||||
|
import com.dfsek.terra.api.addon.annotations.Version;
|
||||||
|
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
|
||||||
|
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||||
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
|
||||||
|
|
||||||
|
@Addon("config-structure")
|
||||||
|
@Version("1.0.0")
|
||||||
|
@Author("Terra")
|
||||||
|
public class StructureAddon extends TerraAddon {
|
||||||
|
@Inject
|
||||||
|
private Platform platform;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
platform.getEventManager()
|
||||||
|
.getHandler(FunctionalEventHandler.class)
|
||||||
|
.register(this, ConfigPackPreLoadEvent.class)
|
||||||
|
.then(event -> event.getPack().applyLoader(ConfiguredStructure.class, (t, o, l) -> null))
|
||||||
|
.failThrough();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.dfsek.terra.addons.structure;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.config.ConfigFactory;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
|
||||||
|
|
||||||
|
public class StructureFactory implements ConfigFactory<StructureTemplate, ConfiguredStructure> {
|
||||||
|
@Override
|
||||||
|
public ConfiguredStructure build(StructureTemplate config, Platform platform) {
|
||||||
|
return new TerraStructure(config.getStructures(), config.getY(), config.getSpawn());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package com.dfsek.terra.addons.structure;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
|
||||||
|
import net.jafama.FastMath;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.config.WorldConfig;
|
||||||
|
import com.dfsek.terra.api.profiler.ProfileFrame;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
import com.dfsek.terra.api.structure.rotation.Rotation;
|
||||||
|
import com.dfsek.terra.api.util.PopulationUtil;
|
||||||
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
|
import com.dfsek.terra.api.world.Chunk;
|
||||||
|
import com.dfsek.terra.api.world.World;
|
||||||
|
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||||
|
import com.dfsek.terra.api.world.generator.Chunkified;
|
||||||
|
import com.dfsek.terra.api.world.generator.GenerationStage;
|
||||||
|
|
||||||
|
|
||||||
|
public class StructurePopulator implements GenerationStage, Chunkified {
|
||||||
|
private final Platform platform;
|
||||||
|
|
||||||
|
public StructurePopulator(Platform platform) {
|
||||||
|
this.platform = platform;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("try")
|
||||||
|
@Override
|
||||||
|
public void populate(@NotNull World world, @NotNull Chunk chunk) {
|
||||||
|
try(ProfileFrame ignore = platform.getProfiler().profile("structure")) {
|
||||||
|
if(world.getConfig().disableStructures()) return;
|
||||||
|
|
||||||
|
int cx = (chunk.getX() << 4);
|
||||||
|
int cz = (chunk.getZ() << 4);
|
||||||
|
BiomeProvider provider = world.getBiomeProvider();
|
||||||
|
WorldConfig config = world.getConfig();
|
||||||
|
for(ConfiguredStructure conf : config.getRegistry(TerraStructure.class).entries()) {
|
||||||
|
Vector3 spawn = conf.getSpawn().getNearestSpawn(cx + 8, cz + 8, world.getSeed());
|
||||||
|
|
||||||
|
if(!provider.getBiome(spawn, world.getSeed()).getContext().get(BiomeStructures.class).getStructures().contains(conf)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Random random = new Random(PopulationUtil.getCarverChunkSeed(FastMath.floorDiv(spawn.getBlockX(), 16),
|
||||||
|
FastMath.floorDiv(spawn.getBlockZ(), 16), world.getSeed()));
|
||||||
|
conf.getStructure().get(random).generate(spawn.setY(conf.getSpawnStart().get(random)), world, chunk, random,
|
||||||
|
Rotation.fromDegrees(90 * random.nextInt(4)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.dfsek.terra.addons.structure;
|
||||||
|
|
||||||
|
import com.dfsek.tectonic.annotations.Final;
|
||||||
|
import com.dfsek.tectonic.annotations.Value;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.config.AbstractableTemplate;
|
||||||
|
import com.dfsek.terra.api.config.meta.Meta;
|
||||||
|
import com.dfsek.terra.api.structure.Structure;
|
||||||
|
import com.dfsek.terra.api.structure.StructureSpawn;
|
||||||
|
import com.dfsek.terra.api.util.Range;
|
||||||
|
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unused", "FieldMayBeFinal" })
|
||||||
|
public class StructureTemplate implements AbstractableTemplate {
|
||||||
|
@Value("id")
|
||||||
|
@Final
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Value("scripts")
|
||||||
|
private @Meta ProbabilityCollection<@Meta Structure> structure;
|
||||||
|
|
||||||
|
@Value("spawn.start")
|
||||||
|
private @Meta Range y;
|
||||||
|
|
||||||
|
@Value("spawn")
|
||||||
|
private @Meta StructureSpawn spawn;
|
||||||
|
|
||||||
|
public String getID() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProbabilityCollection<Structure> getStructures() {
|
||||||
|
return structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Range getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StructureSpawn getSpawn() {
|
||||||
|
return spawn;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.dfsek.terra.addons.structure;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.structure.Structure;
|
||||||
|
import com.dfsek.terra.api.structure.StructureSpawn;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
import com.dfsek.terra.api.util.Range;
|
||||||
|
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||||
|
|
||||||
|
|
||||||
|
public class TerraStructure implements ConfiguredStructure {
|
||||||
|
private final ProbabilityCollection<Structure> structure;
|
||||||
|
private final Range spawnStart;
|
||||||
|
private final StructureSpawn spawn;
|
||||||
|
|
||||||
|
public TerraStructure(ProbabilityCollection<Structure> structures, Range spawnStart, StructureSpawn spawn) {
|
||||||
|
this.structure = structures;
|
||||||
|
this.spawnStart = spawnStart;
|
||||||
|
this.spawn = spawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProbabilityCollection<Structure> getStructure() {
|
||||||
|
return structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Range getSpawnStart() {
|
||||||
|
return spawnStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StructureSpawn getSpawn() {
|
||||||
|
return spawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getID() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
|
import com.dfsek.terra.api.world.World;
|
||||||
|
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||||
|
|
||||||
|
|
||||||
|
public class AsyncStructureFinder implements Runnable {
|
||||||
|
protected final BiomeProvider provider;
|
||||||
|
protected final ConfiguredStructure target;
|
||||||
|
protected final int startRadius;
|
||||||
|
protected final int maxRadius;
|
||||||
|
protected final int centerX;
|
||||||
|
protected final int centerZ;
|
||||||
|
protected final World world;
|
||||||
|
protected final Platform platform;
|
||||||
|
private final Consumer<Vector3> callback;
|
||||||
|
protected int searchSize = 1;
|
||||||
|
|
||||||
|
public AsyncStructureFinder(BiomeProvider provider, ConfiguredStructure target, @NotNull Vector3 origin, World world, int startRadius,
|
||||||
|
int maxRadius, Consumer<Vector3> callback, Platform platform) {
|
||||||
|
//setSearchSize(target.getSpawn().getWidth() + 2 * target.getSpawn().getSeparation());
|
||||||
|
this.provider = provider;
|
||||||
|
this.target = target;
|
||||||
|
this.platform = platform;
|
||||||
|
this.startRadius = startRadius;
|
||||||
|
this.maxRadius = maxRadius;
|
||||||
|
this.centerX = origin.getBlockX();
|
||||||
|
this.centerZ = origin.getBlockZ();
|
||||||
|
this.world = world;
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 finalizeVector(Vector3 orig) {
|
||||||
|
return orig;//target.getSpawn().getChunkSpawn(orig.getBlockX(), orig.getBlockZ(), world.getSeed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int x = centerX;
|
||||||
|
int z = centerZ;
|
||||||
|
|
||||||
|
x /= searchSize;
|
||||||
|
z /= searchSize;
|
||||||
|
|
||||||
|
int run = 1;
|
||||||
|
boolean toggle = true;
|
||||||
|
boolean found = false;
|
||||||
|
|
||||||
|
main:
|
||||||
|
for(int i = startRadius; i < maxRadius; i++) {
|
||||||
|
for(int j = 0; j < run; j++) {
|
||||||
|
if(isValid(x, z, target)) {
|
||||||
|
found = true;
|
||||||
|
break main;
|
||||||
|
}
|
||||||
|
if(toggle) x += 1;
|
||||||
|
else x -= 1;
|
||||||
|
}
|
||||||
|
for(int j = 0; j < run; j++) {
|
||||||
|
if(isValid(x, z, target)) {
|
||||||
|
found = true;
|
||||||
|
break main;
|
||||||
|
}
|
||||||
|
if(toggle) z += 1;
|
||||||
|
else z -= 1;
|
||||||
|
}
|
||||||
|
run++;
|
||||||
|
toggle = !toggle;
|
||||||
|
}
|
||||||
|
Vector3 finalSpawn = found ? finalizeVector(new Vector3(x, 0, z)) : null;
|
||||||
|
callback.accept(finalSpawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid(int x, int z, ConfiguredStructure target) {
|
||||||
|
//Vector3 spawn = target.getSpawn().getChunkSpawn(x, z, world.getSeed());
|
||||||
|
//if(!((UserDefinedBiome) provider.getBiome(spawn)).getConfig().getStructures().contains(target)) return false;
|
||||||
|
//Random random = new Random(PopulationUtil.getCarverChunkSeed(FastMath.floorDiv(spawn.getBlockX(), 16), FastMath.floorDiv(spawn
|
||||||
|
// .getBlockZ(), 16), world.getSeed()));
|
||||||
|
//return target.getStructure().get(random).test(spawn.setY(target.getSpawnStart().get(random)), world, random, Rotation
|
||||||
|
// .fromDegrees(90 * random.nextInt(4)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfiguredStructure getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public World getWorld() {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BiomeProvider getProvider() {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSearchSize() {
|
||||||
|
return searchSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchSize(int searchSize) {
|
||||||
|
this.searchSize = searchSize;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.command.CommandTemplate;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Command;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Subcommand;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
subcommands = {
|
||||||
|
@Subcommand(
|
||||||
|
clazz = StructureExportCommand.class,
|
||||||
|
value = "export",
|
||||||
|
aliases = "ex"
|
||||||
|
),
|
||||||
|
@Subcommand(
|
||||||
|
clazz = StructureLoadCommand.class,
|
||||||
|
value = "load",
|
||||||
|
aliases = "ld"
|
||||||
|
),
|
||||||
|
@Subcommand(
|
||||||
|
clazz = StructureLocateCommand.class,
|
||||||
|
value = "locate",
|
||||||
|
aliases = "l"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
usage = "/te structure"
|
||||||
|
)
|
||||||
|
public class StructureCommand implements CommandTemplate {
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender) {
|
||||||
|
//LangUtil.send("command.structure.main-menu", sender);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.block.entity.BlockEntity;
|
||||||
|
import com.dfsek.terra.api.block.entity.Sign;
|
||||||
|
import com.dfsek.terra.api.block.state.BlockState;
|
||||||
|
import com.dfsek.terra.api.command.CommandTemplate;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Argument;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Command;
|
||||||
|
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||||
|
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||||
|
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||||
|
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
import com.dfsek.terra.api.entity.Player;
|
||||||
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||||
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
|
|
||||||
|
|
||||||
|
@PlayerCommand
|
||||||
|
@WorldCommand
|
||||||
|
@DebugCommand
|
||||||
|
@Command(arguments = @Argument("id"), usage = "/terra structure export <ID>")
|
||||||
|
public class StructureExportCommand implements CommandTemplate {
|
||||||
|
@Inject
|
||||||
|
private Platform platform;
|
||||||
|
|
||||||
|
@ArgumentTarget("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
|
||||||
|
Pair<Vector3, Vector3> l = platform.getWorldHandle().getSelectedLocation(player);
|
||||||
|
|
||||||
|
Vector3 l1 = l.getLeft();
|
||||||
|
Vector3 l2 = l.getRight();
|
||||||
|
|
||||||
|
StringBuilder scriptBuilder = new StringBuilder("id \"" + id + "\";\nnum y = 0;\n");
|
||||||
|
|
||||||
|
int centerX = 0;
|
||||||
|
int centerY = 0;
|
||||||
|
int centerZ = 0;
|
||||||
|
|
||||||
|
for(int x = l1.getBlockX(); x <= l2.getBlockX(); x++) {
|
||||||
|
for(int y = l1.getBlockY(); y <= l2.getBlockY(); y++) {
|
||||||
|
for(int z = l1.getBlockZ(); z <= l2.getBlockZ(); z++) {
|
||||||
|
BlockEntity state = player.world().getBlockState(x, y, z);
|
||||||
|
if(state instanceof Sign) {
|
||||||
|
Sign sign = (Sign) state;
|
||||||
|
if(sign.getLine(0).equals("[TERRA]") && sign.getLine(1).equals("[CENTER]")) {
|
||||||
|
centerX = x - l1.getBlockX();
|
||||||
|
centerY = y - l1.getBlockY();
|
||||||
|
centerZ = z - l1.getBlockZ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int x = l1.getBlockX(); x <= l2.getBlockX(); x++) {
|
||||||
|
for(int y = l1.getBlockY(); y <= l2.getBlockY(); y++) {
|
||||||
|
for(int z = l1.getBlockZ(); z <= l2.getBlockZ(); z++) {
|
||||||
|
|
||||||
|
BlockState data = player.world().getBlockData(x, y, z);
|
||||||
|
if(data.isStructureVoid()) continue;
|
||||||
|
BlockEntity state = player.world().getBlockState(x, y, z);
|
||||||
|
if(state instanceof Sign) {
|
||||||
|
Sign sign = (Sign) state;
|
||||||
|
if(sign.getLine(0).equals("[TERRA]")) {
|
||||||
|
data = platform.getWorldHandle().createBlockData(sign.getLine(2) + sign.getLine(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!data.isStructureVoid()) {
|
||||||
|
scriptBuilder.append("block(").append(x - l1.getBlockX() - centerX).append(", y + ").append(
|
||||||
|
y - l1.getBlockY() - centerY).append(", ").append(z - l1.getBlockZ() - centerZ).append(", ")
|
||||||
|
.append("\"");
|
||||||
|
scriptBuilder.append(data.getAsString()).append("\");\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File file = new File(platform.getDataFolder() + File.separator + "export" + File.separator + "structures", id + ".tesf");
|
||||||
|
try {
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
file.createNewFile();
|
||||||
|
} catch(IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
try(BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||||
|
writer.write(scriptBuilder.toString());
|
||||||
|
} catch(IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
sender.sendMessage("Exported structure to " + file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.structure.command.structure.argument.ScriptArgumentParser;
|
||||||
|
import com.dfsek.terra.addons.structure.command.structure.completer.RotationCompleter;
|
||||||
|
import com.dfsek.terra.addons.structure.command.structure.completer.ScriptCompleter;
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.command.CommandTemplate;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Argument;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Command;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Switch;
|
||||||
|
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||||
|
import com.dfsek.terra.api.command.annotation.inject.SwitchTarget;
|
||||||
|
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||||
|
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||||
|
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||||
|
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
import com.dfsek.terra.api.entity.Player;
|
||||||
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.structure.Structure;
|
||||||
|
import com.dfsek.terra.api.structure.rotation.Rotation;
|
||||||
|
|
||||||
|
|
||||||
|
@PlayerCommand
|
||||||
|
@DebugCommand
|
||||||
|
@WorldCommand
|
||||||
|
@Command(arguments = {
|
||||||
|
@Argument(
|
||||||
|
value = "structure",
|
||||||
|
tabCompleter = ScriptCompleter.class,
|
||||||
|
argumentParser = ScriptArgumentParser.class
|
||||||
|
),
|
||||||
|
@Argument(
|
||||||
|
value = "rotation",
|
||||||
|
required = false,
|
||||||
|
tabCompleter = RotationCompleter.class,
|
||||||
|
argumentParser = IntegerArgumentParser.class,
|
||||||
|
defaultValue = "0"
|
||||||
|
)
|
||||||
|
}, switches = @Switch(value = "chunk",
|
||||||
|
aliases = "c"
|
||||||
|
), usage = "/terra structure load [ROTATION] [-c]")
|
||||||
|
public class StructureLoadCommand implements CommandTemplate {
|
||||||
|
@ArgumentTarget("rotation")
|
||||||
|
private final Integer rotation = 0;
|
||||||
|
|
||||||
|
@SwitchTarget("chunk")
|
||||||
|
private boolean chunk;
|
||||||
|
|
||||||
|
@ArgumentTarget("structure")
|
||||||
|
private Structure script;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Platform platform;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
|
||||||
|
long t = System.nanoTime();
|
||||||
|
Random random = new Random(ThreadLocalRandom.current().nextLong());
|
||||||
|
Rotation r;
|
||||||
|
try {
|
||||||
|
r = Rotation.fromDegrees(rotation);
|
||||||
|
} catch(Exception e) {
|
||||||
|
sender.sendMessage("Invalid rotation: " + rotation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(script == null) {
|
||||||
|
sender.sendMessage("Invalid structure.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(this.chunk) {
|
||||||
|
script.generate(player.position(), player.world(), player.world().getChunkAt(player.position()), random, r);
|
||||||
|
} else {
|
||||||
|
script.generate(player.position(), player.world(), random, r);
|
||||||
|
}
|
||||||
|
long l = System.nanoTime() - t;
|
||||||
|
|
||||||
|
sender.sendMessage("Took " + ((double) l) / 1000000 + "ms");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.structure.command.AsyncStructureFinder;
|
||||||
|
import com.dfsek.terra.addons.structure.command.structure.argument.StructureArgumentParser;
|
||||||
|
import com.dfsek.terra.addons.structure.command.structure.completer.StructureCompleter;
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.command.CommandTemplate;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Argument;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Command;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Switch;
|
||||||
|
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||||
|
import com.dfsek.terra.api.command.annotation.inject.SwitchTarget;
|
||||||
|
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||||
|
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||||
|
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
import com.dfsek.terra.api.entity.Player;
|
||||||
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
|
|
||||||
|
|
||||||
|
@PlayerCommand
|
||||||
|
@WorldCommand
|
||||||
|
@Command(arguments = {
|
||||||
|
@Argument(
|
||||||
|
value = "structure",
|
||||||
|
tabCompleter = StructureCompleter.class,
|
||||||
|
argumentParser = StructureArgumentParser.class
|
||||||
|
),
|
||||||
|
@Argument(
|
||||||
|
value = "radius",
|
||||||
|
required = false,
|
||||||
|
defaultValue = "100",
|
||||||
|
argumentParser = IntegerArgumentParser.class
|
||||||
|
)
|
||||||
|
}, switches = @Switch(
|
||||||
|
value = "teleport",
|
||||||
|
aliases = { "t", "tp" }
|
||||||
|
))
|
||||||
|
public class StructureLocateCommand implements CommandTemplate {
|
||||||
|
@Inject
|
||||||
|
private Platform platform;
|
||||||
|
|
||||||
|
@ArgumentTarget("structure")
|
||||||
|
private ConfiguredStructure structure;
|
||||||
|
|
||||||
|
@ArgumentTarget("radius")
|
||||||
|
private Integer radius;
|
||||||
|
|
||||||
|
@SwitchTarget("teleport")
|
||||||
|
private boolean teleport;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
|
||||||
|
new Thread(new AsyncStructureFinder(player.world().getBiomeProvider(), structure,
|
||||||
|
player.position().clone().multiply((1D / platform.getTerraConfig().getBiomeSearchResolution())),
|
||||||
|
player.world(), 0, radius, location -> {
|
||||||
|
if(location != null) {
|
||||||
|
sender.sendMessage(
|
||||||
|
String.format("The nearest %s is at [%d, ~, %d] (%.1f blocks away)", structure.getID().toLowerCase(Locale.ROOT),
|
||||||
|
location.getBlockX(), location.getBlockZ(),
|
||||||
|
location.add(new Vector3(0, player.position().getY(), 0)).distance(player.position())));
|
||||||
|
if(teleport) {
|
||||||
|
platform.runPossiblyUnsafeTask(
|
||||||
|
() -> player.position(new Vector3(location.getX(), player.position().getY(), location.getZ())));
|
||||||
|
}
|
||||||
|
} //else LangUtil.send("command.biome.unable-to-locate", sender);
|
||||||
|
}, platform), "Biome Location Thread").start();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure.argument;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.command.arg.ArgumentParser;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
import com.dfsek.terra.api.entity.Player;
|
||||||
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.structure.Structure;
|
||||||
|
|
||||||
|
|
||||||
|
public class ScriptArgumentParser implements ArgumentParser<Structure> {
|
||||||
|
@Inject
|
||||||
|
private Platform platform;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Structure parse(CommandSender sender, String arg) {
|
||||||
|
return ((Player) sender).world().getConfig().getRegistry(Structure.class).get(arg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure.argument;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.command.arg.ArgumentParser;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
import com.dfsek.terra.api.entity.Player;
|
||||||
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
|
||||||
|
|
||||||
|
public class StructureArgumentParser implements ArgumentParser<ConfiguredStructure> {
|
||||||
|
@Inject
|
||||||
|
private Platform platform;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfiguredStructure parse(CommandSender sender, String arg) {
|
||||||
|
return ((Player) sender).world().getConfig().getRegistry(ConfiguredStructure.class).get(arg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure.completer;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.command.tab.TabCompleter;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
|
||||||
|
|
||||||
|
public class RotationCompleter implements TabCompleter {
|
||||||
|
@Override
|
||||||
|
public List<String> complete(CommandSender sender) {
|
||||||
|
return Arrays.asList("0", "90", "180", "270");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure.completer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.command.tab.TabCompleter;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
import com.dfsek.terra.api.entity.Player;
|
||||||
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.structure.Structure;
|
||||||
|
|
||||||
|
|
||||||
|
public class ScriptCompleter implements TabCompleter {
|
||||||
|
@Inject
|
||||||
|
private Platform platform;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> complete(CommandSender sender) {
|
||||||
|
return ((Player) sender).world().getConfig().getRegistry(Structure.class).entries().stream().map(Structure::getID).collect(
|
||||||
|
Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.command.structure.completer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.command.tab.TabCompleter;
|
||||||
|
import com.dfsek.terra.api.entity.CommandSender;
|
||||||
|
import com.dfsek.terra.api.entity.Player;
|
||||||
|
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||||
|
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
||||||
|
|
||||||
|
|
||||||
|
public class StructureCompleter implements TabCompleter {
|
||||||
|
@Inject
|
||||||
|
private Platform platform;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> complete(CommandSender sender) {
|
||||||
|
Player player = (Player) sender;
|
||||||
|
return new ArrayList<>(player.world().getConfig().getRegistry(ConfiguredStructure.class).keys());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.structures.loot;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
|
||||||
|
import net.jafama.FastMath;
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.dfsek.terra.addons.structure.structures.loot.functions.AmountFunction;
|
||||||
|
import com.dfsek.terra.addons.structure.structures.loot.functions.DamageFunction;
|
||||||
|
import com.dfsek.terra.addons.structure.structures.loot.functions.EnchantFunction;
|
||||||
|
import com.dfsek.terra.addons.structure.structures.loot.functions.LootFunction;
|
||||||
|
import com.dfsek.terra.api.inventory.Item;
|
||||||
|
import com.dfsek.terra.api.inventory.ItemStack;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a single item entry within a Loot Table pool.
|
||||||
|
*/
|
||||||
|
public class Entry {
|
||||||
|
private final Item item;
|
||||||
|
private final long weight;
|
||||||
|
private final List<LootFunction> functions = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates an Entry from a JSON representation.
|
||||||
|
*
|
||||||
|
* @param entry The JSON Object to instantiate from.
|
||||||
|
*/
|
||||||
|
public Entry(JSONObject entry, Platform platform) {
|
||||||
|
String id = entry.get("name").toString();
|
||||||
|
this.item = platform.getItemHandle().createItem(id);
|
||||||
|
|
||||||
|
long weight1;
|
||||||
|
try {
|
||||||
|
weight1 = (long) entry.get("weight");
|
||||||
|
} catch(NullPointerException e) {
|
||||||
|
weight1 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.weight = weight1;
|
||||||
|
if(entry.containsKey("functions")) {
|
||||||
|
for(Object function : (JSONArray) entry.get("functions")) {
|
||||||
|
switch(((String) ((JSONObject) function).get("function"))) {
|
||||||
|
case "minecraft:set_count", "set_count" -> {
|
||||||
|
Object loot = ((JSONObject) function).get("count");
|
||||||
|
long max, min;
|
||||||
|
if(loot instanceof Long) {
|
||||||
|
max = (Long) loot;
|
||||||
|
min = (Long) loot;
|
||||||
|
} else {
|
||||||
|
max = (long) ((JSONObject) loot).get("max");
|
||||||
|
min = (long) ((JSONObject) loot).get("min");
|
||||||
|
}
|
||||||
|
functions.add(new AmountFunction(FastMath.toIntExact(min), FastMath.toIntExact(max)));
|
||||||
|
}
|
||||||
|
case "minecraft:set_damage", "set_damage" -> {
|
||||||
|
long maxDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("max");
|
||||||
|
long minDamage = (long) ((JSONObject) ((JSONObject) function).get("damage")).get("min");
|
||||||
|
functions.add(new DamageFunction(FastMath.toIntExact(minDamage), FastMath.toIntExact(maxDamage)));
|
||||||
|
}
|
||||||
|
case "minecraft:enchant_with_levels", "enchant_with_levels" -> {
|
||||||
|
long maxEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("max");
|
||||||
|
long minEnchant = (long) ((JSONObject) ((JSONObject) function).get("levels")).get("min");
|
||||||
|
JSONArray disabled = null;
|
||||||
|
if(((JSONObject) function).containsKey("disabled_enchants"))
|
||||||
|
disabled = (JSONArray) ((JSONObject) function).get("disabled_enchants");
|
||||||
|
functions.add(
|
||||||
|
new EnchantFunction(FastMath.toIntExact(minEnchant), FastMath.toIntExact(maxEnchant), disabled, platform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches a single ItemStack from the Entry, applying all functions to it.
|
||||||
|
*
|
||||||
|
* @param r The Random instance to apply functions with
|
||||||
|
*
|
||||||
|
* @return ItemStack - The ItemStack with all functions applied.
|
||||||
|
*/
|
||||||
|
public ItemStack getItem(Random r) {
|
||||||
|
ItemStack item = this.item.newItemStack(1);
|
||||||
|
for(LootFunction f : functions) {
|
||||||
|
item = f.apply(item, r);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the weight attribute of the Entry.
|
||||||
|
*
|
||||||
|
* @return long - The weight of the Entry.
|
||||||
|
*/
|
||||||
|
public long getWeight() {
|
||||||
|
return this.weight;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.structures.loot;
|
||||||
|
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
import com.dfsek.terra.api.inventory.Inventory;
|
||||||
|
import com.dfsek.terra.api.inventory.ItemStack;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class representation of a Loot Table to populate chest loot.
|
||||||
|
*/
|
||||||
|
public class LootTableImpl implements com.dfsek.terra.api.structure.LootTable {
|
||||||
|
private final List<Pool> pools = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a LootTable from a JSON String.
|
||||||
|
*
|
||||||
|
* @param json The JSON String representing the loot table.
|
||||||
|
*
|
||||||
|
* @throws ParseException if malformed JSON is passed.
|
||||||
|
*/
|
||||||
|
public LootTableImpl(String json, Platform platform) throws ParseException {
|
||||||
|
JSONParser jsonParser = new JSONParser();
|
||||||
|
Object tableJSON = jsonParser.parse(json);
|
||||||
|
JSONArray poolArray = (JSONArray) ((JSONObject) tableJSON).get("pools");
|
||||||
|
for(Object pool : poolArray) {
|
||||||
|
pools.add(new Pool((JSONObject) pool, platform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fillInventory(Inventory i, Random r) {
|
||||||
|
List<ItemStack> loot = getLoot(r);
|
||||||
|
for(ItemStack stack : loot) {
|
||||||
|
int attempts = 0;
|
||||||
|
while(stack.getAmount() != 0 && attempts < 10) {
|
||||||
|
ItemStack newStack = stack.getType().newItemStack(stack.getAmount());
|
||||||
|
newStack.setItemMeta(stack.getItemMeta());
|
||||||
|
newStack.setAmount(1);
|
||||||
|
int slot = r.nextInt(i.getSize());
|
||||||
|
ItemStack slotItem = i.getItem(slot);
|
||||||
|
if(slotItem == null) {
|
||||||
|
i.setItem(slot, newStack);
|
||||||
|
stack.setAmount(stack.getAmount() - 1);
|
||||||
|
} else if(slotItem.getType().equals(newStack.getType())) {
|
||||||
|
ItemStack dep = newStack.getType().newItemStack(newStack.getAmount());
|
||||||
|
dep.setItemMeta(newStack.getItemMeta());
|
||||||
|
dep.setAmount(newStack.getAmount() + slotItem.getAmount());
|
||||||
|
i.setItem(slot, dep);
|
||||||
|
stack.setAmount(stack.getAmount() - 1);
|
||||||
|
}
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ItemStack> getLoot(Random r) {
|
||||||
|
List<ItemStack> itemList = new ArrayList<>();
|
||||||
|
for(Pool pool : pools) {
|
||||||
|
itemList.addAll(pool.getItems(r));
|
||||||
|
}
|
||||||
|
return itemList;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.structures.loot;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
|
||||||
|
import net.jafama.FastMath;
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.inventory.ItemStack;
|
||||||
|
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representation of a Loot Table pool, or a set of items to be fetched independently.
|
||||||
|
*/
|
||||||
|
public class Pool {
|
||||||
|
private final int max;
|
||||||
|
private final int min;
|
||||||
|
private final ProbabilityCollection<Entry> entries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a Pool from a JSON representation.
|
||||||
|
*
|
||||||
|
* @param pool The JSON Object to instantiate from.
|
||||||
|
*/
|
||||||
|
public Pool(JSONObject pool, Platform platform) {
|
||||||
|
entries = new ProbabilityCollection<>();
|
||||||
|
Object amount = pool.get("rolls");
|
||||||
|
if(amount instanceof Long) {
|
||||||
|
max = FastMath.toIntExact((Long) amount);
|
||||||
|
min = FastMath.toIntExact((Long) amount);
|
||||||
|
} else {
|
||||||
|
max = FastMath.toIntExact((Long) ((JSONObject) amount).get("max"));
|
||||||
|
min = FastMath.toIntExact((Long) ((JSONObject) amount).get("min"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Object entryJSON : (JSONArray) pool.get("entries")) {
|
||||||
|
Entry entry = new Entry((JSONObject) entryJSON, platform);
|
||||||
|
entries.add(entry, FastMath.toIntExact(entry.getWeight()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches a list of items from the pool using the provided Random instance.
|
||||||
|
*
|
||||||
|
* @param r The Random instance to use.
|
||||||
|
*
|
||||||
|
* @return List<ItemStack> - The list of items fetched.
|
||||||
|
*/
|
||||||
|
public List<ItemStack> getItems(Random r) {
|
||||||
|
|
||||||
|
int rolls = r.nextInt(max - min + 1) + min;
|
||||||
|
List<ItemStack> items = new ArrayList<>();
|
||||||
|
for(int i = 0; i < rolls; i++) {
|
||||||
|
items.add(entries.get(r).getItem(r));
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.structures.loot.functions;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.inventory.ItemStack;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loot LootFunction fot setting the amount of an item.
|
||||||
|
*/
|
||||||
|
public class AmountFunction implements LootFunction {
|
||||||
|
private final int max;
|
||||||
|
private final int min;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates an AmountFunction.
|
||||||
|
*
|
||||||
|
* @param min Minimum amount.
|
||||||
|
* @param max Maximum amount.
|
||||||
|
*/
|
||||||
|
public AmountFunction(int min, int max) {
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the function to an ItemStack.
|
||||||
|
*
|
||||||
|
* @param original The ItemStack on which to apply the function.
|
||||||
|
* @param r The Random instance to use.
|
||||||
|
*
|
||||||
|
* @return - ItemStack - The mutated ItemStack.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ItemStack apply(ItemStack original, Random r) {
|
||||||
|
original.setAmount(r.nextInt(max - min + 1) + min);
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.structures.loot.functions;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.inventory.ItemStack;
|
||||||
|
import com.dfsek.terra.api.inventory.item.Damageable;
|
||||||
|
import com.dfsek.terra.api.inventory.item.ItemMeta;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loot LootFunction for setting the damage on items in Loot Tables
|
||||||
|
*/
|
||||||
|
public class DamageFunction implements LootFunction {
|
||||||
|
private final int max;
|
||||||
|
private final int min;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a DamageFunction.
|
||||||
|
*
|
||||||
|
* @param min Minimum amount of damage (percentage, out of 100)
|
||||||
|
* @param max Maximum amount of damage (percentage, out of 100)
|
||||||
|
*/
|
||||||
|
public DamageFunction(int min, int max) {
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the function to an ItemStack.
|
||||||
|
*
|
||||||
|
* @param original The ItemStack on which to apply the function.
|
||||||
|
* @param r The Random instance to use.
|
||||||
|
*
|
||||||
|
* @return - ItemStack - The mutated ItemStack.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ItemStack apply(ItemStack original, Random r) {
|
||||||
|
if(original == null) return null;
|
||||||
|
if(!original.isDamageable()) return original;
|
||||||
|
ItemMeta meta = original.getItemMeta();
|
||||||
|
double itemDurability = (r.nextDouble() * (max - min)) + min;
|
||||||
|
Damageable damage = (Damageable) meta;
|
||||||
|
damage.setDamage((int) (original.getType().getMaxDurability() - (itemDurability / 100) * original.getType().getMaxDurability()));
|
||||||
|
original.setItemMeta((ItemMeta) damage);
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.structures.loot.functions;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.Platform;
|
||||||
|
|
||||||
|
import net.jafama.FastMath;
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.inventory.ItemStack;
|
||||||
|
import com.dfsek.terra.api.inventory.item.Enchantment;
|
||||||
|
import com.dfsek.terra.api.inventory.item.ItemMeta;
|
||||||
|
|
||||||
|
|
||||||
|
public class EnchantFunction implements LootFunction {
|
||||||
|
private final int min;
|
||||||
|
private final int max;
|
||||||
|
private final JSONArray disabled;
|
||||||
|
private final Platform platform;
|
||||||
|
|
||||||
|
|
||||||
|
public EnchantFunction(int min, int max, JSONArray disabled, Platform platform) {
|
||||||
|
this.max = max;
|
||||||
|
this.min = min;
|
||||||
|
this.disabled = disabled;
|
||||||
|
this.platform = platform;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the function to an ItemStack.
|
||||||
|
*
|
||||||
|
* @param original The ItemStack on which to apply the function.
|
||||||
|
* @param r The Random instance to use.
|
||||||
|
*
|
||||||
|
* @return - ItemStack - The mutated ItemStack.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ItemStack apply(ItemStack original, Random r) {
|
||||||
|
if(original.getItemMeta() == null) return original;
|
||||||
|
|
||||||
|
double enchant = (r.nextDouble() * (max - min)) + min;
|
||||||
|
List<Enchantment> possible = new ArrayList<>();
|
||||||
|
for(Enchantment ench : platform.getItemHandle().getEnchantments()) {
|
||||||
|
if(ench.canEnchantItem(original) && (disabled == null || !this.disabled.contains(ench.getID()))) {
|
||||||
|
possible.add(ench);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int numEnchant = (r.nextInt((int) FastMath.abs(enchant)) / 10 + 1);
|
||||||
|
Collections.shuffle(possible);
|
||||||
|
ItemMeta meta = original.getItemMeta();
|
||||||
|
iter:
|
||||||
|
for(int i = 0; i < numEnchant && i < possible.size(); i++) {
|
||||||
|
Enchantment chosen = possible.get(i);
|
||||||
|
for(Enchantment ench : meta.getEnchantments().keySet()) {
|
||||||
|
if(chosen.conflictsWith(ench)) continue iter;
|
||||||
|
}
|
||||||
|
int lvl = r.nextInt(1 + (int) (((enchant / 40 > 1) ? 1 : enchant / 40) * (chosen.getMaxLevel())));
|
||||||
|
try {
|
||||||
|
meta.addEnchantment(chosen, FastMath.max(lvl, 1));
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
platform.logger().warning(
|
||||||
|
"Attempted to enchant " + original.getType() + " with " + chosen + " at level " + FastMath.max(lvl, 1) +
|
||||||
|
", but an unexpected exception occurred! Usually this is caused by a misbehaving enchantment plugin.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
original.setItemMeta(meta);
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.dfsek.terra.addons.structure.structures.loot.functions;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.inventory.ItemStack;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for mutating items in Loot Tables.
|
||||||
|
*/
|
||||||
|
public interface LootFunction {
|
||||||
|
/**
|
||||||
|
* Applies the function to an ItemStack.
|
||||||
|
*
|
||||||
|
* @param original The ItemStack on which to apply the function.
|
||||||
|
* @param r The Random instance to use.
|
||||||
|
*
|
||||||
|
* @return - ItemStack - The mutated ItemStack.
|
||||||
|
*/
|
||||||
|
ItemStack apply(ItemStack original, Random r);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user