Finish prototype mesh environment
This commit is contained in:
@@ -1,5 +1,46 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.mesh.environment;
|
||||
|
||||
public class ChunkMeshCache {
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkLocation;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.ChunkMesh;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.util.ChunkMeshUtil;
|
||||
|
||||
public class ChunkMeshCache {
|
||||
File directory;
|
||||
|
||||
public ChunkMeshCache( File directory ) {
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
public ChunkMesh load( ChunkLocation location ) {
|
||||
final File file = new File( directory, 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;
|
||||
}
|
||||
|
||||
public void save( ChunkLocation location, ChunkMesh mesh ) {
|
||||
final File file = new File( directory, 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
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;
|
||||
@@ -16,7 +13,9 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -50,78 +49,139 @@ import com.aaaaahhhhhhh.bananapuncher714.mesh.environment.objects.BlockDataInfor
|
||||
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 Map< ChunkLocation, Collection< Location > > updateLocations = new TreeMap< ChunkLocation, Collection< Location > >();
|
||||
private Map< ChunkLocation, ChunkMesh > chunkMeshes = new HashMap< ChunkLocation, ChunkMesh >();
|
||||
|
||||
private Map< ChunkLocation, ChunkTask > tasks = new HashMap< ChunkLocation, ChunkTask >();
|
||||
|
||||
private ChunkMeshCache cache;
|
||||
|
||||
private ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
final BukkitTask task = Bukkit.getScheduler().runTaskTimer( plugin, () -> {
|
||||
// final Collection< ChunkLocation > locations = new ArrayDeque< ChunkLocation >();
|
||||
lock.lock();
|
||||
updateLocations.entrySet().stream().forEach( e -> {
|
||||
ChunkMesh mesh = chunkMeshes.get( e.getKey() );
|
||||
if ( mesh != null ) {
|
||||
final Collection< Location > locs = update( mesh, 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() );
|
||||
lock.unlock();
|
||||
}, 1, 1 );
|
||||
|
||||
final Function< ChunkLocation, Collection< Location > > getLocationFor = c -> {
|
||||
lock.lock();
|
||||
Collection< Location > locations = updateLocations.get( c );
|
||||
if ( locations == null ) {
|
||||
locations = new HashSet< Location >();
|
||||
updateLocations.put( c, locations );
|
||||
}
|
||||
lock.unlock();
|
||||
return locations;
|
||||
};
|
||||
|
||||
private Listener eventListener = new Listener() {
|
||||
@EventHandler
|
||||
private void onChunkLoad( ChunkLoadEvent event ) {
|
||||
// TODO Queue chunk load
|
||||
loadOrGenerateMesh( event.getChunk() );
|
||||
final ChunkLocation location = new ChunkLocation( event.getChunk() );
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
if ( chunkMeshes.containsKey( location ) ) {
|
||||
// Do nothing
|
||||
} else {
|
||||
final ChunkTask task = tasks.get( location );
|
||||
if ( task == null ) {
|
||||
loadMesh( location );
|
||||
} else if ( task.type == ChunkTaskType.LOAD ) {
|
||||
// Do nothing
|
||||
} else if ( task.type == ChunkTaskType.UNLOAD ) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
/*
|
||||
* Order of operations:
|
||||
* - Check if:
|
||||
* - The mesh is loaded
|
||||
* - Do nothing
|
||||
* - There is an unload queued
|
||||
* - Do nothing
|
||||
* - There is a load queued
|
||||
* - Do nothing
|
||||
* - Nothing is queued
|
||||
* - Queue a load
|
||||
*/
|
||||
}
|
||||
|
||||
@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 ChunkLocation location = new ChunkLocation( event.getChunk() );
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
if ( chunkMeshes.containsKey( location ) ) {
|
||||
if ( tasks.containsKey( location ) ) {
|
||||
// Wait for the chunk to finish loading
|
||||
} else {
|
||||
// Force all updates for this chunk
|
||||
// Queue an unload
|
||||
unloadMesh( location );
|
||||
}
|
||||
} else {
|
||||
final ChunkTask task = tasks.get( location );
|
||||
if ( task == null ) {
|
||||
// Do nothing
|
||||
} else if ( task.type == ChunkTaskType.LOAD ) {
|
||||
// Do nothing
|
||||
} else if ( task.type == ChunkTaskType.UNLOAD ) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
/*
|
||||
* Order of operations:
|
||||
* - Check if:
|
||||
* - The mesh is unloaded
|
||||
* - Do nothing
|
||||
* - There is an unload queued
|
||||
* - Do nothing
|
||||
* - There is a load queued
|
||||
* - Do nothing
|
||||
* - Nothing is queued
|
||||
* - Queue an unload
|
||||
*/
|
||||
}
|
||||
|
||||
@EventHandler( priority = EventPriority.MONITOR )
|
||||
private void onBlockUpdateEvent( final BlockPhysicsEvent event ) {
|
||||
@@ -133,6 +193,7 @@ public class MeshEnvironment {
|
||||
public MeshEnvironment( JavaPlugin plugin, File cacheDirectory ) {
|
||||
this.plugin = plugin;
|
||||
this.cacheDirectory = cacheDirectory;
|
||||
cache = new ChunkMeshCache( new File( cacheDirectory, "meshes" ) );
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
@@ -143,52 +204,136 @@ public class MeshEnvironment {
|
||||
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();
|
||||
private void completeTask( ChunkLocation location ) {
|
||||
lock.lock();
|
||||
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 ) {
|
||||
ChunkTask task = new ChunkTask();
|
||||
lock.lock();
|
||||
try {
|
||||
tasks.put( location, task );
|
||||
|
||||
task.type = ChunkTaskType.LOAD;
|
||||
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();
|
||||
try {
|
||||
tasks.put( location, task );
|
||||
|
||||
if ( !applyUpdatesToMesh( location ) ) {
|
||||
// Not good! Piston issue somewhere
|
||||
}
|
||||
|
||||
task.type = ChunkTaskType.UNLOAD;
|
||||
task.task = Bukkit.getScheduler().runTaskAsynchronously( plugin, () -> {
|
||||
lock.lock();
|
||||
try {
|
||||
ChunkMesh mesh = chunkMeshes.get( location );
|
||||
if ( mesh != null ) {
|
||||
// Save the mesh
|
||||
cache.save( location, mesh );
|
||||
} else {
|
||||
// Not really good
|
||||
}
|
||||
|
||||
completeTask( location );
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} );
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
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 boolean applyUpdatesToMesh( ChunkLocation location ) {
|
||||
lock.lock();
|
||||
try {
|
||||
final Collection< Location > locations = updateLocations.get( location );
|
||||
final ChunkMesh mesh = chunkMeshes.get( location );
|
||||
|
||||
if ( locations != null && !locations.isEmpty() && mesh != null ) {
|
||||
locations.removeAll( update( mesh, locations ) );
|
||||
|
||||
return locations.isEmpty();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void generateSpareMesh( JavaPlugin plugin, World world, Collection< Vector > locations, Consumer< SparseMesh > callback ) {
|
||||
if ( locations.isEmpty() ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private SparseMesh generateSpareMesh( World world, Collection< Vector > locations ) {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
|
||||
boolean set = false;
|
||||
Vector min;
|
||||
Vector max;
|
||||
Vector min = new Vector();
|
||||
Vector max = new Vector();
|
||||
|
||||
for ( Vector v : locations ) {
|
||||
if ( !set ) {
|
||||
@@ -335,22 +480,19 @@ public class MeshEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
// Mesh the data and get the output
|
||||
final MeshResult meshResult = generateMeshFrom( polygons );
|
||||
|
||||
sparseMesh.planes = meshResult.meshes;
|
||||
sparseMesh.pointReferences = meshResult.points;
|
||||
|
||||
// DONE
|
||||
|
||||
return sparseMesh;
|
||||
Bukkit.getScheduler().runTaskAsynchronously( plugin, () -> {
|
||||
// Mesh the data and get the output
|
||||
final MeshResult meshResult = generateMeshFrom( polygons );
|
||||
|
||||
sparseMesh.planes = meshResult.meshes;
|
||||
sparseMesh.pointReferences = meshResult.points;
|
||||
|
||||
callback.accept( sparseMesh );
|
||||
} );
|
||||
}
|
||||
|
||||
private void generateMesh( final Chunk chunk ) {
|
||||
final long start = System.currentTimeMillis();
|
||||
final World world = chunk.getWorld();
|
||||
|
||||
final ChunkLocation chunkLocation = new ChunkLocation( chunk );
|
||||
// TODO Use ChunkSnapshot in the future
|
||||
private static void generateMesh( JavaPlugin plugin, World world, final Chunk chunk, Consumer< ChunkMesh > callback ) {
|
||||
final int worldMinHeight = world.getMinHeight();
|
||||
final int worldMaxHeight = world.getMaxHeight();
|
||||
final int worldHeight = worldMaxHeight - worldMinHeight;
|
||||
@@ -508,44 +650,15 @@ public class MeshEnvironment {
|
||||
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" );
|
||||
} );
|
||||
callback.accept( chunkMesh );
|
||||
} );
|
||||
}
|
||||
|
||||
private Collection< Location > update( final AbstractMesh mesh, final Collection< Location > locations ) {
|
||||
private static 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 > >();
|
||||
@@ -775,23 +888,10 @@ public class MeshEnvironment {
|
||||
// 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 ) {
|
||||
private static 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();
|
||||
@@ -875,9 +975,11 @@ public class MeshEnvironment {
|
||||
|
||||
// Add all vector references
|
||||
result.points = vertices;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private class CompleteMesh {
|
||||
private static class CompleteMesh {
|
||||
Mesh< RegionSimple > mesh;
|
||||
Collection< Polygon > triangles;
|
||||
|
||||
@@ -887,8 +989,17 @@ public class MeshEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
private class MeshResult {
|
||||
private static class MeshResult {
|
||||
Map< MinecraftPlane, PlaneMesh > meshes;
|
||||
TreeSet< VectorReference > points;
|
||||
}
|
||||
|
||||
private enum ChunkTaskType {
|
||||
LOAD, UNLOAD
|
||||
}
|
||||
|
||||
private class ChunkTask {
|
||||
BukkitTask task;
|
||||
ChunkTaskType type;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user