Compare commits
4 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
3282e3870b | 2 months ago |
|
|
a84d6ece02 | 2 months ago |
|
|
7e91d400a4 | 2 months ago |
|
|
6461f94865 | 10 months ago |
53 changed files with 247 additions and 4583 deletions
@ -0,0 +1,95 @@ |
|||||||
|
package xyz.soukup.ecoCraftCore.commands; |
||||||
|
|
||||||
|
import com.mojang.brigadier.arguments.IntegerArgumentType; |
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
||||||
|
import com.mojang.brigadier.context.CommandContext; |
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack; |
||||||
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder; |
||||||
|
import io.papermc.paper.command.brigadier.Commands; |
||||||
|
import org.bukkit.command.CommandSender; |
||||||
|
import org.bukkit.entity.Player; |
||||||
|
import xyz.soukup.ecoCraftCore.objects.Shop; |
||||||
|
import xyz.soukup.ecoCraftCore.utilities.Messages; |
||||||
|
|
||||||
|
public class ShopEditCommand { |
||||||
|
public static LiteralArgumentBuilder<CommandSourceStack> createCommand() { |
||||||
|
|
||||||
|
RequiredArgumentBuilder<CommandSourceStack, Integer> shopId = Commands.argument("shop-id", IntegerArgumentType.integer()); |
||||||
|
RequiredArgumentBuilder<CommandSourceStack, Integer> amount = Commands.argument("amount", IntegerArgumentType.integer()); |
||||||
|
RequiredArgumentBuilder<CommandSourceStack, Integer> price = Commands.argument("price", IntegerArgumentType.integer()); |
||||||
|
LiteralArgumentBuilder<CommandSourceStack> changePriceSell = Commands.literal("change-price-sell"); |
||||||
|
LiteralArgumentBuilder<CommandSourceStack> changePriceBuy = Commands.literal("change-price-buy"); |
||||||
|
LiteralArgumentBuilder<CommandSourceStack> changeItemAmount = Commands.literal("change-item-amount"); |
||||||
|
|
||||||
|
|
||||||
|
return Commands.literal("shop-edit") |
||||||
|
.then(shopId |
||||||
|
.then(changePriceSell.then(price.executes(ShopEditCommand::changePriceSell))) |
||||||
|
.then(changePriceBuy.then(price.executes(ShopEditCommand::changePriceBuy))) |
||||||
|
.then(changeItemAmount.then(amount.executes(ShopEditCommand::changeItemAmount)))); |
||||||
|
} |
||||||
|
|
||||||
|
private static int changePriceSell(CommandContext<CommandSourceStack> context) { |
||||||
|
CommandSender commandSender = context.getSource().getSender(); |
||||||
|
Integer shopId = context.getArgument("shop-id", Integer.class); |
||||||
|
Integer price = context.getArgument("price", Integer.class); |
||||||
|
|
||||||
|
if (!(commandSender instanceof Player)){ |
||||||
|
Messages.send(commandSender, "generic.error.not-player"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
Shop shop = Shop.findById(shopId); |
||||||
|
if (shop == null){ |
||||||
|
Messages.send(commandSender, "shop.error.not-found"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
shop.setPriceSell(price); |
||||||
|
Messages.send(commandSender, "shop.edit.price-sell-changed"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
private static int changePriceBuy(CommandContext<CommandSourceStack> context) { |
||||||
|
CommandSender commandSender = context.getSource().getSender(); |
||||||
|
Integer shopId = context.getArgument("shop-id", Integer.class); |
||||||
|
Integer price = context.getArgument("price", Integer.class); |
||||||
|
|
||||||
|
if (!(commandSender instanceof Player)){ |
||||||
|
Messages.send(commandSender, "generic.error.not-player"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
Shop shop = Shop.findById(shopId); |
||||||
|
if (shop == null){ |
||||||
|
Messages.send(commandSender, "shop.error.not-found"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
shop.setPriceBuy(price); |
||||||
|
Messages.send(commandSender, "shop.edit.price-buy-changed"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
private static int changeItemAmount(CommandContext<CommandSourceStack> context) { |
||||||
|
CommandSender commandSender = context.getSource().getSender(); |
||||||
|
Integer shopId = context.getArgument("shop-id", Integer.class); |
||||||
|
Integer amount = context.getArgument("amount", Integer.class); |
||||||
|
|
||||||
|
if (!(commandSender instanceof Player)){ |
||||||
|
Messages.send(commandSender, "generic.error.not-player"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
Shop shop = Shop.findById(shopId); |
||||||
|
if (shop == null){ |
||||||
|
Messages.send(commandSender, "shop.error.not-found"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
shop.setAmount(amount); |
||||||
|
Messages.send(commandSender, "shop.edit.item-amount-changed"); |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,34 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.database.objects; |
|
||||||
|
|
||||||
|
|
||||||
import com.j256.ormlite.field.DatabaseField; |
|
||||||
import com.j256.ormlite.table.DatabaseTable; |
|
||||||
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
|
||||||
|
|
||||||
import java.sql.SQLException; |
|
||||||
|
|
||||||
@DatabaseTable(tableName = "active_servers") |
|
||||||
public class ActiveServer { |
|
||||||
@DatabaseField(unique = true, id = true) |
|
||||||
private String name; |
|
||||||
|
|
||||||
public ActiveServer(){ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public ActiveServer(String name){ |
|
||||||
this.name = name; |
|
||||||
} |
|
||||||
|
|
||||||
public void save() throws SQLException { |
|
||||||
DaoRegistry.getActiveServerDao().createIfNotExists(this); |
|
||||||
} |
|
||||||
|
|
||||||
public void delete() throws SQLException { |
|
||||||
DaoRegistry.getActiveServerDao().delete(this); |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return name; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,213 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.database.objects; |
|
||||||
|
|
||||||
import com.j256.ormlite.dao.ForeignCollection; |
|
||||||
import com.j256.ormlite.field.DatabaseField; |
|
||||||
import com.j256.ormlite.field.ForeignCollectionField; |
|
||||||
import com.j256.ormlite.table.DatabaseTable; |
|
||||||
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
|
||||||
|
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
@DatabaseTable(tableName = "regions") |
|
||||||
public class Region { |
|
||||||
|
|
||||||
public static final HashMap<String, List<Region>> cache = new HashMap<>(); |
|
||||||
|
|
||||||
@DatabaseField(generatedId = true) |
|
||||||
private int id; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private String island; |
|
||||||
|
|
||||||
@DatabaseField(columnName = "region_type", canBeNull = false) |
|
||||||
private int regionType; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private int x1; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private int y1; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private int z1; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private int x2; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private int y2; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private int z2; |
|
||||||
|
|
||||||
@ForeignCollectionField(eager = true) |
|
||||||
private ForeignCollection<RegionMember> regionMembers; |
|
||||||
|
|
||||||
@DatabaseField() |
|
||||||
private Integer value; |
|
||||||
|
|
||||||
public Region() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public Region(String island, int regionType, int x1, int y1, int z1, int x2, int y2, int z2) { |
|
||||||
this.island = island; |
|
||||||
this.regionType = regionType; |
|
||||||
this.x1 = Math.min(x1, x2); |
|
||||||
this.y1 = Math.min(y1, y2); |
|
||||||
this.x2 = Math.max(x1, x2); |
|
||||||
this.y2 = Math.max(y1, y2); |
|
||||||
this.z1 = Math.min(z1, z2); |
|
||||||
this.z2 = Math.max(z1, z2); |
|
||||||
|
|
||||||
} |
|
||||||
public int getId() { |
|
||||||
return id; |
|
||||||
} |
|
||||||
|
|
||||||
public int getRegionType() { |
|
||||||
return regionType; |
|
||||||
} |
|
||||||
|
|
||||||
public int getX1() { |
|
||||||
return x1; |
|
||||||
} |
|
||||||
|
|
||||||
public int getZ1() { |
|
||||||
return z1; |
|
||||||
} |
|
||||||
|
|
||||||
public int getZ2() { |
|
||||||
return z2; |
|
||||||
} |
|
||||||
|
|
||||||
public int getY1() { |
|
||||||
return y1; |
|
||||||
} |
|
||||||
|
|
||||||
public int getX2() { |
|
||||||
return x2; |
|
||||||
} |
|
||||||
|
|
||||||
public int getY2() { |
|
||||||
return y2; |
|
||||||
} |
|
||||||
|
|
||||||
public ForeignCollection<RegionMember> getRegionMembers() { |
|
||||||
return regionMembers; |
|
||||||
} |
|
||||||
|
|
||||||
public Integer getValue() { |
|
||||||
return value; |
|
||||||
} |
|
||||||
|
|
||||||
public String getIsland() { |
|
||||||
return island; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void setRegionType(int regionType) { |
|
||||||
this.regionType = regionType; |
|
||||||
} |
|
||||||
|
|
||||||
public void setValue(Integer value) { |
|
||||||
this.value = value; |
|
||||||
} |
|
||||||
|
|
||||||
public void save(){ |
|
||||||
try { |
|
||||||
|
|
||||||
DaoRegistry.getRegionDao().createOrUpdate(this); |
|
||||||
List<Region> regions = cache.get(island); |
|
||||||
|
|
||||||
if (regions == null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
regions.removeIf(region -> region.getId() == this.id); |
|
||||||
regions.add(this); |
|
||||||
} catch (Exception e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public void addRegionMember(String memberType, String member, String membershipType){ |
|
||||||
RegionMember regionMember = new RegionMember(this, memberType, member, membershipType); |
|
||||||
regionMember.save(); |
|
||||||
|
|
||||||
Region updatedRegion = Region.findById(this.id); |
|
||||||
List<Region> regions = cache.get(island); |
|
||||||
|
|
||||||
if (regions == null) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
regions.removeIf(region -> region.getId() == this.id); |
|
||||||
regions.add(updatedRegion); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public boolean isInside(int x, int y, int z) { |
|
||||||
return x >= this.x1 && x <= this.x2 && y >= this.y1 && y <= this.y2 && z >= this.z1 && z <= this.z2; |
|
||||||
} |
|
||||||
|
|
||||||
public static Region findById(int id) { |
|
||||||
try { |
|
||||||
return DaoRegistry.getRegionDao().queryForId(id); |
|
||||||
} catch (Exception e) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void cacheRegions(String island) { |
|
||||||
try { |
|
||||||
List<Region> regions = DaoRegistry.getRegionDao().queryBuilder() |
|
||||||
.where() |
|
||||||
.eq("island", island) |
|
||||||
.query(); |
|
||||||
cache.put(island, regions); |
|
||||||
} catch (Exception e) { |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static Region findRegion(int x, int y, int z, String island) { |
|
||||||
|
|
||||||
Region region = null; |
|
||||||
int highestType = -1; |
|
||||||
|
|
||||||
if (!cache.containsKey(island)) { |
|
||||||
cacheRegions(island); |
|
||||||
} |
|
||||||
|
|
||||||
for (Region cachedRegion : cache.get(island)) { |
|
||||||
if (!cachedRegion.isInside(x, y, z)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (highestType >= cachedRegion.getRegionType()){ |
|
||||||
continue; |
|
||||||
} |
|
||||||
region = cachedRegion; |
|
||||||
} |
|
||||||
|
|
||||||
return region; |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public void changeBoundaries(int x1, int y1, int z1, int x2, int y2, int z2){ |
|
||||||
this.x1 = Math.min(x1, x2); |
|
||||||
this.y1 = Math.min(y1, y2); |
|
||||||
this.x2 = Math.max(x1, x2); |
|
||||||
this.y2 = Math.max(y1, y2); |
|
||||||
this.z1 = Math.min(z1, z2); |
|
||||||
this.z2 = Math.max(z1, z2); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@ -1,65 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.database.objects; |
|
||||||
|
|
||||||
import com.j256.ormlite.field.DatabaseField; |
|
||||||
import com.j256.ormlite.table.DatabaseTable; |
|
||||||
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
|
||||||
|
|
||||||
import java.sql.SQLException; |
|
||||||
|
|
||||||
@DatabaseTable(tableName = "region_members") |
|
||||||
public class RegionMember { |
|
||||||
|
|
||||||
@DatabaseField(generatedId = true) |
|
||||||
private int id; |
|
||||||
|
|
||||||
@DatabaseField(foreign = true, foreignAutoRefresh = true) |
|
||||||
private Region region; |
|
||||||
|
|
||||||
@DatabaseField(columnName = "member_type", canBeNull = false) |
|
||||||
private String membertype; |
|
||||||
|
|
||||||
@DatabaseField(columnName = "member_name", canBeNull = false) |
|
||||||
private String memberName; |
|
||||||
|
|
||||||
@DatabaseField(columnName = "membership_type", canBeNull = false) |
|
||||||
private String membershipType; |
|
||||||
|
|
||||||
public RegionMember(){ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public RegionMember(Region region, String membertype, String memberName, String membershipType){ |
|
||||||
this.region = region; |
|
||||||
this.membertype = membertype; |
|
||||||
this.memberName = memberName; |
|
||||||
this.membershipType = membershipType; |
|
||||||
} |
|
||||||
|
|
||||||
public Region getRegion() { |
|
||||||
return region; |
|
||||||
} |
|
||||||
|
|
||||||
public String getMembertype() { |
|
||||||
return membertype; |
|
||||||
} |
|
||||||
|
|
||||||
public String getName() { |
|
||||||
return memberName; |
|
||||||
} |
|
||||||
|
|
||||||
public String getMembershipType() { |
|
||||||
return membershipType; |
|
||||||
} |
|
||||||
|
|
||||||
public void setMembershipType(String membershipType) { |
|
||||||
this.membershipType = membershipType; |
|
||||||
} |
|
||||||
|
|
||||||
public void save(){ |
|
||||||
try { |
|
||||||
DaoRegistry.getRegionMemberDao().createOrUpdate(this); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,96 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.database.objects; |
|
||||||
|
|
||||||
import com.j256.ormlite.field.DatabaseField; |
|
||||||
import com.j256.ormlite.table.DatabaseTable; |
|
||||||
import org.bukkit.Location; |
|
||||||
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
|
||||||
|
|
||||||
import java.sql.SQLException; |
|
||||||
|
|
||||||
@DatabaseTable(tableName = "teleport_requests") |
|
||||||
public class TeleportRequest { |
|
||||||
|
|
||||||
@DatabaseField(unique = true, id = true) |
|
||||||
private String player; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private String server; |
|
||||||
|
|
||||||
@DatabaseField(canBeNull = false) |
|
||||||
private String world; |
|
||||||
|
|
||||||
@DatabaseField |
|
||||||
private Integer x; |
|
||||||
|
|
||||||
@DatabaseField |
|
||||||
private Integer y; |
|
||||||
|
|
||||||
@DatabaseField |
|
||||||
private Integer z; |
|
||||||
|
|
||||||
@DatabaseField |
|
||||||
private Float yaw; |
|
||||||
|
|
||||||
@DatabaseField |
|
||||||
private Float pitch; |
|
||||||
|
|
||||||
public TeleportRequest() { |
|
||||||
} |
|
||||||
|
|
||||||
public TeleportRequest(String player, String server, String world) { |
|
||||||
this.player = player; |
|
||||||
this.server = server; |
|
||||||
this.world = world; |
|
||||||
} |
|
||||||
|
|
||||||
public TeleportRequest(String player, String server, String world, Integer x, Integer y, Integer z, Float yaw, Float pitch) { |
|
||||||
this.player = player; |
|
||||||
this.server = server; |
|
||||||
this.world = world; |
|
||||||
this.x = x; |
|
||||||
this.y = y; |
|
||||||
this.z = z; |
|
||||||
this.yaw = yaw; |
|
||||||
this.pitch = pitch; |
|
||||||
} |
|
||||||
|
|
||||||
public String getServer() { |
|
||||||
return server; |
|
||||||
} |
|
||||||
|
|
||||||
public String getWorld() { |
|
||||||
return world; |
|
||||||
} |
|
||||||
|
|
||||||
public String getPlayer() { |
|
||||||
return player; |
|
||||||
} |
|
||||||
|
|
||||||
public Integer getX() { |
|
||||||
return x; |
|
||||||
} |
|
||||||
|
|
||||||
public Integer getY() { |
|
||||||
return y; |
|
||||||
} |
|
||||||
|
|
||||||
public Integer getZ() { |
|
||||||
return z; |
|
||||||
} |
|
||||||
|
|
||||||
public Float getYaw() { |
|
||||||
return yaw; |
|
||||||
} |
|
||||||
|
|
||||||
public Float getPitch() { |
|
||||||
return pitch; |
|
||||||
} |
|
||||||
|
|
||||||
public void save() throws SQLException { |
|
||||||
DaoRegistry.getTeleportRequestsDao().createOrUpdate(this); |
|
||||||
} |
|
||||||
|
|
||||||
public void delete() throws SQLException { |
|
||||||
DaoRegistry.getTeleportRequestsDao().delete(this); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,257 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.islands; |
|
||||||
|
|
||||||
import com.github.retrooper.packetevents.event.PacketListener; |
|
||||||
import com.github.retrooper.packetevents.event.PacketSendEvent; |
|
||||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType; |
|
||||||
import com.github.retrooper.packetevents.protocol.world.chunk.BaseChunk; |
|
||||||
import com.github.retrooper.packetevents.protocol.world.chunk.Column; |
|
||||||
import com.github.retrooper.packetevents.protocol.world.chunk.LightData; |
|
||||||
import com.github.retrooper.packetevents.protocol.world.chunk.TileEntity; |
|
||||||
import com.github.retrooper.packetevents.protocol.world.chunk.impl.v_1_18.Chunk_v1_18; |
|
||||||
import com.github.retrooper.packetevents.protocol.world.chunk.palette.DataPalette; |
|
||||||
import com.github.retrooper.packetevents.protocol.world.chunk.palette.PaletteType; |
|
||||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChunkData; |
|
||||||
import org.bukkit.Bukkit; |
|
||||||
import org.bukkit.NamespacedKey; |
|
||||||
import org.bukkit.World; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import org.bukkit.persistence.PersistentDataContainer; |
|
||||||
import org.bukkit.persistence.PersistentDataType; |
|
||||||
import org.bukkit.plugin.java.JavaPlugin; |
|
||||||
|
|
||||||
import java.lang.reflect.Field; |
|
||||||
import java.lang.reflect.Method; |
|
||||||
import java.util.BitSet; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.HashMap; |
|
||||||
|
|
||||||
public class ChunkModifier implements PacketListener { |
|
||||||
|
|
||||||
private final JavaPlugin plugin; |
|
||||||
private final NamespacedKey keyX1, keyX2, keyZ1, keyZ2, keyType; |
|
||||||
|
|
||||||
HashMap<String, Integer> blockStates = new HashMap<>(); |
|
||||||
|
|
||||||
public ChunkModifier(JavaPlugin plugin) { |
|
||||||
this.plugin = plugin; |
|
||||||
this.keyX1 = new NamespacedKey(plugin, "borderx1"); |
|
||||||
this.keyX2 = new NamespacedKey(plugin, "borderx2"); |
|
||||||
this.keyZ1 = new NamespacedKey(plugin, "bordery1"); // Based on your spec
|
|
||||||
this.keyZ2 = new NamespacedKey(plugin, "borderx2"); // Based on your spec
|
|
||||||
this.keyType = new NamespacedKey(plugin, "island_type"); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onPacketSend(PacketSendEvent event) { |
|
||||||
if (event.getPacketType() != PacketType.Play.Server.CHUNK_DATA) return; |
|
||||||
|
|
||||||
Player bukkitPlayer = Bukkit.getPlayer(event.getUser().getUUID()); |
|
||||||
if (bukkitPlayer == null) return; |
|
||||||
|
|
||||||
World world = bukkitPlayer.getWorld(); |
|
||||||
PersistentDataContainer pdc = world.getPersistentDataContainer(); |
|
||||||
|
|
||||||
String type = pdc.get(keyType, PersistentDataType.STRING); |
|
||||||
if (type == null) return; |
|
||||||
|
|
||||||
String block; |
|
||||||
|
|
||||||
switch (type){ |
|
||||||
case "flat_grass": |
|
||||||
case "flat_sand": |
|
||||||
block = "WATER"; |
|
||||||
break; |
|
||||||
case "flat_hell": |
|
||||||
block = "LAVA"; |
|
||||||
break; |
|
||||||
default: |
|
||||||
return; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
Integer x1 = pdc.get(keyX1, PersistentDataType.INTEGER); |
|
||||||
Integer x2 = pdc.get(keyX2, PersistentDataType.INTEGER); |
|
||||||
Integer z1 = pdc.get(keyZ1, PersistentDataType.INTEGER); |
|
||||||
Integer z2 = pdc.get(keyZ2, PersistentDataType.INTEGER); |
|
||||||
if (x1 == null || x2 == null || z1 == null || z2 == null) return; |
|
||||||
|
|
||||||
int minCX = Math.min(x1 >> 4, x2 >> 4) - 1; |
|
||||||
int maxCX = Math.max(x1 >> 4, x2 >> 4) + 1; |
|
||||||
int minCZ = Math.min(z1 >> 4, z2 >> 4) - 1; |
|
||||||
int maxCZ = Math.max(z1 >> 4, z2 >> 4) + 1; |
|
||||||
|
|
||||||
WrapperPlayServerChunkData wrapper = new WrapperPlayServerChunkData(event); |
|
||||||
|
|
||||||
Column original = wrapper.getColumn(); |
|
||||||
if (original == null) return; |
|
||||||
|
|
||||||
int chunkX = original.getX(); |
|
||||||
int chunkZ = original.getZ(); |
|
||||||
if (chunkX >= minCX && chunkX <= maxCX && chunkZ >= minCZ && chunkZ <= maxCZ) return; |
|
||||||
|
|
||||||
Column ghostColumn = createGhostColumn(world, original, resolveBlockStateID(block)); |
|
||||||
if (ghostColumn == null) return; |
|
||||||
|
|
||||||
wrapper.setColumn(ghostColumn); |
|
||||||
|
|
||||||
wrapper.setLightData(buildFullBrightLightData(world)); |
|
||||||
} |
|
||||||
|
|
||||||
private static LightData buildFullBrightLightData(World world) { |
|
||||||
int sections = (world.getMaxHeight() - world.getMinHeight()) >> 4; |
|
||||||
if (sections <= 0) sections = 24; |
|
||||||
|
|
||||||
int lightCount = sections + 2; |
|
||||||
|
|
||||||
byte[] fullSky = new byte[2048]; |
|
||||||
Arrays.fill(fullSky, (byte) 0xFF); |
|
||||||
|
|
||||||
byte[] noBlock = new byte[2048]; |
|
||||||
|
|
||||||
|
|
||||||
boolean hasSkyLight = world.getEnvironment() != World.Environment.NETHER |
|
||||||
&& world.getEnvironment() != World.Environment.THE_END; // adjust if you have custom dims
|
|
||||||
|
|
||||||
BitSet skyMask = new BitSet(lightCount); |
|
||||||
BitSet blockMask = new BitSet(lightCount); |
|
||||||
BitSet emptySkyMask = new BitSet(lightCount); |
|
||||||
BitSet emptyBlockMask = new BitSet(lightCount); |
|
||||||
|
|
||||||
byte[][] skyArray; |
|
||||||
int skyCount; |
|
||||||
if (hasSkyLight) { |
|
||||||
skyMask.set(0, lightCount); |
|
||||||
skyCount = lightCount; |
|
||||||
skyArray = new byte[skyCount][]; |
|
||||||
for (int i = 0; i < skyCount; i++) { |
|
||||||
skyArray[i] = fullSky; |
|
||||||
} |
|
||||||
} else { |
|
||||||
// no skylight dimension
|
|
||||||
emptySkyMask.set(0, lightCount); |
|
||||||
skyCount = 0; |
|
||||||
skyArray = new byte[0][]; |
|
||||||
} |
|
||||||
|
|
||||||
blockMask.set(0, lightCount); |
|
||||||
int blockCount = lightCount; |
|
||||||
byte[][] blockArray = new byte[blockCount][]; |
|
||||||
for (int i = 0; i < blockCount; i++) { |
|
||||||
blockArray[i] = noBlock; |
|
||||||
} |
|
||||||
|
|
||||||
LightData ld = new LightData(); |
|
||||||
ld.setTrustEdges(true); |
|
||||||
ld.setSkyLightMask(skyMask); |
|
||||||
ld.setBlockLightMask(blockMask); |
|
||||||
ld.setEmptySkyLightMask(emptySkyMask); |
|
||||||
ld.setEmptyBlockLightMask(emptyBlockMask); |
|
||||||
ld.setSkyLightCount(skyCount); |
|
||||||
ld.setBlockLightCount(blockCount); |
|
||||||
ld.setSkyLightArray(skyArray); |
|
||||||
ld.setBlockLightArray(blockArray); |
|
||||||
return ld; |
|
||||||
} |
|
||||||
|
|
||||||
private Column createGhostColumn(World world, Column original, int blockID) { |
|
||||||
int sections = (world.getMaxHeight() - world.getMinHeight()) >> 4; |
|
||||||
if (sections <= 0) sections = 24; |
|
||||||
|
|
||||||
BaseChunk[] originalChunks = original.getChunks(); |
|
||||||
|
|
||||||
// Find any existing biome palette from the original packet; we will reuse it.
|
|
||||||
DataPalette fallbackBiomePalette = null; |
|
||||||
if (originalChunks != null) { |
|
||||||
for (BaseChunk bc : originalChunks) { |
|
||||||
if (bc instanceof Chunk_v1_18 c) { |
|
||||||
fallbackBiomePalette = c.getBiomeData(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
BaseChunk[] chunks = new BaseChunk[sections]; |
|
||||||
|
|
||||||
for (int sectionIndex = 0; sectionIndex < sections; sectionIndex++) { |
|
||||||
DataPalette biomePalette = fallbackBiomePalette; |
|
||||||
|
|
||||||
if (originalChunks != null && sectionIndex < originalChunks.length && originalChunks[sectionIndex] instanceof Chunk_v1_18 c) { |
|
||||||
// Prefer the matching section's biome palette if present
|
|
||||||
biomePalette = c.getBiomeData(); |
|
||||||
} |
|
||||||
|
|
||||||
DataPalette blockPalette = PaletteType.CHUNK.create(); |
|
||||||
|
|
||||||
Chunk_v1_18 section = new Chunk_v1_18(0, blockPalette, biomePalette); |
|
||||||
section.set(0, 0, 0, 0); |
|
||||||
|
|
||||||
chunks[sectionIndex] = section; |
|
||||||
} |
|
||||||
|
|
||||||
if (chunks[0] instanceof Chunk_v1_18 section0) { |
|
||||||
for (int localY = 0; localY <= 1; localY++) { |
|
||||||
for (int x = 0; x < 16; x++) { |
|
||||||
for (int z = 0; z < 16; z++) { |
|
||||||
section0.set(x, localY, z, blockID); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return new Column( |
|
||||||
original.getX(), |
|
||||||
original.getZ(), |
|
||||||
true, |
|
||||||
chunks, |
|
||||||
new TileEntity[0], |
|
||||||
original.getHeightMaps() |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
private int resolveBlockStateID(String name) { |
|
||||||
Integer stateID = blockStates.get(name); |
|
||||||
if (stateID != null) return stateID; |
|
||||||
|
|
||||||
int resolved = 0; |
|
||||||
|
|
||||||
try { |
|
||||||
Object blockState = resolveNmsBlockState(name); |
|
||||||
if (blockState != null) { |
|
||||||
Integer id = tryGetBlockStateIdViaBlockGetId(blockState); |
|
||||||
if (id != null && id > 0) { |
|
||||||
resolved = id; |
|
||||||
} |
|
||||||
} |
|
||||||
} catch (ReflectiveOperationException ignored) { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
blockStates.put(name, resolved); |
|
||||||
return resolved; |
|
||||||
} |
|
||||||
|
|
||||||
private static Object resolveNmsBlockState(String name) throws ReflectiveOperationException { |
|
||||||
Class<?> blocksClass = Class.forName("net.minecraft.world.level.block.Blocks"); |
|
||||||
Field waterField = blocksClass.getField(name); |
|
||||||
Object waterBlock = waterField.get(null); |
|
||||||
|
|
||||||
Method defaultBlockState = waterBlock.getClass().getMethod("defaultBlockState"); |
|
||||||
return defaultBlockState.invoke(waterBlock); |
|
||||||
} |
|
||||||
|
|
||||||
private static Integer tryGetBlockStateIdViaBlockGetId(Object blockState) throws ReflectiveOperationException { |
|
||||||
// Block.getId(BlockState) exists on many modern versions
|
|
||||||
Class<?> blockClass = Class.forName("net.minecraft.world.level.block.Block"); |
|
||||||
Class<?> blockStateClass = Class.forName("net.minecraft.world.level.block.state.BlockState"); |
|
||||||
|
|
||||||
try { |
|
||||||
Method getId = blockClass.getMethod("getId", blockStateClass); |
|
||||||
Object idObj = getId.invoke(null, blockState); |
|
||||||
return (idObj instanceof Integer i) ? i : null; |
|
||||||
} catch (NoSuchMethodException ignored) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,72 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.islands; |
|
||||||
|
|
||||||
import com.infernalsuite.asp.api.exceptions.UnknownWorldException; |
|
||||||
import com.infernalsuite.asp.api.loaders.SlimeLoader; |
|
||||||
import xyz.soukup.ecoCraftCore.EcoCraftCore; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
import java.nio.file.Files; |
|
||||||
import java.nio.file.Path; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.List; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
|
|
||||||
public class FileIslandLoader implements SlimeLoader { |
|
||||||
|
|
||||||
private final Path storagePath; |
|
||||||
private static final String EXTENSION = ".slime"; |
|
||||||
|
|
||||||
public FileIslandLoader() { |
|
||||||
// Creates a directory named 'islands' inside your plugin folder
|
|
||||||
this.storagePath = EcoCraftCore.plugin.getDataFolder().toPath().resolve("island_templates"); |
|
||||||
|
|
||||||
if (!Files.exists(storagePath)) { |
|
||||||
storagePath.toFile().mkdirs(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Path getWorldPath(String worldName) { |
|
||||||
return storagePath.resolve(worldName + EXTENSION); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public byte[] readWorld(String worldName) throws UnknownWorldException, IOException { |
|
||||||
Path path = getWorldPath(worldName); |
|
||||||
if (!Files.exists(path)) { |
|
||||||
throw new UnknownWorldException(worldName); |
|
||||||
} |
|
||||||
return Files.readAllBytes(path); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean worldExists(String worldName) throws IOException { |
|
||||||
return Files.exists(getWorldPath(worldName)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void saveWorld(String worldName, byte[] serializedWorld) throws IOException { |
|
||||||
// Files.write will create or overwrite the file automatically
|
|
||||||
Files.write(getWorldPath(worldName), serializedWorld); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void deleteWorld(String worldName) throws IOException { |
|
||||||
Files.deleteIfExists(getWorldPath(worldName)); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public List<String> listWorlds() throws IOException { |
|
||||||
File folder = storagePath.toFile(); |
|
||||||
File[] files = folder.listFiles((dir, name) -> name.endsWith(EXTENSION)); |
|
||||||
|
|
||||||
if (files == null) { |
|
||||||
return Collections.emptyList(); |
|
||||||
} |
|
||||||
|
|
||||||
return Arrays.stream(files) |
|
||||||
.map(file -> file.getName().replace(EXTENSION, "")) |
|
||||||
.collect(Collectors.toList()); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,347 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.islands; |
|
||||||
|
|
||||||
import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; |
|
||||||
import com.infernalsuite.asp.api.world.SlimeWorld; |
|
||||||
import com.j256.ormlite.stmt.QueryBuilder; |
|
||||||
import com.mojang.brigadier.arguments.IntegerArgumentType; |
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType; |
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
|
||||||
import com.mojang.brigadier.context.CommandContext; |
|
||||||
import io.papermc.paper.command.brigadier.CommandSourceStack; |
|
||||||
import io.papermc.paper.command.brigadier.Commands; |
|
||||||
import org.bukkit.Bukkit; |
|
||||||
import org.bukkit.Location; |
|
||||||
import org.bukkit.NamespacedKey; |
|
||||||
import org.bukkit.Registry; |
|
||||||
import org.bukkit.block.Biome; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import org.bukkit.persistence.PersistentDataContainer; |
|
||||||
import org.bukkit.persistence.PersistentDataType; |
|
||||||
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.Island; |
|
||||||
import xyz.soukup.ecoCraftCore.messages.Messages; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.sql.SQLException; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import static xyz.soukup.ecoCraftCore.EcoCraftCore.config; |
|
||||||
import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin; |
|
||||||
|
|
||||||
public class IslandAdminCommand { |
|
||||||
private final AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance(); |
|
||||||
|
|
||||||
|
|
||||||
public static LiteralArgumentBuilder<CommandSourceStack> getCommand() { |
|
||||||
|
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> tp = Commands.literal("tp") |
|
||||||
.then(Commands.argument("uuid", StringArgumentType.word()) |
|
||||||
.executes(IslandAdminCommand::teleport) |
|
||||||
.suggests(((context, builder) -> { |
|
||||||
try { |
|
||||||
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
|
||||||
queryBuilder.selectColumns("uuid"); |
|
||||||
List<Island> islands = queryBuilder.query(); |
|
||||||
for (Island island : islands) { |
|
||||||
builder.suggest(island.getUuid()); |
|
||||||
} |
|
||||||
return builder.buildFuture(); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
}))); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> create = Commands.literal("create") |
|
||||||
.then(Commands.argument("type", StringArgumentType.word()) |
|
||||||
.suggests(((context, builder) -> { |
|
||||||
try { |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
FileIslandLoader fileLoader = islandManager.fileLoader; |
|
||||||
for (String world: fileLoader.listWorlds()){ |
|
||||||
builder.suggest(world); |
|
||||||
} |
|
||||||
} catch (IOException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
return builder.buildFuture(); |
|
||||||
})) |
|
||||||
.then(Commands.argument("display_name", StringArgumentType.string()) |
|
||||||
.then(Commands.argument("description", StringArgumentType.greedyString()) |
|
||||||
.executes(IslandAdminCommand::createWorld)))); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> load = Commands.literal("load") |
|
||||||
.then(Commands.argument("uuid", StringArgumentType.word()) |
|
||||||
.suggests(((context, builder) -> { |
|
||||||
try { |
|
||||||
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
|
||||||
queryBuilder.selectColumns("uuid"); |
|
||||||
List<Island> islands = queryBuilder.query(); |
|
||||||
for (Island island : islands) { |
|
||||||
builder.suggest(island.getUuid()); |
|
||||||
} |
|
||||||
return builder.buildFuture(); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
})) |
|
||||||
.executes(IslandAdminCommand::loadWorld)); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> loadTemplate = Commands.literal("loadTemplate") |
|
||||||
.then(Commands.argument("name", StringArgumentType.word()) |
|
||||||
.suggests(((context, builder) -> { |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
FileIslandLoader fileLoader = islandManager.fileLoader; |
|
||||||
|
|
||||||
try { |
|
||||||
for (String world: fileLoader.listWorlds()){ |
|
||||||
builder.suggest(world); |
|
||||||
} |
|
||||||
} catch (IOException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
return builder.buildFuture(); |
|
||||||
})) |
|
||||||
.executes(IslandAdminCommand::loadTemplate)); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> setBiome = Commands.literal("biome") |
|
||||||
.then(Commands.argument("biome", StringArgumentType.string()) |
|
||||||
.suggests(((context, builder) -> { |
|
||||||
Registry<Biome> biomeRegistry = Registry.BIOME; |
|
||||||
biomeRegistry.stream().forEach(biome -> builder.suggest(biome.getKey().asString())); |
|
||||||
return builder.buildFuture(); |
|
||||||
})) |
|
||||||
.executes(IslandAdminCommand::setBiome)); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> template = Commands.literal("template") |
|
||||||
.then(Commands.argument("uuid", StringArgumentType.word()) |
|
||||||
.suggests((context, builder) -> { |
|
||||||
try { |
|
||||||
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
|
||||||
queryBuilder.selectColumns("uuid"); |
|
||||||
List<Island> islands = queryBuilder.query(); |
|
||||||
for (Island island : islands) { |
|
||||||
builder.suggest(island.getUuid()); |
|
||||||
} |
|
||||||
return builder.buildFuture(); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
}) |
|
||||||
.then(Commands.argument("templateName", StringArgumentType.word()) |
|
||||||
.executes(IslandAdminCommand::createTemplate))); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> metadata = Commands.literal("metadata") |
|
||||||
.then(Commands.argument("key", StringArgumentType.word()) |
|
||||||
.then(Commands.argument("value", IntegerArgumentType.integer()) |
|
||||||
.executes(IslandAdminCommand::setMetadata))); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> metadataString = Commands.literal("metadataString") |
|
||||||
.then(Commands.argument("key", StringArgumentType.word()) |
|
||||||
.then(Commands.argument("value", StringArgumentType.string()) |
|
||||||
.executes(IslandAdminCommand::setMetadataString))); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> expand = Commands.literal("expand") |
|
||||||
.then(Commands.argument("lenght", IntegerArgumentType.integer()) |
|
||||||
.executes(IslandAdminCommand::expandIsland)); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> listMetadata = Commands.literal("listMetadata") |
|
||||||
.executes(IslandAdminCommand::readAllMetadata); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> spawn = Commands.literal("spawn") |
|
||||||
.executes(IslandAdminCommand::setSpawn); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> enviroment = Commands.literal("environment") |
|
||||||
.then(Commands.argument("environment", StringArgumentType.word()) |
|
||||||
.executes(IslandAdminCommand::setEnvironment) |
|
||||||
.suggests(((context, builder) -> { |
|
||||||
builder.suggest("normal"); |
|
||||||
builder.suggest("nether"); |
|
||||||
builder.suggest("the_end"); |
|
||||||
return builder.buildFuture(); |
|
||||||
}))); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> setDefaultIsland = Commands.literal("setDefaultIsland") |
|
||||||
.executes(IslandAdminCommand::setDefualtIsland); |
|
||||||
|
|
||||||
return Commands.literal("island-admin") |
|
||||||
.requires(commandSourceStack -> commandSourceStack.getSender().isOp()) |
|
||||||
.then(tp) |
|
||||||
.then(create) |
|
||||||
.then(load) |
|
||||||
.then(template) |
|
||||||
.then(metadata) |
|
||||||
.then(metadataString) |
|
||||||
.then(listMetadata) |
|
||||||
.then(loadTemplate) |
|
||||||
.then(spawn) |
|
||||||
.then(enviroment) |
|
||||||
.then(expand) |
|
||||||
.then(setDefaultIsland) |
|
||||||
.then(setBiome); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private static int setDefualtIsland(CommandContext<CommandSourceStack> context){ |
|
||||||
if (!(context.getSource().getSender() instanceof Player player)) return 0; |
|
||||||
String uuid = player.getWorld().getName(); |
|
||||||
config.set("islands.spawn", uuid); |
|
||||||
plugin.saveConfig(); |
|
||||||
player.sendMessage("done."); |
|
||||||
return 0; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private static int setSpawn(CommandContext<CommandSourceStack> context) { |
|
||||||
if (!(context.getSource().getSender() instanceof Player player)) return 0; |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
Location spawn = player.getLocation(); |
|
||||||
String uuid = player.getWorld().getName(); |
|
||||||
islandManager.changeSpawn(spawn, uuid); |
|
||||||
Messages.send(player, "island.setSpawn.success"); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static int setEnvironment(CommandContext<CommandSourceStack> context) { |
|
||||||
if (!(context.getSource().getSender() instanceof Player player)) return 0; |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
String uuid = player.getWorld().getName(); |
|
||||||
islandManager.changeEnviroment(context.getArgument("environment", String.class), uuid); |
|
||||||
Messages.send(player, "island.setEnvironment.success"); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static int setBiome(CommandContext<CommandSourceStack> context) { |
|
||||||
if (!(context.getSource().getSender() instanceof Player player)) return 0; |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
String uuid = player.getWorld().getName(); |
|
||||||
islandManager.changeBiome(context.getArgument("biome", String.class), uuid); |
|
||||||
Messages.send(player, "island.set-biome.success"); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private static int teleport(CommandContext<CommandSourceStack> context) { |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
try { |
|
||||||
Integer status = islandManager.teleport((Player) context.getSource().getSender(), context.getArgument("uuid", String.class)); |
|
||||||
context.getSource().getSender().sendMessage(String.valueOf(status)); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static int createWorld(CommandContext<CommandSourceStack> context) { |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
String type = context.getArgument("type", String.class); |
|
||||||
String displayName = context.getArgument("display_name", String.class); |
|
||||||
String description = context.getArgument("description", String.class); |
|
||||||
String owner = context.getSource().getSender().getName(); |
|
||||||
String uuid = islandManager.createIsland(type, displayName, description, owner, "player"); |
|
||||||
context.getSource().getSender().sendMessage("Created island: " + uuid); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static int loadWorld(CommandContext<CommandSourceStack> context) { |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
islandManager.loadIsland(context.getArgument("uuid", String.class)); |
|
||||||
context.getSource().getSender().sendMessage("done."); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static int loadTemplate(CommandContext<CommandSourceStack> context) { |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
islandManager.loadIslandTemplate(context.getArgument("name", String.class)); |
|
||||||
context.getSource().getSender().sendMessage("done."); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static int createTemplate(CommandContext<CommandSourceStack> context) { |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
String uuid = StringArgumentType.getString(context, "uuid"); |
|
||||||
String templateName = StringArgumentType.getString(context, "templateName"); |
|
||||||
context.getSource().getSender().sendMessage("§aCreating template '" + templateName + "' from world '" + uuid + "'..."); |
|
||||||
islandManager.createIslandTemplate(uuid, templateName); |
|
||||||
context.getSource().getSender().sendMessage("§aTemplate created successfully!"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
private static int setMetadata(CommandContext<CommandSourceStack> context) { |
|
||||||
if (!(context.getSource().getSender() instanceof Player player)) return 0; |
|
||||||
|
|
||||||
String keyName = StringArgumentType.getString(context, "key"); |
|
||||||
Integer value = IntegerArgumentType.getInteger(context, "value"); |
|
||||||
|
|
||||||
player.getWorld().getPersistentDataContainer().set(new NamespacedKey(plugin, keyName), PersistentDataType.INTEGER, value); |
|
||||||
context.getSource().getSender().sendMessage(keyName + " set to " + value); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
private static int setMetadataString(CommandContext<CommandSourceStack> context) { |
|
||||||
if (!(context.getSource().getSender() instanceof Player player)) return 0; |
|
||||||
|
|
||||||
String keyName = StringArgumentType.getString(context, "key"); |
|
||||||
String value = StringArgumentType.getString(context, "value"); |
|
||||||
|
|
||||||
player.getWorld().getPersistentDataContainer().set(new NamespacedKey(plugin, keyName), PersistentDataType.STRING, value); |
|
||||||
context.getSource().getSender().sendMessage(keyName + " set to " + value); |
|
||||||
|
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
private static int readAllMetadata(CommandContext<CommandSourceStack> context) { |
|
||||||
if (!(context.getSource().getSender() instanceof Player player)) { |
|
||||||
context.getSource().getSender().sendMessage("§cOnly players can use this."); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
PersistentDataContainer pdc = player.getWorld().getPersistentDataContainer(); |
|
||||||
if (pdc.getKeys().isEmpty()) { |
|
||||||
player.sendMessage("§eNo metadata found."); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
player.sendMessage("§6--- World Metadata ---"); |
|
||||||
for (NamespacedKey key : pdc.getKeys()) { |
|
||||||
String val = "unknown"; |
|
||||||
// Logic to determine type for display
|
|
||||||
if (pdc.has(key, PersistentDataType.STRING)) val = pdc.get(key, PersistentDataType.STRING); |
|
||||||
else if (pdc.has(key, PersistentDataType.INTEGER)) val = String.valueOf(pdc.get(key, PersistentDataType.INTEGER)); |
|
||||||
|
|
||||||
player.sendMessage("§b" + key.getKey() + "§7: §f" + val); |
|
||||||
} |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
private static int expandIsland(CommandContext<CommandSourceStack> context){ |
|
||||||
|
|
||||||
Player player = (Player) context.getSource().getSender(); |
|
||||||
float yaw = player.getLocation().getYaw(); |
|
||||||
int lenght = IntegerArgumentType.getInteger(context, "lenght"); |
|
||||||
String uuid = player.getWorld().getName(); |
|
||||||
|
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
islandManager.expandIsland(yaw, lenght, uuid); |
|
||||||
|
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static void saveSlimeWorld(SlimeWorld world, Player player, String key, String val) { |
|
||||||
try { |
|
||||||
AdvancedSlimePaperAPI.instance().saveWorld(world); |
|
||||||
player.sendMessage("§aMetadata set: §f" + key + " §7= §f" + val); |
|
||||||
} catch (IOException e) { |
|
||||||
player.sendMessage("§cFailed to save world metadata!"); |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,32 @@ |
|||||||
|
package xyz.soukup.ecoCraftCore.islands; |
||||||
|
|
||||||
|
import com.mojang.brigadier.arguments.StringArgumentType; |
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
||||||
|
import com.mojang.brigadier.context.CommandContext; |
||||||
|
import io.papermc.paper.command.brigadier.CommandSourceStack; |
||||||
|
import io.papermc.paper.command.brigadier.Commands; |
||||||
|
|
||||||
|
|
||||||
|
public class IslandCommand { |
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> tp = Commands.literal("tp") |
||||||
|
.then(Commands.argument("uuid", StringArgumentType.word()) |
||||||
|
.executes(IslandCommand::teleport)); |
||||||
|
|
||||||
|
LiteralArgumentBuilder<CommandSourceStack> create = Commands.literal("create") |
||||||
|
.then(Commands.argument("name", StringArgumentType.word()) |
||||||
|
.then(Commands.argument("display_name", StringArgumentType.string()))); |
||||||
|
|
||||||
|
private static int teleport(CommandContext<CommandSourceStack> context) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
private static int createWorld(CommandContext<CommandSourceStack> context) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
private static int loadWorld(CommandContext<CommandSourceStack> context) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,188 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.islands; |
|
||||||
|
|
||||||
import com.github.stefvanschie.inventoryframework.gui.GuiItem; |
|
||||||
import com.github.stefvanschie.inventoryframework.gui.type.ChestGui; |
|
||||||
import com.github.stefvanschie.inventoryframework.gui.type.HopperGui; |
|
||||||
import com.github.stefvanschie.inventoryframework.pane.OutlinePane; |
|
||||||
import com.github.stefvanschie.inventoryframework.pane.PaginatedPane; |
|
||||||
import com.github.stefvanschie.inventoryframework.pane.component.PagingButtons; |
|
||||||
import com.github.stefvanschie.inventoryframework.pane.util.Slot; |
|
||||||
import com.j256.ormlite.stmt.QueryBuilder; |
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
|
||||||
import com.mojang.brigadier.context.CommandContext; |
|
||||||
import io.papermc.paper.command.brigadier.CommandSourceStack; |
|
||||||
import io.papermc.paper.command.brigadier.Commands; |
|
||||||
import net.kyori.adventure.text.Component; |
|
||||||
import net.kyori.adventure.text.format.TextColor; |
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; |
|
||||||
import org.bukkit.Material; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.Island; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.Region; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.RegionMember; |
|
||||||
import xyz.soukup.ecoCraftCore.gui.GuiItemBuilder; |
|
||||||
import xyz.soukup.ecoCraftCore.messages.Messages; |
|
||||||
|
|
||||||
import java.sql.SQLException; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Objects; |
|
||||||
|
|
||||||
public class IslandSelectorCommand { |
|
||||||
|
|
||||||
public static LiteralArgumentBuilder<CommandSourceStack> getCommand(){ |
|
||||||
return Commands.literal("is") |
|
||||||
.executes(IslandSelectorCommand::displayIslandListSelectorGui); |
|
||||||
} |
|
||||||
|
|
||||||
private static int displayIslandListSelectorGui(CommandContext<CommandSourceStack> context) { |
|
||||||
String title = LegacyComponentSerializer.legacySection().serialize(Messages.get("menu.island-selector.title")); |
|
||||||
HopperGui hopperGui = new HopperGui(title); |
|
||||||
hopperGui.setOnGlobalClick(event -> event.setCancelled(true)); |
|
||||||
|
|
||||||
OutlinePane outlinePane = new OutlinePane(0, 0, 5, 1); |
|
||||||
Player player = (Player) context.getSource().getSender(); |
|
||||||
|
|
||||||
outlinePane.addItem(selectorItem("menu.island-selector.my-islands", Material.GRASS_BLOCK, getMyIslands(player))); |
|
||||||
outlinePane.addItem(selectorItem("menu.island-selector.shared-islands", Material.MOSS_BLOCK, getSharedIslands(player))); |
|
||||||
outlinePane.addItem(selectorItem("menu.island-selector.public-islands", Material.SAND, getPublicIslands())); |
|
||||||
|
|
||||||
hopperGui.getSlotsComponent().addPane(outlinePane); |
|
||||||
|
|
||||||
if (player.isOp()){ |
|
||||||
outlinePane.addItem(selectorItem("menu.island-selector.all-islands", Material.CRIMSON_NYLIUM, getAllIslands())); |
|
||||||
} |
|
||||||
|
|
||||||
hopperGui.show(player); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static List<Island> getAllIslands(){ |
|
||||||
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
|
||||||
queryBuilder.selectColumns("display_name", "uuid", "descritpion", "type"); |
|
||||||
try { |
|
||||||
return queryBuilder.query(); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static List<Island> getPublicIslands(){ |
|
||||||
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
|
||||||
queryBuilder.selectColumns("display_name", "uuid", "descritpion", "type"); |
|
||||||
try { |
|
||||||
queryBuilder.where().eq("is_public", true); |
|
||||||
return queryBuilder.query(); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static List<Island> getMyIslands(Player player){ |
|
||||||
QueryBuilder<Island, Integer> queryBuilder = DaoRegistry.getIslandDao().queryBuilder(); |
|
||||||
queryBuilder.selectColumns("display_name", "uuid", "descritpion", "type"); |
|
||||||
try { |
|
||||||
queryBuilder.where().eq("owner", player.getName()).and().eq("owner_type", "player"); |
|
||||||
return queryBuilder.query(); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static List<Island> getSharedIslands(Player player){ |
|
||||||
QueryBuilder<RegionMember, Integer> memberQb = DaoRegistry.getRegionMemberDao().queryBuilder(); |
|
||||||
memberQb.selectColumns("region_id"); |
|
||||||
try { |
|
||||||
memberQb.where().eq("member_name", player.getName()).and().eq("member_type", "player"); |
|
||||||
|
|
||||||
QueryBuilder<Region, Integer> regionQb = DaoRegistry.getRegionDao().queryBuilder(); |
|
||||||
regionQb.selectColumns("island"); |
|
||||||
regionQb.where().in("id", memberQb); |
|
||||||
|
|
||||||
return DaoRegistry.getIslandDao().queryBuilder() |
|
||||||
.where() |
|
||||||
.in("uuid", regionQb) |
|
||||||
.query(); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public static GuiItem selectorItem(String key, Material material, List<Island> islands){ |
|
||||||
GuiItemBuilder guiItemBuilder = new GuiItemBuilder(material); |
|
||||||
guiItemBuilder.setName(Messages.get(key)); |
|
||||||
GuiItem guiItem = guiItemBuilder.build(); |
|
||||||
guiItem.setAction(event -> openIslandListGui((Player) event.getWhoClicked(), islands)); |
|
||||||
return guiItem; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private static void openIslandListGui(Player player, List<Island> islands){ |
|
||||||
String title = LegacyComponentSerializer.legacySection().serialize(Messages.get("menu.island-selector.title")); |
|
||||||
ChestGui chestGui = new ChestGui(4, title); |
|
||||||
chestGui.setOnGlobalClick(event -> event.setCancelled(true)); |
|
||||||
|
|
||||||
PaginatedPane paginatedPane = new PaginatedPane(0, 0, 9, 3); |
|
||||||
|
|
||||||
paginatedPane.populateWithGuiItems(itemsFromIslands(player, islands)); |
|
||||||
PagingButtons pagingButtons = new PagingButtons(Slot.fromXY(0, 3), 9, paginatedPane); |
|
||||||
|
|
||||||
chestGui.addPane(paginatedPane); |
|
||||||
chestGui.addPane(pagingButtons); |
|
||||||
|
|
||||||
chestGui.show(player); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private static List<GuiItem> itemsFromIslands(Player player, List<Island> islands){ |
|
||||||
List<GuiItem> guiItems = new ArrayList<>(); |
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
for (Island island : islands){ |
|
||||||
Material material; |
|
||||||
TextColor color; |
|
||||||
|
|
||||||
switch (island.getType()){ |
|
||||||
case "flat_grass": |
|
||||||
material = Material.GRASS_BLOCK; |
|
||||||
color = TextColor.color(0x02bd02); |
|
||||||
break; |
|
||||||
case "flat_sand": |
|
||||||
material = Material.SAND; |
|
||||||
color = TextColor.color(0xfccf03); |
|
||||||
break; |
|
||||||
case "flat_hell": |
|
||||||
material = Material.SOUL_SAND; |
|
||||||
color = TextColor.color(0xf00707); |
|
||||||
break; |
|
||||||
case "void": |
|
||||||
material = Material.GLASS; |
|
||||||
color = TextColor.color(0xffffff); |
|
||||||
break; |
|
||||||
default: |
|
||||||
material = Material.WHITE_WOOL; |
|
||||||
color = TextColor.color(0xffffff); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
GuiItemBuilder guiItemBuilder = new GuiItemBuilder(material); |
|
||||||
guiItemBuilder.setName(Component.text(island.getDisplayName(), color)); |
|
||||||
guiItemBuilder.setRawLore(island.getDescritpion()); |
|
||||||
|
|
||||||
GuiItem guiItem = guiItemBuilder.build(); |
|
||||||
guiItem.setAction(event -> { |
|
||||||
try { |
|
||||||
islandManager.teleport(player, island.getUuid()); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
guiItems.add(guiItem); |
|
||||||
|
|
||||||
} |
|
||||||
return guiItems; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,4 +1,4 @@ |
|||||||
package xyz.soukup.ecoCraftCore.islands; |
package xyz.soukup.ecoCraftCore.islands; |
||||||
|
|
||||||
public class UnloadIsland { |
public class UnloadWorld { |
||||||
} |
} |
||||||
@ -1,18 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.messages; |
|
||||||
|
|
||||||
import org.bukkit.event.EventHandler; |
|
||||||
import org.bukkit.event.Listener; |
|
||||||
import org.bukkit.event.player.PlayerJoinEvent; |
|
||||||
import org.bukkit.event.player.PlayerQuitEvent; |
|
||||||
|
|
||||||
public class JoinLeaveMessageSupress implements Listener { |
|
||||||
@EventHandler |
|
||||||
public void onJoin(PlayerJoinEvent event) { |
|
||||||
event.joinMessage(null); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onQuit(PlayerQuitEvent event) { |
|
||||||
event.quitMessage(null); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,75 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines; |
|
||||||
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
|
||||||
import com.mojang.brigadier.context.CommandContext; |
|
||||||
import io.papermc.paper.command.brigadier.CommandSourceStack; |
|
||||||
import io.papermc.paper.command.brigadier.Commands; |
|
||||||
import org.bukkit.Location; |
|
||||||
import org.bukkit.World; |
|
||||||
import org.bukkit.command.CommandSender; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import xyz.soukup.ecoCraftCore.messages.Messages; |
|
||||||
|
|
||||||
@SuppressWarnings("UnstableApiUsage") |
|
||||||
public class MineCommand { |
|
||||||
|
|
||||||
public static LiteralArgumentBuilder<CommandSourceStack> createCommand() { |
|
||||||
LiteralArgumentBuilder<CommandSourceStack> regenerate = Commands.literal("regenerate") |
|
||||||
.executes(MineCommand::regenerateMines); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> tp = Commands.literal("tp") |
|
||||||
.requires(source -> source.getSender() instanceof Player) |
|
||||||
.executes(MineCommand::teleportToMines); |
|
||||||
|
|
||||||
return Commands.literal("mine") |
|
||||||
.then(regenerate) |
|
||||||
.then(tp); |
|
||||||
} |
|
||||||
|
|
||||||
private static int regenerateMines(CommandContext<CommandSourceStack> context) { |
|
||||||
CommandSender sender = context.getSource().getSender(); |
|
||||||
World world = MineWorldManager.getWorld(); |
|
||||||
|
|
||||||
if (world == null) { |
|
||||||
Messages.send(sender, "mine.error.no-world"); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
Messages.send(sender, "mine.regenerating"); |
|
||||||
|
|
||||||
for (Player player : world.getPlayers()) { |
|
||||||
player.teleport(player.getServer().getWorlds().getFirst().getSpawnLocation()); |
|
||||||
Messages.send(player, "mine.teleported-out"); |
|
||||||
} |
|
||||||
|
|
||||||
MineWorldManager.recreateWorld(newWorld -> { |
|
||||||
boolean success = MineManager.regenerate(newWorld); |
|
||||||
if (success) { |
|
||||||
Messages.send(sender, "mine.regenerate-complete"); |
|
||||||
} else { |
|
||||||
Messages.send(sender, "mine.error.regenerate-failed"); |
|
||||||
} |
|
||||||
}); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
private static int teleportToMines(CommandContext<CommandSourceStack> context) { |
|
||||||
Player player = (Player) context.getSource().getSender(); |
|
||||||
World world = MineWorldManager.getWorld(); |
|
||||||
|
|
||||||
if (world == null) { |
|
||||||
Messages.send(player, "mine.error.no-world"); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
Location spawn = MineWorldManager.getSpawnLocation(); |
|
||||||
if (spawn == null) { |
|
||||||
Messages.send(player, "mine.error.no-world"); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
player.teleport(spawn); |
|
||||||
Messages.send(player, "mine.teleporting"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,62 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines; |
|
||||||
|
|
||||||
import org.bukkit.Location; |
|
||||||
import org.bukkit.World; |
|
||||||
import xyz.soukup.ecoCraftCore.mines.generation.MineGenerationConfig; |
|
||||||
import xyz.soukup.ecoCraftCore.mines.generation.MineGenerator; |
|
||||||
import xyz.soukup.ecoCraftCore.mines.generation.MineRoomLibrary; |
|
||||||
|
|
||||||
import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin; |
|
||||||
|
|
||||||
public final class MineManager { |
|
||||||
|
|
||||||
private MineManager() { |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean regenerate(World world) { |
|
||||||
MineGenerationConfig generationConfig = MineGenerationConfig.fromConfiguration(plugin.getConfig(), world); |
|
||||||
MineRoomLibrary roomLibrary = MineRoomLibrary.load( |
|
||||||
plugin.getDataFolder(), |
|
||||||
generationConfig.roomsDirectory(), |
|
||||||
plugin.getLogger() |
|
||||||
); |
|
||||||
|
|
||||||
if (roomLibrary.isEmpty()) { |
|
||||||
plugin.getLogger().severe("[MineGen] No valid room prefabs were loaded from: " |
|
||||||
+ roomLibrary.roomsDirectory().getAbsolutePath()); |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
MineGenerator.Result generationResult = new MineGenerator( |
|
||||||
world, |
|
||||||
generationConfig, |
|
||||||
roomLibrary, |
|
||||||
plugin.getLogger() |
|
||||||
).generate(); |
|
||||||
|
|
||||||
if (!generationResult.success()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
Location spawn = getConfiguredSpawnLocation(world); |
|
||||||
world.setSpawnLocation(spawn); |
|
||||||
|
|
||||||
plugin.getLogger().info("[MineGen] Mine generated with " + generationResult.roomsPlaced() + " rooms."); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public static Location getConfiguredSpawnLocation(World world) { |
|
||||||
Location fallback = new Location(world, 5.5, world.getMaxHeight() - 9, 5.5, 0f, 0f); |
|
||||||
|
|
||||||
if (!plugin.getConfig().isConfigurationSection("mine.spawn")) { |
|
||||||
return fallback; |
|
||||||
} |
|
||||||
|
|
||||||
double x = plugin.getConfig().getDouble("mine.spawn.x", fallback.getX()); |
|
||||||
double y = plugin.getConfig().getDouble("mine.spawn.y", fallback.getY()); |
|
||||||
double z = plugin.getConfig().getDouble("mine.spawn.z", fallback.getZ()); |
|
||||||
float yaw = (float) plugin.getConfig().getDouble("mine.spawn.yaw", 0.0); |
|
||||||
float pitch = (float) plugin.getConfig().getDouble("mine.spawn.pitch", 0.0); |
|
||||||
return new Location(world, x, y, z, yaw, pitch); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,230 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines; |
|
||||||
|
|
||||||
import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; |
|
||||||
import com.infernalsuite.asp.api.world.SlimeWorld; |
|
||||||
import com.infernalsuite.asp.api.world.properties.SlimeProperties; |
|
||||||
import com.infernalsuite.asp.api.world.properties.SlimePropertyMap; |
|
||||||
import org.bukkit.Bukkit; |
|
||||||
import org.bukkit.GameRule; |
|
||||||
import org.bukkit.Location; |
|
||||||
import org.bukkit.Material; |
|
||||||
import org.bukkit.World; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import org.bukkit.event.EventHandler; |
|
||||||
import org.bukkit.event.Listener; |
|
||||||
import org.bukkit.event.block.BlockBreakEvent; |
|
||||||
import org.bukkit.event.block.BlockExplodeEvent; |
|
||||||
import org.bukkit.event.entity.EntityExplodeEvent; |
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent; |
|
||||||
import org.bukkit.event.player.PlayerChangedWorldEvent; |
|
||||||
import org.bukkit.event.player.PlayerItemDamageEvent; |
|
||||||
import org.bukkit.event.player.PlayerJoinEvent; |
|
||||||
import org.bukkit.potion.PotionEffect; |
|
||||||
import org.bukkit.potion.PotionEffectType; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.Island; |
|
||||||
import xyz.soukup.ecoCraftCore.islands.DatabaseIslandLoader; |
|
||||||
|
|
||||||
import java.util.function.Consumer; |
|
||||||
|
|
||||||
import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin; |
|
||||||
|
|
||||||
public class MineWorldManager implements Listener { |
|
||||||
|
|
||||||
public static final String MINE_WORLD_NAME = "mine_world"; |
|
||||||
private static World mineWorld; |
|
||||||
|
|
||||||
public static void init() { |
|
||||||
AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance(); |
|
||||||
DatabaseIslandLoader loader = new DatabaseIslandLoader(); |
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { |
|
||||||
try { |
|
||||||
SlimeWorld slimeWorld = null; |
|
||||||
|
|
||||||
if (loader.worldExists(MINE_WORLD_NAME)) { |
|
||||||
try { |
|
||||||
slimeWorld = asp.readWorld(loader, MINE_WORLD_NAME, false, new SlimePropertyMap()); |
|
||||||
} catch (Exception exception) { |
|
||||||
plugin.getLogger().warning("Mine world data is corrupted, recreating..."); |
|
||||||
loader.deleteWorld(MINE_WORLD_NAME); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (slimeWorld == null) { |
|
||||||
SlimePropertyMap properties = new SlimePropertyMap(); |
|
||||||
properties.setValue(SlimeProperties.ENVIRONMENT, "NORMAL"); |
|
||||||
|
|
||||||
Island island = new Island("mine", MINE_WORLD_NAME, "Mine World", "Shared mine world", "server", "system", null); |
|
||||||
island.save(); |
|
||||||
|
|
||||||
slimeWorld = asp.createEmptyWorld(MINE_WORLD_NAME, false, properties, loader); |
|
||||||
} |
|
||||||
|
|
||||||
SlimeWorld finalWorld = slimeWorld; |
|
||||||
Bukkit.getScheduler().runTask(plugin, () -> { |
|
||||||
asp.loadWorld(finalWorld, true); |
|
||||||
mineWorld = Bukkit.getWorld(MINE_WORLD_NAME); |
|
||||||
|
|
||||||
if (mineWorld != null) { |
|
||||||
mineWorld.setGameRule(GameRule.DO_MOB_SPAWNING, false); |
|
||||||
mineWorld.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); |
|
||||||
mineWorld.setGameRule(GameRule.DO_WEATHER_CYCLE, false); |
|
||||||
mineWorld.setTime(6000); |
|
||||||
if (plugin.getConfig().getBoolean("mine.paste-on-startup", false)) { |
|
||||||
MineManager.regenerate(mineWorld); |
|
||||||
} |
|
||||||
plugin.getLogger().info("Mine world loaded successfully."); |
|
||||||
} |
|
||||||
}); |
|
||||||
} catch (Exception exception) { |
|
||||||
exception.printStackTrace(); |
|
||||||
plugin.getLogger().severe("Failed to load mine world."); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
public static World getWorld() { |
|
||||||
return mineWorld; |
|
||||||
} |
|
||||||
|
|
||||||
public static Location getSpawnLocation() { |
|
||||||
if (mineWorld == null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
return MineManager.getConfiguredSpawnLocation(mineWorld); |
|
||||||
} |
|
||||||
|
|
||||||
public static void recreateWorld(Consumer<World> callback) { |
|
||||||
AdvancedSlimePaperAPI asp = AdvancedSlimePaperAPI.instance(); |
|
||||||
DatabaseIslandLoader loader = new DatabaseIslandLoader(); |
|
||||||
|
|
||||||
plugin.getLogger().info("[MineWorld] Unloading old mine world..."); |
|
||||||
|
|
||||||
if (mineWorld != null) { |
|
||||||
Bukkit.unloadWorld(mineWorld, false); |
|
||||||
mineWorld = null; |
|
||||||
} |
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { |
|
||||||
try { |
|
||||||
loader.deleteWorld(MINE_WORLD_NAME); |
|
||||||
plugin.getLogger().info("[MineWorld] Old mine world metadata deleted."); |
|
||||||
|
|
||||||
SlimePropertyMap properties = new SlimePropertyMap(); |
|
||||||
properties.setValue(SlimeProperties.ENVIRONMENT, "NORMAL"); |
|
||||||
|
|
||||||
Island island = new Island("mine", MINE_WORLD_NAME, "Mine World", "Shared mine world", "server", "system", null); |
|
||||||
island.save(); |
|
||||||
|
|
||||||
SlimeWorld slimeWorld = asp.createEmptyWorld(MINE_WORLD_NAME, false, properties, loader); |
|
||||||
|
|
||||||
Bukkit.getScheduler().runTask(plugin, () -> { |
|
||||||
asp.loadWorld(slimeWorld, true); |
|
||||||
mineWorld = Bukkit.getWorld(MINE_WORLD_NAME); |
|
||||||
|
|
||||||
if (mineWorld != null) { |
|
||||||
mineWorld.setGameRule(GameRule.DO_MOB_SPAWNING, false); |
|
||||||
mineWorld.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); |
|
||||||
mineWorld.setGameRule(GameRule.DO_WEATHER_CYCLE, false); |
|
||||||
mineWorld.setTime(6000); |
|
||||||
plugin.getLogger().info("[MineWorld] Fresh mine world created and loaded."); |
|
||||||
callback.accept(mineWorld); |
|
||||||
} else { |
|
||||||
plugin.getLogger().severe("[MineWorld] Failed to load fresh mine world."); |
|
||||||
} |
|
||||||
}); |
|
||||||
} catch (Exception exception) { |
|
||||||
exception.printStackTrace(); |
|
||||||
plugin.getLogger().severe("[MineWorld] Failed to recreate mine world."); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
private boolean isInMineWorld(Player player) { |
|
||||||
return player.getWorld().equals(mineWorld); |
|
||||||
} |
|
||||||
|
|
||||||
private boolean isInMineWorld(World world) { |
|
||||||
return world.equals(mineWorld); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onWorldChange(PlayerChangedWorldEvent event) { |
|
||||||
Player player = event.getPlayer(); |
|
||||||
|
|
||||||
if (isInMineWorld(player)) { |
|
||||||
applyMiningFatigue(player); |
|
||||||
} |
|
||||||
|
|
||||||
if (isInMineWorld(event.getFrom())) { |
|
||||||
player.removePotionEffect(PotionEffectType.MINING_FATIGUE); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onJoin(PlayerJoinEvent event) { |
|
||||||
Player player = event.getPlayer(); |
|
||||||
if (isInMineWorld(player)) { |
|
||||||
applyMiningFatigue(player); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onDeath(PlayerDeathEvent event) { |
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> { |
|
||||||
Player player = event.getPlayer(); |
|
||||||
if (isInMineWorld(player)) { |
|
||||||
applyMiningFatigue(player); |
|
||||||
} |
|
||||||
}, 1L); |
|
||||||
} |
|
||||||
|
|
||||||
private void applyMiningFatigue(Player player) { |
|
||||||
player.addPotionEffect(new PotionEffect( |
|
||||||
PotionEffectType.MINING_FATIGUE, |
|
||||||
Integer.MAX_VALUE, |
|
||||||
0, |
|
||||||
true, |
|
||||||
false, |
|
||||||
false |
|
||||||
)); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onItemDamage(PlayerItemDamageEvent event) { |
|
||||||
if (!isInMineWorld(event.getPlayer())) { |
|
||||||
return; |
|
||||||
} |
|
||||||
if (event.getItem().getType().getMaxDurability() <= 0) { |
|
||||||
return; |
|
||||||
} |
|
||||||
event.setDamage(event.getDamage() * 2); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onEntityExplode(EntityExplodeEvent event) { |
|
||||||
if (!isInMineWorld(event.getEntity().getWorld())) { |
|
||||||
return; |
|
||||||
} |
|
||||||
event.blockList().removeIf(block -> block.getType() == Material.BEDROCK); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onBlockExplode(BlockExplodeEvent event) { |
|
||||||
if (!isInMineWorld(event.getBlock().getWorld())) { |
|
||||||
return; |
|
||||||
} |
|
||||||
event.blockList().removeIf(block -> block.getType() == Material.BEDROCK); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onBlockBreak(BlockBreakEvent event) { |
|
||||||
if (!isInMineWorld(event.getPlayer())) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (event.getBlock().getType() == Material.BEDROCK) { |
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,50 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines.generation; |
|
||||||
|
|
||||||
import java.util.Locale; |
|
||||||
|
|
||||||
public record MineBranchState( |
|
||||||
int branchId, |
|
||||||
boolean mainPath, |
|
||||||
int depth, |
|
||||||
String activeNaturalBiome, |
|
||||||
int biomeOriginDepth, |
|
||||||
int naturalBiomeLength |
|
||||||
) { |
|
||||||
|
|
||||||
public boolean hasActiveNaturalBiome() { |
|
||||||
return activeNaturalBiome != null && !activeNaturalBiome.isBlank(); |
|
||||||
} |
|
||||||
|
|
||||||
public MineBranchState withDepth(int newDepth) { |
|
||||||
return new MineBranchState( |
|
||||||
branchId, |
|
||||||
mainPath, |
|
||||||
newDepth, |
|
||||||
activeNaturalBiome, |
|
||||||
biomeOriginDepth, |
|
||||||
naturalBiomeLength |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
public MineBranchState clearNaturalBiome() { |
|
||||||
return new MineBranchState( |
|
||||||
branchId, |
|
||||||
mainPath, |
|
||||||
depth, |
|
||||||
null, |
|
||||||
-1, |
|
||||||
0 |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
public MineBranchState activateNaturalBiome(String biome, int originDepth, int length) { |
|
||||||
return new MineBranchState( |
|
||||||
branchId, |
|
||||||
mainPath, |
|
||||||
depth, |
|
||||||
biome == null ? null : biome.toUpperCase(Locale.ROOT), |
|
||||||
originDepth, |
|
||||||
Math.max(1, length) |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,68 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines.generation; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
public enum MineDirection { |
|
||||||
FRONT(1 << 0, 0, 0, 1), |
|
||||||
BACK(1 << 1, 0, 0, -1), |
|
||||||
LEFT(1 << 2, -1, 0, 0), |
|
||||||
RIGHT(1 << 3, 1, 0, 0), |
|
||||||
TOP(1 << 4, 0, 1, 0), |
|
||||||
BOTTOM(1 << 5, 0, -1, 0); |
|
||||||
|
|
||||||
private static final List<MineDirection> HORIZONTAL_DIRECTIONS = List.of(FRONT, BACK, LEFT, RIGHT); |
|
||||||
|
|
||||||
private final int bitMask; |
|
||||||
private final int deltaX; |
|
||||||
private final int deltaY; |
|
||||||
private final int deltaZ; |
|
||||||
|
|
||||||
MineDirection(int bitMask, int deltaX, int deltaY, int deltaZ) { |
|
||||||
this.bitMask = bitMask; |
|
||||||
this.deltaX = deltaX; |
|
||||||
this.deltaY = deltaY; |
|
||||||
this.deltaZ = deltaZ; |
|
||||||
} |
|
||||||
|
|
||||||
public int bitMask() { |
|
||||||
return bitMask; |
|
||||||
} |
|
||||||
|
|
||||||
public int deltaX() { |
|
||||||
return deltaX; |
|
||||||
} |
|
||||||
|
|
||||||
public int deltaY() { |
|
||||||
return deltaY; |
|
||||||
} |
|
||||||
|
|
||||||
public int deltaZ() { |
|
||||||
return deltaZ; |
|
||||||
} |
|
||||||
|
|
||||||
public MineDirection opposite() { |
|
||||||
return switch (this) { |
|
||||||
case FRONT -> BACK; |
|
||||||
case BACK -> FRONT; |
|
||||||
case LEFT -> RIGHT; |
|
||||||
case RIGHT -> LEFT; |
|
||||||
case TOP -> BOTTOM; |
|
||||||
case BOTTOM -> TOP; |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
public static List<MineDirection> horizontalDirections() { |
|
||||||
return HORIZONTAL_DIRECTIONS; |
|
||||||
} |
|
||||||
|
|
||||||
public static List<MineDirection> directionsFromMask(int exitsMask) { |
|
||||||
List<MineDirection> directions = new ArrayList<>(); |
|
||||||
for (MineDirection direction : values()) { |
|
||||||
if ((exitsMask & direction.bitMask) != 0) { |
|
||||||
directions.add(direction); |
|
||||||
} |
|
||||||
} |
|
||||||
return directions; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,191 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines.generation; |
|
||||||
|
|
||||||
import com.sk89q.worldedit.math.BlockVector3; |
|
||||||
import org.bukkit.World; |
|
||||||
import org.bukkit.configuration.file.FileConfiguration; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Comparator; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Locale; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.regex.Pattern; |
|
||||||
|
|
||||||
public record MineGenerationConfig( |
|
||||||
String roomsDirectory, |
|
||||||
String starterRoomId, |
|
||||||
String defaultBiome, |
|
||||||
int roomSize, |
|
||||||
int maxDepth, |
|
||||||
int maxRooms, |
|
||||||
boolean ignoreAir, |
|
||||||
BlockVector3 origin, |
|
||||||
List<DepthBiomeRule> depthBiomes, |
|
||||||
List<NaturalBiomeRule> naturalBiomes |
|
||||||
) { |
|
||||||
|
|
||||||
private static final String BASE_PATH = "mine.generator"; |
|
||||||
private static final Pattern ROOM_IDENTIFIER_PATTERN = Pattern.compile("^[A-Z]{2}\\d+$"); |
|
||||||
|
|
||||||
public static MineGenerationConfig fromConfiguration(FileConfiguration configuration, World world) { |
|
||||||
String roomsDirectory = configuration.getString(BASE_PATH + ".rooms-directory", "rooms"); |
|
||||||
String starterRoomId = normalizeRoomIdentifier(configuration.getString(BASE_PATH + ".starter-room", "ST15")); |
|
||||||
String defaultBiome = normalizeBiome(configuration.getString(BASE_PATH + ".default-biome", "ST"), "ST"); |
|
||||||
|
|
||||||
int roomSize = Math.max(1, configuration.getInt(BASE_PATH + ".room-size", 16)); |
|
||||||
int maxDepth = Math.max(1, configuration.getInt(BASE_PATH + ".max-depth", 64)); |
|
||||||
int maxRooms = Math.max(1, configuration.getInt(BASE_PATH + ".max-rooms", 320)); |
|
||||||
boolean ignoreAir = configuration.getBoolean(BASE_PATH + ".ignore-air", false); |
|
||||||
|
|
||||||
int defaultY = world.getMaxHeight() - 10; |
|
||||||
BlockVector3 origin = BlockVector3.at( |
|
||||||
configuration.getInt(BASE_PATH + ".origin.x", 0), |
|
||||||
configuration.getInt(BASE_PATH + ".origin.y", defaultY), |
|
||||||
configuration.getInt(BASE_PATH + ".origin.z", 0) |
|
||||||
); |
|
||||||
|
|
||||||
List<DepthBiomeRule> depthBiomes = parseDepthBiomes( |
|
||||||
configuration.getMapList(BASE_PATH + ".depth-biomes"), |
|
||||||
defaultBiome |
|
||||||
); |
|
||||||
List<NaturalBiomeRule> naturalBiomes = parseNaturalBiomes( |
|
||||||
configuration.getMapList(BASE_PATH + ".natural-biomes") |
|
||||||
); |
|
||||||
|
|
||||||
return new MineGenerationConfig( |
|
||||||
roomsDirectory, |
|
||||||
starterRoomId, |
|
||||||
defaultBiome, |
|
||||||
roomSize, |
|
||||||
maxDepth, |
|
||||||
maxRooms, |
|
||||||
ignoreAir, |
|
||||||
origin, |
|
||||||
depthBiomes, |
|
||||||
naturalBiomes |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
public String resolveDepthBiome(int depth) { |
|
||||||
String biome = defaultBiome; |
|
||||||
for (DepthBiomeRule rule : depthBiomes) { |
|
||||||
if (depth >= rule.minDepth()) { |
|
||||||
biome = rule.biome(); |
|
||||||
} else { |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
return biome; |
|
||||||
} |
|
||||||
|
|
||||||
private static List<DepthBiomeRule> parseDepthBiomes(List<Map<?, ?>> entries, String defaultBiome) { |
|
||||||
List<DepthBiomeRule> rules = new ArrayList<>(); |
|
||||||
for (Map<?, ?> entry : entries) { |
|
||||||
String biome = normalizeBiome(entry.get("biome"), null); |
|
||||||
if (biome == null) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
int minDepth = Math.max(0, readInt(entry, "min-depth", 0)); |
|
||||||
rules.add(new DepthBiomeRule(biome, minDepth)); |
|
||||||
} |
|
||||||
|
|
||||||
if (rules.isEmpty()) { |
|
||||||
rules.add(new DepthBiomeRule(defaultBiome, 0)); |
|
||||||
} |
|
||||||
|
|
||||||
rules.sort(Comparator.comparingInt(DepthBiomeRule::minDepth)); |
|
||||||
return List.copyOf(rules); |
|
||||||
} |
|
||||||
|
|
||||||
private static List<NaturalBiomeRule> parseNaturalBiomes(List<Map<?, ?>> entries) { |
|
||||||
List<NaturalBiomeRule> rules = new ArrayList<>(); |
|
||||||
for (Map<?, ?> entry : entries) { |
|
||||||
String biome = normalizeBiome(entry.get("biome"), null); |
|
||||||
if (biome == null) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
double chance = clamp(readDouble(entry, "chance", 0.0), 0.0, 1.0); |
|
||||||
if (chance <= 0.0) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
int length = Math.max(1, readInt(entry, "length", 1)); |
|
||||||
rules.add(new NaturalBiomeRule(biome, chance, length)); |
|
||||||
} |
|
||||||
|
|
||||||
return List.copyOf(rules); |
|
||||||
} |
|
||||||
|
|
||||||
private static int readInt(Map<?, ?> entry, String key, int fallback) { |
|
||||||
Object value = entry.get(key); |
|
||||||
if (value instanceof Number number) { |
|
||||||
return number.intValue(); |
|
||||||
} |
|
||||||
if (value instanceof String stringValue) { |
|
||||||
try { |
|
||||||
return Integer.parseInt(stringValue); |
|
||||||
} catch (NumberFormatException ignored) { |
|
||||||
return fallback; |
|
||||||
} |
|
||||||
} |
|
||||||
return fallback; |
|
||||||
} |
|
||||||
|
|
||||||
private static double readDouble(Map<?, ?> entry, String key, double fallback) { |
|
||||||
Object value = entry.get(key); |
|
||||||
if (value instanceof Number number) { |
|
||||||
return number.doubleValue(); |
|
||||||
} |
|
||||||
if (value instanceof String stringValue) { |
|
||||||
try { |
|
||||||
return Double.parseDouble(stringValue); |
|
||||||
} catch (NumberFormatException ignored) { |
|
||||||
return fallback; |
|
||||||
} |
|
||||||
} |
|
||||||
return fallback; |
|
||||||
} |
|
||||||
|
|
||||||
private static double clamp(double value, double min, double max) { |
|
||||||
if (value < min) { |
|
||||||
return min; |
|
||||||
} |
|
||||||
if (value > max) { |
|
||||||
return max; |
|
||||||
} |
|
||||||
return value; |
|
||||||
} |
|
||||||
|
|
||||||
private static String normalizeRoomIdentifier(String rawValue) { |
|
||||||
if (rawValue == null || rawValue.isBlank()) { |
|
||||||
return "ST15"; |
|
||||||
} |
|
||||||
|
|
||||||
String normalized = rawValue.trim().toUpperCase(Locale.ROOT); |
|
||||||
int extensionIndex = normalized.indexOf('.'); |
|
||||||
if (extensionIndex > 0) { |
|
||||||
normalized = normalized.substring(0, extensionIndex); |
|
||||||
} |
|
||||||
|
|
||||||
if (!ROOM_IDENTIFIER_PATTERN.matcher(normalized).matches()) { |
|
||||||
return "ST15"; |
|
||||||
} |
|
||||||
|
|
||||||
return normalized; |
|
||||||
} |
|
||||||
|
|
||||||
private static String normalizeBiome(Object rawValue, String fallback) { |
|
||||||
if (!(rawValue instanceof String biome) || biome.isBlank()) { |
|
||||||
return fallback; |
|
||||||
} |
|
||||||
|
|
||||||
return biome.trim().toUpperCase(Locale.ROOT); |
|
||||||
} |
|
||||||
|
|
||||||
public record DepthBiomeRule(String biome, int minDepth) { |
|
||||||
} |
|
||||||
|
|
||||||
public record NaturalBiomeRule(String biome, double chance, int length) { |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,9 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines.generation; |
|
||||||
|
|
||||||
public record MineGenerationPoint( |
|
||||||
MineGridPosition gridPosition, |
|
||||||
MineDirection incomingDirection, |
|
||||||
MineDirection travelDirection, |
|
||||||
MineBranchState branchState |
|
||||||
) { |
|
||||||
} |
|
||||||
@ -1,376 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines.generation; |
|
||||||
|
|
||||||
import com.sk89q.worldedit.EditSession; |
|
||||||
import com.sk89q.worldedit.WorldEdit; |
|
||||||
import com.sk89q.worldedit.WorldEditException; |
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter; |
|
||||||
import com.sk89q.worldedit.function.operation.Operation; |
|
||||||
import com.sk89q.worldedit.function.operation.Operations; |
|
||||||
import com.sk89q.worldedit.math.BlockVector3; |
|
||||||
import com.sk89q.worldedit.session.ClipboardHolder; |
|
||||||
import org.bukkit.World; |
|
||||||
|
|
||||||
import java.util.ArrayDeque; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Deque; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Random; |
|
||||||
import java.util.concurrent.ThreadLocalRandom; |
|
||||||
import java.util.logging.Level; |
|
||||||
import java.util.logging.Logger; |
|
||||||
|
|
||||||
public final class MineGenerator { |
|
||||||
|
|
||||||
private static final MineGridPosition STARTER_GRID_POSITION = new MineGridPosition(0, 0, 0); |
|
||||||
|
|
||||||
private final World world; |
|
||||||
private final MineGenerationConfig config; |
|
||||||
private final MineRoomLibrary roomLibrary; |
|
||||||
private final Logger logger; |
|
||||||
private final Random random; |
|
||||||
|
|
||||||
private int nextBranchId = 1; |
|
||||||
|
|
||||||
public MineGenerator(World world, MineGenerationConfig config, MineRoomLibrary roomLibrary, Logger logger) { |
|
||||||
this.world = world; |
|
||||||
this.config = config; |
|
||||||
this.roomLibrary = roomLibrary; |
|
||||||
this.logger = logger; |
|
||||||
this.random = ThreadLocalRandom.current(); |
|
||||||
} |
|
||||||
|
|
||||||
public Result generate() { |
|
||||||
List<MineRoomPrefab> starterCandidates = roomLibrary.roomsForIdentifier(config.starterRoomId()); |
|
||||||
if (starterCandidates.isEmpty()) { |
|
||||||
logger.severe("[MineGen] Starter room '" + config.starterRoomId() + "' was not found in room prefabs."); |
|
||||||
return Result.failure(); |
|
||||||
} |
|
||||||
|
|
||||||
MineRoomPrefab starterRoom = chooseWeighted(starterCandidates); |
|
||||||
if (starterRoom == null) { |
|
||||||
logger.severe("[MineGen] Starter room selection failed."); |
|
||||||
return Result.failure(); |
|
||||||
} |
|
||||||
|
|
||||||
if (!hasAllHorizontalExits(starterRoom)) { |
|
||||||
logger.severe("[MineGen] Starter room '" + starterRoom.sourceFile().getName() |
|
||||||
+ "' must contain FRONT, BACK, LEFT and RIGHT exits."); |
|
||||||
return Result.failure(); |
|
||||||
} |
|
||||||
|
|
||||||
Map<MineGridPosition, MineRoomPrefab> occupiedPositions = new HashMap<>(); |
|
||||||
Deque<MineGenerationPoint> generationQueue = new ArrayDeque<>(); |
|
||||||
int roomsPlaced = 0; |
|
||||||
|
|
||||||
com.sk89q.worldedit.world.World worldEditWorld = BukkitAdapter.adapt(world); |
|
||||||
try (EditSession editSession = WorldEdit.getInstance().newEditSession(worldEditWorld)) { |
|
||||||
pasteRoom(editSession, starterRoom, STARTER_GRID_POSITION); |
|
||||||
occupiedPositions.put(STARTER_GRID_POSITION, starterRoom); |
|
||||||
roomsPlaced++; |
|
||||||
|
|
||||||
for (MineDirection direction : MineDirection.horizontalDirections()) { |
|
||||||
MineBranchState branchState = new MineBranchState(nextBranchId++, true, 1, null, -1, 0); |
|
||||||
enqueueNextPoint(generationQueue, STARTER_GRID_POSITION, direction, branchState); |
|
||||||
} |
|
||||||
|
|
||||||
while (!generationQueue.isEmpty() && roomsPlaced < config.maxRooms()) { |
|
||||||
MineGenerationPoint point = generationQueue.poll(); |
|
||||||
MineBranchState branchState = expireNaturalBiomeIfNeeded(point.branchState()); |
|
||||||
|
|
||||||
if (branchState.depth() > config.maxDepth()) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (occupiedPositions.containsKey(point.gridPosition())) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
MineBranchState placementState = maybeActivateNaturalBiome(branchState); |
|
||||||
String resolvedBiome = resolveBiome(placementState); |
|
||||||
|
|
||||||
MineRoomPrefab selectedRoom = selectRoom( |
|
||||||
point, |
|
||||||
placementState, |
|
||||||
resolvedBiome, |
|
||||||
occupiedPositions |
|
||||||
); |
|
||||||
if (selectedRoom == null) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
pasteRoom(editSession, selectedRoom, point.gridPosition()); |
|
||||||
occupiedPositions.put(point.gridPosition(), selectedRoom); |
|
||||||
roomsPlaced++; |
|
||||||
|
|
||||||
enqueueFollowingPoints( |
|
||||||
generationQueue, |
|
||||||
point, |
|
||||||
placementState, |
|
||||||
selectedRoom |
|
||||||
); |
|
||||||
} |
|
||||||
} catch (WorldEditException exception) { |
|
||||||
logger.log(Level.SEVERE, "[MineGen] Failed to generate mine layout.", exception); |
|
||||||
return Result.failure(); |
|
||||||
} |
|
||||||
|
|
||||||
return new Result(true, roomsPlaced); |
|
||||||
} |
|
||||||
|
|
||||||
private String resolveBiome(MineBranchState branchState) { |
|
||||||
if (branchState.hasActiveNaturalBiome()) { |
|
||||||
return branchState.activeNaturalBiome(); |
|
||||||
} |
|
||||||
return config.resolveDepthBiome(branchState.depth()); |
|
||||||
} |
|
||||||
|
|
||||||
private MineRoomPrefab selectRoom( |
|
||||||
MineGenerationPoint point, |
|
||||||
MineBranchState branchState, |
|
||||||
String biome, |
|
||||||
Map<MineGridPosition, MineRoomPrefab> occupiedPositions |
|
||||||
) { |
|
||||||
List<MineRoomPrefab> candidates = collectCandidateRooms( |
|
||||||
point, |
|
||||||
branchState, |
|
||||||
biome, |
|
||||||
occupiedPositions, |
|
||||||
true |
|
||||||
); |
|
||||||
|
|
||||||
if (candidates.isEmpty()) { |
|
||||||
candidates = collectCandidateRooms( |
|
||||||
point, |
|
||||||
branchState, |
|
||||||
biome, |
|
||||||
occupiedPositions, |
|
||||||
false |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
if (candidates.isEmpty()) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
return chooseWeighted(candidates); |
|
||||||
} |
|
||||||
|
|
||||||
private List<MineRoomPrefab> collectCandidateRooms( |
|
||||||
MineGenerationPoint point, |
|
||||||
MineBranchState branchState, |
|
||||||
String biome, |
|
||||||
Map<MineGridPosition, MineRoomPrefab> occupiedPositions, |
|
||||||
boolean avoidOccupiedExitTargets |
|
||||||
) { |
|
||||||
int blockedExitMask = buildBlockedExitMask(point.gridPosition(), point.incomingDirection(), occupiedPositions); |
|
||||||
|
|
||||||
List<MineRoomPrefab> candidates = new ArrayList<>(); |
|
||||||
for (MineRoomPrefab room : roomLibrary.allRooms()) { |
|
||||||
if (!room.biome().equalsIgnoreCase(biome)) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (!room.hasExit(point.incomingDirection())) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (!matchesBranchConstraints(room, branchState.mainPath())) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (avoidOccupiedExitTargets && (room.exitsMask() & blockedExitMask) != 0) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
candidates.add(room); |
|
||||||
} |
|
||||||
|
|
||||||
return candidates; |
|
||||||
} |
|
||||||
|
|
||||||
private boolean matchesBranchConstraints(MineRoomPrefab room, boolean mainPath) { |
|
||||||
int exitCount = room.exitCount(); |
|
||||||
if (mainPath) { |
|
||||||
return exitCount >= 2; |
|
||||||
} |
|
||||||
return exitCount == 2; |
|
||||||
} |
|
||||||
|
|
||||||
private int buildBlockedExitMask( |
|
||||||
MineGridPosition targetPosition, |
|
||||||
MineDirection incomingDirection, |
|
||||||
Map<MineGridPosition, MineRoomPrefab> occupiedPositions |
|
||||||
) { |
|
||||||
int blockedMask = 0; |
|
||||||
for (MineDirection direction : MineDirection.values()) { |
|
||||||
if (direction == incomingDirection) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (occupiedPositions.containsKey(targetPosition.offset(direction))) { |
|
||||||
blockedMask |= direction.bitMask(); |
|
||||||
} |
|
||||||
} |
|
||||||
return blockedMask; |
|
||||||
} |
|
||||||
|
|
||||||
private void enqueueFollowingPoints( |
|
||||||
Deque<MineGenerationPoint> generationQueue, |
|
||||||
MineGenerationPoint point, |
|
||||||
MineBranchState placementState, |
|
||||||
MineRoomPrefab room |
|
||||||
) { |
|
||||||
List<MineDirection> outgoingDirections = room.exits().stream() |
|
||||||
.filter(direction -> direction != point.incomingDirection()) |
|
||||||
.toList(); |
|
||||||
|
|
||||||
if (outgoingDirections.isEmpty()) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
MineDirection continuationDirection = chooseContinuationDirection(outgoingDirections, point.travelDirection()); |
|
||||||
MineBranchState continuationState = placementState.withDepth(placementState.depth() + 1); |
|
||||||
enqueueNextPoint(generationQueue, point.gridPosition(), continuationDirection, continuationState); |
|
||||||
|
|
||||||
if (!placementState.mainPath()) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
for (MineDirection direction : outgoingDirections) { |
|
||||||
if (direction == continuationDirection) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
MineBranchState childBranchState = new MineBranchState( |
|
||||||
nextBranchId++, |
|
||||||
false, |
|
||||||
placementState.depth() + 1, |
|
||||||
placementState.activeNaturalBiome(), |
|
||||||
placementState.biomeOriginDepth(), |
|
||||||
placementState.naturalBiomeLength() |
|
||||||
); |
|
||||||
enqueueNextPoint(generationQueue, point.gridPosition(), direction, childBranchState); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private MineDirection chooseContinuationDirection(List<MineDirection> outgoingDirections, MineDirection preferredDirection) { |
|
||||||
if (outgoingDirections.contains(preferredDirection)) { |
|
||||||
return preferredDirection; |
|
||||||
} |
|
||||||
return outgoingDirections.get(random.nextInt(outgoingDirections.size())); |
|
||||||
} |
|
||||||
|
|
||||||
private MineBranchState expireNaturalBiomeIfNeeded(MineBranchState branchState) { |
|
||||||
if (!branchState.hasActiveNaturalBiome()) { |
|
||||||
return branchState; |
|
||||||
} |
|
||||||
|
|
||||||
int roomsSpentInBiome = branchState.depth() - branchState.biomeOriginDepth(); |
|
||||||
if (roomsSpentInBiome >= branchState.naturalBiomeLength()) { |
|
||||||
return branchState.clearNaturalBiome(); |
|
||||||
} |
|
||||||
return branchState; |
|
||||||
} |
|
||||||
|
|
||||||
private MineBranchState maybeActivateNaturalBiome(MineBranchState branchState) { |
|
||||||
if (branchState.hasActiveNaturalBiome()) { |
|
||||||
return branchState; |
|
||||||
} |
|
||||||
if (config.naturalBiomes().isEmpty()) { |
|
||||||
return branchState; |
|
||||||
} |
|
||||||
|
|
||||||
double totalChance = 0.0; |
|
||||||
for (MineGenerationConfig.NaturalBiomeRule rule : config.naturalBiomes()) { |
|
||||||
totalChance += rule.chance(); |
|
||||||
} |
|
||||||
|
|
||||||
if (totalChance <= 0.0) { |
|
||||||
return branchState; |
|
||||||
} |
|
||||||
|
|
||||||
if (random.nextDouble() > Math.min(1.0, totalChance)) { |
|
||||||
return branchState; |
|
||||||
} |
|
||||||
|
|
||||||
double selectionRoll = random.nextDouble(totalChance); |
|
||||||
double cumulativeChance = 0.0; |
|
||||||
for (MineGenerationConfig.NaturalBiomeRule rule : config.naturalBiomes()) { |
|
||||||
cumulativeChance += rule.chance(); |
|
||||||
if (selectionRoll <= cumulativeChance) { |
|
||||||
return branchState.activateNaturalBiome(rule.biome(), branchState.depth(), rule.length()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return branchState; |
|
||||||
} |
|
||||||
|
|
||||||
private boolean hasAllHorizontalExits(MineRoomPrefab room) { |
|
||||||
for (MineDirection direction : MineDirection.horizontalDirections()) { |
|
||||||
if (!room.hasExit(direction)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
private static void enqueueNextPoint( |
|
||||||
Deque<MineGenerationPoint> generationQueue, |
|
||||||
MineGridPosition currentPosition, |
|
||||||
MineDirection outgoingDirection, |
|
||||||
MineBranchState branchState |
|
||||||
) { |
|
||||||
generationQueue.add(new MineGenerationPoint( |
|
||||||
currentPosition.offset(outgoingDirection), |
|
||||||
outgoingDirection.opposite(), |
|
||||||
outgoingDirection, |
|
||||||
branchState |
|
||||||
)); |
|
||||||
} |
|
||||||
|
|
||||||
private MineRoomPrefab chooseWeighted(List<MineRoomPrefab> rooms) { |
|
||||||
if (rooms.isEmpty()) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
if (rooms.size() == 1) { |
|
||||||
return rooms.getFirst(); |
|
||||||
} |
|
||||||
|
|
||||||
int totalWeight = 0; |
|
||||||
for (MineRoomPrefab room : rooms) { |
|
||||||
totalWeight += Math.max(1, room.weight()); |
|
||||||
} |
|
||||||
|
|
||||||
int roll = random.nextInt(totalWeight); |
|
||||||
int runningWeight = 0; |
|
||||||
for (MineRoomPrefab room : rooms) { |
|
||||||
runningWeight += Math.max(1, room.weight()); |
|
||||||
if (roll < runningWeight) { |
|
||||||
return room; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return rooms.getLast(); |
|
||||||
} |
|
||||||
|
|
||||||
private void pasteRoom(EditSession editSession, MineRoomPrefab room, MineGridPosition gridPosition) throws WorldEditException { |
|
||||||
BlockVector3 target = toWorldPosition(gridPosition); |
|
||||||
Operation operation = new ClipboardHolder(room.clipboard()) |
|
||||||
.createPaste(editSession) |
|
||||||
.to(target) |
|
||||||
.ignoreAirBlocks(config.ignoreAir()) |
|
||||||
.build(); |
|
||||||
Operations.complete(operation); |
|
||||||
} |
|
||||||
|
|
||||||
private BlockVector3 toWorldPosition(MineGridPosition gridPosition) { |
|
||||||
return config.origin().add( |
|
||||||
gridPosition.x() * config.roomSize(), |
|
||||||
gridPosition.y() * config.roomSize(), |
|
||||||
gridPosition.z() * config.roomSize() |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
public record Result(boolean success, int roomsPlaced) { |
|
||||||
|
|
||||||
public static Result failure() { |
|
||||||
return new Result(false, 0); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,12 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines.generation; |
|
||||||
|
|
||||||
public record MineGridPosition(int x, int y, int z) { |
|
||||||
|
|
||||||
public MineGridPosition offset(MineDirection direction) { |
|
||||||
return new MineGridPosition( |
|
||||||
x + direction.deltaX(), |
|
||||||
y + direction.deltaY(), |
|
||||||
z + direction.deltaZ() |
|
||||||
); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,181 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines.generation; |
|
||||||
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard; |
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; |
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; |
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.FileInputStream; |
|
||||||
import java.io.IOException; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Locale; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.logging.Logger; |
|
||||||
import java.util.regex.Matcher; |
|
||||||
import java.util.regex.Pattern; |
|
||||||
import java.util.stream.Collectors; |
|
||||||
|
|
||||||
public final class MineRoomLibrary { |
|
||||||
|
|
||||||
private static final Pattern ROOM_FILE_PATTERN = Pattern.compile("^([A-Za-z]{2})(\\d+)(?:_(\\d+))?$"); |
|
||||||
|
|
||||||
private final File roomsDirectory; |
|
||||||
private final List<MineRoomPrefab> prefabs; |
|
||||||
private final Map<String, List<MineRoomPrefab>> prefabsByIdentifier; |
|
||||||
|
|
||||||
private MineRoomLibrary( |
|
||||||
File roomsDirectory, |
|
||||||
List<MineRoomPrefab> prefabs, |
|
||||||
Map<String, List<MineRoomPrefab>> prefabsByIdentifier |
|
||||||
) { |
|
||||||
this.roomsDirectory = roomsDirectory; |
|
||||||
this.prefabs = prefabs; |
|
||||||
this.prefabsByIdentifier = prefabsByIdentifier; |
|
||||||
} |
|
||||||
|
|
||||||
public static MineRoomLibrary load(File dataFolder, String roomsDirectoryName, Logger logger) { |
|
||||||
String safeDirectoryName = roomsDirectoryName == null || roomsDirectoryName.isBlank() |
|
||||||
? "rooms" |
|
||||||
: roomsDirectoryName; |
|
||||||
|
|
||||||
File roomsDirectory = new File(dataFolder, safeDirectoryName); |
|
||||||
if (!roomsDirectory.exists() && !roomsDirectory.mkdirs()) { |
|
||||||
logger.warning("[MineGen] Could not create room prefab directory: " + roomsDirectory.getAbsolutePath()); |
|
||||||
} |
|
||||||
|
|
||||||
File[] roomFiles = roomsDirectory.listFiles(MineRoomLibrary::isSupportedRoomFile); |
|
||||||
if (roomFiles == null || roomFiles.length == 0) { |
|
||||||
return new MineRoomLibrary(roomsDirectory, List.of(), Map.of()); |
|
||||||
} |
|
||||||
|
|
||||||
List<MineRoomPrefab> prefabs = new ArrayList<>(); |
|
||||||
Map<String, List<MineRoomPrefab>> prefabsByIdentifier = new HashMap<>(); |
|
||||||
|
|
||||||
for (File roomFile : roomFiles) { |
|
||||||
RoomFileMetadata metadata = parseMetadata(roomFile.getName(), logger); |
|
||||||
if (metadata == null) { |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
ClipboardFormat format = ClipboardFormats.findByFile(roomFile); |
|
||||||
if (format == null) { |
|
||||||
logger.warning("[MineGen] Unsupported room format: " + roomFile.getName()); |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
try ( |
|
||||||
FileInputStream inputStream = new FileInputStream(roomFile); |
|
||||||
ClipboardReader reader = format.getReader(inputStream) |
|
||||||
) { |
|
||||||
Clipboard clipboard = reader.read(); |
|
||||||
MineRoomPrefab prefab = new MineRoomPrefab( |
|
||||||
metadata.identifier(), |
|
||||||
metadata.biome(), |
|
||||||
metadata.exitsMask(), |
|
||||||
metadata.weight(), |
|
||||||
roomFile, |
|
||||||
clipboard |
|
||||||
); |
|
||||||
prefabs.add(prefab); |
|
||||||
prefabsByIdentifier.computeIfAbsent(metadata.identifier(), ignored -> new ArrayList<>()).add(prefab); |
|
||||||
} catch (IOException exception) { |
|
||||||
logger.warning("[MineGen] Failed to load room prefab " + roomFile.getName() |
|
||||||
+ ": " + exception.getMessage()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return new MineRoomLibrary( |
|
||||||
roomsDirectory, |
|
||||||
List.copyOf(prefabs), |
|
||||||
prefabsByIdentifier.entrySet().stream() |
|
||||||
.collect(Collectors.toUnmodifiableMap( |
|
||||||
Map.Entry::getKey, |
|
||||||
entry -> List.copyOf(entry.getValue()) |
|
||||||
)) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
public File roomsDirectory() { |
|
||||||
return roomsDirectory; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isEmpty() { |
|
||||||
return prefabs.isEmpty(); |
|
||||||
} |
|
||||||
|
|
||||||
public List<MineRoomPrefab> allRooms() { |
|
||||||
return prefabs; |
|
||||||
} |
|
||||||
|
|
||||||
public List<MineRoomPrefab> roomsForIdentifier(String identifier) { |
|
||||||
if (identifier == null) { |
|
||||||
return List.of(); |
|
||||||
} |
|
||||||
|
|
||||||
return prefabsByIdentifier.getOrDefault(identifier.toUpperCase(Locale.ROOT), List.of()); |
|
||||||
} |
|
||||||
|
|
||||||
private static boolean isSupportedRoomFile(File file) { |
|
||||||
if (!file.isFile()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
String lowerName = file.getName().toLowerCase(Locale.ROOT); |
|
||||||
return lowerName.endsWith(".schematic") || lowerName.endsWith(".schem"); |
|
||||||
} |
|
||||||
|
|
||||||
private static RoomFileMetadata parseMetadata(String fileName, Logger logger) { |
|
||||||
int extensionIndex = fileName.lastIndexOf('.'); |
|
||||||
if (extensionIndex <= 0) { |
|
||||||
logger.warning("[MineGen] Ignoring room prefab '" + fileName + "': missing file extension."); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
String baseName = fileName.substring(0, extensionIndex); |
|
||||||
Matcher matcher = ROOM_FILE_PATTERN.matcher(baseName); |
|
||||||
if (!matcher.matches()) { |
|
||||||
logger.warning("[MineGen] Ignoring room prefab '" + fileName |
|
||||||
+ "': expected format <room_biome><room_exits>_<room_weight>."); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
String biome = matcher.group(1).toUpperCase(Locale.ROOT); |
|
||||||
int exitsMask; |
|
||||||
try { |
|
||||||
exitsMask = Integer.parseInt(matcher.group(2)); |
|
||||||
} catch (NumberFormatException exception) { |
|
||||||
logger.warning("[MineGen] Ignoring room prefab '" + fileName + "': invalid exits value."); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
if (exitsMask <= 0 || exitsMask > 63) { |
|
||||||
logger.warning("[MineGen] Ignoring room prefab '" + fileName |
|
||||||
+ "': exits bitmask must be in range 1..63."); |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
int weight = 1; |
|
||||||
String weightGroup = matcher.group(3); |
|
||||||
if (weightGroup != null) { |
|
||||||
try { |
|
||||||
weight = Integer.parseInt(weightGroup); |
|
||||||
if (weight <= 0) { |
|
||||||
logger.warning("[MineGen] Room prefab '" + fileName + "' has non-positive weight, using 1."); |
|
||||||
weight = 1; |
|
||||||
} |
|
||||||
} catch (NumberFormatException exception) { |
|
||||||
logger.warning("[MineGen] Room prefab '" + fileName + "' has invalid weight, using 1."); |
|
||||||
weight = 1; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
String identifier = biome + exitsMask; |
|
||||||
return new RoomFileMetadata(identifier, biome, exitsMask, weight); |
|
||||||
} |
|
||||||
|
|
||||||
private record RoomFileMetadata(String identifier, String biome, int exitsMask, int weight) { |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,28 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.mines.generation; |
|
||||||
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
public record MineRoomPrefab( |
|
||||||
String identifier, |
|
||||||
String biome, |
|
||||||
int exitsMask, |
|
||||||
int weight, |
|
||||||
File sourceFile, |
|
||||||
Clipboard clipboard |
|
||||||
) { |
|
||||||
|
|
||||||
public boolean hasExit(MineDirection direction) { |
|
||||||
return (exitsMask & direction.bitMask()) != 0; |
|
||||||
} |
|
||||||
|
|
||||||
public int exitCount() { |
|
||||||
return Integer.bitCount(exitsMask); |
|
||||||
} |
|
||||||
|
|
||||||
public List<MineDirection> exits() { |
|
||||||
return MineDirection.directionsFromMask(exitsMask); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,27 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.player; |
|
||||||
|
|
||||||
import com.destroystokyo.paper.event.player.PlayerPostRespawnEvent; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import org.bukkit.event.EventHandler; |
|
||||||
import org.bukkit.event.Listener; |
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent; |
|
||||||
import org.bukkit.event.player.PlayerRespawnEvent; |
|
||||||
import xyz.soukup.ecoCraftCore.islands.IslandManager; |
|
||||||
|
|
||||||
import static xyz.soukup.ecoCraftCore.EcoCraftCore.config; |
|
||||||
|
|
||||||
public class OnKill implements Listener { |
|
||||||
@EventHandler |
|
||||||
public void spawnTeleportOnKill(PlayerPostRespawnEvent event){ |
|
||||||
Player player = event.getPlayer(); |
|
||||||
|
|
||||||
String uuid = config.getString("islands.spawn"); |
|
||||||
|
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
try { |
|
||||||
islandManager.teleport(player, uuid); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,50 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.player; |
|
||||||
|
|
||||||
import com.google.common.eventbus.DeadEvent; |
|
||||||
import com.j256.ormlite.stmt.QueryBuilder; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import org.bukkit.event.EventHandler; |
|
||||||
import org.bukkit.event.Listener; |
|
||||||
import org.bukkit.event.entity.PlayerDeathEvent; |
|
||||||
import org.bukkit.event.player.PlayerJoinEvent; |
|
||||||
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.TeleportRequest; |
|
||||||
import xyz.soukup.ecoCraftCore.islands.IslandManager; |
|
||||||
|
|
||||||
import java.sql.SQLException; |
|
||||||
|
|
||||||
import static xyz.soukup.ecoCraftCore.EcoCraftCore.config; |
|
||||||
|
|
||||||
public class TeleportRequestsHandler implements Listener { |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void teleportRequestHandler(PlayerJoinEvent event){ |
|
||||||
try { |
|
||||||
Player player = event.getPlayer(); |
|
||||||
|
|
||||||
QueryBuilder<TeleportRequest, Integer> queryBuilder = DaoRegistry.getTeleportRequestsDao().queryBuilder(); |
|
||||||
queryBuilder.where().eq("player", player.getName()); |
|
||||||
|
|
||||||
TeleportRequest teleportRequest = queryBuilder.queryForFirst(); |
|
||||||
|
|
||||||
IslandManager islandManager = new IslandManager(); |
|
||||||
|
|
||||||
|
|
||||||
if (teleportRequest == null){ |
|
||||||
islandManager.teleport(player, config.getString("islands.spawn")); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
islandManager.teleportLocally(player, teleportRequest.getWorld(), teleportRequest.getX(), teleportRequest.getY(), teleportRequest.getY(), teleportRequest.getYaw(), teleportRequest.getPitch()); |
|
||||||
|
|
||||||
teleportRequest.delete(); |
|
||||||
|
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} catch (Exception e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -1,97 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.regions; |
|
||||||
|
|
||||||
import com.j256.ormlite.stmt.QueryBuilder; |
|
||||||
import com.mojang.brigadier.arguments.IntegerArgumentType; |
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType; |
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
|
||||||
import com.mojang.brigadier.context.CommandContext; |
|
||||||
import io.papermc.paper.command.brigadier.CommandSourceStack; |
|
||||||
import io.papermc.paper.command.brigadier.Commands; |
|
||||||
import org.bukkit.command.CommandSender; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import xyz.soukup.ecoCraftCore.database.DaoRegistry; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.Region; |
|
||||||
import xyz.soukup.ecoCraftCore.messages.Messages; |
|
||||||
|
|
||||||
import java.sql.SQLException; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin; |
|
||||||
|
|
||||||
public class RegionAdminCommand { |
|
||||||
public static LiteralArgumentBuilder<CommandSourceStack> getCommand() { |
|
||||||
LiteralArgumentBuilder<CommandSourceStack> create = Commands.literal("create") |
|
||||||
.then(Commands.argument("type", IntegerArgumentType.integer(0, 1)) |
|
||||||
.executes(RegionAdminCommand::createRegion)); |
|
||||||
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> addMember = Commands.literal("addMember") |
|
||||||
.then(Commands.argument("id", IntegerArgumentType.integer()) |
|
||||||
.suggests((context, builder) -> { |
|
||||||
try { |
|
||||||
QueryBuilder<Region, Integer> queryBuilder = DaoRegistry.getRegionDao().queryBuilder(); |
|
||||||
queryBuilder.selectColumns("id"); |
|
||||||
List<Region> regions = queryBuilder.query(); |
|
||||||
for (Region region : regions) { |
|
||||||
builder.suggest(region.getId()); |
|
||||||
} |
|
||||||
return builder.buildFuture(); |
|
||||||
} catch (SQLException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
}) |
|
||||||
.then(Commands.argument("player", StringArgumentType.word()) |
|
||||||
.suggests((context, builder) -> { |
|
||||||
for (Player onlinePlayer : plugin.getServer().getOnlinePlayers()) { |
|
||||||
builder.suggest(onlinePlayer.getName()); |
|
||||||
} |
|
||||||
return builder.buildFuture(); |
|
||||||
}) |
|
||||||
.then(Commands.argument("membership", StringArgumentType.word()) |
|
||||||
.suggests(((context, builder) -> { |
|
||||||
builder.suggest("owner"); |
|
||||||
builder.suggest("editor"); |
|
||||||
builder.suggest("member"); |
|
||||||
return builder.buildFuture(); |
|
||||||
})) |
|
||||||
.executes(RegionAdminCommand::addMember)))); |
|
||||||
|
|
||||||
|
|
||||||
return Commands.literal("region") |
|
||||||
.then(create) |
|
||||||
.then(addMember); |
|
||||||
} |
|
||||||
|
|
||||||
private static int createRegion(CommandContext<CommandSourceStack> context) { |
|
||||||
Integer type = context.getArgument("type", Integer.class); |
|
||||||
if(!(context.getSource().getSender() instanceof Player player)){ |
|
||||||
Messages.send(context.getSource().getSender(), "generic.error.not-player"); |
|
||||||
return 0; |
|
||||||
}; |
|
||||||
|
|
||||||
int status = RegionManager.createRegion(player, type, player.getName(), "player"); |
|
||||||
|
|
||||||
switch (status){ |
|
||||||
case 0 -> Messages.send(player, "generic.success.created"); |
|
||||||
case 1 -> Messages.send(player, "region.error.not-marked"); |
|
||||||
case 2 -> Messages.send(player, "region.error.not-same-world"); |
|
||||||
} |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
private static int addMember(CommandContext<CommandSourceStack> context) { |
|
||||||
Integer id = context.getArgument("id", Integer.class); |
|
||||||
String player = context.getArgument("player", String.class); |
|
||||||
String membership = context.getArgument("membership", String.class); |
|
||||||
CommandSender commandSender = context.getSource().getSender(); |
|
||||||
|
|
||||||
int status = RegionManager.addMember(id, "player", player, membership); |
|
||||||
switch (status){ |
|
||||||
case 0 -> Messages.send(commandSender, "generic.success.created"); |
|
||||||
case 1 -> Messages.send(commandSender, "region.error.not-exist"); |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
@ -1,319 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.regions; |
|
||||||
|
|
||||||
import org.bukkit.Location; |
|
||||||
import org.bukkit.NamespacedKey; |
|
||||||
import org.bukkit.block.Block; |
|
||||||
import org.bukkit.entity.Entity; |
|
||||||
import org.bukkit.entity.Item; |
|
||||||
import org.bukkit.entity.Minecart; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import org.bukkit.event.EventHandler; |
|
||||||
import org.bukkit.event.Listener; |
|
||||||
import org.bukkit.event.block.Action; |
|
||||||
import org.bukkit.event.block.BlockBreakEvent; |
|
||||||
import org.bukkit.event.block.BlockPlaceEvent; |
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent; |
|
||||||
import org.bukkit.event.inventory.InventoryPickupItemEvent; |
|
||||||
import org.bukkit.event.player.*; |
|
||||||
import org.bukkit.event.vehicle.VehicleDestroyEvent; |
|
||||||
import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; |
|
||||||
import org.bukkit.inventory.ItemStack; |
|
||||||
import org.bukkit.persistence.PersistentDataType; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.Region; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.RegionMember; |
|
||||||
|
|
||||||
import static xyz.soukup.ecoCraftCore.EcoCraftCore.plugin; |
|
||||||
|
|
||||||
public class RegionEvents implements Listener { |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onPlayerInteract(PlayerInteractEvent event){ |
|
||||||
switch (event.getAction()) { |
|
||||||
case RIGHT_CLICK_BLOCK: |
|
||||||
case LEFT_CLICK_BLOCK: |
|
||||||
break; |
|
||||||
default: |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
Block block = event.getClickedBlock(); |
|
||||||
ItemStack item = event.getItem(); |
|
||||||
if (block == null) return; |
|
||||||
|
|
||||||
if (item != null && item.getType().isBlock() && !block.getType().isInteractable()) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
block.getWorld().getName(), |
|
||||||
event.getPlayer(), |
|
||||||
block.getX(), |
|
||||||
block.getY(), |
|
||||||
block.getZ() |
|
||||||
); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onPlayerInteractPhysical(PlayerInteractEvent event){ |
|
||||||
if (!event.getAction().equals(Action.PHYSICAL)){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
Player player = event.getPlayer(); |
|
||||||
Location location = player.getLocation(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
location.getWorld().getName(), |
|
||||||
player, |
|
||||||
location.getBlockX(), |
|
||||||
location.getBlockY(), |
|
||||||
location.getBlockZ() |
|
||||||
); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onBlockPlace(BlockPlaceEvent event) { |
|
||||||
Block block = event.getBlockPlaced(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
block.getWorld().getName(), |
|
||||||
event.getPlayer(), |
|
||||||
block.getX(), |
|
||||||
block.getY(), |
|
||||||
block.getZ() |
|
||||||
); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onBlockBreak(BlockBreakEvent event) { |
|
||||||
|
|
||||||
Block block = event.getBlock(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
block.getWorld().getName(), |
|
||||||
event.getPlayer(), |
|
||||||
block.getX(), |
|
||||||
block.getY(), |
|
||||||
block.getZ() |
|
||||||
); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onBucketUse(PlayerBucketEmptyEvent event) { |
|
||||||
Block clickedBlock = event.getBlockClicked(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
clickedBlock.getWorld().getName(), |
|
||||||
event.getPlayer(), |
|
||||||
clickedBlock.getX(), |
|
||||||
clickedBlock.getY(), |
|
||||||
clickedBlock.getZ() |
|
||||||
); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onBucketUse(PlayerBucketFillEvent event) { |
|
||||||
Block clickedBlock = event.getBlockClicked(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
clickedBlock.getWorld().getName(), |
|
||||||
event.getPlayer(), |
|
||||||
clickedBlock.getX(), |
|
||||||
clickedBlock.getY(), |
|
||||||
clickedBlock.getZ() |
|
||||||
); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onEntityInteract(PlayerInteractEntityEvent event){ |
|
||||||
Entity entity = event.getRightClicked(); |
|
||||||
Location location = entity.getLocation(); |
|
||||||
|
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
location.getWorld().getName(), |
|
||||||
event.getPlayer(), |
|
||||||
location.getBlockX(), |
|
||||||
location.getBlockY(), |
|
||||||
location.getBlockZ()); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onEntityHit(EntityDamageByEntityEvent event){ |
|
||||||
|
|
||||||
if (!(event.getDamager() instanceof Player player)){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
Entity entity = event.getEntity(); |
|
||||||
Location location = entity.getLocation(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
location.getWorld().getName(), |
|
||||||
player, |
|
||||||
location.getBlockX(), |
|
||||||
location.getBlockY(), |
|
||||||
location.getBlockZ()); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onMinecartPush(VehicleEntityCollisionEvent event) { |
|
||||||
|
|
||||||
|
|
||||||
if (!(event.getEntity() instanceof Player player)){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
Location location = event.getVehicle().getLocation(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
location.getWorld().getName(), |
|
||||||
player, |
|
||||||
location.getBlockX(), |
|
||||||
location.getBlockY(), |
|
||||||
location.getBlockZ()); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
//Preventing hopper interaction :P
|
|
||||||
@EventHandler |
|
||||||
public void onDrop(PlayerDropItemEvent event) { |
|
||||||
Player player = event.getPlayer(); |
|
||||||
Location location = player.getLocation(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
location.getWorld().getName(), |
|
||||||
player, |
|
||||||
location.getBlockX(), |
|
||||||
location.getBlockY(), |
|
||||||
location.getBlockZ()); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
Item item = event.getItemDrop(); |
|
||||||
|
|
||||||
item.getPersistentDataContainer().set(new NamespacedKey(plugin, "hopper_stopper"), PersistentDataType.BYTE, (byte) 1); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onHopperPickup(InventoryPickupItemEvent event) { |
|
||||||
Item item = event.getItem(); |
|
||||||
|
|
||||||
if (!item.getPersistentDataContainer().has(new NamespacedKey(plugin, "hopper_stopper"), PersistentDataType.BYTE)) { |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onVehicleDestroy(VehicleDestroyEvent event) { |
|
||||||
if (!(event.getAttacker() instanceof Player player)){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
Location location = event.getVehicle().getLocation(); |
|
||||||
|
|
||||||
boolean allowed = isAllowedToInteract( |
|
||||||
location.getWorld().getName(), |
|
||||||
player, |
|
||||||
location.getBlockX(), |
|
||||||
location.getBlockY(), |
|
||||||
location.getBlockZ()); |
|
||||||
|
|
||||||
if (allowed){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private boolean isAllowedToInteract(String island, Player player, Location location){ |
|
||||||
return isAllowedToInteract(island, player, location.getBlockX(), location.getBlockY(), location.getBlockZ()); |
|
||||||
} |
|
||||||
|
|
||||||
private boolean isAllowedToInteract(String island, Player player, int x, int y, int z){ |
|
||||||
if (player.isOp()){ |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
Region region = Region.findRegion(x, y, z, island); |
|
||||||
|
|
||||||
if (region == null){ |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
String name = player.getName(); |
|
||||||
|
|
||||||
for (RegionMember regionMember : region.getRegionMembers()){ |
|
||||||
|
|
||||||
if (regionMember.getMembertype().equals("player") && regionMember.getName().equals(name)){ |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
@ -1,77 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.regions; |
|
||||||
|
|
||||||
import org.bukkit.Location; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.Region; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.RegionMember; |
|
||||||
import xyz.soukup.ecoCraftCore.positionMarker.MarkerEvent; |
|
||||||
|
|
||||||
public class RegionManager { |
|
||||||
public static int createRegion(Player player, Integer type, String owner, String ownerType){ |
|
||||||
Location primaryLocation = MarkerEvent.primaryLocations.get(player); |
|
||||||
Location secondaryLocation = MarkerEvent.secondaryLocations.get(player); |
|
||||||
|
|
||||||
if (primaryLocation == null || secondaryLocation == null){ |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
if (primaryLocation.getWorld() != secondaryLocation.getWorld()){ |
|
||||||
return 2; |
|
||||||
} |
|
||||||
|
|
||||||
String worldName = primaryLocation.getWorld().getName(); |
|
||||||
int x1 = primaryLocation.getBlockX(); |
|
||||||
int y1 = primaryLocation.getBlockY(); |
|
||||||
int z1 = primaryLocation.getBlockZ(); |
|
||||||
int x2 = secondaryLocation.getBlockX(); |
|
||||||
int y2 = secondaryLocation.getBlockY(); |
|
||||||
int z2 = secondaryLocation.getBlockZ(); |
|
||||||
|
|
||||||
Region region = new Region(worldName, type, x1, y1, z1, x2, y2, z2); |
|
||||||
region.save(); |
|
||||||
|
|
||||||
region.addRegionMember(ownerType, owner, "owner"); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
public static int addMember(int id, String memberType, String member, String membershipType){ |
|
||||||
Region region = Region.findById(id); |
|
||||||
|
|
||||||
if (region == null){ |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
region.addRegionMember(memberType, member, membershipType); |
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isAllowedToInteract(Player player, Location location){ |
|
||||||
if (player.isOp()){ |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
int x = location.getBlockX(); |
|
||||||
int y = location.getBlockY(); |
|
||||||
int z = location.getBlockZ(); |
|
||||||
String island = location.getWorld().getName(); |
|
||||||
|
|
||||||
Region region = Region.findRegion(x, y, z, island); |
|
||||||
|
|
||||||
if (region == null){ |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
String name = player.getName(); |
|
||||||
|
|
||||||
for (RegionMember regionMember : region.getRegionMembers()){ |
|
||||||
|
|
||||||
if (regionMember.getMembertype().equals("player") && regionMember.getName().equals(name)){ |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,187 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.sign; |
|
||||||
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder; |
|
||||||
import com.mojang.brigadier.context.CommandContext; |
|
||||||
import io.papermc.paper.command.brigadier.CommandSourceStack; |
|
||||||
import io.papermc.paper.command.brigadier.Commands; |
|
||||||
import io.papermc.paper.dialog.Dialog; |
|
||||||
import io.papermc.paper.dialog.DialogResponseView; |
|
||||||
import io.papermc.paper.registry.data.dialog.ActionButton; |
|
||||||
import io.papermc.paper.registry.data.dialog.DialogBase; |
|
||||||
import io.papermc.paper.registry.data.dialog.action.DialogAction; |
|
||||||
import io.papermc.paper.registry.data.dialog.input.DialogInput; |
|
||||||
import io.papermc.paper.registry.data.dialog.type.DialogType; |
|
||||||
import net.kyori.adventure.audience.Audience; |
|
||||||
import net.kyori.adventure.text.Component; |
|
||||||
import net.kyori.adventure.text.event.ClickCallback; |
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage; |
|
||||||
import org.bukkit.Location; |
|
||||||
import org.bukkit.block.Block; |
|
||||||
import org.bukkit.block.BlockState; |
|
||||||
import org.bukkit.block.Sign; |
|
||||||
import org.bukkit.block.sign.Side; |
|
||||||
import org.bukkit.block.sign.SignSide; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import org.bukkit.persistence.PersistentDataType; |
|
||||||
import xyz.soukup.ecoCraftCore.database.objects.Shop; |
|
||||||
import xyz.soukup.ecoCraftCore.messages.Messages; |
|
||||||
import xyz.soukup.ecoCraftCore.regions.RegionManager; |
|
||||||
import xyz.soukup.ecoCraftCore.utilities.PDC; |
|
||||||
|
|
||||||
import javax.sound.sampled.Line; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
|
|
||||||
public class SignEditCommand { |
|
||||||
|
|
||||||
private static final HashMap<Player, List<String>> clipBoard = new HashMap<>(); |
|
||||||
|
|
||||||
public static LiteralArgumentBuilder<CommandSourceStack> getCommand(){ |
|
||||||
return Commands.literal("edit-sign") |
|
||||||
.requires(source -> source.getSender() instanceof Player) |
|
||||||
.executes(SignEditCommand::openEditMenu); |
|
||||||
} |
|
||||||
|
|
||||||
private static int openEditMenu(CommandContext<CommandSourceStack> context){ |
|
||||||
Player player = (Player) context.getSource().getSender(); |
|
||||||
Block block = player.getTargetBlock(null, 10); |
|
||||||
BlockState blockState = block.getState(); |
|
||||||
|
|
||||||
if (!(blockState instanceof Sign sign)){ |
|
||||||
Messages.send(player, "sign-edit.error.not-sign"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
Location location = sign.getLocation(); |
|
||||||
|
|
||||||
if (!RegionManager.isAllowedToInteract(player, location)){ |
|
||||||
Messages.send(player, "region.error.not-allowed-to-interact"); |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
Dialog dialog = buildEditDialog(sign, player, null); |
|
||||||
player.showDialog(dialog); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static Dialog buildEditDialog(Sign sign, Player player, List<String> lines){ |
|
||||||
|
|
||||||
if (lines == null){ |
|
||||||
lines = getLines(sign); |
|
||||||
} |
|
||||||
|
|
||||||
List<ActionButton> actionButtons = new ArrayList<>(); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
actionButtons.add(ActionButton.builder(Messages.get("gui.sign-edit.buttons.copy")) |
|
||||||
.action(DialogAction.customClick((view, audience) -> copySignText(view, player, sign), ClickCallback.Options.builder().build())) |
|
||||||
.build()); |
|
||||||
actionButtons.add(ActionButton.builder(Messages.get("gui.sign-edit.buttons.paste")) |
|
||||||
.action(DialogAction.customClick((view, audience) -> pasteSignText(sign, player), ClickCallback.Options.builder().build())) |
|
||||||
.build()); |
|
||||||
actionButtons.add(ActionButton.builder(Messages.get("gui.sign-edit.buttons.confirm")) |
|
||||||
.action(DialogAction.customClick((view, audience) -> editSign(view, sign, player), ClickCallback.Options.builder().build())) |
|
||||||
.build()); |
|
||||||
actionButtons.add(ActionButton.builder(Messages.get("gui.sign-edit.buttons.cancel")) |
|
||||||
.action(DialogAction.customClick((view, audience) -> audience.closeDialog(), ClickCallback.Options.builder().build())) |
|
||||||
.build()); |
|
||||||
|
|
||||||
|
|
||||||
List<String> finalLines = lines; |
|
||||||
|
|
||||||
return Dialog.create(builder -> builder.empty() |
|
||||||
.base(DialogBase.builder(Messages.get("gui.sign-edit.title")) |
|
||||||
.inputs(List.of( |
|
||||||
DialogInput.text("line1", Messages.get("gui.sign-edit.inputs.line1")) |
|
||||||
.initial(finalLines.getFirst()) |
|
||||||
.maxLength(256) |
|
||||||
.build(), |
|
||||||
DialogInput.text("line2", Messages.get("gui.sign-edit.inputs.line2")) |
|
||||||
.initial(finalLines.get(1)) |
|
||||||
.maxLength(256) |
|
||||||
.build(), |
|
||||||
DialogInput.text("line3", Messages.get("gui.sign-edit.inputs.line3")) |
|
||||||
.initial(finalLines.get(2)) |
|
||||||
.maxLength(256) |
|
||||||
.build(), |
|
||||||
DialogInput.text("line4", Messages.get("gui.sign-edit.inputs.line4")) |
|
||||||
.initial(finalLines.get(3)) |
|
||||||
.maxLength(256) |
|
||||||
.build() |
|
||||||
)) |
|
||||||
.build()) |
|
||||||
.type(DialogType.multiAction(actionButtons).build()) |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
private static List<String> getLines(Sign sign){ |
|
||||||
List<String> lines = new ArrayList<>(); |
|
||||||
|
|
||||||
if (PDC.getUniversal(sign, "line1", PersistentDataType.STRING) != null){ |
|
||||||
for (int i = 1; i<5; i++){ |
|
||||||
lines.add((String) PDC.getUniversal(sign, "line" + i,PersistentDataType.STRING)); |
|
||||||
} |
|
||||||
return lines; |
|
||||||
} |
|
||||||
|
|
||||||
SignSide signSide = sign.getSide(Side.FRONT); |
|
||||||
List<Component> componentLines = signSide.lines(); |
|
||||||
|
|
||||||
for (Component componentLine : componentLines){ |
|
||||||
lines.add(MiniMessage.miniMessage().serialize(componentLine)); |
|
||||||
} |
|
||||||
|
|
||||||
return lines; |
|
||||||
} |
|
||||||
|
|
||||||
private static void copySignText(DialogResponseView view, Player player, Sign sign){ |
|
||||||
List<String> lines = new ArrayList<>(); |
|
||||||
|
|
||||||
lines.add(view.getText("line1")); |
|
||||||
lines.add(view.getText("line2")); |
|
||||||
lines.add(view.getText("line3")); |
|
||||||
lines.add(view.getText("line4")); |
|
||||||
|
|
||||||
clipBoard.put(player, lines); |
|
||||||
Messages.send(player, "gui.sign-edit.success.copied"); |
|
||||||
pasteSignText(sign, player); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
private static void pasteSignText(Sign sign, Player player){ |
|
||||||
Dialog dialog = buildEditDialog(sign, player, clipBoard.get(player)); |
|
||||||
player.showDialog(dialog); |
|
||||||
} |
|
||||||
|
|
||||||
private static void editSign(DialogResponseView view, Sign sign, Audience audience){ |
|
||||||
MiniMessage mm = MiniMessage.miniMessage(); |
|
||||||
SignSide signSide = sign.getSide(Side.FRONT); |
|
||||||
|
|
||||||
List<Component> lines = new ArrayList<>(); |
|
||||||
|
|
||||||
|
|
||||||
for (int i = 1; i < 5; i++) { |
|
||||||
String key = "line" + i; |
|
||||||
String line = view.getText(key); |
|
||||||
|
|
||||||
if (line == null){ |
|
||||||
line = ""; |
|
||||||
} |
|
||||||
|
|
||||||
PDC.setUniversal(sign, key, line, PersistentDataType.STRING); |
|
||||||
signSide.line(i-1, mm.deserialize(line)); |
|
||||||
|
|
||||||
} |
|
||||||
sign.update(); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} |
|
||||||
@ -1,142 +0,0 @@ |
|||||||
package xyz.soukup.ecoCraftCore.sit; |
|
||||||
|
|
||||||
import org.bukkit.Location; |
|
||||||
import org.bukkit.World; |
|
||||||
import org.bukkit.block.Block; |
|
||||||
import org.bukkit.block.data.Bisected; |
|
||||||
import org.bukkit.block.data.type.Stairs; |
|
||||||
import org.bukkit.entity.ArmorStand; |
|
||||||
import org.bukkit.entity.Entity; |
|
||||||
import org.bukkit.entity.Player; |
|
||||||
import org.bukkit.event.EventHandler; |
|
||||||
import org.bukkit.event.Listener; |
|
||||||
import org.bukkit.event.block.Action; |
|
||||||
import org.bukkit.event.player.PlayerInteractEvent; |
|
||||||
import org.bukkit.event.player.PlayerQuitEvent; |
|
||||||
import org.bukkit.event.player.PlayerTeleportEvent; |
|
||||||
import org.bukkit.event.vehicle.VehicleExitEvent; |
|
||||||
import org.bukkit.persistence.PersistentDataType; |
|
||||||
import xyz.soukup.ecoCraftCore.utilities.PDC; |
|
||||||
|
|
||||||
|
|
||||||
public class LetMeSit implements Listener { |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void onStairsClick(PlayerInteractEvent event){ |
|
||||||
Player player = event.getPlayer(); |
|
||||||
|
|
||||||
if (player.isSneaking()){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
Block block = event.getClickedBlock(); |
|
||||||
|
|
||||||
if (block == null){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (!(block.getBlockData() instanceof Stairs stairs)){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
if (stairs.getHalf() == Bisected.Half.TOP){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
switch (stairs.getShape()) { |
|
||||||
case INNER_LEFT: |
|
||||||
case INNER_RIGHT: |
|
||||||
case OUTER_LEFT: |
|
||||||
case OUTER_RIGHT: |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
float yaw = switch (stairs.getFacing()) { |
|
||||||
case NORTH -> 0f; |
|
||||||
case WEST -> -90f; |
|
||||||
case EAST -> 90f; |
|
||||||
default -> 180f; |
|
||||||
}; |
|
||||||
|
|
||||||
Location location = block.getLocation(); |
|
||||||
location.add(0.5, 0.5, 0.5); |
|
||||||
location.setYaw(yaw); |
|
||||||
|
|
||||||
World world = location.getWorld(); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (Entity entity : world.getNearbyEntities(location, 0.5, 1,0.5)){ |
|
||||||
if (!(entity instanceof ArmorStand armorStand)){ |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (PDC.getUniversal(armorStand, "chair", PersistentDataType.BOOLEAN) == null){ |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (!armorStand.getPassengers().isEmpty()){ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
player.setRotation(armorStand.getYaw(), 0f); |
|
||||||
armorStand.addPassenger(player); |
|
||||||
event.setCancelled(true); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
ArmorStand armorStand = world.spawn(location, ArmorStand.class, stand -> { |
|
||||||
stand.setInvisible(true); |
|
||||||
stand.setInvulnerable(true); |
|
||||||
stand.setGravity(false); |
|
||||||
stand.setSilent(true); |
|
||||||
stand.setMarker(true); |
|
||||||
}); |
|
||||||
|
|
||||||
PDC.setUniversal(armorStand, "chair", true, PersistentDataType.BOOLEAN); |
|
||||||
player.setRotation(yaw, 0f); |
|
||||||
armorStand.addPassenger(player); |
|
||||||
event.setCancelled(true); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void unmount(VehicleExitEvent event){ |
|
||||||
Location location = event.getVehicle().getLocation(); |
|
||||||
cleanArmorStand(location); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void playerLeave(PlayerQuitEvent event){ |
|
||||||
Location location = event.getPlayer().getLocation(); |
|
||||||
cleanArmorStand(location); |
|
||||||
} |
|
||||||
|
|
||||||
@EventHandler |
|
||||||
public void teleport(PlayerTeleportEvent event){ |
|
||||||
Location location = event.getFrom(); |
|
||||||
cleanArmorStand(location); |
|
||||||
} |
|
||||||
|
|
||||||
private void cleanArmorStand(Location location){ |
|
||||||
World world = location.getWorld(); |
|
||||||
for (Entity entity : world.getNearbyEntities(location, 0.5, 1,0.5)){ |
|
||||||
if (!(entity instanceof ArmorStand armorStand)){ |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (PDC.getUniversal(armorStand, "chair", PersistentDataType.BOOLEAN) == null){ |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
if (!armorStand.getPassengers().isEmpty()){ |
|
||||||
continue; |
|
||||||
} |
|
||||||
|
|
||||||
armorStand.remove(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue