random loc class remapped + Chunk based rtp'ing

This commit is contained in:
SuperRonanCraft 2023-02-27 00:25:55 -05:00
parent 50fcfb598d
commit e20126a034
10 changed files with 318 additions and 144 deletions

View File

@ -7,7 +7,7 @@
<groupId>me.SuperRonanCraft</groupId>
<artifactId>BetterRTP</artifactId>
<packaging>jar</packaging>
<version>3.6.2</version>
<version>4.0.0-DEVBUILD</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>

View File

@ -14,7 +14,8 @@ public enum RTPCommandType {
//SETTINGS(new CmdSettings(), true),
TEST(new CmdTest(), true),
VERSION(new CmdVersion()),
WORLD(new CmdWorld());
WORLD(new CmdWorld()),
DEV(new CmdDeveloper(), true);
private final RTPCommand cmd;
private boolean debugOnly = false;

View File

@ -0,0 +1,30 @@
package me.SuperRonanCraft.BetterRTP.player.commands.types;
import me.SuperRonanCraft.BetterRTP.player.commands.RTPCommand;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.RandomLocation;
import org.bukkit.command.CommandSender;
import java.util.List;
public class CmdDeveloper implements RTPCommand {
public String getName() {
return "dev";
}
public void execute(CommandSender sendi, String label, String[] args) {
RandomLocation.runChunkTest();
}
@Override public List<String> tabComplete(CommandSender sendi, String[] args) {
return null;
}
public boolean permission(CommandSender sendi) {
return sendi.getName().equalsIgnoreCase("SuperRonanCraft") || sendi.getName().equalsIgnoreCase("RonanCrafts");
}
public void usage(CommandSender sendi, String label) {
sendi.sendMessage("This is for Developement use only!");
}
}

View File

@ -1,16 +1,16 @@
package me.SuperRonanCraft.BetterRTP.player.rtp;
import io.papermc.lib.PaperLib;
import lombok.Getter;
import me.SuperRonanCraft.BetterRTP.BetterRTP;
import me.SuperRonanCraft.BetterRTP.references.customEvents.RTP_FindLocationEvent;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.QueueData;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.QueueHandler;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.worlds.WORLD_TYPE;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.RandomLocation;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.worlds.WorldPlayer;
import io.papermc.lib.PaperLib;
import me.SuperRonanCraft.BetterRTP.BetterRTP;
import org.apache.commons.lang.UnhandledException;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -57,7 +57,7 @@ public class RTPPlayer {
if (queueData != null)
loc = queueData.getLocation();
else
loc = WorldPlayer.generateLocation(worldPlayer);
loc = RandomLocation.generateLocation(worldPlayer);
}
attempts++; //Add an attempt
//Load chunk and find out if safe location (asynchronously)
@ -69,6 +69,7 @@ public class RTPPlayer {
attempt(sendi, loc);
});
} catch (IllegalStateException e) {
//Legacy non-async support
attempt(sendi, loc);
} catch (Throwable ignored) {
@ -80,7 +81,7 @@ public class RTPPlayer {
private void attempt(CommandSender sendi, Location loc) {
Location tpLoc;
tpLoc = getSafeLocation(worldPlayer.getWorldtype(), worldPlayer.getWorld(), loc, worldPlayer.getMinY(), worldPlayer.getMaxY(), worldPlayer.getBiomes());
tpLoc = RandomLocation.getSafeLocation(worldPlayer.getWorldtype(), worldPlayer.getWorld(), loc, worldPlayer.getMinY(), worldPlayer.getMaxY(), worldPlayer.getBiomes());
attemptedLocations.add(loc);
//Valid location?
if (tpLoc != null && checkDepends(tpLoc)) {
@ -97,14 +98,6 @@ public class RTPPlayer {
}
}
public static Location getSafeLocation(WORLD_TYPE type, World world, Location loc, int minY, int maxY, List<String> biomes) {
switch (type) { //Get a Y position and check for bad blocks
case NETHER: return getLocAtNether(loc.getBlockX(), loc.getBlockZ(), minY, maxY, world, biomes);
case NORMAL:
default: return getLocAtNormal(loc.getBlockX(), loc.getBlockZ(), minY, maxY, world, biomes);
}
}
// Compressed code for MaxAttempts being met
private void metMax(CommandSender sendi, Player p) {
settings.teleport.failedTeleport(p, sendi);
@ -112,67 +105,10 @@ public class RTPPlayer {
getPl().getpInfo().getRtping().put(p, false);
}
private static Location getLocAtNormal(int x, int z, int minY, int maxY, World world, List<String> biomes) {
Block b = world.getHighestBlockAt(x, z);
if (b.getType().toString().endsWith("AIR")) //1.15.1 or less
b = world.getBlockAt(x, b.getY() - 1, z);
else if (!b.getType().isSolid()) { //Water, lava, shrubs...
if (!badBlock(b.getType().name(), x, z, world, null)) { //Make sure it's not an invalid block (ex: water, lava...)
//int y = world.getHighestBlockYAt(x, z);
b = world.getBlockAt(x, b.getY() - 1, z);
}
}
//Between max and min y
if ( b.getY() >= minY
&& b.getY() <= maxY
&& !badBlock(b.getType().name(), x, z, world, biomes)) {
return new Location(world, x, b.getY() + 1, z);
}
return null;
}
private static Location getLocAtNether(int x, int z, int minY, int maxY, World world, List<String> biomes) {
//Max and Min Y
for (int y = minY + 1; y < maxY/*world.getMaxHeight()*/; y++) {
Block block_current = world.getBlockAt(x, y, z);
if (block_current.getType().name().endsWith("AIR") || !block_current.getType().isSolid()) {
if (!block_current.getType().name().endsWith("AIR") &&
!block_current.getType().isSolid()) { //Block is not a solid (ex: lava, water...)
String block_in = block_current.getType().name();
if (badBlock(block_in, x, z, world, null))
continue;
}
String block = world.getBlockAt(x, y - 1, z).getType().name();
if (block.endsWith("AIR")) //Block below is air, skip
continue;
if (world.getBlockAt(x, y + 1, z).getType().name().endsWith("AIR") //Head space
&& !badBlock(block, x, z, world, biomes)) //Valid block
return new Location(world, x, y, z);
}
}
return null;
}
public static boolean checkDepends(Location loc) {
return RTPPluginValidation.checkLocation(loc);
}
// Bad blocks, or bad biome
public static boolean badBlock(String block, int x, int z, World world, List<String> biomes) {
for (String currentBlock : BetterRTP.getInstance().getRTP().blockList) //Check Block
if (currentBlock.toUpperCase().equals(block))
return true;
//Check Biomes
if (biomes == null || biomes.isEmpty())
return false;
String biomeCurrent = world.getBiome(x, z).name();
for (String biome : biomes)
if (biomeCurrent.toUpperCase().contains(biome.toUpperCase()))
return false;
return true;
//FALSE MEANS NO BAD BLOCKS/BIOME WHERE FOUND!
}
private BetterRTP getPl() {
return BetterRTP.getInstance();
}

View File

@ -0,0 +1,76 @@
package me.SuperRonanCraft.BetterRTP.references.database;
import lombok.Getter;
import lombok.NonNull;
import me.SuperRonanCraft.BetterRTP.BetterRTP;
import me.SuperRonanCraft.BetterRTP.references.player.playerdata.PlayerData;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.QueueData;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.QueueGenerator;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.worlds.RTPWorld;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Biome;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
public class DatabaseChunkData extends SQLite {
public DatabaseChunkData() {
super(DATABASE_TYPE.CHUNK_DATA);
}
@Override
public List<String> getTables() {
List<String> list = new ArrayList<>();
list.add("ChunkData");
return list;
}
public enum COLUMNS {
ID("id", "integer PRIMARY KEY AUTOINCREMENT"),
//Chunk Data
WORLD("world", "varchar(32)"),
X("x", "long"),
Z("z", "long"),
BIOME("biome", "string"),
MAX_Y("max_y", "integer"),
;
public final String name;
public final String type;
COLUMNS(String name, String type) {
this.name = name;
this.type = type;
}
}
public void addChunk(Chunk chunk, int maxy, Biome biome) {
Bukkit.getScheduler().runTaskAsynchronously(BetterRTP.getInstance(), () -> {
String pre = "INSERT OR REPLACE INTO ";
String sql = pre + tables.get(0) + " ("
+ COLUMNS.WORLD.name + ", "
+ COLUMNS.X.name + ", "
+ COLUMNS.Z.name + ", "
+ COLUMNS.BIOME.name + ", "
+ COLUMNS.MAX_Y.name + " "
+ ") VALUES(?, ?, ?, ?, ?)";
List<Object> params = new ArrayList<Object>() {{
add(chunk.getWorld().getName());
add(chunk.getX());
add(chunk.getZ());
add(biome.name());
add(maxy);
}};
sqlUpdate(sql, params);
});
}
}

View File

@ -2,6 +2,7 @@ package me.SuperRonanCraft.BetterRTP.references.database;
import lombok.Getter;
import me.SuperRonanCraft.BetterRTP.BetterRTP;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.RandomLocation;
import org.bukkit.Bukkit;
public class DatabaseHandler {
@ -9,12 +10,14 @@ public class DatabaseHandler {
@Getter private final DatabasePlayers databasePlayers = new DatabasePlayers();
@Getter private final DatabaseCooldowns databaseCooldowns = new DatabaseCooldowns();
@Getter private final DatabaseQueue databaseQueue = new DatabaseQueue();
@Getter private final DatabaseChunkData databaseChunks = new DatabaseChunkData();
public void load() {
Bukkit.getScheduler().runTaskAsynchronously(BetterRTP.getInstance(), () -> {
databasePlayers.load();
databaseCooldowns.load();
databaseQueue.load();
databaseChunks.load();
});
}
@ -30,4 +33,8 @@ public class DatabaseHandler {
return BetterRTP.getInstance().getDatabaseHandler().getDatabaseQueue();
}
public static DatabaseChunkData getChunks() {
return BetterRTP.getInstance().getDatabaseHandler().getDatabaseChunks();
}
}

View File

@ -3,6 +3,7 @@ package me.SuperRonanCraft.BetterRTP.references.database;
import lombok.Getter;
import lombok.NonNull;
import me.SuperRonanCraft.BetterRTP.BetterRTP;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.RandomLocation;
import org.bukkit.Bukkit;
import java.io.File;
@ -112,6 +113,7 @@ public abstract class SQLite {
private Enum<?>[] getColumns(DATABASE_TYPE type) {
switch (type) {
case CHUNK_DATA: return DatabaseChunkData.COLUMNS.values();
case PLAYERS: return DatabasePlayers.COLUMNS.values();
case QUEUE: return DatabaseQueue.COLUMNS.values();
case COOLDOWN:
@ -121,6 +123,7 @@ public abstract class SQLite {
private String getColumnName(DATABASE_TYPE type, Enum<?> column) {
switch (type) {
case CHUNK_DATA: return ((DatabaseChunkData.COLUMNS) column).name;
case PLAYERS: return ((DatabasePlayers.COLUMNS) column).name;
case QUEUE: return ((DatabaseQueue.COLUMNS) column).name;
case COOLDOWN:
@ -130,6 +133,7 @@ public abstract class SQLite {
private String getColumnType(DATABASE_TYPE type, Enum<?> column) {
switch (type) {
case CHUNK_DATA: return ((DatabaseChunkData.COLUMNS) column).type;
case PLAYERS: return ((DatabasePlayers.COLUMNS) column).type;
case QUEUE: return ((DatabaseQueue.COLUMNS) column).type;
case COOLDOWN:
@ -230,5 +234,6 @@ public abstract class SQLite {
PLAYERS,
COOLDOWN,
QUEUE,
CHUNK_DATA,
}
}

View File

@ -149,13 +149,13 @@ public class QueueGenerator {
}
private void addQueue(RTPWorld rtpWorld, String id, ReQueueData reQueueData) {
Location loc = WorldPlayer.generateLocation(rtpWorld);
Location loc = RandomLocation.generateLocation(rtpWorld);
if (loc != null) {
Bukkit.getScheduler().runTask(BetterRTP.getInstance(), () -> {
//BetterRTP.debug("Queued up a new position, attempts " + reQueueData.attempts);
PaperLib.getChunkAtAsync(loc)
.thenAccept(v -> {
Location safeLoc = RTPPlayer.getSafeLocation(
Location safeLoc = RandomLocation.getSafeLocation(
HelperRTP.getWorldType(rtpWorld.getWorld()),
loc.getWorld(),
loc,

View File

@ -0,0 +1,186 @@
package me.SuperRonanCraft.BetterRTP.references.rtpinfo;
import io.papermc.lib.PaperLib;
import me.SuperRonanCraft.BetterRTP.BetterRTP;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.worlds.RTPWorld;
import me.SuperRonanCraft.BetterRTP.references.rtpinfo.worlds.WORLD_TYPE;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
public class RandomLocation {
public static Location generateLocation(RTPWorld rtpWorld) {
Location loc;
switch (rtpWorld.getShape()) {
case CIRCLE: loc = generateRound(rtpWorld); break;
case SQUARE:
default: loc = generateSquare(rtpWorld); break;
}
return loc;
}
private static Location generateSquare(RTPWorld rtpWorld) {
//Generate a random X and Z based off the quadrant selected
int min = rtpWorld.getMinRadius();
int max = rtpWorld.getMaxRadius() - min;
int x, z;
int quadrant = new Random().nextInt(4);
try {
switch (quadrant) {
case 0: // Positive X and Z
x = new Random().nextInt(max) + min;
z = new Random().nextInt(max) + min;
break;
case 1: // Negative X and Z
x = -new Random().nextInt(max) - min;
z = -(new Random().nextInt(max) + min);
break;
case 2: // Negative X and Positive Z
x = -new Random().nextInt(max) - min;
z = new Random().nextInt(max) + min;
break;
default: // Positive X and Negative Z
x = new Random().nextInt(max) + min;
z = -(new Random().nextInt(max) + min);
break;
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
BetterRTP.getInstance().getLogger().warning("A bounding location was negative! Please check your config only has positive x/z for max/min radius!");
BetterRTP.getInstance().getLogger().warning("Max: " + rtpWorld.getMaxRadius() + " Min: " + rtpWorld.getMinRadius());
return null;
}
x += rtpWorld.getCenterX();
z += rtpWorld.getCenterZ();
//System.out.println(quadrant);
return new Location(rtpWorld.getWorld(), x, 69, z);
}
private static Location generateRound(RTPWorld rtpWorld) {
//Generate a random X and Z based off location on a spiral curve
int min = rtpWorld.getMinRadius();
int max = rtpWorld.getMaxRadius() - min;
int x, z;
double area = Math.PI * (max - min) * (max + min); //of all the area in this donut
double subArea = area * new Random().nextDouble(); //pick a random subset of that area
double r = Math.sqrt(subArea/Math.PI + min * min); //convert area to radius
double theta = (r - (int) r) * 2 * Math.PI; //use the remainder as an angle
// polar to cartesian
x = (int) (r * Math.cos(theta));
z = (int) (r * Math.sin(theta));
x += rtpWorld.getCenterX();
z += rtpWorld.getCenterZ();
return new Location(rtpWorld.getWorld(), x, 69, z);
}
public static Location getSafeLocation(WORLD_TYPE type, World world, Location loc, int minY, int maxY, List<String> biomes) {
switch (type) { //Get a Y position and check for bad blocks
case NETHER: return getLocAtNether(loc.getBlockX(), loc.getBlockZ(), minY, maxY, world, biomes);
case NORMAL:
default: return getLocAtNormal(loc.getBlockX(), loc.getBlockZ(), minY, maxY, world, biomes);
}
}
private static Location getLocAtNormal(int x, int z, int minY, int maxY, World world, List<String> biomes) {
Block b = getHighestBlock(x, z, world);
if (!b.getType().isSolid()) { //Water, lava, shrubs...
if (!badBlock(b.getType().name(), x, z, world, null)) { //Make sure it's not an invalid block (ex: water, lava...)
//int y = world.getHighestBlockYAt(x, z);
b = world.getBlockAt(x, b.getY() - 1, z);
}
}
//Between max and min y
if ( b.getY() >= minY
&& b.getY() <= maxY
&& !badBlock(b.getType().name(), x, z, world, biomes)) {
return new Location(world, x, b.getY() + 1, z);
}
return null;
}
public static Block getHighestBlock(int x, int z, World world) {
Block b = world.getHighestBlockAt(x, z);
if (b.getType().toString().endsWith("AIR")) //1.15.1 or less
b = world.getBlockAt(x, b.getY() - 1, z);
return b;
}
private static Location getLocAtNether(int x, int z, int minY, int maxY, World world, List<String> biomes) {
//Max and Min Y
for (int y = minY + 1; y < maxY/*world.getMaxHeight()*/; y++) {
Block block_current = world.getBlockAt(x, y, z);
if (block_current.getType().name().endsWith("AIR") || !block_current.getType().isSolid()) {
if (!block_current.getType().name().endsWith("AIR") &&
!block_current.getType().isSolid()) { //Block is not a solid (ex: lava, water...)
String block_in = block_current.getType().name();
if (badBlock(block_in, x, z, world, null))
continue;
}
String block = world.getBlockAt(x, y - 1, z).getType().name();
if (block.endsWith("AIR")) //Block below is air, skip
continue;
if (world.getBlockAt(x, y + 1, z).getType().name().endsWith("AIR") //Head space
&& !badBlock(block, x, z, world, biomes)) //Valid block
return new Location(world, x, y, z);
}
}
return null;
}
// Bad blocks, or bad biome
public static boolean badBlock(String block, int x, int z, World world, List<String> biomes) {
for (String currentBlock : BetterRTP.getInstance().getRTP().getBlockList()) //Check Block
if (currentBlock.equalsIgnoreCase(block))
return true;
//Check Biomes
if (biomes == null || biomes.isEmpty())
return false;
String biomeCurrent = world.getBiome(x, z).name();
for (String biome : biomes)
if (biomeCurrent.toUpperCase().contains(biome.toUpperCase()))
return false;
return true;
//FALSE MEANS NO BAD BLOCKS/BIOME WHERE FOUND!
}
public static void runChunkTest() {
BetterRTP.getInstance().getLogger().info("---------------- Starting chunk test!");
World world = Bukkit.getWorld("world");
cacheChunkAt(world, 32, -32, -32, -32);
}
private static void cacheTask(World world, int goal, int start, int xat, int zat) {
zat += 1;
if (zat > goal) {
zat = start;
xat += 1;
}
if (xat <= goal)
cacheChunkAt(world, goal, start, xat, zat);
}
private static void cacheChunkAt(World world, int goal, int start, int xat, int zat) {
CompletableFuture<Chunk> task = PaperLib.getChunkAtAsync(new Location(world, xat * 16, 0, zat * 16));
task.thenAccept(chunk -> {
try {
ChunkSnapshot snapshot = chunk.getChunkSnapshot(true, true, false);
int maxy = snapshot.getHighestBlockYAt(8, 8);
Biome biome = snapshot.getBiome(8, 8);
//BetterRTP.getInstance().getLogger().info("Added " + chunk.getX() + " " + chunk.getZ());
BetterRTP.getInstance().getDatabaseHandler().getDatabaseChunks().addChunk(chunk, maxy, biome);
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException();
//BetterRTP.getInstance().getLogger().info("Tried Adding " + chunk.getX() + " " + chunk.getZ());
}
}).thenRun(() -> cacheTask(world, goal, start, xat, zat));
}
}

View File

@ -114,73 +114,6 @@ public class WorldPlayer implements RTPWorld, RTPWorld_Defaulted {
return _zLoc >= _zLMax && (_zLoc <= _zLMin || _zLoc >= _zRMin) && _zLoc <= _zRMax;
}
public static Location generateLocation(RTPWorld rtpWorld) {
Location loc;
switch (rtpWorld.getShape()) {
case CIRCLE: loc = generateRound(rtpWorld); break;
case SQUARE:
default: loc = generateSquare(rtpWorld); break;
}
return loc;
}
private static Location generateSquare(RTPWorld rtpWorld) {
//Generate a random X and Z based off the quadrant selected
int min = rtpWorld.getMinRadius();
int max = rtpWorld.getMaxRadius() - min;
int x, z;
int quadrant = new Random().nextInt(4);
try {
switch (quadrant) {
case 0: // Positive X and Z
x = new Random().nextInt(max) + min;
z = new Random().nextInt(max) + min;
break;
case 1: // Negative X and Z
x = -new Random().nextInt(max) - min;
z = -(new Random().nextInt(max) + min);
break;
case 2: // Negative X and Positive Z
x = -new Random().nextInt(max) - min;
z = new Random().nextInt(max) + min;
break;
default: // Positive X and Negative Z
x = new Random().nextInt(max) + min;
z = -(new Random().nextInt(max) + min);
break;
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
BetterRTP.getInstance().getLogger().warning("A bounding location was negative! Please check your config only has positive x/z for max/min radius!");
BetterRTP.getInstance().getLogger().warning("Max: " + rtpWorld.getMaxRadius() + " Min: " + rtpWorld.getMinRadius());
return null;
}
x += rtpWorld.getCenterX();
z += rtpWorld.getCenterZ();
//System.out.println(quadrant);
return new Location(rtpWorld.getWorld(), x, 69, z);
}
private static Location generateRound(RTPWorld rtpWorld) {
//Generate a random X and Z based off location on a spiral curve
int min = rtpWorld.getMinRadius();
int max = rtpWorld.getMaxRadius() - min;
int x, z;
double area = Math.PI * (max - min) * (max + min); //of all the area in this donut
double subArea = area * new Random().nextDouble(); //pick a random subset of that area
double r = Math.sqrt(subArea/Math.PI + min * min); //convert area to radius
double theta = (r - (int) r) * 2 * Math.PI; //use the remainder as an angle
// polar to cartesian
x = (int) (r * Math.cos(theta));
z = (int) (r * Math.sin(theta));
x += rtpWorld.getCenterX();
z += rtpWorld.getCenterZ();
return new Location(rtpWorld.getWorld(), x, 69, z);
}
@NotNull
@Override
public World getWorld() {