diff --git a/common/addons/config-structure/LICENSE b/common/addons/config-structure/LICENSE new file mode 100644 index 000000000..64c1cd516 --- /dev/null +++ b/common/addons/config-structure/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2021 Polyhedral Development + +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. \ No newline at end of file diff --git a/common/addons/config-structure/README.md b/common/addons/config-structure/README.md new file mode 100644 index 000000000..60e62972a --- /dev/null +++ b/common/addons/config-structure/README.md @@ -0,0 +1,3 @@ +# config-structure + +Registers the default configuration for Terra Structures, `STRUCTURE`. \ No newline at end of file diff --git a/common/addons/config-structure/build.gradle.kts b/common/addons/config-structure/build.gradle.kts new file mode 100644 index 000000000..8a207092b --- /dev/null +++ b/common/addons/config-structure/build.gradle.kts @@ -0,0 +1,4 @@ +dependencies { + "shadedApi"("com.googlecode.json-simple:json-simple:1.1.1") + "shadedApi"(project(":common:addons:manifest-addon-loader")) +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/BiomeStructures.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/BiomeStructures.java new file mode 100644 index 000000000..16a0e84b6 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/BiomeStructures.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 structures; + + public BiomeStructures(Set structures) { + this.structures = structures; + } + + public Set getStructures() { + return structures; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/BiomeStructuresTemplate.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/BiomeStructuresTemplate.java new file mode 100644 index 000000000..18c008880 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/BiomeStructuresTemplate.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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; + + +@SuppressWarnings("FieldMayBeFinal") +public class BiomeStructuresTemplate implements ObjectTemplate { + @Value("structures") + @Default + private @Meta Set<@Meta ConfiguredStructure> structures = Collections.emptySet(); + + @Override + public BiomeStructures get() { + return new BiomeStructures(structures); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureAddon.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureAddon.java new file mode 100644 index 000000000..3ce1264f9 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureAddon.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.structure; + +import com.dfsek.terra.addons.manifest.api.AddonInitializer; +import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.addon.BaseAddon; +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; + + +public class StructureAddon implements AddonInitializer { + @Inject + private Platform platform; + + @Inject + private BaseAddon addon; + + @Override + public void initialize() { + platform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(addon, ConfigPackPreLoadEvent.class) + .then(event -> event.getPack().registerConfigType(new StructureConfigType(), "STRUCTURE", 2)) + .failThrough(); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureConfigType.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureConfigType.java new file mode 100644 index 000000000..1545080e8 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureConfigType.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.structure; + +import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.config.ConfigFactory; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.config.ConfigType; +import com.dfsek.terra.api.registry.OpenRegistry; +import com.dfsek.terra.api.structure.configured.ConfiguredStructure; +import com.dfsek.terra.api.util.reflection.TypeKey; + +import java.util.function.Supplier; + + +public class StructureConfigType implements ConfigType { + private final ConfigFactory factory = new StructureFactory(); + public static final TypeKey CONFIGURED_STRUCTURE_TYPE_KEY = new TypeKey<>(){}; + + @Override + public StructureTemplate getTemplate(ConfigPack pack, Platform platform) { + return new StructureTemplate(); + } + + @Override + public ConfigFactory getFactory() { + return factory; + } + + @Override + public TypeKey getTypeKey() { + return CONFIGURED_STRUCTURE_TYPE_KEY; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureFactory.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureFactory.java new file mode 100644 index 000000000..8b0a8f05e --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureFactory.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 { + @Override + public ConfiguredStructure build(StructureTemplate config, Platform platform) { + return new TerraStructure(config.getStructures(), config.getY(), config.getSpawn(), config.getID()); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructurePopulator.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructurePopulator.java new file mode 100644 index 000000000..f78a5260c --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructurePopulator.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.structure; + +import net.jafama.FastMath; +import org.jetbrains.annotations.NotNull; + +import java.util.Random; + +import com.dfsek.terra.api.Platform; +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))); + } + } + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureTemplate.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureTemplate.java new file mode 100644 index 000000000..881913ebc --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/StructureTemplate.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 getStructures() { + return structure; + } + + public Range getY() { + return y; + } + + public StructureSpawn getSpawn() { + return spawn; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/TerraStructure.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/TerraStructure.java new file mode 100644 index 000000000..cef38f2b9 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/TerraStructure.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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; + private final Range spawnStart; + private final StructureSpawn spawn; + + private final String id; + + public TerraStructure(ProbabilityCollection structures, Range spawnStart, StructureSpawn spawn, String id) { + this.structure = structures; + this.spawnStart = spawnStart; + this.spawn = spawn; + this.id = id; + } + + @Override + public ProbabilityCollection getStructure() { + return structure; + } + + @Override + public Range getSpawnStart() { + return spawnStart; + } + + @Override + public StructureSpawn getSpawn() { + return spawn; + } + + @Override + public String getID() { + return id; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/AsyncStructureFinder.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/AsyncStructureFinder.java new file mode 100644 index 000000000..6422cdcf2 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/AsyncStructureFinder.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.structure.command; + +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +import com.dfsek.terra.api.Platform; +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 callback; + protected int searchSize = 1; + + public AsyncStructureFinder(BiomeProvider provider, ConfiguredStructure target, @NotNull Vector3 origin, World world, int startRadius, + int maxRadius, Consumer 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; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureCommand.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureCommand.java new file mode 100644 index 000000000..b5c9fd1a2 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureCommand.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 = 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); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureLoadCommand.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureLoadCommand.java new file mode 100644 index 000000000..14de36122 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureLoadCommand.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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"); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureLocateCommand.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureLocateCommand.java new file mode 100644 index 000000000..60fd05f84 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/StructureLocateCommand.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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(); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/argument/ScriptArgumentParser.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/argument/ScriptArgumentParser.java new file mode 100644 index 000000000..ca700ee60 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/argument/ScriptArgumentParser.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 { + @Inject + private Platform platform; + + @Override + public Structure parse(CommandSender sender, String arg) { + return ((Player) sender).world().getConfig().getRegistry(Structure.class).get(arg); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/argument/StructureArgumentParser.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/argument/StructureArgumentParser.java new file mode 100644 index 000000000..33738a1d1 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/argument/StructureArgumentParser.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 { + @Inject + private Platform platform; + + @Override + public ConfiguredStructure parse(CommandSender sender, String arg) { + return ((Player) sender).world().getConfig().getRegistry(ConfiguredStructure.class).get(arg); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/RotationCompleter.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/RotationCompleter.java new file mode 100644 index 000000000..27bb94e8c --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/RotationCompleter.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 complete(CommandSender sender) { + return Arrays.asList("0", "90", "180", "270"); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/ScriptCompleter.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/ScriptCompleter.java new file mode 100644 index 000000000..bf64d398e --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/ScriptCompleter.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 complete(CommandSender sender) { + return ((Player) sender).world().getConfig().getRegistry(Structure.class).entries().stream().map(Structure::getID).collect( + Collectors.toList()); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/StructureCompleter.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/StructureCompleter.java new file mode 100644 index 000000000..af6a239d4 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/command/structure/completer/StructureCompleter.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 complete(CommandSender sender) { + Player player = (Player) sender; + return new ArrayList<>(player.world().getConfig().getRegistry(ConfiguredStructure.class).keys()); + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/Entry.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/Entry.java new file mode 100644 index 000000000..ab8be10e2 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/Entry.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.structure.structures.loot; + +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.Platform; +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 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; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/LootTableImpl.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/LootTableImpl.java new file mode 100644 index 000000000..c817c2d2d --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/LootTableImpl.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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 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 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 getLoot(Random r) { + List itemList = new ArrayList<>(); + for(Pool pool : pools) { + itemList.addAll(pool.getItems(r)); + } + return itemList; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/Pool.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/Pool.java new file mode 100644 index 000000000..a807cb4a1 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/Pool.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.structure.structures.loot; + +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.Platform; +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 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 getItems(Random r) { + + int rolls = r.nextInt(max - min + 1) + min; + List items = new ArrayList<>(); + for(int i = 0; i < rolls; i++) { + items.add(entries.get(r).getItem(r)); + } + return items; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/AmountFunction.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/AmountFunction.java new file mode 100644 index 000000000..8fd59a5ee --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/AmountFunction.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/DamageFunction.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/DamageFunction.java new file mode 100644 index 000000000..09eda7417 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/DamageFunction.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/EnchantFunction.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/EnchantFunction.java new file mode 100644 index 000000000..0e1f54843 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/EnchantFunction.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +package com.dfsek.terra.addons.structure.structures.loot.functions; + +import com.dfsek.terra.api.Platform; +import com.dfsek.terra.api.inventory.ItemStack; +import com.dfsek.terra.api.inventory.item.Enchantment; +import com.dfsek.terra.api.inventory.item.ItemMeta; + +import net.jafama.FastMath; +import org.json.simple.JSONArray; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + + +public class EnchantFunction implements LootFunction { + private final int min; + private final int max; + private final JSONArray disabled; + private final Platform platform; + + private static final Logger LOGGER = LoggerFactory.getLogger(EnchantFunction.class); + + + 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 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) { + LOGGER.warn( + "Attempted to enchant {} with {} at level {}, but an unexpected exception occurred! Usually this is caused by a " + + "misbehaving enchantment plugin.", + original.getType(), chosen, FastMath.max(lvl, 1)); + } + } + original.setItemMeta(meta); + return original; + } +} diff --git a/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/LootFunction.java b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/LootFunction.java new file mode 100644 index 000000000..ebe0fd550 --- /dev/null +++ b/common/addons/config-structure/src/main/java/com/dfsek/terra/addons/structure/structures/loot/functions/LootFunction.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020-2021 Polyhedral Development + * + * The Terra Core Addons are licensed under the terms of the MIT License. For more details, + * reference the LICENSE file in this module's root directory. + */ + +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); +} diff --git a/common/addons/config-structure/src/main/resources/terra.addon.yml b/common/addons/config-structure/src/main/resources/terra.addon.yml new file mode 100644 index 000000000..f2171efc1 --- /dev/null +++ b/common/addons/config-structure/src/main/resources/terra.addon.yml @@ -0,0 +1,12 @@ +schema-version: 1 +contributors: + - Terra contributors +id: config-structure +version: 0.1.0 +entrypoints: + - "com.dfsek.terra.addons.structure.StructureAddon" +website: + issues: https://github.com/PolyhedralDev/Terra-config-structure/issues + source: https://github.com/PolyhedralDev/Terra-config-structure + docs: https://github.com/PolyhedralDev/Terra/wiki +license: GNU LGPL v3.0 \ No newline at end of file