Create standalone physics plugin
This commit is contained in:
@@ -66,19 +66,6 @@
|
|||||||
<release>21</release>
|
<release>21</release>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<version>3.5.0</version>
|
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<addClasspath>true</addClasspath>
|
|
||||||
<mainClass>com.aaaaahhhhhhh.bananapuncher714.minietest.MeshingTest6</mainClass>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment;
|
||||||
|
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkLocation;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
|
||||||
|
|
||||||
|
public interface EnvironmentHandler {
|
||||||
|
public void onMeshLoad( ChunkLocation location, ChunkMesh mesh );
|
||||||
|
public void onMeshUnload( ChunkLocation location, ChunkMesh mesh );
|
||||||
|
public void onMeshUpdate( ChunkLocation location, ChunkMesh mesh );
|
||||||
|
}
|
||||||
@@ -59,36 +59,34 @@ import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.NmsUtil;
|
|||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.NmsUtil.BlockShapeType;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.NmsUtil.BlockShapeType;
|
||||||
|
|
||||||
public class MeshEnvironment {
|
public class MeshEnvironment {
|
||||||
private JavaPlugin plugin;
|
private JavaPlugin plugin;
|
||||||
private File cacheDirectory;
|
private File cacheDirectory;
|
||||||
|
|
||||||
private Map< ChunkLocation, Collection< Location > > updateLocations = new TreeMap< ChunkLocation, Collection< Location > >();
|
private Map< ChunkLocation, Collection< Location > > updateLocations = new TreeMap< ChunkLocation, Collection< Location > >();
|
||||||
private Map< ChunkLocation, ChunkMesh > chunkMeshes = new HashMap< ChunkLocation, ChunkMesh >();
|
private Map< ChunkLocation, ChunkMesh > chunkMeshes = new HashMap< ChunkLocation, ChunkMesh >();
|
||||||
|
|
||||||
private Map< ChunkLocation, ChunkTask > tasks = new HashMap< ChunkLocation, ChunkTask >();
|
private Map< ChunkLocation, ChunkTask > tasks = new HashMap< ChunkLocation, ChunkTask >();
|
||||||
|
|
||||||
private ChunkMeshCache cache;
|
private ChunkMeshCache cache;
|
||||||
|
|
||||||
private ReentrantLock lock = new ReentrantLock();
|
private EnvironmentHandler handler;
|
||||||
|
|
||||||
|
private ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
final BukkitTask task = Bukkit.getScheduler().runTaskTimer( plugin, () -> {
|
final BukkitTask task = Bukkit.getScheduler().runTaskTimer( plugin, () -> {
|
||||||
// final Collection< ChunkLocation > locations = new ArrayDeque< ChunkLocation >();
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
updateLocations.entrySet().stream().forEach( e -> {
|
updateLocations.entrySet().stream().forEach( e -> {
|
||||||
ChunkMesh mesh = chunkMeshes.get( e.getKey() );
|
ChunkMesh mesh = chunkMeshes.get( e.getKey() );
|
||||||
if ( mesh != null ) {
|
if ( mesh != null ) {
|
||||||
final Collection< Location > locs = update( mesh, e.getValue() );
|
final Collection< Location > locs = update( mesh, e.getValue() );
|
||||||
e.getValue().removeAll( locs );
|
e.getValue().removeAll( locs );
|
||||||
// if ( !locs.isEmpty() ) {
|
|
||||||
// locations.add( e.getKey() );
|
if ( handler != null && !locs.isEmpty() ) {
|
||||||
// }
|
handler.onMeshUpdate( e.getKey(), mesh );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// if ( !locations.isEmpty() ) {
|
|
||||||
// space.activateAll( true );
|
|
||||||
// }
|
|
||||||
|
|
||||||
updateLocations.values().removeIf( c -> c.isEmpty() );
|
updateLocations.values().removeIf( c -> c.isEmpty() );
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}, 1, 1 );
|
}, 1, 1 );
|
||||||
@@ -104,41 +102,41 @@ public class MeshEnvironment {
|
|||||||
return locations;
|
return locations;
|
||||||
};
|
};
|
||||||
|
|
||||||
private Listener eventListener = new Listener() {
|
private Listener eventListener = new Listener() {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
private void onChunkLoad( ChunkLoadEvent event ) {
|
private void onChunkLoad( ChunkLoadEvent event ) {
|
||||||
final ChunkLocation location = new ChunkLocation( event.getChunk() );
|
final ChunkLocation location = new ChunkLocation( event.getChunk() );
|
||||||
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
if ( chunkMeshes.containsKey( location ) ) {
|
if ( chunkMeshes.containsKey( location ) ) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else {
|
} else {
|
||||||
final ChunkTask task = tasks.get( location );
|
final ChunkTask task = tasks.get( location );
|
||||||
if ( task == null ) {
|
if ( task == null ) {
|
||||||
loadMesh( location );
|
loadMesh( location );
|
||||||
} else if ( task.type == ChunkTaskType.LOAD ) {
|
} else if ( task.type == ChunkTaskType.LOAD ) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else if ( task.type == ChunkTaskType.UNLOAD ) {
|
} else if ( task.type == ChunkTaskType.UNLOAD ) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Order of operations:
|
* Order of operations:
|
||||||
* - Check if:
|
* - Check if:
|
||||||
* - The mesh is loaded
|
* - The mesh is loaded
|
||||||
* - Do nothing
|
* - Do nothing
|
||||||
* - There is an unload queued
|
* - There is an unload queued
|
||||||
* - Do nothing
|
* - Do nothing
|
||||||
* - There is a load queued
|
* - There is a load queued
|
||||||
* - Do nothing
|
* - Do nothing
|
||||||
* - Nothing is queued
|
* - Nothing is queued
|
||||||
* - Queue a load
|
* - Queue a load
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -190,94 +188,107 @@ public class MeshEnvironment {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public MeshEnvironment( JavaPlugin plugin, File cacheDirectory ) {
|
public MeshEnvironment( JavaPlugin plugin, File cacheDirectory ) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.cacheDirectory = cacheDirectory;
|
this.cacheDirectory = cacheDirectory;
|
||||||
cache = new ChunkMeshCache( new File( cacheDirectory, "meshes" ) );
|
cache = new ChunkMeshCache( new File( cacheDirectory, "meshes" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void activate() {
|
public void activate() {
|
||||||
Bukkit.getPluginManager().registerEvents( eventListener, plugin );
|
Bukkit.getPluginManager().registerEvents( eventListener, plugin );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
HandlerList.unregisterAll( eventListener );
|
HandlerList.unregisterAll( eventListener );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void completeTask( ChunkLocation location ) {
|
public void load( ChunkLocation location ) {
|
||||||
lock.lock();
|
loadMesh( location );
|
||||||
try {
|
}
|
||||||
final ChunkTask task = tasks.remove( location );
|
|
||||||
if ( task.type == ChunkTaskType.LOAD ) {
|
|
||||||
if ( !location.isLoaded() ) {
|
|
||||||
// Update all and unload
|
|
||||||
unloadMesh( location );
|
|
||||||
} else {
|
|
||||||
// Chunk is still loaded, do nothing
|
|
||||||
}
|
|
||||||
} else if ( task.type == ChunkTaskType.UNLOAD ) {
|
|
||||||
if ( !location.isLoaded() ) {
|
|
||||||
// Check if there are any updates that we missed
|
|
||||||
// If so, then queue another unload with the newest mesh
|
|
||||||
// Otherwise, remove the location from our list of locations
|
|
||||||
if ( updateLocations.containsKey( location ) ) {
|
|
||||||
unloadMesh( location );
|
|
||||||
} else {
|
|
||||||
chunkMeshes.remove( location );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Chunk is loaded, but we saved. Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadMesh( ChunkLocation location ) {
|
public void setHandler( EnvironmentHandler handler ) {
|
||||||
ChunkTask task = new ChunkTask();
|
this.handler = handler;
|
||||||
lock.lock();
|
}
|
||||||
try {
|
|
||||||
tasks.put( location, task );
|
|
||||||
|
|
||||||
task.type = ChunkTaskType.LOAD;
|
private void completeTask( ChunkLocation location ) {
|
||||||
task.task = Bukkit.getScheduler().runTaskAsynchronously( plugin, () -> {
|
lock.lock();
|
||||||
final ChunkMesh mesh = cache.load( location );
|
try {
|
||||||
if ( mesh != null ) {
|
final ChunkTask task = tasks.remove( location );
|
||||||
lock.lock();
|
if ( task.type == ChunkTaskType.LOAD ) {
|
||||||
try {
|
handler.onMeshLoad( location, chunkMeshes.get( location ) );
|
||||||
// Save the mesh
|
if ( !location.isLoaded() ) {
|
||||||
if ( !chunkMeshes.containsKey( location ) ) {
|
// Update all and unload
|
||||||
chunkMeshes.put( location, mesh );
|
unloadMesh( location );
|
||||||
}
|
} else {
|
||||||
|
// Chunk is still loaded, do nothing
|
||||||
|
}
|
||||||
|
} else if ( task.type == ChunkTaskType.UNLOAD ) {
|
||||||
|
if ( !location.isLoaded() ) {
|
||||||
|
// Check if there are any updates that we missed
|
||||||
|
// If so, then queue another unload with the newest mesh
|
||||||
|
// Otherwise, remove the location from our list of locations
|
||||||
|
if ( updateLocations.containsKey( location ) ) {
|
||||||
|
unloadMesh( location );
|
||||||
|
} else {
|
||||||
|
final ChunkMesh mesh = chunkMeshes.remove( location );
|
||||||
|
|
||||||
completeTask( location );
|
if ( handler != null ) {
|
||||||
} finally {
|
handler.onMeshUnload( location, mesh );
|
||||||
lock.unlock();
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Process and generate the mesh
|
// Chunk is loaded, but we saved. Do nothing
|
||||||
Bukkit.getScheduler().runTask( plugin, () -> {
|
}
|
||||||
generateMesh( plugin, location.getWorld(), location.getChunk(), m -> {
|
}
|
||||||
lock.lock();
|
} finally {
|
||||||
try {
|
lock.unlock();
|
||||||
chunkMeshes.put( location, m );
|
}
|
||||||
|
}
|
||||||
|
|
||||||
completeTask( location );
|
private void loadMesh( ChunkLocation location ) {
|
||||||
} finally {
|
ChunkTask task = new ChunkTask();
|
||||||
lock.unlock();
|
lock.lock();
|
||||||
}
|
try {
|
||||||
} );
|
tasks.put( location, task );
|
||||||
} );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void unloadMesh( ChunkLocation location ) {
|
task.type = ChunkTaskType.LOAD;
|
||||||
ChunkTask task = new ChunkTask();
|
task.task = Bukkit.getScheduler().runTaskAsynchronously( plugin, () -> {
|
||||||
|
final ChunkMesh mesh = cache.load( location );
|
||||||
|
if ( mesh != null ) {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
// Save the mesh
|
||||||
|
if ( !chunkMeshes.containsKey( location ) ) {
|
||||||
|
chunkMeshes.put( location, mesh );
|
||||||
|
}
|
||||||
|
|
||||||
|
completeTask( location );
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Process and generate the mesh
|
||||||
|
Bukkit.getScheduler().runTask( plugin, () -> {
|
||||||
|
generateMesh( plugin, location.getWorld(), location.getChunk(), m -> {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
chunkMeshes.put( location, m );
|
||||||
|
|
||||||
|
completeTask( location );
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unloadMesh( ChunkLocation location ) {
|
||||||
|
ChunkTask task = new ChunkTask();
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
tasks.put( location, task );
|
tasks.put( location, task );
|
||||||
@@ -306,46 +317,51 @@ public class MeshEnvironment {
|
|||||||
} finally {
|
} finally {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean applyUpdatesToMesh( ChunkLocation location ) {
|
private boolean applyUpdatesToMesh( ChunkLocation location ) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
final Collection< Location > locations = updateLocations.get( location );
|
final Collection< Location > locations = updateLocations.get( location );
|
||||||
final ChunkMesh mesh = chunkMeshes.get( location );
|
final ChunkMesh mesh = chunkMeshes.get( location );
|
||||||
|
|
||||||
if ( locations != null && !locations.isEmpty() && mesh != null ) {
|
if ( locations != null && !locations.isEmpty() && mesh != null ) {
|
||||||
locations.removeAll( update( mesh, locations ) );
|
final Collection< Location > removed = update( mesh, locations );
|
||||||
|
locations.removeAll( removed );
|
||||||
|
|
||||||
return locations.isEmpty();
|
if ( handler != null && !removed.isEmpty() ) {
|
||||||
}
|
handler.onMeshUpdate( location, mesh );
|
||||||
} finally {
|
}
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return locations.isEmpty();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
private static void generateSpareMesh( JavaPlugin plugin, World world, Collection< Vector > locations, Consumer< SparseMesh > callback ) {
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generateSpareMesh( JavaPlugin plugin, World world, Collection< Vector > locations, Consumer< SparseMesh > callback ) {
|
||||||
if ( locations.isEmpty() ) {
|
if ( locations.isEmpty() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean set = false;
|
boolean set = false;
|
||||||
Vector min = new Vector();
|
Vector min = new Vector();
|
||||||
Vector max = new Vector();
|
Vector max = new Vector();
|
||||||
|
|
||||||
for ( Vector v : locations ) {
|
for ( Vector v : locations ) {
|
||||||
if ( !set ) {
|
if ( !set ) {
|
||||||
set = true;
|
set = true;
|
||||||
|
|
||||||
min = v.toBlockVector();
|
min = v.toBlockVector();
|
||||||
max = v.toBlockVector();
|
max = v.toBlockVector();
|
||||||
} else {
|
} else {
|
||||||
min = Vector.getMinimum( min, v.toBlockVector() );
|
min = Vector.getMinimum( min, v.toBlockVector() );
|
||||||
max = Vector.getMaximum( max, v.toBlockVector() );
|
max = Vector.getMaximum( max, v.toBlockVector() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final SparseMesh sparseMesh = new SparseMesh( min, max );
|
final SparseMesh sparseMesh = new SparseMesh( min, max );
|
||||||
final Map< MinecraftPlane, Collection< Polygon > > polygons = new TreeMap< MinecraftPlane, Collection< Polygon > >();
|
final Map< MinecraftPlane, Collection< Polygon > > polygons = new TreeMap< MinecraftPlane, Collection< Polygon > >();
|
||||||
@@ -361,9 +377,9 @@ public class MeshEnvironment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for ( final Vector location : locations ) {
|
for ( final Vector location : locations ) {
|
||||||
final Block block = world.getBlockAt( location.getBlockX(), location.getBlockY(), location.getBlockZ() );
|
final Block block = world.getBlockAt( location.getBlockX(), location.getBlockY(), location.getBlockZ() );
|
||||||
|
|
||||||
if ( !( block.isEmpty() && block.isLiquid() ) ) {
|
if ( !( block.isEmpty() && block.isLiquid() ) ) {
|
||||||
final BlockData data = block.getBlockData();
|
final BlockData data = block.getBlockData();
|
||||||
final Location loc = block.getLocation();
|
final Location loc = block.getLocation();
|
||||||
|
|
||||||
@@ -374,12 +390,12 @@ public class MeshEnvironment {
|
|||||||
|
|
||||||
if ( boundingBoxes.length == 0 ) {
|
if ( boundingBoxes.length == 0 ) {
|
||||||
// No bounding box
|
// No bounding box
|
||||||
information.type = BlockDataType.NONE;
|
information.type = BlockDataType.NONE;
|
||||||
} else if ( boundingBoxes.length == 1 && boundingBoxes[ 0 ].getVolume() == 1 ) {
|
} else if ( boundingBoxes.length == 1 && boundingBoxes[ 0 ].getVolume() == 1 ) {
|
||||||
// Solid
|
// Solid
|
||||||
information.type = BlockDataType.SOLID;
|
information.type = BlockDataType.SOLID;
|
||||||
} else {
|
} else {
|
||||||
information.type = BlockDataType.COMPLEX;
|
information.type = BlockDataType.COMPLEX;
|
||||||
// Complex bounding shape
|
// Complex bounding shape
|
||||||
|
|
||||||
// Add the voxel shape to the chunk mesh
|
// Add the voxel shape to the chunk mesh
|
||||||
@@ -396,19 +412,19 @@ public class MeshEnvironment {
|
|||||||
new Point( minY, maxZ ),
|
new Point( minY, maxZ ),
|
||||||
new Point( maxY, maxZ ),
|
new Point( maxY, maxZ ),
|
||||||
new Point( maxY, minZ )
|
new Point( maxY, minZ )
|
||||||
) );
|
) );
|
||||||
final Polygon yPoly = new Polygon( Arrays.asList(
|
final Polygon yPoly = new Polygon( Arrays.asList(
|
||||||
new Point( minX, minZ ),
|
new Point( minX, minZ ),
|
||||||
new Point( minX, maxZ ),
|
new Point( minX, maxZ ),
|
||||||
new Point( maxX, maxZ ),
|
new Point( maxX, maxZ ),
|
||||||
new Point( maxX, minZ )
|
new Point( maxX, minZ )
|
||||||
) );
|
) );
|
||||||
final Polygon zPoly = new Polygon( Arrays.asList(
|
final Polygon zPoly = new Polygon( Arrays.asList(
|
||||||
new Point( minX, minY ),
|
new Point( minX, minY ),
|
||||||
new Point( minX, maxY ),
|
new Point( minX, maxY ),
|
||||||
new Point( maxX, maxY ),
|
new Point( maxX, maxY ),
|
||||||
new Point( maxX, minY )
|
new Point( maxX, minY )
|
||||||
) );
|
) );
|
||||||
|
|
||||||
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
|
||||||
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
|
||||||
@@ -421,62 +437,62 @@ public class MeshEnvironment {
|
|||||||
information.boundingBoxes = boundingBoxes;
|
information.boundingBoxes = boundingBoxes;
|
||||||
sparseMesh.setBlockDataInformationFor( information, loc.toVector().subtract( min ) );
|
sparseMesh.setBlockDataInformationFor( information, loc.toVector().subtract( min ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now generate facets for each solid block based on if the side they are on is visible
|
// Now generate facets for each solid block based on if the side they are on is visible
|
||||||
for ( final Vector location : locations ) {
|
for ( final Vector location : locations ) {
|
||||||
final Vector blockVector = location.toBlockVector().subtract( min );
|
final Vector blockVector = location.toBlockVector().subtract( min );
|
||||||
final BlockDataInformation info = sparseMesh.getBlockDataInformationFor( blockVector );
|
final BlockDataInformation info = sparseMesh.getBlockDataInformationFor( blockVector );
|
||||||
if ( info != null ) {
|
if ( info != null ) {
|
||||||
if ( info.type == BlockDataType.SOLID ) {
|
if ( info.type == BlockDataType.SOLID ) {
|
||||||
final Polygon xPoly = new Polygon( Arrays.asList(
|
final Polygon xPoly = new Polygon( Arrays.asList(
|
||||||
new Point( blockVector.getY(), blockVector.getZ() ),
|
new Point( blockVector.getY(), blockVector.getZ() ),
|
||||||
new Point( blockVector.getY(), blockVector.getZ() + 1 ),
|
new Point( blockVector.getY(), blockVector.getZ() + 1 ),
|
||||||
new Point( blockVector.getY() + 1, blockVector.getZ() + 1 ),
|
new Point( blockVector.getY() + 1, blockVector.getZ() + 1 ),
|
||||||
new Point( blockVector.getY() + 1, blockVector.getZ() )
|
new Point( blockVector.getY() + 1, blockVector.getZ() )
|
||||||
) );
|
) );
|
||||||
final Polygon yPoly = new Polygon( Arrays.asList(
|
final Polygon yPoly = new Polygon( Arrays.asList(
|
||||||
new Point( blockVector.getX(), blockVector.getZ() ),
|
new Point( blockVector.getX(), blockVector.getZ() ),
|
||||||
new Point( blockVector.getX(), blockVector.getZ() + 1 ),
|
new Point( blockVector.getX(), blockVector.getZ() + 1 ),
|
||||||
new Point( blockVector.getX() + 1, blockVector.getZ() + 1 ),
|
new Point( blockVector.getX() + 1, blockVector.getZ() + 1 ),
|
||||||
new Point( blockVector.getX() + 1, blockVector.getZ() )
|
new Point( blockVector.getX() + 1, blockVector.getZ() )
|
||||||
) );
|
) );
|
||||||
final Polygon zPoly = new Polygon( Arrays.asList(
|
final Polygon zPoly = new Polygon( Arrays.asList(
|
||||||
new Point( blockVector.getX(), blockVector.getY() ),
|
new Point( blockVector.getX(), blockVector.getY() ),
|
||||||
new Point( blockVector.getX(), blockVector.getY() + 1 ),
|
new Point( blockVector.getX(), blockVector.getY() + 1 ),
|
||||||
new Point( blockVector.getX() + 1, blockVector.getY() + 1 ),
|
new Point( blockVector.getX() + 1, blockVector.getY() + 1 ),
|
||||||
new Point( blockVector.getX() + 1, blockVector.getY() )
|
new Point( blockVector.getX() + 1, blockVector.getY() )
|
||||||
) );
|
) );
|
||||||
|
|
||||||
BlockDataInformation adjacent;
|
BlockDataInformation adjacent;
|
||||||
if ( ( adjacent = sparseMesh.getBlockDataInformationFor( blockVector.clone().subtract( new Vector( 0, 1, 0 ) ) ) ) == null || adjacent.type != BlockDataType.SOLID ) {
|
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 );
|
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 ) {
|
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 );
|
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 ) {
|
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 );
|
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 ) {
|
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 );
|
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 ) {
|
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 );
|
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 ) {
|
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 );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, blockVector.getX() + 1 ) ).add( xPoly );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Shouldn't be null btw
|
// Shouldn't be null btw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +508,7 @@ public class MeshEnvironment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Use ChunkSnapshot in the future
|
// TODO Use ChunkSnapshot in the future
|
||||||
private static void generateMesh( JavaPlugin plugin, World world, final Chunk chunk, Consumer< ChunkMesh > callback ) {
|
public static void generateMesh( JavaPlugin plugin, World world, final Chunk chunk, Consumer< ChunkMesh > callback ) {
|
||||||
final int worldMinHeight = world.getMinHeight();
|
final int worldMinHeight = world.getMinHeight();
|
||||||
final int worldMaxHeight = world.getMaxHeight();
|
final int worldMaxHeight = world.getMaxHeight();
|
||||||
final int worldHeight = worldMaxHeight - worldMinHeight;
|
final int worldHeight = worldMaxHeight - worldMinHeight;
|
||||||
@@ -555,19 +571,19 @@ public class MeshEnvironment {
|
|||||||
new Point( minY, maxZ ),
|
new Point( minY, maxZ ),
|
||||||
new Point( maxY, maxZ ),
|
new Point( maxY, maxZ ),
|
||||||
new Point( maxY, minZ )
|
new Point( maxY, minZ )
|
||||||
) );
|
) );
|
||||||
final Polygon yPoly = new Polygon( Arrays.asList(
|
final Polygon yPoly = new Polygon( Arrays.asList(
|
||||||
new Point( minX, minZ ),
|
new Point( minX, minZ ),
|
||||||
new Point( minX, maxZ ),
|
new Point( minX, maxZ ),
|
||||||
new Point( maxX, maxZ ),
|
new Point( maxX, maxZ ),
|
||||||
new Point( maxX, minZ )
|
new Point( maxX, minZ )
|
||||||
) );
|
) );
|
||||||
final Polygon zPoly = new Polygon( Arrays.asList(
|
final Polygon zPoly = new Polygon( Arrays.asList(
|
||||||
new Point( minX, minY ),
|
new Point( minX, minY ),
|
||||||
new Point( minX, maxY ),
|
new Point( minX, maxY ),
|
||||||
new Point( maxX, maxY ),
|
new Point( maxX, maxY ),
|
||||||
new Point( maxX, minY )
|
new Point( maxX, minY )
|
||||||
) );
|
) );
|
||||||
|
|
||||||
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
|
||||||
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
|
||||||
@@ -599,19 +615,19 @@ public class MeshEnvironment {
|
|||||||
new Point( y, z + 1 ),
|
new Point( y, z + 1 ),
|
||||||
new Point( y + 1, z + 1 ),
|
new Point( y + 1, z + 1 ),
|
||||||
new Point( y + 1, z )
|
new Point( y + 1, z )
|
||||||
) );
|
) );
|
||||||
final Polygon yPoly = new Polygon( Arrays.asList(
|
final Polygon yPoly = new Polygon( Arrays.asList(
|
||||||
new Point( x, z ),
|
new Point( x, z ),
|
||||||
new Point( x, z + 1 ),
|
new Point( x, z + 1 ),
|
||||||
new Point( x + 1, z + 1 ),
|
new Point( x + 1, z + 1 ),
|
||||||
new Point( x + 1, z )
|
new Point( x + 1, z )
|
||||||
) );
|
) );
|
||||||
final Polygon zPoly = new Polygon( Arrays.asList(
|
final Polygon zPoly = new Polygon( Arrays.asList(
|
||||||
new Point( x, y ),
|
new Point( x, y ),
|
||||||
new Point( x, y + 1 ),
|
new Point( x, y + 1 ),
|
||||||
new Point( x + 1, y + 1 ),
|
new Point( x + 1, y + 1 ),
|
||||||
new Point( x + 1, y )
|
new Point( x + 1, y )
|
||||||
) );
|
) );
|
||||||
|
|
||||||
// Check each face
|
// Check each face
|
||||||
if ( y == 0 || chunkMesh.getType( index - 256 ) != BlockDataType.SOLID ) {
|
if ( y == 0 || chunkMesh.getType( index - 256 ) != BlockDataType.SOLID ) {
|
||||||
@@ -654,7 +670,7 @@ public class MeshEnvironment {
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Collection< Location > update( final AbstractMesh mesh, final Collection< Location > locations ) {
|
public static Collection< Location > update( final AbstractMesh mesh, final Collection< Location > locations ) {
|
||||||
if ( locations.isEmpty() ) {
|
if ( locations.isEmpty() ) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
@@ -697,14 +713,14 @@ public class MeshEnvironment {
|
|||||||
final Vector position = location.toVector().subtract( mesh.getMinimumCorner() );
|
final Vector position = location.toVector().subtract( mesh.getMinimumCorner() );
|
||||||
final BlockDataInformation information = mesh.getBlockDataInformationFor( position );
|
final BlockDataInformation information = mesh.getBlockDataInformationFor( position );
|
||||||
if ( information != null ) {
|
if ( information != null ) {
|
||||||
canRemove.add( location );
|
canRemove.add( location );
|
||||||
if ( information.isBlockData( data ) ) {
|
if ( information.isBlockData( data ) ) {
|
||||||
// Ignore if the block data has not changed
|
// Ignore if the block data has not changed
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
final List< BoundingBox > boxes = NmsUtil.getShape( data, location, BlockShapeType.COLLISION_SHAPE ).e().stream()
|
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() );
|
.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 BlockDataType oldType = information.type;
|
||||||
final BoundingBox[] otherBoxes = information.boundingBoxes;
|
final BoundingBox[] otherBoxes = information.boundingBoxes;
|
||||||
if ( boxes.size() == 0 ) {
|
if ( boxes.size() == 0 ) {
|
||||||
if ( oldType == BlockDataType.NONE ) {
|
if ( oldType == BlockDataType.NONE ) {
|
||||||
@@ -764,19 +780,19 @@ public class MeshEnvironment {
|
|||||||
new Point( minY, maxZ ),
|
new Point( minY, maxZ ),
|
||||||
new Point( maxY, maxZ ),
|
new Point( maxY, maxZ ),
|
||||||
new Point( maxY, minZ )
|
new Point( maxY, minZ )
|
||||||
) );
|
) );
|
||||||
final Polygon yPoly = new Polygon( Arrays.asList(
|
final Polygon yPoly = new Polygon( Arrays.asList(
|
||||||
new Point( minX, minZ ),
|
new Point( minX, minZ ),
|
||||||
new Point( minX, maxZ ),
|
new Point( minX, maxZ ),
|
||||||
new Point( maxX, maxZ ),
|
new Point( maxX, maxZ ),
|
||||||
new Point( maxX, minZ )
|
new Point( maxX, minZ )
|
||||||
) );
|
) );
|
||||||
final Polygon zPoly = new Polygon( Arrays.asList(
|
final Polygon zPoly = new Polygon( Arrays.asList(
|
||||||
new Point( minX, minY ),
|
new Point( minX, minY ),
|
||||||
new Point( minX, maxY ),
|
new Point( minX, maxY ),
|
||||||
new Point( maxX, maxY ),
|
new Point( maxX, maxY ),
|
||||||
new Point( maxX, minY )
|
new Point( maxX, minY )
|
||||||
) );
|
) );
|
||||||
|
|
||||||
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, minX ) ).add( xPoly );
|
||||||
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.X, maxX ) ).add( xPoly );
|
||||||
@@ -785,7 +801,7 @@ public class MeshEnvironment {
|
|||||||
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, minZ ) ).add( zPoly );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, minZ ) ).add( zPoly );
|
||||||
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, maxZ ) ).add( zPoly );
|
getPolygons.apply( new MinecraftPlane( PlaneAxis.Z, maxZ ) ).add( zPoly );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,11 +826,11 @@ public class MeshEnvironment {
|
|||||||
|
|
||||||
// Add all polygons that were previously generated
|
// Add all polygons that were previously generated
|
||||||
for ( final Polygon polygon : planeMesh.generatedRegions ) {
|
for ( final Polygon polygon : planeMesh.generatedRegions ) {
|
||||||
mesher.addPolygon( polygon, RegionRuleWinding.CLOCKWISE );
|
mesher.addPolygon( polygon, RegionRuleWinding.CLOCKWISE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ( final Polygon polygon : entry.getValue() ) {
|
for ( final Polygon polygon : entry.getValue() ) {
|
||||||
mesher.addPolygon( polygon, RegionRuleWinding.CLOCKWISE );
|
mesher.addPolygon( polygon, RegionRuleWinding.CLOCKWISE );
|
||||||
}
|
}
|
||||||
|
|
||||||
meshMap.put( plane, mesher );
|
meshMap.put( plane, mesher );
|
||||||
@@ -834,9 +850,9 @@ public class MeshEnvironment {
|
|||||||
final PlaneMesh newMesh = new PlaneMesh();
|
final PlaneMesh newMesh = new PlaneMesh();
|
||||||
newMesh.completedPolygons = new ArrayList< IndexedTriangle >();
|
newMesh.completedPolygons = new ArrayList< IndexedTriangle >();
|
||||||
for ( final Polygon tri : tris ) {
|
for ( final Polygon tri : tris ) {
|
||||||
final IndexedTriangle newPoly = new IndexedTriangle();
|
final IndexedTriangle newPoly = new IndexedTriangle();
|
||||||
for ( int i = 0; i < tri.getPoints().size() && i < 3; ++i ) {
|
for ( int i = 0; i < tri.getPoints().size() && i < 3; ++i ) {
|
||||||
final Point point = tri.getPoints().get( i );
|
final Point point = tri.getPoints().get( i );
|
||||||
final Vector vert = plane.convert( point );
|
final Vector vert = plane.convert( point );
|
||||||
|
|
||||||
// Find an existing vertex reference if one exists
|
// Find an existing vertex reference if one exists
|
||||||
@@ -862,18 +878,18 @@ public class MeshEnvironment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch ( i ) {
|
switch ( i ) {
|
||||||
case 0:
|
case 0:
|
||||||
newPoly.setPoint1( ref );
|
newPoly.setPoint1( ref );
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
newPoly.setPoint2( ref );
|
newPoly.setPoint2( ref );
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
newPoly.setPoint3( ref );
|
newPoly.setPoint3( ref );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Should never be here!
|
// Should never be here!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newMesh.completedPolygons.add( newPoly );
|
newMesh.completedPolygons.add( newPoly );
|
||||||
}
|
}
|
||||||
@@ -891,8 +907,8 @@ public class MeshEnvironment {
|
|||||||
return canRemove;
|
return canRemove;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MeshResult generateMeshFrom( final Map< MinecraftPlane, Collection< Polygon > > polygons ) {
|
public static MeshResult generateMeshFrom( final Map< MinecraftPlane, Collection< Polygon > > polygons ) {
|
||||||
final Map< MinecraftPlane, Mesh< RegionSimple > > meshMap = new HashMap< MinecraftPlane, Mesh< RegionSimple > >();
|
final Map< MinecraftPlane, Mesh< RegionSimple > > meshMap = new HashMap< MinecraftPlane, Mesh< RegionSimple > >();
|
||||||
for ( final Entry< MinecraftPlane, Collection< Polygon > > entry : polygons.entrySet() ) {
|
for ( final Entry< MinecraftPlane, Collection< Polygon > > entry : polygons.entrySet() ) {
|
||||||
final MinecraftPlane plane = entry.getKey();
|
final MinecraftPlane plane = entry.getKey();
|
||||||
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> new RegionSimple( GluWindingRule.ODD ) );
|
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> new RegionSimple( GluWindingRule.ODD ) );
|
||||||
@@ -922,45 +938,45 @@ public class MeshEnvironment {
|
|||||||
for ( final Polygon tri : tris ) {
|
for ( final Polygon tri : tris ) {
|
||||||
final IndexedTriangle newPoly = new IndexedTriangle();
|
final IndexedTriangle newPoly = new IndexedTriangle();
|
||||||
for ( int i = 0; i < tri.getPoints().size() && i < 3; ++i ) {
|
for ( int i = 0; i < tri.getPoints().size() && i < 3; ++i ) {
|
||||||
final Point point = tri.getPoints().get( i );
|
final Point point = tri.getPoints().get( i );
|
||||||
final Vector vert = plane.convert( point );
|
final Vector vert = plane.convert( point );
|
||||||
|
|
||||||
final VectorReference tempRef = new VectorReference( vert );
|
final VectorReference tempRef = new VectorReference( vert );
|
||||||
// Find an existing vertex reference if one exists
|
// Find an existing vertex reference if one exists
|
||||||
VectorReference ref = null;
|
VectorReference ref = null;
|
||||||
if ( ref == null ) {
|
if ( ref == null ) {
|
||||||
final VectorReference upperRef = vertices.ceiling( tempRef );
|
final VectorReference upperRef = vertices.ceiling( tempRef );
|
||||||
if ( upperRef != null && upperRef.vector.distanceSquared( vert ) < 1e-8 ) {
|
if ( upperRef != null && upperRef.vector.distanceSquared( vert ) < 1e-8 ) {
|
||||||
ref = upperRef;
|
ref = upperRef;
|
||||||
} else {
|
} else {
|
||||||
final VectorReference lowerRef = vertices.floor( tempRef );
|
final VectorReference lowerRef = vertices.floor( tempRef );
|
||||||
if ( lowerRef != null && lowerRef.vector.distanceSquared( vert ) < 1e-8 ) {
|
if ( lowerRef != null && lowerRef.vector.distanceSquared( vert ) < 1e-8 ) {
|
||||||
ref = lowerRef;
|
ref = lowerRef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ref == null ) {
|
if ( ref == null ) {
|
||||||
ref = tempRef;
|
ref = tempRef;
|
||||||
ref.referenceCount = 1;
|
ref.referenceCount = 1;
|
||||||
vertices.add( ref );
|
vertices.add( ref );
|
||||||
} else {
|
} else {
|
||||||
++ref.referenceCount;
|
++ref.referenceCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ( i ) {
|
switch ( i ) {
|
||||||
case 0:
|
case 0:
|
||||||
newPoly.setPoint1( ref );
|
newPoly.setPoint1( ref );
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
newPoly.setPoint2( ref );
|
newPoly.setPoint2( ref );
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
newPoly.setPoint3( ref );
|
newPoly.setPoint3( ref );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Should never be here!
|
// Should never be here!
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
newMesh.completedPolygons.add( newPoly );
|
newMesh.completedPolygons.add( newPoly );
|
||||||
@@ -989,9 +1005,9 @@ public class MeshEnvironment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MeshResult {
|
public static class MeshResult {
|
||||||
Map< MinecraftPlane, PlaneMesh > meshes;
|
Map< MinecraftPlane, PlaneMesh > meshes;
|
||||||
TreeSet< VectorReference > points;
|
TreeSet< VectorReference > points;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ChunkTaskType {
|
private enum ChunkTaskType {
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
name: MC-Mesh-Environment
|
name: MC-Mesh-Environment
|
||||||
main: com.aaaaahhhhhhh.bananapuncher714.minietest.MiniePlugin
|
main: com.aaaaahhhhhhh.bananapuncher714.mesh.environment.McMeshEnvironmentPlugin
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
description: BulletJME and MC-Mesh integration
|
description: BulletJME and MC-Mesh integration
|
||||||
author: BananaPuncher714
|
author: BananaPuncher714
|
||||||
api-version: 1.13
|
api-version: 1.13
|
||||||
#libraries:
|
|
||||||
#- com.github.stephengold:Minie:7.5.0
|
|
||||||
|
|
||||||
commands:
|
|
||||||
minie:
|
|
||||||
description: Main Minie command
|
|
||||||
aliases: []
|
|
||||||
permission: minie
|
|
||||||
53
plugin/physics/pom.xml
Normal file
53
plugin/physics/pom.xml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
|
||||||
|
<artifactId>mc-mesh-plugin</artifactId>
|
||||||
|
<version>0.0.1</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>mc-mesh-plugin-physics</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spigotmc</groupId>
|
||||||
|
<artifactId>spigot</artifactId>
|
||||||
|
<version>1.21.10-R0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aaaaahhhhhhh.bananapuncher714</groupId>
|
||||||
|
<artifactId>mc-mesh-plugin-environment</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>3.1.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.14.1</version>
|
||||||
|
<configuration>
|
||||||
|
<release>21</release>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.mesh.physics;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Display;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
class AuxiliaryDisplayStruct {
|
||||||
|
Display display;
|
||||||
|
Vector offset;
|
||||||
|
Vector scale;
|
||||||
|
|
||||||
|
AuxiliaryDisplayStruct( Display display, Vector offset ) {
|
||||||
|
this.display = display;
|
||||||
|
this.offset = offset.clone();
|
||||||
|
this.scale = new Vector( 1, 1, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
AuxiliaryDisplayStruct setScale( Vector scale ) {
|
||||||
|
this.scale = scale.clone();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
package com.aaaaahhhhhhh.bananapuncher714.mesh.physics;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.BlockDisplay;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.util.BoundingBox;
|
||||||
|
import org.bukkit.util.Transformation;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Quaternionf;
|
||||||
|
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.command.CommandParameters;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.command.SubCommand;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.command.executor.CommandExecutableMessage;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.InputValidatorDouble;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.InputValidatorInt;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.command.validator.sender.SenderValidatorPlayer;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.EnvironmentHandler;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.MeshEnvironment;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkLocation;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.NmsUtil;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.NmsUtil.BlockShapeType;
|
||||||
|
import com.jme3.bullet.PhysicsSpace;
|
||||||
|
import com.jme3.bullet.PhysicsSpace.BroadphaseType;
|
||||||
|
import com.jme3.bullet.collision.PhysicsCollisionEvent;
|
||||||
|
import com.jme3.bullet.collision.PhysicsCollisionListener;
|
||||||
|
import com.jme3.bullet.collision.PhysicsCollisionObject;
|
||||||
|
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
|
||||||
|
import com.jme3.bullet.collision.shapes.CollisionShape;
|
||||||
|
import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
|
||||||
|
import com.jme3.bullet.collision.shapes.MeshCollisionShape;
|
||||||
|
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
|
||||||
|
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 McMeshPhysicsPlugin extends JavaPlugin {
|
||||||
|
private static final int TIME_STEPS = 5;
|
||||||
|
private static final float SIMULATION_SPEED = 1f;
|
||||||
|
|
||||||
|
private MeshEnvironment environment;
|
||||||
|
|
||||||
|
private PhysicsSpace space;
|
||||||
|
private boolean paused = false;
|
||||||
|
private boolean teleportOnDeactivate = false;
|
||||||
|
private float tick = 0;
|
||||||
|
private Map< PhysicsCollisionObject, AuxiliaryDisplayStruct > linkedDisplays = new HashMap< PhysicsCollisionObject, AuxiliaryDisplayStruct >();
|
||||||
|
private Set< PhysicsCollisionObject > active = new HashSet< PhysicsCollisionObject >();
|
||||||
|
private Map< ChunkLocation, PhysicsRigidBody > chunks = new HashMap< ChunkLocation, PhysicsRigidBody >();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
registerCommands();
|
||||||
|
|
||||||
|
space = new PhysicsSpace( BroadphaseType.DBVT );
|
||||||
|
space.setAccuracy( 1f / ( TIME_STEPS * 20f ) );
|
||||||
|
|
||||||
|
environment = new MeshEnvironment( this, new File( getDataFolder(), "environment" ) );
|
||||||
|
environment.setHandler( new EnvironmentHandler() {
|
||||||
|
@Override
|
||||||
|
public void onMeshLoad( ChunkLocation location, ChunkMesh mesh ) {
|
||||||
|
// Now, create a physics object from the chunk mesh
|
||||||
|
final IndexedMesh nativeMesh = mesh.toIndexedMesh();
|
||||||
|
// Enable quantized AABB compression... hopefully that doesn't mess with the accuracy or anything...
|
||||||
|
final MeshCollisionShape meshCollision = new MeshCollisionShape( true, nativeMesh );
|
||||||
|
|
||||||
|
// Create a rigid body
|
||||||
|
PhysicsRigidBody rigid = new PhysicsRigidBody( meshCollision, PhysicsBody.massForStatic );
|
||||||
|
rigid.setPhysicsLocation( new Vector3f( location.getX() << 4, location.getWorld().getMinHeight(), location.getZ() << 4 ) );
|
||||||
|
rigid.setPhysicsRotation( new Quaternion( 0, 0, 0, 1 ) );
|
||||||
|
rigid.setKinematic( false );
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTask( McMeshPhysicsPlugin.this, () -> {
|
||||||
|
space.addCollisionObject( rigid );
|
||||||
|
|
||||||
|
PhysicsRigidBody old = chunks.put( location, rigid );
|
||||||
|
if ( old != null ) {
|
||||||
|
space.remove( old );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMeshUnload( ChunkLocation location, ChunkMesh mesh ) {
|
||||||
|
space.removeCollisionObject( chunks.get( location ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMeshUpdate( ChunkLocation location, ChunkMesh mesh ) {
|
||||||
|
// Now, create a physics object from the chunk mesh
|
||||||
|
final IndexedMesh nativeMesh = mesh.toIndexedMesh();
|
||||||
|
// Enable quantized AABB compression... hopefully that doesn't mess with the accuracy or anything...
|
||||||
|
final MeshCollisionShape meshCollision = new MeshCollisionShape( true, nativeMesh );
|
||||||
|
|
||||||
|
// Create a rigid body
|
||||||
|
PhysicsRigidBody rigid = new PhysicsRigidBody( meshCollision, PhysicsBody.massForStatic );
|
||||||
|
rigid.setPhysicsLocation( new Vector3f( location.getX() << 4, location.getWorld().getMinHeight(), location.getZ() << 4 ) );
|
||||||
|
rigid.setPhysicsRotation( new Quaternion( 0, 0, 0, 1 ) );
|
||||||
|
rigid.setKinematic( false );
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTask( McMeshPhysicsPlugin.this, () -> {
|
||||||
|
space.addCollisionObject( rigid );
|
||||||
|
|
||||||
|
PhysicsRigidBody old = chunks.put( location, rigid );
|
||||||
|
if ( old != null ) {
|
||||||
|
space.remove( old );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
space.activateAll( true );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskTimer( this, () -> {
|
||||||
|
if ( !paused ) {
|
||||||
|
// Update the real world with the physics space objects
|
||||||
|
space.distributeEvents();
|
||||||
|
space.update( tick, TIME_STEPS );
|
||||||
|
|
||||||
|
for ( Iterator< Entry< PhysicsCollisionObject, AuxiliaryDisplayStruct > > it = linkedDisplays.entrySet().iterator(); it.hasNext(); ) {
|
||||||
|
Entry< PhysicsCollisionObject, AuxiliaryDisplayStruct > entry = it.next();
|
||||||
|
PhysicsCollisionObject obj = entry.getKey();
|
||||||
|
AuxiliaryDisplayStruct disp = entry.getValue();
|
||||||
|
|
||||||
|
if ( !disp.display.isValid() ) {
|
||||||
|
it.remove();
|
||||||
|
space.removeCollisionObject( obj );
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Location displayLocation = disp.display.getLocation();
|
||||||
|
|
||||||
|
// Do not calculate for this object if it is inactive
|
||||||
|
if ( !obj.isActive() ) {
|
||||||
|
if ( teleportOnDeactivate && active.remove( obj ) ) {
|
||||||
|
// Newly deactivated object, teleport the display to the actual position to prevent the translation from getting too large
|
||||||
|
|
||||||
|
Transformation currentTransformation = disp.display.getTransformation();
|
||||||
|
org.joml.Vector3f trans = currentTransformation.getTranslation();
|
||||||
|
|
||||||
|
displayLocation.add( trans.x(), trans.y(), trans.z() );
|
||||||
|
disp.display.teleport( displayLocation );
|
||||||
|
|
||||||
|
Transformation newTrans = new Transformation( new org.joml.Vector3f( 0, 0, 0 ), currentTransformation.getLeftRotation(), currentTransformation.getScale(), currentTransformation.getRightRotation() );
|
||||||
|
disp.display.setInterpolationDelay( 0 );
|
||||||
|
disp.display.setInterpolationDuration( 0 );
|
||||||
|
disp.display.setTransformation( newTrans );
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
active.add( obj );
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f location = obj.getPhysicsLocation();
|
||||||
|
Quaternion rotation = new Quaternion();
|
||||||
|
obj.getPhysicsRotation( rotation );
|
||||||
|
|
||||||
|
Vector offsetVec = disp.offset;
|
||||||
|
Vector scale = disp.scale;
|
||||||
|
Matrix4f transformRot = new Matrix4f();
|
||||||
|
transformRot.set( new Quaternionf( rotation.getX(), rotation.getY(), rotation.getZ(), rotation.getW() ) );
|
||||||
|
|
||||||
|
transformRot.mul( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, - ( float ) offsetVec.getX(), - ( float ) offsetVec.getY(), - ( float ) offsetVec.getZ(), 1 );
|
||||||
|
transformRot.mul( ( float ) scale.getX(), 0, 0, 0, 0, ( float ) scale.getY(), 0, 0, 0, 0, ( float ) scale.getZ(), 0, 0, 0, 0, 1 );
|
||||||
|
Matrix4f transMat = new Matrix4f( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ( float ) ( location.getX() - displayLocation.getX() ), ( float ) ( location.getY() - displayLocation.getY() ), ( float ) ( location.getZ() - displayLocation.getZ() ), 1 );
|
||||||
|
|
||||||
|
disp.display.setInterpolationDelay( 0 );
|
||||||
|
disp.display.setInterpolationDuration( 2 );
|
||||||
|
disp.display.setTransformationMatrix( transMat.mul( transformRot ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
tick += SIMULATION_SPEED / 20f;
|
||||||
|
}
|
||||||
|
}, 0, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCommands() {
|
||||||
|
new SubCommand( "minie" )
|
||||||
|
.addSenderValidator( new SenderValidatorPlayer() )
|
||||||
|
.add( new SubCommand( "spawn" )
|
||||||
|
.add( new SubCommand( new InputValidatorDouble( 0.01, 100 ) )
|
||||||
|
.defaultTo( this::spawnBlock ) )
|
||||||
|
.defaultTo( this::spawnBlock ) )
|
||||||
|
.add( new SubCommand( "toggle" )
|
||||||
|
.defaultTo( ( sender, args, params ) -> {
|
||||||
|
paused = !paused;
|
||||||
|
} ) )
|
||||||
|
.add( new SubCommand( "teleport" )
|
||||||
|
.defaultTo( ( sender, args, params ) -> {
|
||||||
|
teleportOnDeactivate = !teleportOnDeactivate;
|
||||||
|
} ) )
|
||||||
|
.add( new SubCommand( "impulse" )
|
||||||
|
.add( new SubCommand( new InputValidatorInt() )
|
||||||
|
.defaultTo( ( sender, args, params ) -> {
|
||||||
|
Player player = ( Player ) sender;
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
|
||||||
|
impulse( new Vector3f( ( float ) loc.getX(), ( float ) loc.getY(), ( float ) loc.getZ() ), params.getLast( int.class ) );
|
||||||
|
} ) )
|
||||||
|
.defaultTo( ( sender, args, params ) -> {
|
||||||
|
Player player = ( Player ) sender;
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
|
||||||
|
impulse( new Vector3f( ( float ) loc.getX(), ( float ) loc.getY(), ( float ) loc.getZ() ), 15f );
|
||||||
|
} ) )
|
||||||
|
.defaultTo( new CommandExecutableMessage( "An argument must be provided" ) )
|
||||||
|
.whenUnknown( new CommandExecutableMessage( "Unknown argument" ) )
|
||||||
|
.applyTo( getCommand( "minie" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void impulse( Vector3f location, float power ) {
|
||||||
|
PhysicsRigidBody rigid = new PhysicsRigidBody( new SphereCollisionShape( 20 ), 1f );
|
||||||
|
rigid.setPhysicsLocation( location );
|
||||||
|
space.contactTest( rigid, new PhysicsCollisionListener() {
|
||||||
|
@Override
|
||||||
|
public void collision( PhysicsCollisionEvent event ) {
|
||||||
|
if ( event.getObjectB() instanceof PhysicsRigidBody ) {
|
||||||
|
PhysicsRigidBody objB = ( PhysicsRigidBody ) event.getObjectB();
|
||||||
|
|
||||||
|
Vector3f rLoc = objB.getPhysicsLocation();
|
||||||
|
Vector3f to = rLoc.subtract( ( float ) location.getX(), ( float ) location.getY(), ( float ) location.getZ() );
|
||||||
|
|
||||||
|
float distSq = to.lengthSquared();
|
||||||
|
|
||||||
|
if ( distSq != 0 ) {
|
||||||
|
if ( power / distSq > 1 ) {
|
||||||
|
objB.applyCentralImpulse( to.normalize().mult( power / distSq ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnBlock( final CommandSender sender, final String[] args, final CommandParameters params ) {
|
||||||
|
Player player = ( Player ) sender;
|
||||||
|
Location loc = player.getLocation();
|
||||||
|
|
||||||
|
// Optional scale
|
||||||
|
double scale = 1;
|
||||||
|
if ( params.size() > 2 ) {
|
||||||
|
scale = params.getFirst( double.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
loc.setPitch( 0 );
|
||||||
|
loc.setDirection( new Vector( 0, 0, 0 ) );
|
||||||
|
|
||||||
|
BlockData displayData;
|
||||||
|
ItemStack item = player.getInventory().getItemInMainHand();
|
||||||
|
if ( item != null && item.getType() != Material.AIR && item.getType().isBlock() ) {
|
||||||
|
displayData = item.getType().createBlockData();
|
||||||
|
} else {
|
||||||
|
displayData = Material.TNT.createBlockData();
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox[] boxes = NmsUtil.convertFrom( NmsUtil.getShape( displayData, null, BlockShapeType.SHAPE ) );
|
||||||
|
Vector blockCenter = calculateCenter( boxes );
|
||||||
|
|
||||||
|
CollisionShape box;
|
||||||
|
if ( boxes.length == 0 ) {
|
||||||
|
player.sendMessage( "No bounding box detected! Wrong method?" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( boxes.length == 1 ) {
|
||||||
|
Vector min = boxes[ 0 ].getMin();
|
||||||
|
Vector center = boxes[ 0 ].getCenter().subtract( min );
|
||||||
|
box = new BoxCollisionShape( ( float ) center.getX(), ( float ) center.getY(), ( float ) center.getZ() );
|
||||||
|
} else {
|
||||||
|
CompoundCollisionShape compound = new CompoundCollisionShape();
|
||||||
|
for ( BoundingBox aabb : boxes ) {
|
||||||
|
Vector min = aabb.getMin();
|
||||||
|
Vector center = aabb.getCenter();
|
||||||
|
Vector half = center.clone().subtract( min );
|
||||||
|
center.subtract( blockCenter );
|
||||||
|
CollisionShape subShape = new BoxCollisionShape( ( float ) half.getX(), ( float ) half.getY(), ( float ) half.getZ() );
|
||||||
|
compound.addChildShape( subShape, ( float ) center.getX(), ( float ) center.getY(), ( float ) center.getZ() );
|
||||||
|
}
|
||||||
|
box = compound;
|
||||||
|
}
|
||||||
|
|
||||||
|
box.setScale( ( float ) scale );
|
||||||
|
|
||||||
|
PhysicsRigidBody rigid = new PhysicsRigidBody( box, 1f );
|
||||||
|
|
||||||
|
// Since the center of the rigid body and the box shape are different, we need to offset the location
|
||||||
|
rigid.setPhysicsLocation( new Vector3f( ( float ) ( loc.getX() + blockCenter.getX() ), ( float ) ( loc.getY() + blockCenter.getY() ), ( float ) ( loc.getZ() + blockCenter.getZ() ) ) );
|
||||||
|
|
||||||
|
// Convert the display direction vector to a quaternion
|
||||||
|
rigid.setPhysicsRotation( new Quaternion( 0, 0, 0, 1 ) );
|
||||||
|
|
||||||
|
rigid.setMass( rigid.getMass() * ( float ) ( scale * scale ) );
|
||||||
|
|
||||||
|
space.addCollisionObject( rigid );
|
||||||
|
|
||||||
|
// Create the display
|
||||||
|
BlockDisplay display = loc.getWorld().spawn( loc, BlockDisplay.class, d -> {
|
||||||
|
d.setBlock( displayData );
|
||||||
|
d.setViewRange( 1000 );
|
||||||
|
} );
|
||||||
|
|
||||||
|
linkedDisplays.put( rigid, new AuxiliaryDisplayStruct( display, blockCenter.multiply( scale ) ).setScale( new Vector( scale, scale, scale ) ) );
|
||||||
|
|
||||||
|
player.sendMessage( "Created display" );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector calculateCenter( BoundingBox[] boxes ) {
|
||||||
|
Vector center = new Vector( 0, 0, 0 );
|
||||||
|
// TODO Throw error, probably
|
||||||
|
if ( boxes.length == 0 ) {
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
|
||||||
|
double totalVolume = 0;
|
||||||
|
for ( BoundingBox box : boxes ) {
|
||||||
|
Vector mid = box.getCenter();
|
||||||
|
center.add( mid.multiply( box.getVolume() ) );
|
||||||
|
totalVolume += box.getVolume();
|
||||||
|
}
|
||||||
|
return center.multiply( 1 / totalVolume );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment;
|
package com.aaaaahhhhhhh.bananapuncher714.mesh.physics;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
@@ -75,6 +75,7 @@ import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.BlockDataType;
|
|||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkLocation;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkLocation;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.IndexedPolygon;
|
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;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.PlaneMesh;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.PlaneMesh;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.VectorReference;
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.VectorReference;
|
||||||
@@ -1050,7 +1051,7 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
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();
|
||||||
|
|
||||||
if ( existingVec.distanceSquared( vec ) < 1e-8 ) {
|
if ( existingVec.distanceSquared( new Vector( vec.getX(), vec.getY(), vec.getZ() ) ) < 1e-8 ) {
|
||||||
ref = entry.getValue();
|
ref = entry.getValue();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1058,7 +1059,7 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
|
|
||||||
if ( ref == null ) {
|
if ( ref == null ) {
|
||||||
ref = new VectorRef();
|
ref = new VectorRef();
|
||||||
vertices.put( vec, ref );
|
vertices.put( new Vector( vec.getX(), vec.getY(), vec.getZ() ), ref );
|
||||||
}
|
}
|
||||||
|
|
||||||
triangle.refs.add( ref );
|
triangle.refs.add( ref );
|
||||||
@@ -1313,9 +1314,9 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
// Ignore any planes that are empty
|
// Ignore any planes that are empty
|
||||||
if ( !tris.isEmpty() ) {
|
if ( !tris.isEmpty() ) {
|
||||||
final PlaneMesh newMesh = new PlaneMesh();
|
final PlaneMesh newMesh = new PlaneMesh();
|
||||||
newMesh.completedPolygons = new ArrayList< IndexedPolygon >();
|
newMesh.completedPolygons = new ArrayList< IndexedTriangle >();
|
||||||
for ( final Polygon tri : tris ) {
|
for ( final Polygon tri : tris ) {
|
||||||
final IndexedPolygon newPoly = new IndexedPolygon();
|
final IndexedTriangle newPoly = new IndexedTriangle();
|
||||||
for ( final Point point : tri.getPoints() ) {
|
for ( final Point point : tri.getPoints() ) {
|
||||||
final Vector vert = plane.convert( point );
|
final Vector vert = plane.convert( point );
|
||||||
|
|
||||||
@@ -1342,7 +1343,7 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
++ref.referenceCount;
|
++ref.referenceCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
newPoly.points.add( ref );
|
// newPoly.points.add( ref );
|
||||||
}
|
}
|
||||||
newMesh.completedPolygons.add( newPoly );
|
newMesh.completedPolygons.add( newPoly );
|
||||||
}
|
}
|
||||||
@@ -1536,7 +1537,7 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
if ( planeMesh != null ) {
|
if ( planeMesh != null ) {
|
||||||
// Reset all indexed polygons(triangles) for this plane
|
// Reset all indexed polygons(triangles) for this plane
|
||||||
for ( final IndexedPolygon poly : planeMesh.completedPolygons ) {
|
for ( final IndexedPolygon poly : planeMesh.completedPolygons ) {
|
||||||
poly.points.parallelStream().forEach( p -> --p.referenceCount );
|
// poly.points.parallelStream().forEach( p -> --p.referenceCount );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all polygons that were previously generated
|
// Add all polygons that were previously generated
|
||||||
@@ -1563,9 +1564,9 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
// Ignore any planes that are empty
|
// Ignore any planes that are empty
|
||||||
if ( !tris.isEmpty() ) {
|
if ( !tris.isEmpty() ) {
|
||||||
final PlaneMesh newMesh = new PlaneMesh();
|
final PlaneMesh newMesh = new PlaneMesh();
|
||||||
newMesh.completedPolygons = new ArrayList< IndexedPolygon >();
|
newMesh.completedPolygons = new ArrayList< IndexedTriangle >();
|
||||||
for ( final Polygon tri : tris ) {
|
for ( final Polygon tri : tris ) {
|
||||||
final IndexedPolygon newPoly = new IndexedPolygon();
|
final IndexedTriangle newPoly = new IndexedTriangle();
|
||||||
for ( final Point point : tri.getPoints() ) {
|
for ( final Point point : tri.getPoints() ) {
|
||||||
final Vector vert = plane.convert( point );
|
final Vector vert = plane.convert( point );
|
||||||
|
|
||||||
@@ -1591,7 +1592,7 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
++ref.referenceCount;
|
++ref.referenceCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
newPoly.points.add( ref );
|
// newPoly.points.add( ref );
|
||||||
}
|
}
|
||||||
newMesh.completedPolygons.add( newPoly );
|
newMesh.completedPolygons.add( newPoly );
|
||||||
}
|
}
|
||||||
@@ -1667,12 +1668,12 @@ 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();
|
||||||
|
|
||||||
if ( existingVec.distanceSquared( vec ) < 1e-8 ) {
|
if ( existingVec.distanceSquared( new Vector( vec.getX(), vec.getY(), vec.getZ() ) ) < 1e-8 ) {
|
||||||
ref = entry.getValue();
|
ref = entry.getValue();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1680,7 +1681,7 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
|
|
||||||
if ( ref == null ) {
|
if ( ref == null ) {
|
||||||
ref = new VectorRef();
|
ref = new VectorRef();
|
||||||
vertices.put( vec, ref );
|
vertices.put( new Vector( vec.getX(), vec.getY(), vec.getZ() ), ref );
|
||||||
}
|
}
|
||||||
|
|
||||||
triangle.refs.add( ref );
|
triangle.refs.add( ref );
|
||||||
@@ -1765,10 +1766,10 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
|
|
||||||
try ( FileWriter writer = new FileWriter( file ) ) {
|
try ( FileWriter writer = new FileWriter( file ) ) {
|
||||||
for ( final Facet facet : facets ) {
|
for ( final Facet facet : facets ) {
|
||||||
final Vector normal = facet.normal;
|
final Vector3d normal = facet.normal;
|
||||||
|
|
||||||
writer.write( facet.points.size() + " " + normal.getX() + " " + normal.getY() + " " + normal.getZ() + "\n" );
|
writer.write( facet.points.size() + " " + normal.getX() + " " + normal.getY() + " " + normal.getZ() + "\n" );
|
||||||
for ( final Vector point : facet.points ) {
|
for ( final Vector3d point : facet.points ) {
|
||||||
writer.write( point.getX() + " " + point.getY() + " " + point.getZ() + "\n" );
|
writer.write( point.getX() + " " + point.getY() + " " + point.getZ() + "\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
15
plugin/physics/src/main/resources/plugin.yml
Normal file
15
plugin/physics/src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: MC-Mesh-Physics
|
||||||
|
main: com.aaaaahhhhhhh.bananapuncher714.mesh.physics.McMeshPhysicsPlugin
|
||||||
|
version: 0.0.1
|
||||||
|
description: BulletJME and MC-Mesh integration
|
||||||
|
author: BananaPuncher714
|
||||||
|
api-version: 1.13
|
||||||
|
depend: [ "Mc-Mesh-Environment" ]
|
||||||
|
#libraries:
|
||||||
|
#- com.github.stephengold:Minie:7.5.0
|
||||||
|
|
||||||
|
commands:
|
||||||
|
minie:
|
||||||
|
description: Main Minie command
|
||||||
|
aliases: []
|
||||||
|
permission: minie
|
||||||
@@ -13,5 +13,6 @@
|
|||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>environment</module>
|
<module>environment</module>
|
||||||
|
<module>physics</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</project>
|
||||||
Reference in New Issue
Block a user