Skip to content

Commit

Permalink
Fix up important math errs regarding schematic/island placement, grid…
Browse files Browse the repository at this point in the history
… tile detection, etc.
  • Loading branch information
avaerian committed Jun 12, 2024
1 parent b1f5e16 commit 39e0e39
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 96 deletions.
146 changes: 94 additions & 52 deletions main/src/main/java/org/minerift/ether/island/Island.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,27 @@
import org.minerift.ether.Ether;
import org.minerift.ether.config.ConfigType;
import org.minerift.ether.config.main.MainConfig;
import org.minerift.ether.util.CanChange;
import org.minerift.ether.math.Maths;
import org.minerift.ether.math.Vec2i;
import org.minerift.ether.math.Vec3i;
import org.minerift.ether.user.EtherUser;
import org.minerift.ether.util.BukkitUtils;
import org.minerift.ether.util.IBuilder;
import org.minerift.ether.world.ChunkCoords;

import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

import static org.minerift.ether.util.BukkitUtils.asVec3i;

public class Island {
public class Island extends CanChange {

// TODO: when loading islands/players from database, load EtherUser's first (null island),
// then load Island's (set island for users and attach as island members here)
// This may require a DatabaseReaderContext or something similar for handling data loading

private long bottomLeftBound, topRightBound;
private long blChunkZX, trChunkZX;
private int accessibleRegionLength;

// These 2 pieces of data can be calculated from each other
private int id;
Expand All @@ -34,28 +35,32 @@ public class Island {
// Team related fields
private int maxTeamSize;

// NOTE: hard-referencing users could consume memory over time
// For lazy-loading, a proxy could solve this problem
// This feature is not a problem for now
private Set<EtherUser> members;
private Set<UUID> members;

private PermissionSet permissions;

private boolean isDeleted;

// Private constructor
private Island(Island.Builder builder) {

// TODO: load all values from builder to object
this.tile = builder.tile;
this.id = builder.id;
this.isDeleted = builder.isDeleted;
this.permissions = builder.permissions;

this.members = new HashSet<>();
addTeamMember(builder.owner, IslandRole.OWNER);
// TODO: figure out addTeamMember and handling/storing team members for islands
this.members = builder.members.stream().map(EtherUser::getUUID).collect(Collectors.toSet());
if(builder.owner != null) {
members.add(builder.owner.getUUID());
}
//addTeamMember(builder.owner, IslandRole.OWNER);

this.blChunkZX = builder.bottomLeftChunkBound;
this.trChunkZX = builder.topRightChunkBound;

this.bottomLeftBound = builder.bottomLeftBound;
this.topRightBound = builder.topRightBound;
setChanged(false);
}


Expand All @@ -73,41 +78,47 @@ public boolean isInAccessibleRegion(Location loc) {

public boolean isInAccessibleRegion(Vec3i loc) {
final MainConfig config = Ether.getConfig(ConfigType.MAIN);
final int offset = (config.getTileSize() / 2) - (config.getTileAccessibleArea() / 2);
final int offset = (config.getTileLengthBlocks() / 2) - (config.getTileAccessibleAreaBlocks() / 2);

Vec3i.Mutable blBlock = getBottomLeftBlock().asMutable().add(offset, 0, offset);
Vec3i.Mutable trBlock = getTopRightBlock().asMutable().subtract(offset, 0, offset);

return Maths.inRangeInclusive(blBlock, trBlock, loc);
}

public Set<EtherUser> getTeamMembers() {
return Set.copyOf(members);
public List<EtherUser> getTeamMembers() {
List<EtherUser> users = new ArrayList<>(members.size());
members.forEach(uuid -> users.add(Ether.getUserManager().getUser(uuid).orElse(null)));
return users;
}

public Set<EtherUser> getTeamMembersWithRole(IslandRole role) {
return members.stream().filter(member -> member.getIslandRole() == role).collect(Collectors.toSet());
public List<EtherUser> getTeamMembersWithRole(IslandRole role) {
return getTeamMembers().stream().filter(member -> member.getIslandRole() == role).toList();
}

public EtherUser getOwner() {
return getTeamMembersWithRole(IslandRole.OWNER).iterator().next();
}

public boolean isTeamMember(EtherUser user) {
return members.contains(user);
return members.contains(user.getUUID());
}

public void addTeamMember(EtherUser user, IslandRole role) {
members.add(user);
members.add(user.getUUID());
user.setIsland(this);
user.setIslandRole(role);

setChanged(true);
}

public void removeTeamMember(EtherUser user) {
if(isTeamMember(user)) {
members.remove(user);
user.setIsland(null);
members.remove(user.getUUID());
user.setIsland((Integer) null);
user.setIslandRole(IslandRole.VISITOR);

setChanged(true);
}
}

Expand All @@ -124,61 +135,83 @@ public boolean isDeleted() {
}

public void markDeleted() {
this.isDeleted = true;
if(!isDeleted) {
this.isDeleted = true;
setChanged(true);
}
}

public long getBottomLeftChunkKey() {
return bottomLeftBound;
return blChunkZX;
}

public long getTopRightChunkKey() {
return topRightBound;
return trChunkZX;
}

public Vec2i getBottomLeftTile() {
return new Vec2i((int) bottomLeftBound, (int) (bottomLeftBound >> 32));
public Vec2i getBottomLeftChunk() {
return Maths.unpack(blChunkZX, Maths.PackingOrder.ZX);
}

public Vec2i getTopRightTile() {
return new Vec2i((int) topRightBound, (int) (topRightBound >> 32));
public Vec2i getTopRightChunk() {
return Maths.unpack(trChunkZX, Maths.PackingOrder.ZX);
}

public Vec3i getBottomLeftBlock() {
// TODO
return BukkitUtils.getVec3iAt(getBottomLeftTile()).asMutable().setY(0);
// Mutable for math purposes
// NOTE: Height is set to 0
public Vec3i.Mutable getBottomLeftBlock() {
final Vec2i blChunk = getBottomLeftChunk();
return new Vec3i.Mutable(blChunk.getX() * 16, 0, blChunk.getZ() * 16);
}

public Vec3i getTopRightBlock() {
final Vec2i.Mutable trBound = getTopRightTile().asMutable();
trBound.add(1, 1);
final Vec3i.Mutable trBlock = BukkitUtils.getVec3iAt(trBound).asMutable();
trBlock.subtract(1, 0, 1);
return trBlock;
// Mutable for math purposes
// NOTE: Height is set to 0
public Vec3i.Mutable getTopRightBlock() {
final Vec2i.Mutable trChunk = getTopRightChunk().asMutable();
trChunk.add(1, 1);
return new Vec3i.Mutable((trChunk.getX() * 16) - 1, 0, (trChunk.getZ() * 16) - 1);
}

public Chunk getBottomLeftChunk(World world) {
// TODO: extract(?) world.getMinHeight()
return world.getChunkAt(bottomLeftBound);
return world.getChunkAt(blChunkZX);
}

public Chunk getTopRightChunk(World world) {
return world.getChunkAt(topRightBound);
return world.getChunkAt(trChunkZX);
}

public static Island.Builder builder() {
return new Island.Builder();
}

public static class Builder {
@Override
public String toString() {
return "Island{" +
"id=" + id +
", tile=" + tile +
", isDeleted=" + isDeleted +
", bottomLeftBound=" + blChunkZX +
", topRightBound=" + trChunkZX +
", maxTeamSize=" + maxTeamSize +
", members=" + members +
", permissions=" + permissions +
"}\n";
}

public static class Builder implements IBuilder<Island> {

private Vec2i tile;
private int id;
private long bottomLeftBound, topRightBound;
private long bottomLeftChunkBound, topRightChunkBound;
private boolean isDeleted;
private PermissionSet permissions;

private EtherUser owner;
private Set<EtherUser> members;
private List<EtherUser> members;

private Builder() {
this.members = new ArrayList<>();
}

/**
*
Expand Down Expand Up @@ -221,31 +254,40 @@ public Builder setOwner(EtherUser owner) {
return this;
}

public Builder setMembers(Set<EtherUser> members) {
public Builder setMembers(List<EtherUser> members) {
this.members = members;
return this;
}

public Builder setBottomLeftBound(int x, int z) {
return setBottomLeftBound(Chunk.getChunkKey(x, z));
return setBottomLeftBound(ChunkCoords.getChunkKey(x, z));
}

public Builder setBottomLeftBound(Vec2i chunk) {
return setBottomLeftBound(chunk.getX(), chunk.getZ());
}

public Builder setTopRightBound(int x, int z) {
return setTopRightBound(Chunk.getChunkKey(x, z));
return setTopRightBound(ChunkCoords.getChunkKey(x, z));
}

public Builder setTopRightBound(Vec2i chunk) {
return setTopRightBound(chunk.getX(), chunk.getZ());
}

// Corner 1
public Builder setBottomLeftBound(long bottomLeftBound) {
this.bottomLeftBound = bottomLeftBound;
public Builder setBottomLeftBound(long bottomLeftChunkBound) {
this.bottomLeftChunkBound = bottomLeftChunkBound;
return this;
}

// Corner 2
public Builder setTopRightBound(long topRightBound) {
this.topRightBound = topRightBound;
public Builder setTopRightBound(long topRightChunkBound) {
this.topRightChunkBound = topRightChunkBound;
return this;
}

@Override
public Island build() {
validate();
return new Island(this);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package org.minerift.ether.island;

import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.minerift.ether.Ether;
import org.minerift.ether.config.ConfigType;
import org.minerift.ether.config.main.MainConfig;
Expand All @@ -15,56 +18,77 @@

public class IslandCreationRoutine {

public static Island run(IslandGrid grid, EtherUser user) {
public static Island run(IslandGridV2 grid, EtherUser user) {

final Player plr = user.getPlayer().orElseThrow(() -> new IllegalArgumentException("User must be online to create island!"));
final World islandWorld = plr.getWorld(); // TODO: change this to island world (add config thing and load in Ether class)

final MainConfig config = Ether.getConfig(ConfigType.MAIN);
//final SchematicsConfig schemConfig = Ether.getConfig(ConfigType.SCHEM_LIST);

// Register island on grid
// Grid tile starts bottom left
final Vec2i tile = grid.getNextTile();
System.out.println("Tile = " + tile);
final Vec2i bottomLeftChunk = new Vec2i(tile.getX() * config.getTileLengthChunks(), tile.getZ() * config.getTileLengthChunks());
final Vec2i topRightChunk = new Vec2i((config.getTileLengthChunks() * (tile.getX() + 1)) - 1, (config.getTileLengthChunks() * (tile.getZ() + 1)) - 1);

System.out.println("bottomLeftChunk = " + bottomLeftChunk);
System.out.println("topRightChunk = " + topRightChunk);

final Island island = Island.builder()
.setTile(tile, true)
.setBottomLeftBound(bottomLeftChunk)
.setTopRightBound(topRightChunk)
.setDeleted(false)
.setOwner(user)
.build();

grid.registerIsland(island);
System.out.println("bottomLeftBlock = " + island.getBottomLeftBlock());
System.out.println("topRightBlock = " + island.getTopRightBlock());

// Paste island at tile
// Refer to the Island Placement Graph (https://www.desmos.com/calculator/fuwvk1rgkf) for easy maths and representation
final File file = null; // TODO
//final File schemFile = new File(Ether.getPluginDir(), "test_schem1.schem"); // TODO: move this into function parameter
File schemFile = Ether.getPluginFile("test_schem1.schem");

// Get schematic paste position

// OLD CODE:
//final int bottomLeftOffset = (config.getTileSize() / 2) - (config.getTileAccessibleArea() / 2);
//bottomLeftPos.add(bottomLeftOffset, 0, bottomLeftOffset);

// TODO: this needs to be the center of the island, with the schematic offset being the middle of the schematic
final int halfTile = config.getTileSize() / 2;
Vec3i.Mutable tileCenterPos = island.getBottomLeftBlock().asMutable().add(halfTile, 0, halfTile);
final int halfTile = config.getTileLengthBlocks() / 2;
System.out.println("halfTile = " + halfTile);
Vec3i.Mutable tileCenterPos = island.getBottomLeftBlock().asMutable().add(halfTile, 0, halfTile); //.transform(x -> x + halfTile, y -> config.getTileHeight(), z -> z + halfTile);
tileCenterPos.setY(config.getTileHeight());
System.out.println("Tile Center Pos = " + tileCenterPos);

try {
final Schematic schem = Schematic.fromFile(file);
final Vec3i schemCenterOffset = new Vec3i(schem.getWidth() / 2, schem.getHeight() / 2, schem.getLength() / 2);
final Schematic schem = Schematic.fromFile(schemFile);
final Vec3i schemCenterOffset = new Vec3i.Mutable(schem.getWidth() / 2, schem.getHeight() / 2, schem.getLength() / 2); //.transform((x) -> -x, (y) -> -y, (z) -> -z);
//final Vec3i schemCenterOffset = new Vec3i.Mutable(-schem.getWidth() / 2, -schem.getHeight() / 2, -schem.getLength() / 2); // try subtracted offset?
System.out.println("Schem center offset = " + schemCenterOffset);
final SchematicPasteOptions options = SchematicPasteOptions.builder()
.setOffset(schemCenterOffset)
.setOffset(schemCenterOffset) // set pivot around center block
.copyBiomes(true)
.copyEntities(false)
.ignoreAirBlocks(false)
.build();

schem.paste(tileCenterPos, plr.getWorld().getName(), options);
schem.paste(tileCenterPos, islandWorld.getName(), options);
} catch (SchematicFileReadException ex) {
throw new RuntimeException(ex);
}

// Register island after paste operation is successful
grid.registerIsland(island);

// Teleport player
// TODO: find sign and spawn player in front

Location plrTp = new Location(islandWorld, tileCenterPos.getX(), tileCenterPos.getY() + 2, tileCenterPos.getZ());
plr.teleportAsync(plrTp, PlayerTeleportEvent.TeleportCause.PLUGIN);

return island;

}
Expand Down
Loading

0 comments on commit 39e0e39

Please sign in to comment.