mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-19 10:43:14 +00:00
fixes and the majority of treesize retrieval
This commit is contained in:
parent
1534dcc932
commit
c342c5c4f6
@ -4,18 +4,17 @@ import com.volmit.iris.Iris;
|
|||||||
import com.volmit.iris.engine.IrisWorlds;
|
import com.volmit.iris.engine.IrisWorlds;
|
||||||
import com.volmit.iris.engine.framework.IrisAccess;
|
import com.volmit.iris.engine.framework.IrisAccess;
|
||||||
import com.volmit.iris.engine.object.*;
|
import com.volmit.iris.engine.object.*;
|
||||||
|
import com.volmit.iris.engine.object.common.IObjectPlacer;
|
||||||
|
import com.volmit.iris.engine.object.tile.TileData;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.math.RNG;
|
import com.volmit.iris.util.math.RNG;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.block.TileState;
|
||||||
import org.bukkit.TreeType;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.world.StructureGrowEvent;
|
import org.bukkit.event.world.StructureGrowEvent;
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class TreeManager implements Listener {
|
public class TreeManager implements Listener {
|
||||||
@ -46,6 +45,7 @@ public class TreeManager implements Listener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get world access
|
||||||
IrisAccess worldAccess;
|
IrisAccess worldAccess;
|
||||||
try {
|
try {
|
||||||
worldAccess = Objects.requireNonNull(IrisWorlds.access(event.getWorld()));
|
worldAccess = Objects.requireNonNull(IrisWorlds.access(event.getWorld()));
|
||||||
@ -53,20 +53,157 @@ public class TreeManager implements Listener {
|
|||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IrisTreeSettings settings = worldAccess.getCompound().getRootDimension().getSaplingSettings();
|
|
||||||
|
|
||||||
Iris.debug("Custom saplings are enabled: " + (settings.isEnabled() ? "Yes" : "No"));
|
Iris.debug("Custom saplings are " + (worldAccess.getCompound().getRootDimension().getSaplingSettings().isEnabled() ? "" : "NOT") + " enabled.");
|
||||||
|
|
||||||
// Must have override enabled
|
// Calculate size, type & placement
|
||||||
if (!settings.isEnabled()) {
|
IrisTreeType type = IrisTreeType.fromTreeType(event.getSpecies());
|
||||||
|
IrisTreeSize size = getTreeSize(event.getLocation(), type);
|
||||||
|
IrisObjectPlacement placement = getObjectPlacement(worldAccess, type, event.getLocation(), size);
|
||||||
|
|
||||||
|
// Make sure placement was found
|
||||||
|
if (placement == null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KList<String> treeObjects = new KList<>();
|
// Get object from placer
|
||||||
|
IrisObject f = worldAccess.getData().getObjectLoader().load(placement.getPlace().getRandom(RNG.r));
|
||||||
|
|
||||||
// Get biome and region
|
// TODO: Implement placer
|
||||||
IrisBiome biome = worldAccess.getBiome(event.getLocation().getBlockX(), event.getLocation().getBlockY(), event.getLocation().getBlockZ());
|
IObjectPlacer placer = new IObjectPlacer(){
|
||||||
IrisRegion region = worldAccess.getCompound().getDefaultEngine().getRegion(event.getLocation().getBlockX(), event.getLocation().getBlockZ());
|
|
||||||
|
@Override
|
||||||
|
public int getHighest(int x, int z) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHighest(int x, int z, boolean ignoreFluid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(int x, int y, int z, BlockData d) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockData get(int x, int y, int z) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPreventingDecay() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSolid(int x, int y, int z) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUnderwater(int x, int z) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFluidHeight() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDebugSmartBore() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTile(int xx, int yy, int zz, TileData<? extends TileState> tile) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Figure out how to place without wrecking claims, other builds, etc.
|
||||||
|
// Especially with large object
|
||||||
|
|
||||||
|
// Place the object with the placer
|
||||||
|
f.place(
|
||||||
|
event.getLocation().getBlockX(),
|
||||||
|
event.getLocation().getBlockY(),
|
||||||
|
event.getLocation().getBlockZ(),
|
||||||
|
placer,
|
||||||
|
placement,
|
||||||
|
RNG.r,
|
||||||
|
Objects.requireNonNull(IrisWorlds.access(event.getWorld())).getData()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the tree size
|
||||||
|
* @param location The location the event triggers from. This sapling's Material type is used to check other locations
|
||||||
|
* @return The size of the tree
|
||||||
|
*/
|
||||||
|
private IrisTreeSize getTreeSize(Location location, IrisTreeType type) {
|
||||||
|
KList<IrisTreeSize> validSizes = new KList<>();
|
||||||
|
|
||||||
|
IrisTreeSize.isSizeValid();
|
||||||
|
|
||||||
|
return IrisTreeSize.bestSize(validSizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a single object placement (which may contain more than one object) for the requirements species, location & size
|
||||||
|
* @param worldAccess The world to access (check for biome, region, dimension, etc)
|
||||||
|
* @param type The bukkit TreeType to match
|
||||||
|
* @param location The location of the growth event (For biome/region finding)
|
||||||
|
* @param size The size of the sapling area
|
||||||
|
* @return An object placement which contains the matched tree, or null if none were found / it's disabled.
|
||||||
|
*/
|
||||||
|
private IrisObjectPlacement getObjectPlacement(IrisAccess worldAccess, IrisTreeType type, Location location, IrisTreeSize size) {
|
||||||
|
IrisDimension dimension = worldAccess.getCompound().getRootDimension();
|
||||||
|
|
||||||
|
// Return null if not enabled
|
||||||
|
if (!dimension.getSaplingSettings().isEnabled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
KList<IrisObjectPlacement> placements = new KList<>();
|
||||||
|
|
||||||
|
// Retrieve objectPlacements of type `species` from biome
|
||||||
|
IrisBiome biome = worldAccess.getBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
||||||
|
placements.addAll(matchObjectPlacements(biome.getObjects(), size, type));
|
||||||
|
|
||||||
|
// Add more or find any in the region
|
||||||
|
if (dimension.getSaplingSettings().getMode().equals(IrisTreeModes.ALL) || placements.isEmpty()){
|
||||||
|
IrisRegion region = worldAccess.getCompound().getDefaultEngine().getRegion(location.getBlockX(), location.getBlockZ());
|
||||||
|
placements.addAll(matchObjectPlacements(region.getObjects(), size, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add more or find any in the dimension
|
||||||
|
if (dimension.getSaplingSettings().getMode().equals(IrisTreeModes.ALL) || placements.isEmpty()){
|
||||||
|
//TODO: Implement object placement in dimension & here
|
||||||
|
//placements.addAll(matchObjectPlacements(dimension.getObjects(), size, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if no matches were found, return a random one if they are
|
||||||
|
return placements.isNotEmpty() ? placements.getRandom(RNG.r) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters out mismatches and returns matches
|
||||||
|
* @param objects The object placements to check
|
||||||
|
* @param size The size of the sapling area to filter with
|
||||||
|
* @param type The type of the tree to filter with
|
||||||
|
* @return A list of objectPlacements that matched. May be empty.
|
||||||
|
*/
|
||||||
|
private KList<IrisObjectPlacement> matchObjectPlacements(KList<IrisObjectPlacement> objects, IrisTreeSize size, IrisTreeType type) {
|
||||||
|
KList<IrisObjectPlacement> objectPlacements = new KList<>();
|
||||||
|
objects.stream()
|
||||||
|
.filter(objectPlacement -> objectPlacement.getTreeOptions().isEnabled())
|
||||||
|
.filter(objectPlacement -> objectPlacement.getTreeOptions().getTrees().stream().anyMatch(irisTree ->
|
||||||
|
irisTree.getSizes().stream().anyMatch(treeSize -> treeSize == size) &&
|
||||||
|
irisTree.getTreeTypes().stream().anyMatch(treeType -> treeType == type)))
|
||||||
|
.forEach(objectPlacements::add);
|
||||||
|
return objectPlacements;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.volmit.iris.engine.object;
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.object.annotations.ArrayType;
|
||||||
import com.volmit.iris.engine.object.annotations.Desc;
|
import com.volmit.iris.engine.object.annotations.Desc;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@ -18,5 +19,6 @@ public class IrisTreeOptions {
|
|||||||
private boolean enabled = false;
|
private boolean enabled = false;
|
||||||
|
|
||||||
@Desc("Tree overrides affected by these object placements")
|
@Desc("Tree overrides affected by these object placements")
|
||||||
|
@ArrayType(min = 1, type = IrisTree.class)
|
||||||
private KList<IrisTree> trees = new KList<>();
|
private KList<IrisTree> trees = new KList<>();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
package com.volmit.iris.engine.object;
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
import com.volmit.iris.engine.object.annotations.Desc;
|
import com.volmit.iris.engine.object.annotations.Desc;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Desc("Sapling override object picking options")
|
@Desc("Sapling override object picking options")
|
||||||
public enum IrisTreeSize {
|
public enum IrisTreeSize {
|
||||||
@ -11,25 +16,184 @@ public enum IrisTreeSize {
|
|||||||
@Desc("Two by two area")
|
@Desc("Two by two area")
|
||||||
TWO,
|
TWO,
|
||||||
|
|
||||||
@Desc("Three by three area with center")
|
|
||||||
THREE_CENTER,
|
|
||||||
|
|
||||||
@Desc("Three by three any location")
|
@Desc("Three by three any location")
|
||||||
THREE_ANY,
|
THREE_ANY,
|
||||||
|
|
||||||
|
@Desc("Three by three area with center")
|
||||||
|
THREE_CENTER,
|
||||||
|
|
||||||
@Desc("Four by four")
|
@Desc("Four by four")
|
||||||
FOUR,
|
FOUR,
|
||||||
|
|
||||||
@Desc("Five by five center")
|
|
||||||
FIVE_CENTER,
|
|
||||||
|
|
||||||
@Desc("Five by five")
|
@Desc("Five by five")
|
||||||
FIVE_ANY;
|
FIVE_ANY,
|
||||||
|
|
||||||
public static boolean isAnySize(IrisTreeSize treeSize){
|
@Desc("Five by five center")
|
||||||
|
FIVE_CENTER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the position of the any type (not fixed at a center)
|
||||||
|
* @param treeSize The treesize to check
|
||||||
|
*/
|
||||||
|
public static boolean isAnyPosition(IrisTreeSize treeSize){
|
||||||
return switch (treeSize) {
|
return switch (treeSize) {
|
||||||
case THREE_CENTER, FIVE_CENTER -> false;
|
case ONE, THREE_CENTER, FIVE_CENTER -> false;
|
||||||
default -> true;
|
default -> true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the best size to match against from a list of sizes
|
||||||
|
* @param sizes The list of sizes
|
||||||
|
* @return The best size (highest & center > any)
|
||||||
|
*/
|
||||||
|
public static IrisTreeSize bestSize(KList<IrisTreeSize> sizes){
|
||||||
|
if (sizes.contains(FIVE_CENTER)){
|
||||||
|
return FIVE_CENTER;
|
||||||
|
}
|
||||||
|
else if (sizes.contains(FIVE_ANY)){
|
||||||
|
return FIVE_ANY;
|
||||||
|
}
|
||||||
|
else if (sizes.contains(FOUR)){
|
||||||
|
return FOUR;
|
||||||
|
}
|
||||||
|
else if (sizes.contains(THREE_CENTER)){
|
||||||
|
return THREE_CENTER;
|
||||||
|
}
|
||||||
|
else if (sizes.contains(THREE_ANY)){
|
||||||
|
return THREE_ANY;
|
||||||
|
}
|
||||||
|
else if (sizes.contains(TWO)){
|
||||||
|
return TWO;
|
||||||
|
}
|
||||||
|
else if (sizes.contains(ONE)){
|
||||||
|
return ONE;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IrisTreeSize getBestSize(Location location){
|
||||||
|
KList<IrisTreeSize> sizes = new KList<>(ONE, TWO, THREE_ANY, THREE_CENTER, FOUR, FIVE_ANY, FIVE_CENTER);
|
||||||
|
while (sizes.isNotEmpty()){
|
||||||
|
|
||||||
|
// Find the best size & remove from list
|
||||||
|
IrisTreeSize bestSize = bestSize(sizes);
|
||||||
|
assert bestSize != null;
|
||||||
|
sizes.remove(bestSize);
|
||||||
|
|
||||||
|
// Find the best match
|
||||||
|
KList<KList<Location>> best = isSizeValid(bestSize, location);
|
||||||
|
if (best != null){
|
||||||
|
return bestSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the size at a specific location is valid
|
||||||
|
* @param size the IrisTreeSize to check
|
||||||
|
* @param location at this location
|
||||||
|
* @return A list of locations if any match, or null if not.
|
||||||
|
*/
|
||||||
|
public static KList<KList<Location>> isSizeValid(IrisTreeSize size, Location location) {
|
||||||
|
switch (size){
|
||||||
|
case ONE -> {
|
||||||
|
return new KList<KList<Location>>(new KList<>(location));
|
||||||
|
}
|
||||||
|
case TWO -> {
|
||||||
|
return loopLocation(location, 2, location.getBlock().getType());
|
||||||
|
}
|
||||||
|
case THREE_ANY -> {
|
||||||
|
return loopLocation(location, 3, location.getBlock().getType());
|
||||||
|
}
|
||||||
|
case THREE_CENTER -> {
|
||||||
|
KList<KList<Location>> locations = getMap(3, location, true);
|
||||||
|
if (locations == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return isMapValid(locations, location.getBlock().getType()) ? locations : null;
|
||||||
|
}
|
||||||
|
case FOUR -> {
|
||||||
|
return loopLocation(location, 4, location.getBlock().getType());
|
||||||
|
}
|
||||||
|
case FIVE_ANY -> {
|
||||||
|
return loopLocation(location, 5, location.getBlock().getType());
|
||||||
|
}
|
||||||
|
case FIVE_CENTER -> {
|
||||||
|
KList<KList<Location>> locations = getMap(5, location, true);
|
||||||
|
if (locations == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return isMapValid(locations, location.getBlock().getType()) ? locations : null;
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loops over all possible squares based on
|
||||||
|
* @param location top left position
|
||||||
|
* @param size a square size
|
||||||
|
* @param blockType and a type of a block
|
||||||
|
* @return A list of matching locations, or null.
|
||||||
|
*/
|
||||||
|
private static KList<KList<Location>> loopLocation(Location location, int size, Material blockType){
|
||||||
|
Location leftTop = location.add(-size + 1, 0, -size + 1);
|
||||||
|
KList<KList<Location>> locations;
|
||||||
|
for (int i = -size + 1; i <= 0; i++){
|
||||||
|
for (int j = -size + 1; j <= 0; j++){
|
||||||
|
locations = getMap(size, leftTop.add(i, 0, j));
|
||||||
|
if (isMapValid(locations, blockType)){
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if the map is valid, compared to a block material
|
||||||
|
* @param map The map to check inside of
|
||||||
|
* @param block The block material to check with
|
||||||
|
* @return True if it's valid
|
||||||
|
*/
|
||||||
|
private static boolean isMapValid(KList<KList<Location>> map, Material block){
|
||||||
|
return map.stream().allMatch(row -> row.stream().allMatch(location -> location.getBlock().getType().equals(block)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a map with all blocks in a
|
||||||
|
* @param size `size * size` square area
|
||||||
|
* @param leftTop starting from the here
|
||||||
|
* @return A map with all block locations in the area
|
||||||
|
*/
|
||||||
|
private static KList<KList<Location>> getMap(int size, Location leftTop){
|
||||||
|
KList<KList<Location>> locations = new KList<>();
|
||||||
|
for (int i = 0; i < size; i++){
|
||||||
|
KList<Location> row = new KList<>();
|
||||||
|
for (int j = 0; j < size; j++){
|
||||||
|
row.add(leftTop.add(i, 0, j));
|
||||||
|
}
|
||||||
|
locations.add(row);
|
||||||
|
}
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a map with all blocks in a
|
||||||
|
* @param size `size * size` square to check, must be odd (returns null if not)
|
||||||
|
* @param center from a center
|
||||||
|
* @param useCenter boolean toggle to call this function over IrisTreeSize#getMap(size, leftTop)
|
||||||
|
* @return A map with all block locations in the area
|
||||||
|
*/
|
||||||
|
private static KList<KList<Location>> getMap(int size, Location center, boolean useCenter){
|
||||||
|
if (size % 2 != 1){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getMap(size, center.add(-(size - 1) / 2d, 0, -(size - 1) / 2d));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user