9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-26 02:29:14 +00:00

Hella nice goto

This commit is contained in:
cyberpwn
2021-09-13 20:36:50 -04:00
parent 87e6e583a6
commit b1d2ac7822
7 changed files with 326 additions and 71 deletions

View File

@@ -0,0 +1,104 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.edit.JigsawEditor;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.jigsaw.PlannedStructure;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisJigsawPiece;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisPosition;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.ObjectHandler;
import com.volmit.iris.util.format.C;
@Decree(name = "find", origin = DecreeOrigin.PLAYER, description = "Iris Find commands")
public class CommandFind implements DecreeExecutor {
@Decree(description = "Find a biome")
public void biome(
@Param(description = "The biome to look for")
IrisBiome biome
) {
Engine e = engine();
if(e == null)
{
sender().sendMessage(C.GOLD + "Not in an Iris World!");
return;
}
e.gotoBiome(biome, player());
}
@Decree(description = "Find a region")
public void region(
@Param(description = "The region to look for")
IrisRegion region
) {
Engine e = engine();
if(e == null)
{
sender().sendMessage(C.GOLD + "Not in an Iris World!");
return;
}
e.gotoRegion(region, player());
}
@Decree(description = "Find a structure")
public void structure(
@Param(description = "The structure to look for")
IrisJigsawStructure structure
) {
Engine e = engine();
if(e == null)
{
sender().sendMessage(C.GOLD + "Not in an Iris World!");
return;
}
e.gotoJigsaw(structure, player());
}
@Decree(description = "Find an object")
public void object(
@Param(description = "The object to look for", customHandler = ObjectHandler.class)
String object
) {
Engine e = engine();
if(e == null)
{
sender().sendMessage(C.GOLD + "Not in an Iris World!");
return;
}
e.gotoObject(object, player());
}
}

View File

