Refactor and add basic sparse mesh implementation

This commit is contained in:
2026-03-17 00:45:35 -04:00
parent 95e374682b
commit 45c65f4f78
53 changed files with 1408 additions and 292 deletions

View File

@@ -65,7 +65,6 @@ public class MeshTest {
// Now that we have a bunch of bounding boxes, do whatever // Now that we have a bunch of bounding boxes, do whatever
MeshBuilder builder = new MeshBuilder(); MeshBuilder builder = new MeshBuilder();
int i = 0;
for ( AABB box : boxes ) { for ( AABB box : boxes ) {
for ( Facet facet : generateFacetsFor( box ) ) { for ( Facet facet : generateFacetsFor( box ) ) {
builder.addFacet( facet ); builder.addFacet( facet );

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -8,7 +8,7 @@ import java.util.Set;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.permissions.Permission; import org.bukkit.permissions.Permission;
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.BukkitUtil; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.BukkitUtil;
public class CommandBase { public class CommandBase {
protected PluginCommand command; protected PluginCommand command;

View File

@@ -1,8 +1,8 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.executor.CommandExecutable; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor.CommandExecutable;
public class CommandOption { public class CommandOption {
protected CommandExecutable exe; protected CommandExecutable exe;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
public class SplitCommand { public class SplitCommand {
protected String[] input; protected String[] input;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -13,10 +13,10 @@ import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.util.StringUtil; import org.bukkit.util.StringUtil;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.executor.CommandExecutable; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor.CommandExecutable;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.InputValidator; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.InputValidator;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.InputValidatorString; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.InputValidatorString;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.sender.SenderValidator; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender.SenderValidator;
/** /**
* A build and run command framework for automatic tab completions and easy branching. * A build and run command framework for automatic tab completions and easy branching.

View File

@@ -1,8 +1,8 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.executor; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.CommandParameters; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.CommandParameters;
public interface CommandExecutable { public interface CommandExecutable {
void execute( CommandSender sender, String[] args, CommandParameters params ); void execute( CommandSender sender, String[] args, CommandParameters params );

View File

@@ -1,8 +1,8 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.executor; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.CommandParameters; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.CommandParameters;
public class CommandExecutableMessage implements CommandExecutable { public class CommandExecutableMessage implements CommandExecutable {
protected String message; protected String message;

View File

@@ -5,4 +5,4 @@
* @author BananaPuncher714 * @author BananaPuncher714
* *
*/ */
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.executor; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor;

View File

@@ -3,4 +3,4 @@
* *
* @author BananaPuncher714 * @author BananaPuncher714
*/ */
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command; package com.aaaaahhhhhhh.bananapuncher714.mesh.command;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -5,4 +5,4 @@
* @author BananaPuncher714 * @author BananaPuncher714
* *
*/ */
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;

View File

@@ -5,4 +5,4 @@
* @author BananaPuncher714 * @author BananaPuncher714
* *
*/ */
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.sender; package com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender;

View File

@@ -0,0 +1,5 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment;
public class ChunkMeshCache {
}

View File

@@ -1,12 +1,17 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment;
import java.io.File; import java.io.File;
import java.util.logging.Level;
import org.apache.commons.lang.SystemUtils;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.FileUtil; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.FileUtil;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.objects.PhysicsRigidBody;
public class McMeshEnvironment extends JavaPlugin { public class McMeshEnvironmentPlugin extends JavaPlugin {
@Override @Override
public void onEnable() { public void onEnable() {
FileUtil.saveToFile( getResource( "native/windows/x86_64/bulletjme.dll" ), new File( getDataFolder() + "/lib", "bulletjme.dll" ), false ); FileUtil.saveToFile( getResource( "native/windows/x86_64/bulletjme.dll" ), new File( getDataFolder() + "/lib", "bulletjme.dll" ), false );
@@ -17,6 +22,11 @@ public class McMeshEnvironment extends JavaPlugin {
Bukkit.getPluginManager().disablePlugin( this ); Bukkit.getPluginManager().disablePlugin( this );
return; return;
} }
// Don't log anything
PhysicsSpace.logger.setLevel( Level.WARNING );
PhysicsSpace.loggerC.setLevel( Level.WARNING );
PhysicsRigidBody.logger2.setLevel( Level.WARNING );
} }
private final boolean loadNativeLibraries() { private final boolean loadNativeLibraries() {

View File

@@ -0,0 +1,894 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionRuleWinding;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple.GluWindingRule;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.AbstractMesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.BlockDataInformation;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.BlockDataType;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkLocation;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.IndexedPolygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.IndexedTriangle;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.MinecraftPlane;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.MinecraftPlane.PlaneAxis;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.PlaneMesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.SparseMesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.VectorReference;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.ChunkMeshUtil;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.NmsUtil;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.NmsUtil.BlockShapeType;
import com.jme3.bullet.collision.shapes.MeshCollisionShape;
import com.jme3.bullet.collision.shapes.infos.IndexedMesh;
import com.jme3.bullet.objects.PhysicsBody;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
public class MeshEnvironment {
private JavaPlugin plugin;
private File cacheDirectory;
private Map< ChunkLocation, ChunkMesh > chunkMeshes;
private Listener eventListener = new Listener() {
@EventHandler
private void onChunkLoad( ChunkLoadEvent event ) {
// TODO Queue chunk load
loadOrGenerateMesh( event.getChunk() );
}
@EventHandler
private void onChunkUnload( ChunkUnloadEvent event ) {
// TODO Queue chunk unload
if ( event.getWorld().getName().equalsIgnoreCase( "world" ) ) {
final ChunkLocation loc = new ChunkLocation( event.getChunk() );
if ( chunks.containsKey( loc ) ) {
space.removeCollisionObject( chunks.get( loc ) );
chunks.remove( loc );
}
final ChunkMesh mesh = chunkMeshes.remove( loc );
if ( mesh != null ) {
saveMesh( loc, mesh );
}
}
}
final Map< ChunkLocation, Collection< Location > > updateLocations = new TreeMap< ChunkLocation, Collection< Location > >();
final BukkitTask task = Bukkit.getScheduler().runTaskTimer( plugin, () -> {
final Collection< ChunkLocation > locations = new ArrayDeque< ChunkLocation >();
updateLocations.entrySet().stream().forEach( e -> {
final Collection< Location > locs = update( e.getValue() );
e.getValue().removeAll( locs );
if ( !locs.isEmpty() ) {
locations.add( e.getKey() );
}
} );
if ( !locations.isEmpty() ) {
space.activateAll( true );
}
updateLocations.values().removeIf( c -> c.isEmpty() );
}, 1, 1 );
final Function< ChunkLocation, Collection< Location > > getLocationFor = c -> {
Collection< Location > locations = updateLocations.get( c );
if ( locations == null ) {
locations = new HashSet< Location >();
updateLocations.put( c, locations );
}
return locations;
};
@EventHandler( priority = EventPriority.MONITOR )
private void onBlockUpdateEvent( final BlockPhysicsEvent event ) {
final ChunkLocation chunkLocation = new ChunkLocation( event.getBlock().getChunk() );
getLocationFor.apply( chunkLocation ).add( event.getBlock().getLocation() );
}
};
public MeshEnvironment( JavaPlugin plugin, File cacheDirectory ) {
this.plugin = plugin;
this.cacheDirectory = cacheDirectory;
}
public void activate() {
Bukkit.getPluginManager().registerEvents( eventListener, plugin );
}
public void deactivate() {
HandlerList.unregisterAll( eventListener );
}
private void loadOrGenerateMesh( final Chunk chunk ) {
final ChunkLocation location = new ChunkLocation( chunk );
final ChunkMesh mesh = loadMesh( location );
if ( mesh == null ) {
generateMesh( chunk );
} else {
// Save our chunk mesh
chunkMeshes.put( location, mesh );
}
}
private ChunkMesh loadMesh( final ChunkLocation location ) {
final File file = new File( cacheDirectory, "meshes/" + location.getWorldName() + "/" + location.getX() + "/" + location.getZ() + ".cmesh" );
if ( file.exists() ) {
try {
final byte[] data = Files.readAllBytes( file.toPath() );
final ChunkMesh mesh = ChunkMeshUtil.deserialize( data );
return mesh;
} catch ( IOException e ) {
e.printStackTrace();
}
}
return null;
}
private void saveMesh( final ChunkLocation location, final ChunkMesh mesh ) {
final File file = new File( cacheDirectory, "meshes/" + location.getWorldName() + "/" + location.getX() + "/" + location.getZ() + ".cmesh" );
file.getParentFile().mkdirs();
final byte[] data = ChunkMeshUtil.serialize( mesh );
try {
Files.write( file.toPath(), data, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE, StandardOpenOption.WRITE );
} catch ( IOException e ) {
e.printStackTrace();
}
}
private SparseMesh generateSpareMesh( World world, Collection< Vector > locations ) {
final long start = System.currentTimeMillis();
boolean set = false;
Vector min;
Vector max;
for ( Vector v : locations ) {
if ( !set ) {
set = true;
min = v.toBlockVector();
max = v.toBlockVector();
} else {
min = Vector.getMinimum( min, v.toBlockVector() );
max = Vector.getMaximum( max, v.toBlockVector() );
}
}
final SparseMesh sparseMesh = new SparseMesh( min, max );
final Map< MinecraftPlane, Collection< Polygon > > polygons = new TreeMap< MinecraftPlane, Collection< Polygon > >();
{
final Function< MinecraftPlane, Collection< Polygon > > getPolygons = p -> {
Collection< Polygon > polygonCollection = polygons.get( p );
if ( polygonCollection == null ) {
polygonCollection = new ArrayDeque< Polygon >();
polygons.put( p, polygonCollection );
}
return polygonCollection;
};
for ( final Vector location : locations ) {
final Block block = world.getBlockAt( location.getBlockX(), location.getBlockY(), location.getBlockZ() );
if ( !( block.isEmpty() && block.isLiquid() ) ) {
final BlockData data = block.getBlockData();
final Location loc = block.getLocation();
// Start the box at 0, 0, 0
final BoundingBox[] boundingBoxes = NmsUtil.getShape( data, loc, BlockShapeType.COLLISION_SHAPE ).e().stream().map( aabb -> new BoundingBox( aabb.a, aabb.b, aabb.c, aabb.d, aabb.e, aabb.f ) ).toArray( BoundingBox[]::new );
final BlockDataInformation information = new BlockDataInformation( data );
if ( boundingBoxes.length == 0 ) {
// No bounding box
information.type = BlockDataType.NONE;
} else if ( boundingBoxes.length == 1 && boundingBoxes[ 0 ].getVolume() == 1 ) {
// Solid
information.type = BlockDataType.SOLID;
} else {
information.type = BlockDataType.COMPLEX;
// Complex bounding shape
// Add the voxel shape to the chunk mesh
for ( final BoundingBox aabb : boundingBoxes ) {
final double minX = aabb.getMinX() + loc.getBlockX() - min.getBlockX();
final double minY = aabb.getMinY() + loc.getBlockY() - min.getBlockY();
final double minZ = aabb.getMinZ() + loc.getBlockZ() - min.getBlockZ();
final double maxX = aabb.getMaxX() + loc.getBlockX() - min.getBlockX();
final double maxY = aabb.getMaxY() + loc.getBlockY() - min.getBlockY();
final double maxZ = aabb.getMaxZ() + loc.getBlockZ() - min.getBlockZ();
final Polygon xPoly = new Polygon( Arrays.asList(
new Point( minY, minZ ),
new Point( minY, maxZ ),
new Point( maxY, maxZ ),
new Point( maxY, minZ )
) );
final Polygon yPoly = new Polygon( Arrays.asList(
new Point( minX, minZ ),
new Point( minX, maxZ ),
new Point( maxX, maxZ ),
new Point( maxX, minZ )
) );
final Polygon zPoly = new Polygon( Arrays.asList(
new Point( minX, minY ),
new Point( minX, maxY ),
new Point( maxX, maxY ),
new Point( maxX, minY )
) );
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, minY ) ).add( yPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, maxY ) ).add( yPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, minZ ) ).add( zPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, maxZ ) ).add( zPoly );
}
information.boundingBoxes = boundingBoxes;
sparseMesh.setBlockDataInformationFor( information, loc.toVector().subtract( min ) );
}
}
}
// Now generate facets for each solid block based on if the side they are on is visible
for ( final Vector location : locations ) {
final Vector blockVector = location.toBlockVector().subtract( min );
final BlockDataInformation info = sparseMesh.getBlockDataInformationFor( blockVector );
if ( info != null ) {
if ( info.type == BlockDataType.SOLID ) {
final Polygon xPoly = new Polygon( Arrays.asList(
new Point( blockVector.getY(), blockVector.getZ() ),
new Point( blockVector.getY(), blockVector.getZ() + 1 ),
new Point( blockVector.getY() + 1, blockVector.getZ() + 1 ),
new Point( blockVector.getY() + 1, blockVector.getZ() )
) );
final Polygon yPoly = new Polygon( Arrays.asList(
new Point( blockVector.getX(), blockVector.getZ() ),
new Point( blockVector.getX(), blockVector.getZ() + 1 ),
new Point( blockVector.getX() + 1, blockVector.getZ() + 1 ),
new Point( blockVector.getX() + 1, blockVector.getZ() )
) );
final Polygon zPoly = new Polygon( Arrays.asList(
new Point( blockVector.getX(), blockVector.getY() ),
new Point( blockVector.getX(), blockVector.getY() + 1 ),
new Point( blockVector.getX() + 1, blockVector.getY() + 1 ),
new Point( blockVector.getX() + 1, blockVector.getY() )
) );
BlockDataInformation adjacent;
if ( ( adjacent = sparseMesh.getBlockDataInformationFor( blockVector.clone().subtract( new Vector( 0, 1, 0 ) ) ) ) == null || adjacent.type != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, blockVector.getY() ) ).add( yPoly );
}
if ( ( adjacent = sparseMesh.getBlockDataInformationFor( blockVector.clone().add( new Vector( 0, 1, 0 ) ) ) ) == null || adjacent.type != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, blockVector.getY() + 1 ) ).add( yPoly );
}
if ( ( adjacent = sparseMesh.getBlockDataInformationFor( blockVector.clone().subtract( new Vector( 0, 0, 1 ) ) ) ) == null || adjacent.type != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, blockVector.getZ() ) ).add( zPoly );
}
if ( ( adjacent = sparseMesh.getBlockDataInformationFor( blockVector.clone().add( new Vector( 0, 0, 1 ) ) ) ) == null || adjacent.type != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, blockVector.getZ() + 1 ) ).add( zPoly );
}
if ( ( adjacent = sparseMesh.getBlockDataInformationFor( blockVector.clone().subtract( new Vector( 1, 0, 0 ) ) ) ) == null || adjacent.type != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, blockVector.getX() ) ).add( xPoly );
}
if ( ( adjacent = sparseMesh.getBlockDataInformationFor( blockVector.clone().add( new Vector( 1, 0, 0 ) ) ) ) == null || adjacent.type != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, blockVector.getX() + 1 ) ).add( xPoly );
}
}
} else {
// Shouldn't be null btw
}
}
}
// Mesh the data and get the output
final MeshResult meshResult = generateMeshFrom( polygons );
sparseMesh.planes = meshResult.meshes;
sparseMesh.pointReferences = meshResult.points;
// DONE
return sparseMesh;
}
private void generateMesh( final Chunk chunk ) {
final long start = System.currentTimeMillis();
final World world = chunk.getWorld();
final ChunkLocation chunkLocation = new ChunkLocation( chunk );
final int worldMinHeight = world.getMinHeight();
final int worldMaxHeight = world.getMaxHeight();
final int worldHeight = worldMaxHeight - worldMinHeight;
final ChunkMesh chunkMesh = new ChunkMesh( new BoundingBox( 0, 0, 0, 16, worldHeight, 16 ) );
final Map< MinecraftPlane, Collection< Polygon > > polygons = new TreeMap< MinecraftPlane, Collection< Polygon > >();
{
final Function< MinecraftPlane, Collection< Polygon > > getPolygons = p -> {
Collection< Polygon > polygonCollection = polygons.get( p );
if ( polygonCollection == null ) {
polygonCollection = new ArrayDeque< Polygon >();
polygons.put( p, polygonCollection );
}
return polygonCollection;
};
// When we would have inserted each facet, instead, find or create the
// corresponding plane, and add directly.
// Also, create a chunk mesh and populate the structs
for ( int y = worldMinHeight; y < worldMaxHeight; ++y ) {
final int relY = y - worldMinHeight;
final int yIndex = relY << 8;
for ( int z = 0; z < 16; ++z ) {
final int zIndex = yIndex + ( z << 4 );
for ( int x = 0; x < 16; ++x ) {
final int index = zIndex + x;
final Block block = chunk.getBlock( x, y, z );
if ( !( block.isEmpty() && block.isLiquid() ) ) {
final BlockData data = block.getBlockData();
final Location loc = block.getLocation();
// Start the box at 0, 0, 0
final BoundingBox[] boundingBoxes = NmsUtil.getShape( data, loc, BlockShapeType.COLLISION_SHAPE ).e().stream().map( aabb -> new BoundingBox( aabb.a, aabb.b, aabb.c, aabb.d, aabb.e, aabb.f ) ).toArray( BoundingBox[]::new );
if ( boundingBoxes.length == 0 ) {
// No bounding box
chunkMesh.setType( index, BlockDataType.NONE );
} else if ( boundingBoxes.length == 1 && boundingBoxes[ 0 ].getVolume() == 1 ) {
// Solid
chunkMesh.setType( index, BlockDataType.SOLID );
} else {
chunkMesh.setType( index, BlockDataType.COMPLEX );
// Complex bounding shape
// Only store the old block data if we know it is not empty or solid!!
chunkMesh.setData( index, data );
// Add the voxel shape to the chunk mesh
for ( final BoundingBox aabb : boundingBoxes ) {
final double minX = aabb.getMinX() + x;
final double minY = aabb.getMinY() + relY;
final double minZ = aabb.getMinZ() + z;
final double maxX = aabb.getMaxX() + x;
final double maxY = aabb.getMaxY() + relY;
final double maxZ = aabb.getMaxZ() + z;
final Polygon xPoly = new Polygon( Arrays.asList(
new Point( minY, minZ ),
new Point( minY, maxZ ),
new Point( maxY, maxZ ),
new Point( maxY, minZ )
) );
final Polygon yPoly = new Polygon( Arrays.asList(
new Point( minX, minZ ),
new Point( minX, maxZ ),
new Point( maxX, maxZ ),
new Point( maxX, minZ )
) );
final Polygon zPoly = new Polygon( Arrays.asList(
new Point( minX, minY ),
new Point( minX, maxY ),
new Point( maxX, maxY ),
new Point( maxX, minY )
) );
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, minY ) ).add( yPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, maxY ) ).add( yPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, minZ ) ).add( zPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, maxZ ) ).add( zPoly );
}
chunkMesh.setBoxes( index, boundingBoxes );
}
} else {
chunkMesh.setType( index, BlockDataType.NONE );
}
}
}
}
// Now generate facets for each solid block based on if the side they are on is visible
for ( int y = 0; y < worldHeight; ++y ) {
final int yIndex = y << 8;
for ( int z = 0; z < 16; ++z ) {
final int zIndex = z << 4;
for ( int x = 0; x < 16; ++x ) {
final int index = yIndex + zIndex + x;
if ( chunkMesh.getType( index ) == BlockDataType.SOLID ) {
final Polygon xPoly = new Polygon( Arrays.asList(
new Point( y, z ),
new Point( y, z + 1 ),
new Point( y + 1, z + 1 ),
new Point( y + 1, z )
) );
final Polygon yPoly = new Polygon( Arrays.asList(
new Point( x, z ),
new Point( x, z + 1 ),
new Point( x + 1, z + 1 ),
new Point( x + 1, z )
) );
final Polygon zPoly = new Polygon( Arrays.asList(
new Point( x, y ),
new Point( x, y + 1 ),
new Point( x + 1, y + 1 ),
new Point( x + 1, y )
) );
// Check each face
if ( y == 0 || chunkMesh.getType( index - 256 ) != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, y ) ).add( yPoly );
}
if ( y == worldHeight - 1 || chunkMesh.getType( index + 256 ) != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, y + 1 ) ).add( yPoly );
}
if ( z == 0 || chunkMesh.getType( index - 16 ) != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, z ) ).add( zPoly );
}
if ( z == 15 || chunkMesh.getType( index + 16 ) != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, z + 1 ) ).add( zPoly );
}
if ( x == 0 || chunkMesh.getType( index - 1 ) != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, x ) ).add( xPoly );
}
if ( x == 15 || chunkMesh.getType( index + 1 ) != BlockDataType.SOLID ) {
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, x + 1 ) ).add( xPoly );
}
}
}
}
}
}
Bukkit.getScheduler().runTaskAsynchronously( plugin, () -> {
// Mesh the data and get the output
final MeshResult meshResult = generateMeshFrom( polygons );
chunkMesh.planes = meshResult.meshes;
chunkMesh.pointReferences = meshResult.points;
// DONE
// Now, create a physics object from the chunk mesh
final IndexedMesh nativeMesh = chunkMesh.toIndexedMesh();
// Enable quantized AABB compression... hopefully that doesn't mess with the accuracy or anything...
final MeshCollisionShape mesh = new MeshCollisionShape( true, nativeMesh );
// Create a rigid body
PhysicsRigidBody rigid = new PhysicsRigidBody( mesh, PhysicsBody.massForStatic );
rigid.setPhysicsLocation( new Vector3f( chunk.getX() << 4, world.getMinHeight(), chunk.getZ() << 4 ) );
rigid.setPhysicsRotation( new Quaternion( 0, 0, 0, 1 ) );
rigid.setKinematic( false );
Bukkit.getScheduler().runTask( plugin, () -> {
// Save our chunk mesh
chunkMeshes.put( chunkLocation, chunkMesh );
space.addCollisionObject( rigid );
PhysicsRigidBody old = chunks.put( new ChunkLocation( chunk ), rigid );
if ( old != null ) {
getLogger().warning( "Old rigid body found!" );
space.remove( old );
}
final long time = System.currentTimeMillis() - start;
// getLogger().info( "Took " + time + "ms to mesh chunk " + chunk.getX() + ", " + chunk.getZ() + " into " + mesh.countMeshVertices() + " vertices and " + mesh.countMeshTriangles() + " triangles" );
} );
} );
}
private Collection< Location > update( final AbstractMesh mesh, final Collection< Location > locations ) {
if ( locations.isEmpty() ) {
return Collections.emptySet();
}
final World world = locations.iterator().next().getWorld();
final Collection< Location > canRemove = new ArrayDeque< Location >();
// Check each location
final Map< MinecraftPlane, Collection< Polygon > > polygons = new TreeMap< MinecraftPlane, Collection< Polygon > >();
final Function< MinecraftPlane, Collection< Polygon > > getPolygons = p -> {
Collection< Polygon > polygonCollection = polygons.get( p );
if ( polygonCollection == null ) {
polygonCollection = new ArrayDeque< Polygon >();
polygons.put( p, polygonCollection );
}
return polygonCollection;
};
final BiFunction< List< BoundingBox >, BoundingBox[], Boolean > isEqual = ( a, b ) -> {
if ( a.size() == b.length ) {
for ( int i = 0; i < b.length; ++i ) {
final BoundingBox b1 = a.get( i );
final BoundingBox b2 = b[ i ];
if ( !b1.equals( b2 ) ) {
return false;
}
}
}
return true;
};
for ( final Location location : locations ) {
final BlockData data = location.getBlock().getBlockData();
// Defer moving piston updates until another tick when it's done moving
if ( data.getMaterial() == Material.MOVING_PISTON ) {
continue;
}
final Vector position = location.toVector().subtract( mesh.getMinimumCorner() );
final BlockDataInformation information = mesh.getBlockDataInformationFor( position );
if ( information != null ) {
canRemove.add( location );
if ( information.isBlockData( data ) ) {
// Ignore if the block data has not changed
continue;
} else {
final List< BoundingBox > boxes = NmsUtil.getShape( data, location, BlockShapeType.COLLISION_SHAPE ).e().stream()
.map( aabb -> new BoundingBox( aabb.a, aabb.b, aabb.c, aabb.d, aabb.e, aabb.f ) ).collect( Collectors.toList() );
final BlockDataType oldType = information.type;
final BoundingBox[] otherBoxes = information.boundingBoxes;
if ( boxes.size() == 0 ) {
if ( oldType == BlockDataType.NONE ) {
continue;
}
BlockDataInformation newInfo = new BlockDataInformation( data );
newInfo.type = BlockDataType.NONE;
newInfo.boundingBoxes = null;
mesh.setBlockDataInformationFor( newInfo, position );
} else if ( boxes.size() == 1 && boxes.get( 0 ).getVolume() == 1 ) {
if ( oldType == BlockDataType.SOLID ) {
continue;
}
BlockDataInformation newInfo = new BlockDataInformation( data );
newInfo.type = BlockDataType.SOLID;
newInfo.boundingBoxes = null;
mesh.setBlockDataInformationFor( newInfo, position );
} else {
if ( otherBoxes != null && isEqual.apply( boxes, otherBoxes ) ) {
continue;
}
BlockDataInformation newInfo = new BlockDataInformation( data );
newInfo.type = BlockDataType.COMPLEX;
newInfo.boundingBoxes = boxes.toArray( BoundingBox[]::new );
mesh.setBlockDataInformationFor( newInfo, position );
}
if ( oldType == BlockDataType.SOLID ) {
boxes.add( new BoundingBox( 0, 0, 0, 1, 1, 1 ) );
} else if ( oldType == BlockDataType.COMPLEX ) {
if ( otherBoxes == null || otherBoxes.length == 0 ) {
throw new IllegalStateException( "Complex shape but no bounding boxes!" );
}
for ( final BoundingBox box : otherBoxes ) {
boxes.add( box );
}
}
// Add the voxel shape to the chunk mesh
for ( final BoundingBox aabb : boxes ) {
final double minX = aabb.getMinX() + position.getX();
final double minY = aabb.getMinY() + position.getY();
final double minZ = aabb.getMinZ() + position.getZ();
final double maxX = aabb.getMaxX() + position.getX();
final double maxY = aabb.getMaxY() + position.getY();
final double maxZ = aabb.getMaxZ() + position.getZ();
final Polygon xPoly = new Polygon( Arrays.asList(
new Point( minY, minZ ),
new Point( minY, maxZ ),
new Point( maxY, maxZ ),
new Point( maxY, minZ )
) );
final Polygon yPoly = new Polygon( Arrays.asList(
new Point( minX, minZ ),
new Point( minX, maxZ ),
new Point( maxX, maxZ ),
new Point( maxX, minZ )
) );
final Polygon zPoly = new Polygon( Arrays.asList(
new Point( minX, minY ),
new Point( minX, maxY ),
new Point( maxX, maxY ),
new Point( maxX, minY )
) );
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, minY ) ).add( yPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Y, maxY ) ).add( yPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, minZ ) ).add( zPoly );
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, maxZ ) ).add( zPoly );
}
}
}
}
// No polygons found... which means nothing changed
if ( polygons.isEmpty() ) {
return canRemove;
}
final Map< MinecraftPlane, Mesh< RegionSimple > > meshMap = new HashMap< MinecraftPlane, Mesh< RegionSimple > >();
// Now mesh the blocks asynchronously and combine, then do the bare minimum to regenerate the chunk mesh
for ( final Entry< MinecraftPlane, Collection< Polygon > > entry : polygons.entrySet() ) {
final MinecraftPlane plane = entry.getKey();
final PlaneMesh planeMesh = mesh.planes.remove( plane );
final Mesh< RegionSimple > mesher = new Mesh< RegionSimple >( () -> new RegionSimple( GluWindingRule.ODD ) );
if ( planeMesh != null ) {
// Reset all indexed polygons(triangles) for this plane
for ( final IndexedTriangle poly : planeMesh.completedPolygons ) {
poly.getPoints().parallelStream().forEach( p -> --p.referenceCount );
}
// Add all polygons that were previously generated
for ( final Polygon polygon : planeMesh.generatedRegions ) {
mesher.addPolygon( polygon, RegionRuleWinding.CLOCKWISE );
}
}
for ( final Polygon polygon : entry.getValue() ) {
mesher.addPolygon( polygon, RegionRuleWinding.CLOCKWISE );
}
meshMap.put( plane, mesher );
}
// Mesh each plane
final Map< MinecraftPlane, CompleteMesh > triangles = meshMap.entrySet().parallelStream().collect( Collectors.toConcurrentMap( e -> e.getKey(), e -> new CompleteMesh( e.getKey(), e.getValue() ) ) );
for ( final Entry< MinecraftPlane, CompleteMesh > entry : triangles.entrySet() ) {
final MinecraftPlane plane = entry.getKey();
final CompleteMesh completeMesh = entry.getValue();
final Collection< Polygon > tris = completeMesh.triangles;
final Mesh< RegionSimple > mesher = completeMesh.mesh;
// Ignore any planes that are empty
if ( !tris.isEmpty() ) {
final PlaneMesh newMesh = new PlaneMesh();
newMesh.completedPolygons = new ArrayList< IndexedTriangle >();
for ( final Polygon tri : tris ) {
final IndexedTriangle newPoly = new IndexedTriangle();
for ( int i = 0; i < tri.getPoints().size() && i < 3; ++i ) {
final Point point = tri.getPoints().get( i );
final Vector vert = plane.convert( point );
// Find an existing vertex reference if one exists
final VectorReference tempRef = new VectorReference( vert );
VectorReference ref = null;
final VectorReference upperRef = mesh.pointReferences.ceiling( tempRef );
if ( upperRef != null && upperRef.vector.distanceSquared( vert ) < 1e-8 ) {
ref = upperRef;
} else {
final VectorReference lowerRef = mesh.pointReferences.floor( tempRef );
if ( lowerRef != null && lowerRef.vector.distanceSquared( vert ) < 1e-8 ) {
ref = lowerRef;
}
}
if ( ref == null ) {
ref = tempRef;
ref.referenceCount = 1;
mesh.pointReferences.add( ref );
} else {
++ref.referenceCount;
}
switch ( i ) {
case 0:
newPoly.setPoint1( ref );
break;
case 1:
newPoly.setPoint2( ref );
break;
case 2:
newPoly.setPoint3( ref );
break;
default:
// Should never be here!
}
}
newMesh.completedPolygons.add( newPoly );
}
// Save the generated regions as an intermediary step so we can re-use them later
newMesh.generatedRegions = mesher.getPolygons();
mesh.planes.put( plane, newMesh );
}
}
// Remove all vector references that have a reference count of 0
mesh.pointReferences.removeIf( v -> v.referenceCount <= 0 );
// DONE
// Now, create a physics object from the chunk mesh
final IndexedMesh nativeMesh = chunkMesh.toIndexedMesh();
// Enable quantized AABB compression... hopefully that doesn't mess with the accuracy or anything...
final MeshCollisionShape mesh = new MeshCollisionShape( true, nativeMesh );
// Create a rigid body
PhysicsRigidBody rigid = new PhysicsRigidBody( mesh, PhysicsBody.massForStatic );
rigid.setPhysicsLocation( new Vector3f( chunkLocation.getX() << 4, world.getMinHeight(), chunkLocation.getZ() << 4 ) );
rigid.setPhysicsRotation( new Quaternion( 0, 0, 0, 1 ) );
rigid.setKinematic( false );
return canRemove;
}
private MeshResult generateMeshFrom( final Map< MinecraftPlane, Collection< Polygon > > polygons ) {
final Map< MinecraftPlane, Mesh< RegionSimple > > meshMap = new HashMap< MinecraftPlane, Mesh< RegionSimple > >();
for ( final Entry< MinecraftPlane, Collection< Polygon > > entry : polygons.entrySet() ) {
final MinecraftPlane plane = entry.getKey();
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> new RegionSimple( GluWindingRule.ODD ) );
for ( final Polygon polygon : entry.getValue() ) {
mesh.addPolygon( polygon, RegionRuleWinding.CLOCKWISE );
}
meshMap.put( plane, mesh );
}
// Mesh each plane
final Map< MinecraftPlane, CompleteMesh > triangles = meshMap.entrySet().parallelStream().collect( Collectors.toConcurrentMap( e -> e.getKey(), e -> new CompleteMesh( e.getKey(), e.getValue() ) ) );
// Construct a series of indexed polygons
final TreeSet< VectorReference > vertices = new TreeSet< VectorReference >();
final MeshResult result = new MeshResult();
for ( final Entry< MinecraftPlane, CompleteMesh > entry : triangles.entrySet() ) {
final MinecraftPlane plane = entry.getKey();
final CompleteMesh completeMesh = entry.getValue();
final Collection< Polygon > tris = completeMesh.triangles;
final Mesh< RegionSimple > mesh = completeMesh.mesh;
// Ignore any planes that are empty
if ( !tris.isEmpty() ) {
final PlaneMesh newMesh = new PlaneMesh();
newMesh.completedPolygons = new ArrayList< IndexedTriangle >();
for ( final Polygon tri : tris ) {
final IndexedTriangle newPoly = new IndexedTriangle();
for ( int i = 0; i < tri.getPoints().size() && i < 3; ++i ) {
final Point point = tri.getPoints().get( i );
final Vector vert = plane.convert( point );
final VectorReference tempRef = new VectorReference( vert );
// Find an existing vertex reference if one exists
VectorReference ref = null;
if ( ref == null ) {
final VectorReference upperRef = vertices.ceiling( tempRef );
if ( upperRef != null && upperRef.vector.distanceSquared( vert ) < 1e-8 ) {
ref = upperRef;
} else {
final VectorReference lowerRef = vertices.floor( tempRef );
if ( lowerRef != null && lowerRef.vector.distanceSquared( vert ) < 1e-8 ) {
ref = lowerRef;
}
}
}
if ( ref == null ) {
ref = tempRef;
ref.referenceCount = 1;
vertices.add( ref );
} else {
++ref.referenceCount;
}
switch ( i ) {
case 0:
newPoly.setPoint1( ref );
break;
case 1:
newPoly.setPoint2( ref );
break;
case 2:
newPoly.setPoint3( ref );
break;
default:
// Should never be here!
}
}
newMesh.completedPolygons.add( newPoly );
}
// Save the generated regions as an intermediary step so we can re-use them later
newMesh.generatedRegions = mesh.getPolygons();
result.meshes.put( plane, newMesh );
}
}
// Add all vector references
result.points = vertices;
}
private class CompleteMesh {
Mesh< RegionSimple > mesh;
Collection< Polygon > triangles;
CompleteMesh( final MinecraftPlane plane, final Mesh< RegionSimple > mesh ) {
this.mesh = mesh;
triangles = mesh.meshify();
}
}
private class MeshResult {
Map< MinecraftPlane, PlaneMesh > meshes;
TreeSet< VectorReference > points;
}
}

