Updated the plugin to mesh chunks properly; Use the visual shape for chunk generation
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,3 +7,5 @@ new_chunks
|
|||||||
images
|
images
|
||||||
chunk_models
|
chunk_models
|
||||||
chunk_models_new
|
chunk_models_new
|
||||||
|
chunks_test
|
||||||
|
chunk_models_test
|
||||||
@@ -3,11 +3,17 @@ package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
|||||||
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.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.lang.SystemUtils;
|
import org.apache.commons.lang.SystemUtils;
|
||||||
@@ -36,11 +42,18 @@ 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.Polygon;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionRuleWinding;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.mesh.region.simple.RegionSimple.GluWindingRule;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.SubCommand;
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.SubCommand;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor.CommandExecutableMessage;
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor.CommandExecutableMessage;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.InputValidatorInt;
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.InputValidatorInt;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender.SenderValidatorPlayer;
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender.SenderValidatorPlayer;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation;
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Facet;
|
||||||
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.MeshBuilder;
|
||||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.FileUtil;
|
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.FileUtil;
|
||||||
import com.jme3.bullet.PhysicsSpace;
|
import com.jme3.bullet.PhysicsSpace;
|
||||||
import com.jme3.bullet.PhysicsSpace.BroadphaseType;
|
import com.jme3.bullet.PhysicsSpace.BroadphaseType;
|
||||||
@@ -52,8 +65,10 @@ import com.jme3.bullet.collision.PhysicsCollisionObject;
|
|||||||
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
|
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
|
||||||
import com.jme3.bullet.collision.shapes.CollisionShape;
|
import com.jme3.bullet.collision.shapes.CollisionShape;
|
||||||
import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
|
import com.jme3.bullet.collision.shapes.CompoundCollisionShape;
|
||||||
|
import com.jme3.bullet.collision.shapes.MeshCollisionShape;
|
||||||
import com.jme3.bullet.collision.shapes.PlaneCollisionShape;
|
import com.jme3.bullet.collision.shapes.PlaneCollisionShape;
|
||||||
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
|
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
|
||||||
|
import com.jme3.bullet.collision.shapes.infos.IndexedMesh;
|
||||||
import com.jme3.bullet.joints.New6Dof;
|
import com.jme3.bullet.joints.New6Dof;
|
||||||
import com.jme3.bullet.joints.PhysicsJoint;
|
import com.jme3.bullet.joints.PhysicsJoint;
|
||||||
import com.jme3.bullet.joints.motors.MotorParam;
|
import com.jme3.bullet.joints.motors.MotorParam;
|
||||||
@@ -65,7 +80,9 @@ import com.jme3.math.Quaternion;
|
|||||||
import com.jme3.math.Vector3f;
|
import com.jme3.math.Vector3f;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPosition;
|
import net.minecraft.core.BlockPosition;
|
||||||
|
import net.minecraft.server.level.WorldServer;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShapeCollision;
|
||||||
|
|
||||||
public class MiniePlugin extends JavaPlugin {
|
public class MiniePlugin extends JavaPlugin {
|
||||||
private static final int TIME_STEPS = 5;
|
private static final int TIME_STEPS = 5;
|
||||||
@@ -77,6 +94,8 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
private float tick = 0;
|
private float tick = 0;
|
||||||
private Map< PhysicsCollisionObject, AuxiliaryDisplayStruct > linkedDisplays = new HashMap< PhysicsCollisionObject, AuxiliaryDisplayStruct >();
|
private Map< PhysicsCollisionObject, AuxiliaryDisplayStruct > linkedDisplays = new HashMap< PhysicsCollisionObject, AuxiliaryDisplayStruct >();
|
||||||
|
|
||||||
|
private PhysicsRigidBody planeBody;
|
||||||
|
|
||||||
private Set< PhysicsCollisionObject > active = new HashSet< PhysicsCollisionObject >();
|
private Set< PhysicsCollisionObject > active = new HashSet< PhysicsCollisionObject >();
|
||||||
private Set< PhysicsCollisionObject > isTnt = new HashSet< PhysicsCollisionObject >();
|
private Set< PhysicsCollisionObject > isTnt = new HashSet< PhysicsCollisionObject >();
|
||||||
|
|
||||||
@@ -101,9 +120,9 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
|
|
||||||
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 Plane( new Vector3f( 0, 1, 0 ), 0 ) );
|
||||||
PhysicsRigidBody 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 );
|
||||||
space.setAccuracy( 1f / ( TIME_STEPS * 20f ) );
|
space.setAccuracy( 1f / ( TIME_STEPS * 20f ) );
|
||||||
|
|
||||||
space.addContactListener( new ContactListener() {
|
space.addContactListener( new ContactListener() {
|
||||||
@@ -139,9 +158,9 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
private void onChunkLoad( ChunkLoadEvent event ) {
|
private void onChunkLoad( ChunkLoadEvent event ) {
|
||||||
if ( event.getWorld().getName().equalsIgnoreCase( "world" ) ) {
|
if ( event.getWorld().getName().equalsIgnoreCase( "world" ) ) {
|
||||||
getLogger().info( "Loading chunk..." );
|
// getLogger().info( "Loading chunk..." );
|
||||||
// scanAndGenerate( event.getChunk() );
|
// scanAndGenerate( event.getChunk() );
|
||||||
saveChunk( event.getChunk() );
|
// saveChunk( event.getChunk() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,8 +177,8 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
}, this );
|
}, this );
|
||||||
|
|
||||||
|
|
||||||
getLogger().info( "There are " + Bukkit.getWorld( "world" ).getLoadedChunks().length + " chunks" );
|
// getLogger().info( "There are " + Bukkit.getWorld( "world" ).getLoadedChunks().length + " chunks" );
|
||||||
getLogger().info( "Converted " + saveAllChunks( Bukkit.getWorld( "world" ) ) );
|
// getLogger().info( "Converted " + saveAllChunks( Bukkit.getWorld( "world" ) ) );
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskTimer( this, () -> {
|
Bukkit.getScheduler().runTaskTimer( this, () -> {
|
||||||
if ( !paused ) {
|
if ( !paused ) {
|
||||||
@@ -279,9 +298,7 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
displayData = Material.TNT.createBlockData();
|
displayData = Material.TNT.createBlockData();
|
||||||
}
|
}
|
||||||
|
|
||||||
CraftBlockData data = ( CraftBlockData ) displayData;
|
BoundingBox[] boxes = convertFrom( getShape( displayData, null, BlockShapeType.VISUAL_SHAPE ) );
|
||||||
|
|
||||||
BoundingBox[] boxes = convertFrom( data.getState().f( null, null ) );
|
|
||||||
Vector blockCenter = calculateCenter( boxes );
|
Vector blockCenter = calculateCenter( boxes );
|
||||||
|
|
||||||
CollisionShape box;
|
CollisionShape box;
|
||||||
@@ -338,12 +355,10 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
loc.setDirection( new Vector( 0, 0, 0 ) );
|
loc.setDirection( new Vector( 0, 0, 0 ) );
|
||||||
|
|
||||||
BlockData displayData = Material.IRON_TRAPDOOR.createBlockData();
|
BlockData displayData = Material.IRON_TRAPDOOR.createBlockData();
|
||||||
CraftBlockData data = ( CraftBlockData ) displayData;
|
|
||||||
|
|
||||||
final Vector scale = new Vector( 5, 2, 5 );
|
final Vector scale = new Vector( 5, 2, 5 );
|
||||||
|
|
||||||
BlockPosition pos = new BlockPosition( loc.getBlockX(), loc.getBlockY(), loc.getBlockZ() );
|
BoundingBox[] boxes = convertFrom( getShape( displayData, loc, BlockShapeType.VISUAL_SHAPE ) );
|
||||||
BoundingBox[] boxes = convertFrom( data.getState().f( ( ( CraftWorld ) loc.getWorld() ).getHandle(), pos ) );
|
|
||||||
for ( BoundingBox box : boxes ) {
|
for ( BoundingBox box : boxes ) {
|
||||||
Vector min = box.getMin().multiply( scale );
|
Vector min = box.getMin().multiply( scale );
|
||||||
Vector max = box.getMax().multiply( scale );
|
Vector max = box.getMax().multiply( scale );
|
||||||
@@ -419,7 +434,30 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
Player player = ( Player ) sender;
|
Player player = ( Player ) sender;
|
||||||
|
|
||||||
player.sendMessage( "Registering chunk..." );
|
player.sendMessage( "Registering chunk..." );
|
||||||
player.sendMessage( "Registered " + scanAndGenerate( player.getLocation().getChunk() ) );
|
scanAndGenerate( player.getLocation().getChunk() );
|
||||||
|
} ) )
|
||||||
|
.add( new SubCommand( "plane" )
|
||||||
|
.defaultTo( ( sender, args, params ) -> {
|
||||||
|
Player player = ( Player ) sender;
|
||||||
|
|
||||||
|
if ( planeBody != null ) {
|
||||||
|
if ( planeBody.getCollisionGroup() == PhysicsCollisionObject.COLLISION_GROUP_01 ) {
|
||||||
|
player.sendMessage( "Disabling plane" );
|
||||||
|
planeBody.setCollisionGroup( PhysicsCollisionObject.COLLISION_GROUP_02 );
|
||||||
|
} else {
|
||||||
|
player.sendMessage( "Enabling plane" );
|
||||||
|
planeBody.setCollisionGroup( PhysicsCollisionObject.COLLISION_GROUP_01 );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
player.sendMessage( "Plane does not exist!" );
|
||||||
|
}
|
||||||
|
} ) )
|
||||||
|
.add( new SubCommand( "save" )
|
||||||
|
.defaultTo( ( sender, args, params ) -> {
|
||||||
|
Player player = ( Player ) sender;
|
||||||
|
|
||||||
|
player.sendMessage( "Saving chunk..." );
|
||||||
|
player.sendMessage( "Saved " + saveChunk( player.getLocation().getChunk() ) + " boxes" );
|
||||||
} ) )
|
} ) )
|
||||||
.add( new SubCommand( "toggle" )
|
.add( new SubCommand( "toggle" )
|
||||||
.defaultTo( ( sender, args, params ) -> {
|
.defaultTo( ( sender, args, params ) -> {
|
||||||
@@ -489,18 +527,16 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
try ( FileWriter writer = new FileWriter( saveFile ) ) {
|
try ( FileWriter writer = new FileWriter( saveFile ) ) {
|
||||||
World world = chunk.getWorld();
|
World world = chunk.getWorld();
|
||||||
for ( int y = world.getMinHeight(); y < world.getMaxHeight(); y++ ) {
|
for ( int y = world.getMinHeight(); y < world.getMaxHeight(); ++y ) {
|
||||||
for ( int z = 0; z < 16; z++ ) {
|
for ( int z = 0; z < 16; ++z ) {
|
||||||
for ( int x = 0; x < 16; x++ ) {
|
for ( int x = 0; x < 16; ++x ) {
|
||||||
Block block = chunk.getBlock( x, y, z );
|
Block block = chunk.getBlock( x, y, z );
|
||||||
if ( !( block.isEmpty() && block.isLiquid() ) ) {
|
if ( !( block.isEmpty() && block.isLiquid() ) ) {
|
||||||
BlockState state = block.getState();
|
BlockState state = block.getState();
|
||||||
BlockData displayData = state.getBlockData();
|
BlockData data = state.getBlockData();
|
||||||
Location loc = block.getLocation();
|
Location loc = block.getLocation();
|
||||||
CraftBlockData data = ( CraftBlockData ) displayData;
|
|
||||||
|
|
||||||
BlockPosition pos = new BlockPosition( loc.getBlockX(), loc.getBlockY(), loc.getBlockZ() );
|
BoundingBox[] boxes = convertFrom( getShape( data, loc, BlockShapeType.VISUAL_SHAPE ) );
|
||||||
BoundingBox[] boxes = convertFrom( data.getState().f( ( ( CraftWorld ) world ).getHandle(), pos ) );
|
|
||||||
|
|
||||||
if ( boxes.length > 0 ) {
|
if ( boxes.length > 0 ) {
|
||||||
// Save this block
|
// Save this block
|
||||||
@@ -524,110 +560,148 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int scanAndGenerate( World world ) {
|
private void scanAndGenerate( World world ) {
|
||||||
int total = 0;
|
|
||||||
for ( Chunk chunk : world.getLoadedChunks() ) {
|
for ( Chunk chunk : world.getLoadedChunks() ) {
|
||||||
total += scanAndGenerate( chunk );
|
scanAndGenerate( chunk );
|
||||||
}
|
}
|
||||||
return total;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int scanAndGenerate( Chunk chunk ) {
|
private void scanAndGenerate( final Chunk chunk ) {
|
||||||
World world = chunk.getWorld();
|
final long start = System.currentTimeMillis();
|
||||||
CompoundCollisionShape compound = new CompoundCollisionShape();
|
|
||||||
int worldHeight = world.getMaxHeight() - world.getMinHeight();
|
final World world = chunk.getWorld();
|
||||||
boolean[][][] isSolid = new boolean[ worldHeight ][ 16 ][ 16 ];
|
final int worldMinHeight = world.getMinHeight();
|
||||||
for ( int y = 0; y < worldHeight; y++ ) {
|
final int worldMaxHeight = world.getMaxHeight();
|
||||||
for ( int z = 0; z < 16; z++ ) {
|
final Collection< BoundingBox > boxes = new ArrayDeque< BoundingBox >();
|
||||||
for ( int x = 0; x < 16; x++ ) {
|
getLogger().info( "Gathering bounding boxes..." );
|
||||||
Block block = chunk.getBlock( x, y + world.getMinHeight(), z );
|
for ( int y = worldMinHeight; y < worldMaxHeight; ++y ) {
|
||||||
|
for ( int z = 0; z < 16; ++z ) {
|
||||||
|
for ( int x = 0; x < 16; ++x ) {
|
||||||
|
Block block = chunk.getBlock( x, y, z );
|
||||||
if ( !( block.isEmpty() && block.isLiquid() ) ) {
|
if ( !( block.isEmpty() && block.isLiquid() ) ) {
|
||||||
BlockState state = block.getState();
|
final BlockData data = block.getBlockData();
|
||||||
BlockData displayData = state.getBlockData();
|
final Location loc = block.getLocation();
|
||||||
Location loc = block.getLocation();
|
|
||||||
CraftBlockData data = ( CraftBlockData ) displayData;
|
|
||||||
|
|
||||||
BlockPosition pos = new BlockPosition( loc.getBlockX(), loc.getBlockY(), loc.getBlockZ() );
|
// Start the box at 0, 0, 0
|
||||||
BoundingBox[] boxes = convertFrom( data.getState().f( ( ( CraftWorld ) world ).getHandle(), pos ) );
|
final BoundingBox[] boundingBoxes = convertFrom( getShape( data, loc, BlockShapeType.VISUAL_SHAPE ), new Vector( x, y - worldMinHeight, z ) );
|
||||||
|
|
||||||
if ( boxes.length == 1 && boxes[ 0 ].getVolume() == 1 ) {
|
for ( BoundingBox box : boundingBoxes ) {
|
||||||
isSolid[ y ][ z ][ x ] = true;
|
boxes.add( box );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( int y = 0; y < worldHeight; y++ ) {
|
Bukkit.getScheduler().runTaskAsynchronously( this, () -> {
|
||||||
for ( int z = 0; z < 16; z++ ) {
|
getLogger().info( "Building planes..." );
|
||||||
for ( int x = 0; x < 16; x++ ) {
|
final MeshBuilder builder = new MeshBuilder();
|
||||||
if ( x > 0 && x < 15 && z > 0 && z < 15 && y > 0 && y < worldHeight - 1 ) {
|
for ( final BoundingBox box : boxes ) {
|
||||||
// Figure out if this block is surrounded by solid blocks to avoid having to add this block
|
for ( final Facet facet : generateFacetsFor( box ) ) {
|
||||||
if ( isSolid[ y - 1 ][ z ][ x ]
|
builder.addFacet( facet );
|
||||||
&& isSolid[ y + 1 ][ z ][ x ]
|
}
|
||||||
&& isSolid[ y ][ z - 1 ][ x ]
|
|
||||||
&& isSolid[ y ][ z + 1 ][ x ]
|
|
||||||
&& isSolid[ y ][ z ][ x - 1 ]
|
|
||||||
&& isSolid[ y ][ z ][ x + 1 ] ) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLogger().info( "Meshing planes..." );
|
||||||
|
Collection< Facet > facets = builder.planes.parallelStream().flatMap( p -> process( p ).parallelStream().map( p::convert ) ).collect( Collectors.toSet() );
|
||||||
|
|
||||||
|
final class VectorRef {
|
||||||
|
int index;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block block = chunk.getBlock( x, y + world.getMinHeight(), z );
|
final class Triangle {
|
||||||
|
List< VectorRef > refs = new ArrayList< VectorRef >();
|
||||||
if ( !( block.isEmpty() && block.isLiquid() ) ) {
|
|
||||||
BlockState state = block.getState();
|
|
||||||
BlockData displayData = state.getBlockData();
|
|
||||||
Location loc = block.getLocation();
|
|
||||||
CraftBlockData data = ( CraftBlockData ) displayData;
|
|
||||||
|
|
||||||
BlockPosition pos = new BlockPosition( loc.getBlockX(), loc.getBlockY(), loc.getBlockZ() );
|
|
||||||
BoundingBox[] boxes = convertFrom( data.getState().f( ( ( CraftWorld ) world ).getHandle(), pos ) );
|
|
||||||
|
|
||||||
if ( boxes.length == 0 ) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( boxes.length == 1 ) {
|
final Map< Vector, VectorRef > vertices = new HashMap< Vector, VectorRef >();
|
||||||
Vector min = boxes[ 0 ].getMin();
|
final List< Triangle > triangles = new ArrayList< Triangle >();
|
||||||
Vector center = boxes[ 0 ].getCenter().subtract( min );
|
|
||||||
Vector3f halfExtents = new Vector3f( ( float ) center.getX(), ( float ) center.getY(), ( float ) center.getZ() );
|
|
||||||
|
|
||||||
CollisionShape shape = collisionShapes.get( halfExtents );
|
getLogger().info( "Generating triangles..." );
|
||||||
if ( shape == null ) {
|
// Convert each facet to a triangle
|
||||||
shape = new BoxCollisionShape( halfExtents );
|
for ( final Facet facet : facets ) {
|
||||||
collisionShapes.put( halfExtents, shape );
|
if ( facet.points.size() != 3 ) {
|
||||||
|
System.out.println( "Warning: Facet is not a triangle!" );
|
||||||
}
|
}
|
||||||
Vector3f shapeCenter = new Vector3f( ( float ) boxes[ 0 ].getCenterX() + x, ( float ) boxes[ 0 ].getCenterY() + y, ( float ) boxes[ 0 ].getCenterZ() + z );
|
|
||||||
compound.addChildShape( shape, shapeCenter );
|
final Triangle triangle = new Triangle();
|
||||||
|
for ( final Vector vec : facet.points ) {
|
||||||
|
VectorRef ref = null;
|
||||||
|
for ( final Entry< Vector, VectorRef > entry : vertices.entrySet() ) {
|
||||||
|
final Vector existingVec = entry.getKey();
|
||||||
|
|
||||||
|
if ( existingVec.distanceSquared( vec ) < 1e-8 ) {
|
||||||
|
ref = entry.getValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ref == null ) {
|
||||||
|
ref = new VectorRef();
|
||||||
|
vertices.put( vec, ref );
|
||||||
|
}
|
||||||
|
|
||||||
|
triangle.refs.add( ref );
|
||||||
|
}
|
||||||
|
triangles.add( triangle );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the vertices
|
||||||
|
final List< Entry< Vector, VectorRef > > sorted = new ArrayList< Entry< Vector, VectorRef > >( vertices.entrySet() );
|
||||||
|
Collections.sort( sorted, ( aEntry, bEntry ) -> {
|
||||||
|
final Vector a = aEntry.getKey();
|
||||||
|
final Vector b = bEntry.getKey();
|
||||||
|
|
||||||
|
final double xDiff = a.getX() - b.getX();
|
||||||
|
if ( xDiff == 0 ) {
|
||||||
|
final double yDiff = a.getY() - b.getY();
|
||||||
|
if ( yDiff == 0 ) {
|
||||||
|
return Double.compare( a.getZ(), b.getZ() );
|
||||||
} else {
|
} else {
|
||||||
for ( BoundingBox aabb : boxes ) {
|
return Double.compare( yDiff, 0 );
|
||||||
Vector min = aabb.getMin();
|
}
|
||||||
Vector center = aabb.getCenter();
|
} else {
|
||||||
Vector half = center.clone().subtract( min );
|
return Double.compare( xDiff, 0 );
|
||||||
Vector3f halfExtents = new Vector3f( ( float ) half.getX(), ( float ) half.getY(), ( float ) half.getZ() );
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
CollisionShape shape = collisionShapes.get( halfExtents );
|
getLogger().info( "Creating buffers..." );
|
||||||
if ( shape == null ) {
|
final Vector3f[] positionArray = new Vector3f[ sorted.size() ];
|
||||||
shape = new BoxCollisionShape( halfExtents );
|
for ( int i = 0; i < sorted.size(); ++i ) {
|
||||||
collisionShapes.put( halfExtents, shape );
|
final Entry< Vector, VectorRef > entry = sorted.get( i );
|
||||||
}
|
entry.getValue().index = i;
|
||||||
compound.addChildShape( shape, ( float ) center.getX() + x, ( float ) center.getY() + y, ( float ) center.getZ() + z );
|
|
||||||
}
|
final Vector vector = entry.getKey();
|
||||||
}
|
|
||||||
}
|
positionArray[ i ] = new Vector3f( ( float ) vector.getX(), ( float ) vector.getY(), ( float ) vector.getZ() );
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getLogger().info( "Chunk has " + compound.countChildren() );
|
final int[] indexArray = new int[ triangles.size() * 3 ];
|
||||||
|
for ( int i = 0; i < triangles.size(); ++i ) {
|
||||||
|
final Triangle triangle = triangles.get( i );
|
||||||
|
if ( triangle.refs.size() != 3 ) {
|
||||||
|
throw new IllegalStateException( "Triangle does not have exactly 3 vertices!" );
|
||||||
|
}
|
||||||
|
|
||||||
|
final int indexArrayStart = i * 3;
|
||||||
|
indexArray[ indexArrayStart ] = triangle.refs.get( 0 ).index;
|
||||||
|
indexArray[ indexArrayStart + 1 ] = triangle.refs.get( 1 ).index;
|
||||||
|
indexArray[ indexArrayStart + 2 ] = triangle.refs.get( 2 ).index;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogger().info( "Adding mesh collision shape..." );
|
||||||
|
final IndexedMesh nativeMesh = new IndexedMesh( positionArray, indexArray );
|
||||||
|
// Enable quantized AABB compression... hopefully that doesn't mess with the accuracy or anything...
|
||||||
|
final MeshCollisionShape mesh = new MeshCollisionShape( true, nativeMesh );
|
||||||
|
|
||||||
|
getLogger().info( "Mesh has " + mesh.countMeshVertices() + " vertices and " + mesh.countMeshTriangles() + " triangles" );
|
||||||
|
|
||||||
// Create a rigid body
|
// Create a rigid body
|
||||||
PhysicsRigidBody rigid = new PhysicsRigidBody( compound, PhysicsBody.massForStatic );
|
PhysicsRigidBody rigid = new PhysicsRigidBody( mesh, PhysicsBody.massForStatic );
|
||||||
rigid.setPhysicsLocation( new Vector3f( chunk.getX() << 4, world.getMinHeight(), chunk.getZ() << 4 ) );
|
rigid.setPhysicsLocation( new Vector3f( chunk.getX() << 4, world.getMinHeight(), chunk.getZ() << 4 ) );
|
||||||
rigid.setPhysicsRotation( new Quaternion( 0, 0, 0, 1 ) );
|
rigid.setPhysicsRotation( new Quaternion( 0, 0, 0, 1 ) );
|
||||||
|
rigid.setKinematic( false );
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTask( this, () -> {
|
||||||
space.addCollisionObject( rigid );
|
space.addCollisionObject( rigid );
|
||||||
|
|
||||||
PhysicsRigidBody old = chunks.put( new ChunkLocation( chunk ), rigid );
|
PhysicsRigidBody old = chunks.put( new ChunkLocation( chunk ), rigid );
|
||||||
@@ -635,19 +709,19 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
getLogger().warning( "Old rigid body found!" );
|
getLogger().warning( "Old rigid body found!" );
|
||||||
space.remove( old );
|
space.remove( old );
|
||||||
}
|
}
|
||||||
|
getLogger().info( "Done!" );
|
||||||
return compound.countChildren();
|
final long time = System.currentTimeMillis() - start;
|
||||||
|
getLogger().info( "Took " + time + "ms" );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean convert( Block block ) {
|
private boolean convert( Block block ) {
|
||||||
BlockState state = block.getState();
|
BlockState state = block.getState();
|
||||||
BlockData displayData = state.getBlockData();
|
BlockData data = state.getBlockData();
|
||||||
Location loc = block.getLocation();
|
Location loc = block.getLocation();
|
||||||
|
|
||||||
CraftBlockData data = ( CraftBlockData ) displayData;
|
BoundingBox[] boxes = convertFrom( getShape( data, loc, BlockShapeType.VISUAL_SHAPE ) );
|
||||||
|
|
||||||
BlockPosition pos = new BlockPosition( loc.getBlockX(), loc.getBlockY(), loc.getBlockZ() );
|
|
||||||
BoundingBox[] boxes = convertFrom( data.getState().f( ( ( CraftWorld ) loc.getWorld() ).getHandle(), pos ) );
|
|
||||||
Vector blockCenter = calculateCenter( boxes );
|
Vector blockCenter = calculateCenter( boxes );
|
||||||
|
|
||||||
CollisionShape box;
|
CollisionShape box;
|
||||||
@@ -714,6 +788,15 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Collection< Polygon > process( final com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh.Plane plane ) {
|
||||||
|
final Mesh< RegionSimple > mesh = new Mesh< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||||
|
for ( Polygon poly : plane.polygons ) {
|
||||||
|
mesh.addPolygon( poly, RegionRuleWinding.CLOCKWISE );
|
||||||
|
}
|
||||||
|
|
||||||
|
return mesh.meshify();
|
||||||
|
}
|
||||||
|
|
||||||
private static Vector calculateCenter( BoundingBox[] boxes ) {
|
private static Vector calculateCenter( BoundingBox[] boxes ) {
|
||||||
Vector center = new Vector( 0, 0, 0 );
|
Vector center = new Vector( 0, 0, 0 );
|
||||||
// TODO Throw error, probably
|
// TODO Throw error, probably
|
||||||
@@ -730,12 +813,117 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
return center.multiply( 1 / totalVolume );
|
return center.multiply( 1 / totalVolume );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BoundingBox[] convertFrom( VoxelShape shape ) {
|
// 1.21.5
|
||||||
|
private 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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundingBox[] convertFrom( final VoxelShape shape ) {
|
||||||
|
return convertFrom( shape, new Vector() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundingBox[] convertFrom( final VoxelShape shape, final Vector offset ) {
|
||||||
return shape.e().stream()
|
return shape.e().stream()
|
||||||
.map( aabb -> { return new BoundingBox( aabb.a, aabb.b, aabb.c, aabb.d, aabb.e, aabb.f ); } )
|
.map( aabb -> { return new BoundingBox( aabb.a, aabb.b, aabb.c, aabb.d, aabb.e, aabb.f ).shift( offset ); } )
|
||||||
.toArray( BoundingBox[]::new );
|
.toArray( BoundingBox[]::new );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List< Facet > generateFacetsFor( BoundingBox box ) {
|
||||||
|
List< Facet > facets = new ArrayList< Facet >();
|
||||||
|
|
||||||
|
Vector p1 = new Vector( box.getMinX(), box.getMinY(), box.getMinZ() );
|
||||||
|
Vector p2 = new Vector( box.getMinX(), box.getMinY(), box.getMaxZ() );
|
||||||
|
Vector p3 = new Vector( box.getMinX(), box.getMaxY(), box.getMinZ() );
|
||||||
|
Vector p4 = new Vector( box.getMinX(), box.getMaxY(), box.getMaxZ() );
|
||||||
|
Vector p5 = new Vector( box.getMaxX(), box.getMinY(), box.getMinZ() );
|
||||||
|
Vector p6 = new Vector( box.getMaxX(), box.getMinY(), box.getMaxZ() );
|
||||||
|
Vector p7 = new Vector( box.getMaxX(), box.getMaxY(), box.getMinZ() );
|
||||||
|
Vector p8 = new Vector( box.getMaxX(), box.getMaxY(), box.getMaxZ() );
|
||||||
|
|
||||||
|
{
|
||||||
|
Facet facet = new Facet();
|
||||||
|
facet.points.add( p1 );
|
||||||
|
facet.points.add( p2 );
|
||||||
|
facet.points.add( p4 );
|
||||||
|
facet.points.add( p3 );
|
||||||
|
facet.normal = new Vector( -1, 0, 0 );
|
||||||
|
facets.add( facet );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Facet facet = new Facet();
|
||||||
|
facet.points.add( p5 );
|
||||||
|
facet.points.add( p6 );
|
||||||
|
facet.points.add( p8 );
|
||||||
|
facet.points.add( p7 );
|
||||||
|
facet.normal = new Vector( 1, 0, 0 );
|
||||||
|
facets.add( facet );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Facet facet = new Facet();
|
||||||
|
facet.points.add( p1 );
|
||||||
|
facet.points.add( p2 );
|
||||||
|
facet.points.add( p6 );
|
||||||
|
facet.points.add( p5 );
|
||||||
|
facet.normal = new Vector( 0, -1, 0 );
|
||||||
|
facets.add( facet );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Facet facet = new Facet();
|
||||||
|
facet.points.add( p3 );
|
||||||
|
facet.points.add( p4 );
|
||||||
|
facet.points.add( p8 );
|
||||||
|
facet.points.add( p7 );
|
||||||
|
facet.normal = new Vector( 0, 1, 0 );
|
||||||
|
facets.add( facet );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Facet facet = new Facet();
|
||||||
|
facet.points.add( p1 );
|
||||||
|
facet.points.add( p3 );
|
||||||
|
facet.points.add( p7 );
|
||||||
|
facet.points.add( p5 );
|
||||||
|
facet.normal = new Vector( 0, 0, -1 );
|
||||||
|
facets.add( facet );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Facet facet = new Facet();
|
||||||
|
facet.points.add( p2 );
|
||||||
|
facet.points.add( p4 );
|
||||||
|
facet.points.add( p8 );
|
||||||
|
facet.points.add( p6 );
|
||||||
|
facet.normal = new Vector( 0, 0, 1 );
|
||||||
|
facets.add( facet );
|
||||||
|
}
|
||||||
|
|
||||||
|
return facets;
|
||||||
|
}
|
||||||
|
|
||||||
private class JointStruct {
|
private class JointStruct {
|
||||||
BlockState state;
|
BlockState state;
|
||||||
PhysicsRigidBody object;
|
PhysicsRigidBody object;
|
||||||
@@ -765,4 +953,13 @@ public class MiniePlugin extends JavaPlugin {
|
|||||||
Vector offset;
|
Vector offset;
|
||||||
Vector scale;
|
Vector scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum BlockShapeType {
|
||||||
|
SHAPE,
|
||||||
|
COLLISION_SHAPE,
|
||||||
|
VISUAL_SHAPE,
|
||||||
|
INTERACTION_SHAPE,
|
||||||
|
BLOCK_SUPPORT_SHAPE
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user