@@ -52,6 +52,7 @@ public class CommandIris implements DecreeExecutor {
private CommandObject object;
private CommandJigsaw jigsaw;
private CommandWhat what;
private CommandFind find;
@Decree(description = "Create a new world", aliases = {"+", "c"})
public void create(

View File

@@ -365,61 +365,6 @@ public class CommandStudio implements DecreeExecutor {
NoiseExplorerGUI.launch(l, "Custom Generator");
}
@Decree(description = "Find any biome or region", aliases = {"goto", "g"}, origin = DecreeOrigin.PLAYER)
public void find(
@Param(description = "The biome or region to find", defaultValue = "null")
IrisBiome biome,
@Param(description = "The region to find", defaultValue = "null")
IrisRegion region
) {
if (!IrisToolbelt.isIrisWorld(world())) {
sender().sendMessage(C.RED + "You must be in an Iris world to use this command!");
return;
}
if (biome == null && region == null) {
sender().sendMessage(C.RED + "You must specify a biome= or region=!");
return;
}
IrisPosition regionPosition = null;
if (region != null) {
regionPosition = engine().lookForRegion(region, 10000, (v) -> sender().sendMessage("Looking for the " + C.BOLD + C.WHITE + region.getName() + C.RESET + C.GRAY + " region: Checked " + Form.f(v) + " Places"));
if (regionPosition == null) {
sender().sendMessage(C.YELLOW + "Couldn't find the " + region.getName() + " region.");
} else {
sender().sendMessage(C.GREEN + "Found the " + region.getName() + " region!.");
}
}
IrisPosition biomePosition = null;
if (biome != null) {
biomePosition = engine().lookForBiome(biome, 10000, (v) -> sender().sendMessage("Looking for the " + C.BOLD + C.WHITE + biome.getName() + C.RESET + C.GRAY + " biome: Checked " + Form.f(v) + " Places"));
if (biomePosition == null) {
sender().sendMessage(C.YELLOW + "Couldn't find the " + biome.getName() + " biome.");
} else {
sender().sendMessage(C.GREEN + "Found the " + biome.getName() + " biome!.");
}
}
if (regionPosition == null && region != null) {
sender().sendMessage(C.RED + "Could not find the region you specified.");
} else if (regionPosition != null) {
sender().sendMessage(C.GREEN + "Found the region at: " + regionPosition);
}
if (biomePosition == null && biome != null) {
sender().sendMessage(C.RED + "Could not find the biome you specified.");
} else if (biomePosition != null) {
sender().sendMessage(C.GREEN + "Found the biome at: " + biomePosition);
}
final IrisPosition finalL = regionPosition == null ? biomePosition : regionPosition;
if (finalL == null) {
return;
}
J.s(() -> player().teleport(finalL.toLocation(world())));
}
@Decree(description = "Hotload a studio", aliases = "reload", origin = DecreeOrigin.PLAYER)
public void hotload() {
if (noStudio()) return;

View File

@@ -47,7 +47,6 @@ import com.volmit.iris.engine.object.IrisBiomePaletteLayer;
import com.volmit.iris.engine.object.IrisDecorator;
import com.volmit.iris.engine.object.IrisEngineData;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisObjectPlacement;
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
import com.volmit.iris.util.atomics.AtomicRollingSequence;

View File

@@ -22,6 +22,7 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.gui.components.RenderType;
import com.volmit.iris.core.gui.components.Renderer;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.engine.IrisComplex;
import com.volmit.iris.engine.data.cache.Cache;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
@@ -32,6 +33,7 @@ import com.volmit.iris.engine.object.IrisColor;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisEngineData;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
import com.volmit.iris.engine.object.IrisLootMode;
import com.volmit.iris.engine.object.IrisLootReference;
import com.volmit.iris.engine.object.IrisLootTable;
@@ -46,8 +48,10 @@ import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.decree.handlers.JigsawStructureHandler;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.mantle.MantleFlag;
@@ -72,6 +76,7 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
@@ -79,7 +84,6 @@ import org.bukkit.inventory.ItemStack;
import java.awt.Color;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -87,6 +91,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdater, Renderer, Hotloadable {
KList<EngineStage> getStages();
@@ -780,4 +785,127 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
default IrisBiome getBiomeOrMantle(Location l) {
return getBiomeOrMantle(l.getBlockX(), l.getBlockY(), l.getBlockZ());
}
default void gotoBiome(IrisBiome biome, Player player)
{
Set<String> regionKeys = getDimension()
.getAllRegions(this).stream()
.filter((i) -> i.getAllBiomes(this).contains(biome))
.map(IrisRegistrant::getLoadKey)
.collect(Collectors.toSet());
Locator<IrisBiome> lb = Locator.surfaceBiome(biome.getLoadKey());
Locator<IrisBiome> locator = (engine, chunk)
-> regionKeys.contains(getRegion((chunk.getX()<< 4) + 8, (chunk.getZ() << 4) + 8).getLoadKey())
&& lb.matches(engine, chunk);
if(!regionKeys.isEmpty())
{
locator.find(player);
}
else
{
player.sendMessage(C.RED + biome.getName() + " is not in any defined regions!");
}
}
default void gotoJigsaw(IrisJigsawStructure s, Player player)
{
if(getDimension().getJigsawStructures().stream()
.map(IrisJigsawStructurePlacement::getStructure)
.collect(Collectors.toSet()).contains(s.getLoadKey()))
{
Locator.jigsawStructure(s.getLoadKey()).find(player);
}
else
{
Set<String> biomeKeys = getDimension().getAllBiomes(this).stream()
.filter((i) -> i.getJigsawStructures()
.stream()
.anyMatch((j) -> j.getStructure().equals(s.getLoadKey())))
.map(IrisRegistrant::getLoadKey)
.collect(Collectors.toSet());
Set<String> regionKeys = getDimension().getAllRegions(this).stream()
.filter((i) -> i.getAllBiomeIds().stream().anyMatch(biomeKeys::contains)
|| i.getJigsawStructures()
.stream()
.anyMatch((j) -> j.getStructure().equals(s.getLoadKey())))
.map(IrisRegistrant::getLoadKey)
.collect(Collectors.toSet());
Locator<IrisJigsawStructure> sl = Locator.jigsawStructure(s.getLoadKey());
Locator<IrisBiome> locator = (engine, chunk) -> {
if(biomeKeys.contains(getSurfaceBiome((chunk.getX()<< 4) + 8, (chunk.getZ() << 4) + 8).getLoadKey()))
{
return sl.matches(engine, chunk);
}
else if(regionKeys.contains(getRegion((chunk.getX()<< 4) + 8, (chunk.getZ() << 4) + 8).getLoadKey()))
{
return sl.matches(engine, chunk);
}
return false;
};
if(!regionKeys.isEmpty())
{
locator.find(player);
}
else
{
player.sendMessage(C.RED + s.getLoadKey() + " is not in any defined regions, biomes or dimensions!");
}
}
}
default void gotoObject(String s, Player player)
{
Set<String> biomeKeys = getDimension().getAllBiomes(this).stream()
.filter((i) -> i.getObjects().stream().anyMatch((f) -> f.getPlace().contains(s)))
.map(IrisRegistrant::getLoadKey)
.collect(Collectors.toSet());
Set<String> regionKeys = getDimension().getAllRegions(this).stream()
.filter((i) -> i.getAllBiomeIds().stream().anyMatch(biomeKeys::contains)
|| i.getObjects().stream().anyMatch((f) -> f.getPlace().contains(s)))
.map(IrisRegistrant::getLoadKey)
.collect(Collectors.toSet());
Locator<IrisObject> sl = Locator.object(s);
Locator<IrisBiome> locator = (engine, chunk) -> {
if(biomeKeys.contains(getSurfaceBiome((chunk.getX()<< 4) + 8, (chunk.getZ() << 4) + 8).getLoadKey()))
{
return sl.matches(engine, chunk);
}
else if(regionKeys.contains(getRegion((chunk.getX()<< 4) + 8, (chunk.getZ() << 4) + 8).getLoadKey()))
{
return sl.matches(engine, chunk);
}
return false;
};
if(!regionKeys.isEmpty())
{
locator.find(player);
}
else
{
player.sendMessage(C.RED + s + " is not in any defined regions or biomes!");
}
}
default void gotoRegion(IrisRegion r, Player player)
{
if(!getDimension().getAllRegions(this).contains(r))
{
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
return;
}
Locator.region(r.getLoadKey()).find(player);
}
}

View File

@@ -18,52 +18,122 @@
package com.volmit.iris.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.data.cache.AtomicCache;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisJigsawStructure;
import com.volmit.iris.engine.object.IrisObject;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.Spiral;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.matter.MatterCavern;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.SingleJob;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
@FunctionalInterface
public interface Locator<T> {
boolean matches(Engine engine, Position2 chunk);
static void cancelSearch()
{
if(LocatorCanceller.cancel != null)
{
LocatorCanceller.cancel.run();
LocatorCanceller.cancel = null;
}
}
default Future<Position2> find(Engine engine, Position2 pos, long timeout)
default void find(Player player)
{
find(player, 30_000);
}
default void find(Player player, long timeout)
{
AtomicLong checks = new AtomicLong();
long ms = M.ms();
new SingleJob("Searching", () -> {
try {
Position2 at = find(IrisToolbelt.access(player.getWorld()).getEngine(), new Position2(player.getLocation().getBlockX() >> 4, player.getLocation().getBlockZ() >> 4), timeout, checks::set).get();
if(at != null)
{
J.s(() -> player.teleport(new Location(player.getWorld(), (at.getX() << 4) + 8,
IrisToolbelt.access(player.getWorld()).getEngine().getHeight(
(at.getX() << 4) + 8,
(at.getZ() << 4) + 8, false),
(at.getZ() << 4) + 8)));
}
} catch (WrongEngineBroException | InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}){
@Override
public String getName() {
return "Searched " + Form.f(checks.get()) + " Chunks";
}
@Override
public int getTotalWork() {
return (int) timeout;
}
@Override
public int getWorkCompleted() {
return (int) Math.min(M.ms() - ms, timeout-1);
}
}.execute(new VolmitSender(player));
}
default Future<Position2> find(Engine engine, Position2 pos, long timeout, Consumer<Integer> checks) throws WrongEngineBroException {
if(engine.isClosed())
{
throw new WrongEngineBroException();
}
cancelSearch();
return MultiBurst.burst.completeValue(() -> {
int tc = IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()) * 4;
int tc = IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()) * 17;
MultiBurst burst = new MultiBurst("Iris Locator", Thread.MIN_PRIORITY);
AtomicBoolean found = new AtomicBoolean(false);
Position2 cursor = pos;
AtomicInteger searched = new AtomicInteger();
AtomicBoolean stop = new AtomicBoolean(false);
AtomicReference<Position2> foundPos = new AtomicReference<>();
PrecisionStopwatch px = PrecisionStopwatch.start();
LocatorCanceller.cancel = () -> stop.set(true);
while(!found.get() || stop.get() || px.getMilliseconds() > timeout)
AtomicReference<Position2> next = new AtomicReference<>(cursor);
Spiraler s = new Spiraler(100000, 100000, (x, z) -> next.set(new Position2(x, z)));
s.setOffset(cursor.getX(), cursor.getZ());
s.next();
while(!found.get() && !stop.get() && px.getMilliseconds() < timeout)
{
BurstExecutor e = burst.burst(tc);
for(int i = 0; i < tc; i++)
{
Position2 p = cursor;
cursor = Spiral.next(cursor);
Position2 p = next.get();
s.next();
e.queue(() -> {
if(matches(engine, p))
{
@@ -74,12 +144,15 @@ public interface Locator<T> {
found.set(true);
}
searched.incrementAndGet();
});
}
e.complete();
checks.accept(searched.get());
}
LocatorCanceller.cancel = null;
burst.close();
if(found.get() && foundPos.get() != null)
@@ -91,14 +164,12 @@ public interface Locator<T> {
});
}
boolean matches(Engine engine, Position2 chunk);
static Locator<IrisBiome> region(String loadKey)
static Locator<IrisRegion> region(String loadKey)
{
return (e, c) -> e.getRegion((c.getX() << 4) + 8, (c.getZ() << 4) + 8).getLoadKey().equals(loadKey);
}
static Locator<IrisBiome> jigsawStructure(String loadKey)
static Locator<IrisJigsawStructure> jigsawStructure(String loadKey)
{
return (e, c) -> {
IrisJigsawStructure s = e.getStructureAt(c.getX(), c.getZ());
@@ -106,7 +177,7 @@ public interface Locator<T> {
};
}
static Locator<IrisBiome> object(String loadKey)
static Locator<IrisObject> object(String loadKey)
{
return (e, c) -> e.getObjectsAt(c.getX(), c.getZ()).contains(loadKey);
}

View File

@@ -19,6 +19,8 @@
package com.volmit.iris.util.math;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import java.util.Iterator;
@@ -26,7 +28,12 @@ import java.util.Iterator;
/**
* Represents a spiraler which can start from any point within Long.MAX_VALUE by Long.MAX_VALUE and iterate anywhere.
*/
public record Spiral(Position2 start, long max) implements Iterable<Position2> {
@Data
@RequiredArgsConstructor
public class Spiral implements Iterable<Position2> {
private final Position2 start;
private final long max;
@SuppressWarnings("ConstantConditions")
public static Position2 next(Position2 p) {
int x = p.getX();
@@ -88,7 +95,7 @@ public record Spiral(Position2 start, long max) implements Iterable<Position2> {
@Override
public boolean hasNext() {
return itr < s.max();
return itr < s.getMax();
}
@Override