View File

@@ -1,10 +1,9 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
@@ -20,7 +19,6 @@ import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import java.util.logging.Level; import java.util.logging.Level;
@@ -57,30 +55,32 @@ import org.bukkit.util.Vector;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Quaternionf; import org.joml.Quaternionf;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Mesh; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Mesh;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionRuleWinding;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple;
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple.GluWindingRule; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.region.simple.RegionSimple.GluWindingRule;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.CommandParameters; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Facet;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.SubCommand; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.MeshBuilder;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.executor.CommandExecutableMessage; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Plane;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.InputValidatorDouble; import com.aaaaahhhhhhh.bananapuncher714.mesh.base.Vector3d;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.InputValidatorInt; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.CommandParameters;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.command.validator.sender.SenderValidatorPlayer; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.SubCommand;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.BlockDataType; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor.CommandExecutableMessage;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.InputValidatorDouble;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkMesh; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.InputValidatorInt;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.IndexedPolygon; import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender.SenderValidatorPlayer;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.MinecraftPlane; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.BlockDataType;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.MinecraftPlane.PlaneAxis; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkLocation;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.PlaneMesh; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.VectorReference; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.IndexedPolygon;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Facet; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.MinecraftPlane;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.MeshBuilder; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.PlaneMesh;
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.ChunkMeshUtil; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.VectorReference;
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.FileUtil; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.MinecraftPlane.PlaneAxis;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.ChunkMeshUtil;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.FileUtil;
import com.jme3.bullet.PhysicsSpace; import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.PhysicsSpace.BroadphaseType; import com.jme3.bullet.PhysicsSpace.BroadphaseType;
import com.jme3.bullet.RotationOrder; import com.jme3.bullet.RotationOrder;
@@ -101,7 +101,6 @@ import com.jme3.bullet.joints.motors.MotorParam;
import com.jme3.bullet.objects.PhysicsBody; import com.jme3.bullet.objects.PhysicsBody;
import com.jme3.bullet.objects.PhysicsRigidBody; import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.math.Matrix3f; import com.jme3.math.Matrix3f;
import com.jme3.math.Plane;
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
@@ -153,7 +152,7 @@ public class MiniePlugin extends JavaPlugin {
PhysicsRigidBody.logger2.setLevel( Level.WARNING ); PhysicsRigidBody.logger2.setLevel( Level.WARNING );
space = new PhysicsSpace( BroadphaseType.DBVT ); space = new PhysicsSpace( BroadphaseType.DBVT );
PlaneCollisionShape plane = new PlaneCollisionShape( new Plane( new Vector3f( 0, 1, 0 ), 0 ) ); PlaneCollisionShape plane = new PlaneCollisionShape( new com.jme3.math.Plane( new Vector3f( 0, 1, 0 ), 0 ) );
planeBody = new PhysicsRigidBody( plane, PhysicsBody.massForStatic ); planeBody = new PhysicsRigidBody( plane, PhysicsBody.massForStatic );
planeBody.setPhysicsLocation( new Vector3f( 0, 128, 0 ) ); planeBody.setPhysicsLocation( new Vector3f( 0, 128, 0 ) );
// space.addCollisionObject( planeBody ); // space.addCollisionObject( planeBody );
@@ -829,61 +828,61 @@ public class MiniePlugin extends JavaPlugin {
// Check each face // Check each face
if ( y == 0 || types[ index - 256 ] != BlockVoxelType.SOLID ) { if ( y == 0 || types[ index - 256 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y, z ) ); facet.points.add( new Vector3d( x, y, z ) );
facet.points.add( new Vector( x, y, z + 1 ) ); facet.points.add( new Vector3d( x, y, z + 1 ) );
facet.points.add( new Vector( x + 1, y, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y, z + 1 ) );
facet.points.add( new Vector( x + 1, y, z ) ); facet.points.add( new Vector3d( x + 1, y, z ) );
facet.normal = new Vector( 0, -1, 0 ); facet.normal = new Vector3d( 0, -1, 0 );
facets.add( facet ); facets.add( facet );
} }
if ( y == worldHeight - 1 || types[ index + 256 ] != BlockVoxelType.SOLID ) { if ( y == worldHeight - 1 || types[ index + 256 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y + 1, z ) ); facet.points.add( new Vector3d( x, y + 1, z ) );
facet.points.add( new Vector( x, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z ) ); facet.points.add( new Vector3d( x + 1, y + 1, z ) );
facet.normal = new Vector( 0, 1, 0 ); facet.normal = new Vector3d( 0, 1, 0 );
facets.add( facet ); facets.add( facet );
} }
if ( z == 0 || types[ index - 16 ] != BlockVoxelType.SOLID ) { if ( z == 0 || types[ index - 16 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y, z ) ); facet.points.add( new Vector3d( x, y, z ) );
facet.points.add( new Vector( x, y + 1, z ) ); facet.points.add( new Vector3d( x, y + 1, z ) );
facet.points.add( new Vector( x + 1, y + 1, z ) ); facet.points.add( new Vector3d( x + 1, y + 1, z ) );
facet.points.add( new Vector( x + 1, y, z ) ); facet.points.add( new Vector3d( x + 1, y, z ) );
facet.normal = new Vector( 0, 0, -1 ); facet.normal = new Vector3d( 0, 0, -1 );
facets.add( facet ); facets.add( facet );
} }
if ( z == 15 || types[ index + 16 ] != BlockVoxelType.SOLID ) { if ( z == 15 || types[ index + 16 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y, z + 1 ) ); facet.points.add( new Vector3d( x, y, z + 1 ) );
facet.points.add( new Vector( x, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y, z + 1 ) );
facet.normal = new Vector( 0, 0, 1 ); facet.normal = new Vector3d( 0, 0, 1 );
facets.add( facet ); facets.add( facet );
} }
if ( x == 0 || types[ index - 1 ] != BlockVoxelType.SOLID ) { if ( x == 0 || types[ index - 1 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y, z ) ); facet.points.add( new Vector3d( x, y, z ) );
facet.points.add( new Vector( x, y, z + 1 ) ); facet.points.add( new Vector3d( x, y, z + 1 ) );
facet.points.add( new Vector( x, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x, y + 1, z + 1 ) );
facet.points.add( new Vector( x, y + 1, z ) ); facet.points.add( new Vector3d( x, y + 1, z ) );
facet.normal = new Vector( -1, 0, 0 ); facet.normal = new Vector3d( -1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
if ( x == 15 || types[ index + 1 ] != BlockVoxelType.SOLID ) { if ( x == 15 || types[ index + 1 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x + 1, y, z ) ); facet.points.add( new Vector3d( x + 1, y, z ) );
facet.points.add( new Vector( x + 1, y, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z ) ); facet.points.add( new Vector3d( x + 1, y + 1, z ) );
facet.normal = new Vector( 1, 0, 0 ); facet.normal = new Vector3d( 1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
} }
@@ -945,61 +944,61 @@ public class MiniePlugin extends JavaPlugin {
// Check each face // Check each face
if ( y == 0 || types[ index - 256 ] != BlockVoxelType.SOLID ) { if ( y == 0 || types[ index - 256 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y, z ) ); facet.points.add( new Vector3d( x, y, z ) );
facet.points.add( new Vector( x, y, z + 1 ) ); facet.points.add( new Vector3d( x, y, z + 1 ) );
facet.points.add( new Vector( x + 1, y, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y, z + 1 ) );
facet.points.add( new Vector( x + 1, y, z ) ); facet.points.add( new Vector3d( x + 1, y, z ) );
facet.normal = new Vector( 0, -1, 0 ); facet.normal = new Vector3d( 0, -1, 0 );
facets.add( facet ); facets.add( facet );
} }
if ( y == worldHeight - 1 || types[ index + 256 ] != BlockVoxelType.SOLID ) { if ( y == worldHeight - 1 || types[ index + 256 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y + 1, z ) ); facet.points.add( new Vector3d( x, y + 1, z ) );
facet.points.add( new Vector( x, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z ) ); facet.points.add( new Vector3d( x + 1, y + 1, z ) );
facet.normal = new Vector( 0, 1, 0 ); facet.normal = new Vector3d( 0, 1, 0 );
facets.add( facet ); facets.add( facet );
} }
if ( z == 0 || types[ index - 16 ] != BlockVoxelType.SOLID ) { if ( z == 0 || types[ index - 16 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y, z ) ); facet.points.add( new Vector3d( x, y, z ) );
facet.points.add( new Vector( x, y + 1, z ) ); facet.points.add( new Vector3d( x, y + 1, z ) );
facet.points.add( new Vector( x + 1, y + 1, z ) ); facet.points.add( new Vector3d( x + 1, y + 1, z ) );
facet.points.add( new Vector( x + 1, y, z ) ); facet.points.add( new Vector3d( x + 1, y, z ) );
facet.normal = new Vector( 0, 0, -1 ); facet.normal = new Vector3d( 0, 0, -1 );
facets.add( facet ); facets.add( facet );
} }
if ( z == 15 || types[ index + 16 ] != BlockVoxelType.SOLID ) { if ( z == 15 || types[ index + 16 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y, z + 1 ) ); facet.points.add( new Vector3d( x, y, z + 1 ) );
facet.points.add( new Vector( x, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y, z + 1 ) );
facet.normal = new Vector( 0, 0, 1 ); facet.normal = new Vector3d( 0, 0, 1 );
facets.add( facet ); facets.add( facet );
} }
if ( x == 0 || types[ index - 1 ] != BlockVoxelType.SOLID ) { if ( x == 0 || types[ index - 1 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x, y, z ) ); facet.points.add( new Vector3d( x, y, z ) );
facet.points.add( new Vector( x, y, z + 1 ) ); facet.points.add( new Vector3d( x, y, z + 1 ) );
facet.points.add( new Vector( x, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x, y + 1, z + 1 ) );
facet.points.add( new Vector( x, y + 1, z ) ); facet.points.add( new Vector3d( x, y + 1, z ) );
facet.normal = new Vector( -1, 0, 0 ); facet.normal = new Vector3d( -1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
if ( x == 15 || types[ index + 1 ] != BlockVoxelType.SOLID ) { if ( x == 15 || types[ index + 1 ] != BlockVoxelType.SOLID ) {
Facet facet = new Facet(); Facet facet = new Facet();
facet.points.add( new Vector( x + 1, y, z ) ); facet.points.add( new Vector3d( x + 1, y, z ) );
facet.points.add( new Vector( x + 1, y, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z + 1 ) ); facet.points.add( new Vector3d( x + 1, y + 1, z + 1 ) );
facet.points.add( new Vector( x + 1, y + 1, z ) ); facet.points.add( new Vector3d( x + 1, y + 1, z ) );
facet.normal = new Vector( 1, 0, 0 ); facet.normal = new Vector3d( 1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
} }
@@ -1046,7 +1045,7 @@ public class MiniePlugin extends JavaPlugin {
} }
final Triangle triangle = new Triangle(); final Triangle triangle = new Triangle();
for ( final Vector vec : facet.points ) { for ( final Vector3d vec : facet.points ) {
VectorRef ref = null; VectorRef ref = null;
for ( final Entry< Vector, VectorRef > entry : vertices.entrySet() ) { for ( final Entry< Vector, VectorRef > entry : vertices.entrySet() ) {
final Vector existingVec = entry.getKey(); final Vector existingVec = entry.getKey();
@@ -1850,7 +1849,7 @@ public class MiniePlugin extends JavaPlugin {
return true; return true;
} }
private static Collection< Polygon > process( final com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Plane plane ) { private static Collection< Polygon > process( final Plane plane ) {
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } ); final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
for ( Polygon poly : plane.polygons ) { for ( Polygon poly : plane.polygons ) {
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE ); mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
@@ -1914,14 +1913,14 @@ public class MiniePlugin extends JavaPlugin {
private static List< Facet > generateFacetsFor( BoundingBox box ) { private static List< Facet > generateFacetsFor( BoundingBox box ) {
List< Facet > facets = new ArrayList< Facet >(); List< Facet > facets = new ArrayList< Facet >();
Vector p1 = new Vector( box.getMinX(), box.getMinY(), box.getMinZ() ); Vector3d p1 = new Vector3d( box.getMinX(), box.getMinY(), box.getMinZ() );
Vector p2 = new Vector( box.getMinX(), box.getMinY(), box.getMaxZ() ); Vector3d p2 = new Vector3d( box.getMinX(), box.getMinY(), box.getMaxZ() );
Vector p3 = new Vector( box.getMinX(), box.getMaxY(), box.getMinZ() ); Vector3d p3 = new Vector3d( box.getMinX(), box.getMaxY(), box.getMinZ() );
Vector p4 = new Vector( box.getMinX(), box.getMaxY(), box.getMaxZ() ); Vector3d p4 = new Vector3d( box.getMinX(), box.getMaxY(), box.getMaxZ() );
Vector p5 = new Vector( box.getMaxX(), box.getMinY(), box.getMinZ() ); Vector3d p5 = new Vector3d( box.getMaxX(), box.getMinY(), box.getMinZ() );
Vector p6 = new Vector( box.getMaxX(), box.getMinY(), box.getMaxZ() ); Vector3d p6 = new Vector3d( box.getMaxX(), box.getMinY(), box.getMaxZ() );
Vector p7 = new Vector( box.getMaxX(), box.getMaxY(), box.getMinZ() ); Vector3d p7 = new Vector3d( box.getMaxX(), box.getMaxY(), box.getMinZ() );
Vector p8 = new Vector( box.getMaxX(), box.getMaxY(), box.getMaxZ() ); Vector3d p8 = new Vector3d( box.getMaxX(), box.getMaxY(), box.getMaxZ() );
{ {
Facet facet = new Facet(); Facet facet = new Facet();
@@ -1929,7 +1928,7 @@ public class MiniePlugin extends JavaPlugin {
facet.points.add( p2 ); facet.points.add( p2 );
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p3 ); facet.points.add( p3 );
facet.normal = new Vector( -1, 0, 0 ); facet.normal = new Vector3d( -1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -1939,7 +1938,7 @@ public class MiniePlugin extends JavaPlugin {
facet.points.add( p6 ); facet.points.add( p6 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.normal = new Vector( 1, 0, 0 ); facet.normal = new Vector3d( 1, 0, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -1949,7 +1948,7 @@ public class MiniePlugin extends JavaPlugin {
facet.points.add( p2 ); facet.points.add( p2 );
facet.points.add( p6 ); facet.points.add( p6 );
facet.points.add( p5 ); facet.points.add( p5 );
facet.normal = new Vector( 0, -1, 0 ); facet.normal = new Vector3d( 0, -1, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -1959,7 +1958,7 @@ public class MiniePlugin extends JavaPlugin {
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.normal = new Vector( 0, 1, 0 ); facet.normal = new Vector3d( 0, 1, 0 );
facets.add( facet ); facets.add( facet );
} }
@@ -1969,7 +1968,7 @@ public class MiniePlugin extends JavaPlugin {
facet.points.add( p3 ); facet.points.add( p3 );
facet.points.add( p7 ); facet.points.add( p7 );
facet.points.add( p5 ); facet.points.add( p5 );
facet.normal = new Vector( 0, 0, -1 ); facet.normal = new Vector3d( 0, 0, -1 );
facets.add( facet ); facets.add( facet );
} }
@@ -1979,7 +1978,7 @@ public class MiniePlugin extends JavaPlugin {
facet.points.add( p4 ); facet.points.add( p4 );
facet.points.add( p8 ); facet.points.add( p8 );
facet.points.add( p6 ); facet.points.add( p6 );
facet.normal = new Vector( 0, 0, 1 ); facet.normal = new Vector3d( 0, 0, 1 );
facets.add( facet ); facets.add( facet );
} }

View File

@@ -1,8 +1,9 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.io.Serializable; import java.io.Serializable;
import org.bukkit.util.BoundingBox; import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
public class Aabb implements Serializable { public class Aabb implements Serializable {
private static final long serialVersionUID = 6518512405568765913L; private static final long serialVersionUID = 6518512405568765913L;
@@ -18,6 +19,10 @@ public class Aabb implements Serializable {
public final int depth; public final int depth;
public final int height; public final int height;
public Aabb( Vector min, Vector max ) {
this( min.getBlockX(), min.getBlockY(), min.getBlockZ(), max.getBlockX(), max.getBlockY(), max.getBlockZ() );
}
public Aabb( final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ ) { public Aabb( final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ ) {
this.minX = minX; this.minX = minX;
this.minY = minY; this.minY = minY;
@@ -47,4 +52,12 @@ public class Aabb implements Serializable {
public int getVolume() { public int getVolume() {
return width * depth * height; return width * depth * height;
} }
public Vector getMinimumCorner() {
return new Vector( minX, minY, minZ );
}
public Vector getMaximumCorner() {
return new Vector( maxX, maxY, maxZ );
}
} }

View File

@@ -0,0 +1,62 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import org.bukkit.util.Vector;
import com.jme3.bullet.collision.shapes.infos.IndexedMesh;
import com.jme3.math.Vector3f;
public abstract class AbstractMesh {
// References to every point used by at least one planemesh
public TreeSet< VectorReference > pointReferences = new TreeSet< VectorReference >();
// Map of meshes to each plane
// TODO Allow for non axis-aligned planes
public Map< MinecraftPlane, PlaneMesh > planes = new TreeMap< MinecraftPlane, PlaneMesh >();
public abstract Vector getMinimumCorner();
public abstract Vector getMaximumCorner();
public abstract BlockDataInformation getBlockDataInformationFor( Vector position );
public abstract void setBlockDataInformationFor( BlockDataInformation information, Vector position );
public IndexedMesh toIndexedMesh() {
final Vector3f[] positionArray = new Vector3f[ pointReferences.size() ];
int vertexIndex = 0;
for ( final VectorReference ref : pointReferences ) {
final Vector vector = ref.vector;
positionArray[ vertexIndex ] = new Vector3f( ( float ) vector.getX(), ( float ) vector.getY(), ( float ) vector.getZ() );
ref.index = vertexIndex;
++vertexIndex;
}
final int totalTriangleCount = planes.values().stream().mapToInt( m -> m.completedPolygons.size() ).sum();
int triangleIndex = 0;
final int[] indexArray = new int[ totalTriangleCount * 3 ];
for ( final PlaneMesh mesh : planes.values() ) {
for ( final IndexedPolygon triangle : mesh.completedPolygons ) {
Collection< VectorReference > refs = triangle.getPoints();
if ( refs.size() != 3 ) {
throw new IllegalStateException( "Triangle does not have exactly 3 vertices!" );
}
final int indexArrayStart = triangleIndex * 3;
Iterator< VectorReference > it = refs.iterator();
indexArray[ indexArrayStart ] = it.next().index;
indexArray[ indexArrayStart + 1 ] = it.next().index;
indexArray[ indexArrayStart + 2 ] = it.next().index;
++triangleIndex;
}
}
return new IndexedMesh( positionArray, indexArray );
}
}

View File

@@ -0,0 +1,25 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import org.bukkit.block.data.BlockData;
import org.bukkit.util.BoundingBox;
public class BlockDataInformation {
// If the block is complex/simple/empty
public BlockDataType type;
// Hashcode of the current block's blockdata so we can check if it changed
public final int blockDataHash;
// The bounding boxes for each complex block, null if air or a cube
public BoundingBox[] boundingBoxes;
public BlockDataInformation( int hash ) {
blockDataHash = hash;
}
public BlockDataInformation( BlockData data ) {
blockDataHash = data.hashCode();
}
public boolean isBlockData( BlockData data ) {
return blockDataHash == data.hashCode();
}
}

View File

@@ -0,0 +1,5 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
public enum BlockDataType {
NONE, COMPLEX, SOLID
}

View File

@@ -1,9 +1,7 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.BitSet; import java.util.BitSet;
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.BinaryWriter;
public class BlockDataTypeSet { public class BlockDataTypeSet {
private static final int BLOCK_SIZE; private static final int BLOCK_SIZE;
private static final BitSet[] SETS; private static final BitSet[] SETS;

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;

View File

@@ -1,28 +1,25 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.TreeSet;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.util.BoundingBox; import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.MinecraftPlane.PlaneAxis; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.MinecraftPlane.PlaneAxis;
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.BinaryWriter; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.BinaryWriter;
import com.jme3.bullet.collision.shapes.infos.IndexedMesh; import com.jme3.bullet.collision.shapes.infos.IndexedMesh;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
public class ChunkMesh { public class ChunkMesh extends AbstractMesh {
// TODO Public for now while I figure out how to organize the stuff properly // TODO Public for now while I figure out how to organize the stuff properly
// Hashcode of the current block's blockdata so we can check if it changed // Hashcode of the current block's blockdata so we can check if it changed
@@ -31,11 +28,6 @@ public class ChunkMesh {
private BoundingBox[][] boxes; private BoundingBox[][] boxes;
// Stores which blocks are complex/simple/empty // Stores which blocks are complex/simple/empty
private BlockDataTypeSet blockTypes; private BlockDataTypeSet blockTypes;
// References to every point used by at least one planemesh
public TreeSet< VectorReference > pointReferences = new TreeSet< VectorReference >();
// Map of meshes to each plane
// TODO Allow for non axis-aligned planes
public Map< MinecraftPlane, PlaneMesh > planes = new TreeMap< MinecraftPlane, PlaneMesh >();
// Bounding box of this mesh // Bounding box of this mesh
private Aabb box; private Aabb box;
@@ -90,6 +82,37 @@ public class ChunkMesh {
return results; return results;
} }
@Override
public Vector getMinimumCorner() {
return box.getMinimumCorner();
}
@Override
public Vector getMaximumCorner() {
return box.getMaximumCorner();
}
@Override
public BlockDataInformation getBlockDataInformationFor( Vector position ) {
final int index = position.getBlockX() + ( position.getBlockZ() << 4 ) + ( position.getBlockY() << 8 );
BlockDataInformation information = new BlockDataInformation( data[ index ] );
information.type = getType( index );
information.boundingBoxes = getBoxesAt( index );
return information;
}
@Override
public void setBlockDataInformationFor( BlockDataInformation information, Vector position ) {
final int index = position.getBlockX() + ( position.getBlockZ() << 4 ) + ( position.getBlockY() << 8 );
data[ index ] = information.blockDataHash;
setType( index, information.type );
setBoxes( index, information.boundingBoxes );
}
@Override
public IndexedMesh toIndexedMesh() { public IndexedMesh toIndexedMesh() {
final Vector3f[] positionArray = new Vector3f[ pointReferences.size() ]; final Vector3f[] positionArray = new Vector3f[ pointReferences.size() ];
int vertexIndex = 0; int vertexIndex = 0;
@@ -108,14 +131,16 @@ public class ChunkMesh {
final int[] indexArray = new int[ totalTriangleCount * 3 ]; final int[] indexArray = new int[ totalTriangleCount * 3 ];
for ( final PlaneMesh mesh : planes.values() ) { for ( final PlaneMesh mesh : planes.values() ) {
for ( final IndexedPolygon triangle : mesh.completedPolygons ) { for ( final IndexedPolygon triangle : mesh.completedPolygons ) {
if ( triangle.points.size() != 3 ) { Collection< VectorReference > refs = triangle.getPoints();
if ( refs.size() != 3 ) {
throw new IllegalStateException( "Triangle does not have exactly 3 vertices!" ); throw new IllegalStateException( "Triangle does not have exactly 3 vertices!" );
} }
final int indexArrayStart = triangleIndex * 3; final int indexArrayStart = triangleIndex * 3;
indexArray[ indexArrayStart ] = triangle.points.get( 0 ).index; Iterator< VectorReference > it = refs.iterator();
indexArray[ indexArrayStart + 1 ] = triangle.points.get( 1 ).index; indexArray[ indexArrayStart ] = it.next().index;
indexArray[ indexArrayStart + 2 ] = triangle.points.get( 2 ).index; indexArray[ indexArrayStart + 1 ] = it.next().index;
indexArray[ indexArrayStart + 2 ] = it.next().index;
++triangleIndex; ++triangleIndex;
} }
@@ -198,8 +223,8 @@ public class ChunkMesh {
// Write each triangle // Write each triangle
writer.write( mesh.completedPolygons.size() ); writer.write( mesh.completedPolygons.size() );
for ( final IndexedPolygon poly : mesh.completedPolygons ) { for ( final IndexedPolygon poly : mesh.completedPolygons ) {
writer.write( poly.points.size() ); writer.write( poly.getPointCount() );
for ( final VectorReference ref : poly.points ) { for ( final VectorReference ref : poly.getPoints() ) {
writer.write( ref.index ); writer.write( ref.index );
} }
} }
@@ -252,7 +277,7 @@ public class ChunkMesh {
final PlaneMesh planeMesh = new PlaneMesh(); final PlaneMesh planeMesh = new PlaneMesh();
planeMesh.generatedRegions = new ArrayDeque< Polygon >(); planeMesh.generatedRegions = new ArrayDeque< Polygon >();
planeMesh.completedPolygons = new ArrayDeque< IndexedPolygon >(); planeMesh.completedPolygons = new ArrayDeque< IndexedTriangle >();
final int regionCount = buffer.getInt(); final int regionCount = buffer.getInt();
for ( int j = 0; j < regionCount; ++j ) { for ( int j = 0; j < regionCount; ++j ) {
final int vertexCount = buffer.getInt(); final int vertexCount = buffer.getInt();
@@ -269,9 +294,22 @@ public class ChunkMesh {
for ( int j = 0; j < triangleCount; ++j ) { for ( int j = 0; j < triangleCount; ++j ) {
final int vertexCount = buffer.getInt(); final int vertexCount = buffer.getInt();
final IndexedPolygon triangle = new IndexedPolygon(); final IndexedTriangle triangle = new IndexedTriangle();
for ( int k = 0; k < vertexCount; ++k ) { for ( int k = 0; k < vertexCount; ++k ) {
triangle.points.add( references[ buffer.getInt() ] ); switch ( k ) {
case 0:
triangle.setPoint1( references[ buffer.getInt() ] );
break;
case 1:
triangle.setPoint2( references[ buffer.getInt() ] );
break;
case 2:
triangle.setPoint3( references[ buffer.getInt() ] );
break;
default:
// Discard
buffer.getInt();
}
} }
planeMesh.completedPolygons.add( triangle ); planeMesh.completedPolygons.add( triangle );

View File

@@ -0,0 +1,19 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class IndexedNGon implements IndexedPolygon {
List< VectorReference > points = new ArrayList< VectorReference >();
@Override
public Collection< VectorReference > getPoints() {
return points;
}
@Override
public int getPointCount() {
return points.size();
}
}

View File

@@ -0,0 +1,11 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.Collection;
/*
* Represents a polygon with associated vector references
*/
public abstract interface IndexedPolygon {
public Collection< VectorReference > getPoints();
public int getPointCount();
}

View File

@@ -0,0 +1,44 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.Collection;
import java.util.List;
public class IndexedTriangle implements IndexedPolygon {
private VectorReference p1;
private VectorReference p2;
private VectorReference p3;
public VectorReference getPoint1() {
return p1;
}
public VectorReference getPoint2() {
return p2;
}
public VectorReference getPoint3() {
return p3;
}
public void setPoint1( VectorReference p1 ) {
this.p1 = p1;
}
public void setPoint2( VectorReference p2 ) {
this.p2 = p2;
}
public void setPoint3( VectorReference p3 ) {
this.p3 = p3;
}
@Override
public Collection< VectorReference > getPoints() {
return List.of( p1, p2, p3 );
}
@Override
public int getPointCount() {
return 3;
}
}

View File

@@ -1,10 +1,8 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.io.Serializable;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Point; import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Point;
public class MinecraftPlane implements Comparable< MinecraftPlane > { public class MinecraftPlane implements Comparable< MinecraftPlane > {
public final PlaneAxis normal; public final PlaneAxis normal;

View File

@@ -0,0 +1,10 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.Collection;
import com.aaaaahhhhhhh.bananapuncher714.mesh.algorithm.Polygon;
public class PlaneMesh {
public Collection< Polygon > generatedRegions;
public Collection< IndexedTriangle > completedPolygons;
}

View File

@@ -0,0 +1,38 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.util.Vector;
public class SparseMesh extends AbstractMesh {
private Map< Vector, BlockDataInformation > data = new HashMap< Vector, BlockDataInformation >();
// Bounding box of this mesh
private Vector min, max;
public SparseMesh( Vector min, Vector max ) {
this.min = min.clone();
this.max = max.clone();
}
@Override
public Vector getMinimumCorner() {
return min;
}
@Override
public Vector getMaximumCorner() {
return max;
}
@Override
public BlockDataInformation getBlockDataInformationFor( Vector position ) {
return data.get( position.toBlockVector() );
}
@Override
public void setBlockDataInformationFor( BlockDataInformation information, Vector position ) {
data.put( position, information );
}
}

View File

@@ -1,4 +1,4 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects; package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;

View File

@@ -18,7 +18,7 @@ import org.bukkit.plugin.SimplePluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader; import org.bukkit.plugin.java.JavaPluginLoader;
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.McMeshEnvironment; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.McMeshEnvironmentPlugin;
public class BukkitUtil { public class BukkitUtil {
private static Constructor< PluginCommand > PLUGINCOMMAND_CONSTRUCTOR; private static Constructor< PluginCommand > PLUGINCOMMAND_CONSTRUCTOR;
@@ -69,7 +69,7 @@ public class BukkitUtil {
public static PluginCommand constructCommand( String id ) { public static PluginCommand constructCommand( String id ) {
PluginCommand command = null; PluginCommand command = null;
try { try {
command = PLUGINCOMMAND_CONSTRUCTOR.newInstance( id, JavaPlugin.getPlugin( McMeshEnvironment.class ) ); command = PLUGINCOMMAND_CONSTRUCTOR.newInstance( id, JavaPlugin.getPlugin( McMeshEnvironmentPlugin.class ) );
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
@@ -84,7 +84,7 @@ public class BukkitUtil {
if ( Bukkit.getServer().isPrimaryThread() ) { if ( Bukkit.getServer().isPrimaryThread() ) {
Bukkit.getPluginManager().callEvent( event ); Bukkit.getPluginManager().callEvent( event );
} else { } else {
Bukkit.getScheduler().scheduleSyncDelayedTask( JavaPlugin.getPlugin( McMeshEnvironment.class ), () -> { callEventSync( event ); } ); Bukkit.getScheduler().scheduleSyncDelayedTask( JavaPlugin.getPlugin( McMeshEnvironmentPlugin.class ), () -> { callEventSync( event ); } );
} }
} }
@@ -111,7 +111,7 @@ public class BukkitUtil {
if ( JAVAPLUGINLOADER_GETCLASS_1 != null ) { if ( JAVAPLUGINLOADER_GETCLASS_1 != null ) {
return ( Class< ? > ) JAVAPLUGINLOADER_GETCLASS_1.invoke( loader, name ); return ( Class< ? > ) JAVAPLUGINLOADER_GETCLASS_1.invoke( loader, name );
} else { } else {
return ( Class< ? > ) JAVAPLUGINLOADER_GETCLASS_2.invoke( loader, name, true, JavaPlugin.getPlugin( MiniePlugin.class ).getDescription() ); return ( Class< ? > ) JAVAPLUGINLOADER_GETCLASS_2.invoke( loader, name, true, JavaPlugin.getPlugin( McMeshEnvironmentPlugin.class ).getDescription() );
} }
} }
} }

View File

@@ -2,7 +2,7 @@ package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkMesh; import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
public class ChunkMeshUtil { public class ChunkMeshUtil {
public static byte[] serialize( final ChunkMesh mesh ) { public static byte[] serialize( final ChunkMesh mesh ) {

View File

@@ -0,0 +1,59 @@
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util;
import org.bukkit.Location;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_21_R6.CraftWorld;
import org.bukkit.craftbukkit.v1_21_R6.block.data.CraftBlockData;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
import net.minecraft.core.BlockPosition;
import net.minecraft.server.level.WorldServer;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.phys.shapes.VoxelShapeCollision;
public class NmsUtil {
// 1.21.5
public static VoxelShape getShape( BlockData blockData, Location location, BlockShapeType type ) {
final CraftBlockData data = ( CraftBlockData ) blockData;
WorldServer server = null;
BlockPosition pos = null;
if ( location != null ) {
server = ( ( CraftWorld ) location.getWorld() ).getHandle();
pos = new BlockPosition( location.getBlockX(), location.getBlockY(), location.getBlockZ() );
}
switch ( type ) {
default:
case SHAPE:
return data.getState().f( server, pos );
case COLLISION_SHAPE:
return data.getState().g( server, pos );
case VISUAL_SHAPE:
return data.getState().c( server, pos, VoxelShapeCollision.a() );
case INTERACTION_SHAPE:
return data.getState().i( server, pos );
case BLOCK_SUPPORT_SHAPE:
return data.getState().h( server, pos );
}
}
public static BoundingBox[] convertFrom( final VoxelShape shape ) {
return convertFrom( shape, new Vector() );
}
public static BoundingBox[] convertFrom( final VoxelShape shape, final Vector offset ) {
return shape.e().stream()
.map( aabb -> { return new BoundingBox( aabb.a, aabb.b, aabb.c, aabb.d, aabb.e, aabb.f ).shift( offset ); } )
.toArray( BoundingBox[]::new );
}
public enum BlockShapeType {
SHAPE,
COLLISION_SHAPE,
VISUAL_SHAPE,
INTERACTION_SHAPE,
BLOCK_SUPPORT_SHAPE
}
}

View File

@@ -1,51 +0,0 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.locks.ReentrantLock;
import org.bukkit.Chunk;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation;
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkMesh;
public class ChunkMeshCache {
final File directory;
Map< ChunkLocation, ChunkMesh > meshes = new TreeMap< ChunkLocation, ChunkMesh >();
Collection< ChunkLocation > shouldRemove = new HashSet< ChunkLocation >();
ReentrantLock lock = new ReentrantLock();
public ChunkMeshCache( final File directory ) {
this.directory = directory;
}
public void onChunkLoad( final Chunk chunk ) {
final ChunkLocation location = new ChunkLocation( chunk );
// Unqueue this chunk for removal if it's queued
shouldRemove.remove( location );
// TODO Add a ticket
chunk.addPluginChunkTicket( null );
// Does the mesh map contain the current location?
{
// If not, then load or mesh the chunk
// Emit a chunk mesh complete event
}
}
public void saveAndRemove( final ChunkLocation location ) {
lock.lock();
meshes.remove( location );
lock.unlock();
}
public void saveAndRemoveAll() {
lock.unlock();
}
}

View File

@@ -1,37 +0,0 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.PhysicsSpace.BroadphaseType;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.PlaneCollisionShape;
import com.jme3.bullet.objects.PhysicsBody;
import com.jme3.bullet.objects.PhysicsRigidBody;
import com.jme3.math.Plane;
import com.jme3.math.Vector3f;
public class MinieTest {
public static void main( String[] args ) {
System.loadLibrary( "bulletjme" );
System.out.println( "Testing a simple PhysicsSpace" );
PhysicsSpace space = new PhysicsSpace( BroadphaseType.DBVT );
PlaneCollisionShape plane = new PlaneCollisionShape( new Plane( new Vector3f( 0, 1, 0 ), 0 ) );
PhysicsRigidBody planeBody = new PhysicsRigidBody( plane, PhysicsBody.massForStatic );
planeBody.setPhysicsLocation( new Vector3f( 0, 0, 0 ) );
BoxCollisionShape box = new BoxCollisionShape( 0.5f );
PhysicsRigidBody rigid = new PhysicsRigidBody( box, 1f );
rigid.setPhysicsLocation( new Vector3f( 0f, 100f, 0f ) );
space.addCollisionObject( rigid );
space.addCollisionObject( planeBody );
for ( float i = 0; i < 9.6; i += 1 / 256.0 ) {
space.update( i );
Vector3f loc = rigid.getPhysicsLocation();
System.out.println( i + "\t: " + loc.getX() + ", " + loc.getY() + ", " + loc.getZ() );
}
}
}

View File

@@ -1,5 +0,0 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
public enum BlockDataType {
NONE, COMPLEX, SOLID
}

View File

@@ -1,8 +0,0 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
import java.util.ArrayList;
import java.util.List;
public class IndexedPolygon {
public List< VectorReference > points = new ArrayList< VectorReference >();
}

View File

@@ -1,10 +0,0 @@
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
import java.util.Collection;
import com.aaaaahhhhhhh.bananapuncher714.mesh.Polygon;
public class PlaneMesh {
public Collection< Polygon > generatedRegions;
public Collection< IndexedPolygon > completedPolygons;
}

View File

@@ -12,6 +12,6 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<!-- <module>environment</module> --> <module>environment</module>
</modules> </modules>
</project> </project>