Initial commit for historical purposes
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
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.objects.mesh.Plane;
|
||||
|
||||
public class MeshTest {
|
||||
private static final File BASE = new File( System.getProperty( "user.dir" ) );
|
||||
private static final File CHUNK_DIR = new File( BASE, "chunks" );
|
||||
|
||||
public static void main( String[] args ) {
|
||||
if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) {
|
||||
System.out.println( "Found " + CHUNK_DIR.list().length + " files" );
|
||||
for ( File file : CHUNK_DIR.listFiles() ) {
|
||||
doStuff( file );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
System.err.println( "No such directory exists: " + CHUNK_DIR );
|
||||
}
|
||||
}
|
||||
|
||||
private static void doStuff( File file ) {
|
||||
String name = file.getName();
|
||||
String[] split = name.split( "," );
|
||||
ChunkLocation location = new ChunkLocation( split[ 0 ], Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) );
|
||||
|
||||
System.out.println( "Parsing chunk " + location );
|
||||
|
||||
// First parse the file to get a list of all bounding boxes that we can use
|
||||
List< AABB > boxes = new ArrayList< AABB >();
|
||||
try ( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
|
||||
String line;
|
||||
while ( ( line = reader.readLine() ) != null ) {
|
||||
if ( !line.isEmpty() ) {
|
||||
String[] values = line.split( "," );
|
||||
double minX = Double.parseDouble( values[ 0 ] );
|
||||
double minY = Double.parseDouble( values[ 1 ] );
|
||||
double minZ = Double.parseDouble( values[ 2 ] );
|
||||
double maxX = Double.parseDouble( values[ 3 ] );
|
||||
double maxY = Double.parseDouble( values[ 4 ] );
|
||||
double maxZ = Double.parseDouble( values[ 5 ] );
|
||||
boxes.add( new AABB( minX, minY, minZ, maxX, maxY, maxZ ) );
|
||||
}
|
||||
}
|
||||
} catch ( FileNotFoundException e ) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println( "Found " + boxes.size() + " boxes" );
|
||||
// Now that we have a bunch of bounding boxes, do whatever
|
||||
|
||||
MeshBuilder builder = new MeshBuilder();
|
||||
int i = 0;
|
||||
for ( AABB box : boxes ) {
|
||||
for ( Facet facet : generateFacetsFor( box ) ) {
|
||||
builder.addFacet( facet );
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println( "Planes: " + builder.planes.size() );
|
||||
for ( Plane plane : builder.planes ) {
|
||||
System.out.println( "Plane" );
|
||||
System.out.println( "Norm:\t" + plane.normal );
|
||||
System.out.println( "Ref:\t" + plane.point );
|
||||
System.out.println( "Size:\t" + plane.polygons.size() );
|
||||
}
|
||||
|
||||
/*
|
||||
* The general plan is as follows:
|
||||
* - Create a new mesh object
|
||||
* - Insert faces one by one until we have all the shapes we want
|
||||
* - In this case, it happens to be perfect AABB
|
||||
* - Process the faces
|
||||
* - Sort them into their correct plane of existence, along with their normal
|
||||
* - In this case, their unique plane can be defined by their normal, and a point
|
||||
* - Use the first point of the polygon to compare
|
||||
* - Use the smallest point we can find as the reference point
|
||||
* - O(1) operation per face, I suppose
|
||||
* - Need to check point and normal with tolerance which is why
|
||||
* - Now that we have faces each in their assorted group, we can start to tessellate each one
|
||||
* - Generate even/odd regions and remove any colinear edges
|
||||
* - Save this as the pre-mesh
|
||||
* - Now trianglate each group and put that into a mesh collision shape or gimpact shape or whatnot
|
||||
* - Use an IndexedMesh with the two array constructor
|
||||
* - Put into game and test
|
||||
*/
|
||||
}
|
||||
|
||||
private static List< Facet > generateFacetsFor( AABB box ) {
|
||||
List< Facet > facets = new ArrayList< Facet >();
|
||||
|
||||
Vector p1 = new Vector( box.xmin, box.ymin, box.zmin );
|
||||
Vector p2 = new Vector( box.xmin, box.ymin, box.zmax );
|
||||
Vector p3 = new Vector( box.xmin, box.ymax, box.zmin );
|
||||
Vector p4 = new Vector( box.xmin, box.ymax, box.zmax );
|
||||
Vector p5 = new Vector( box.xmax, box.ymin, box.zmin );
|
||||
Vector p6 = new Vector( box.xmax, box.ymin, box.zmax );
|
||||
Vector p7 = new Vector( box.xmax, box.ymax, box.zmin );
|
||||
Vector p8 = new Vector( box.xmax, box.ymax, box.zmax );
|
||||
|
||||
{
|
||||
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( p7 );
|
||||
facet.points.add( p8 );
|
||||
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;
|
||||
}
|
||||
|
||||
static class AABB {
|
||||
double xmin, ymin, zmin;
|
||||
double xmax, ymax, zmax;
|
||||
|
||||
AABB( double xmin, double ymin, double zmin, double xmax, double ymax, double zmax ) {
|
||||
this.xmin = xmin;
|
||||
this.ymax = ymin;
|
||||
this.zmin = zmin;
|
||||
|
||||
this.xmax = xmax;
|
||||
this.ymax = ymax;
|
||||
this.zmax = zmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.MeshTest.AABB;
|
||||
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.objects.mesh.Plane;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.Point;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.Polygon;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.Tess4j;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.Vector2d;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.Vector2dComparator;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.region.RegionSimple;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.region.RegionSimple.GluWindingRule;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.region.WindingRuleSimple;
|
||||
|
||||
public class MeshingTest extends JPanel {
|
||||
private static final File BASE = new File( System.getProperty( "user.dir" ) );
|
||||
private static final File CHUNK_DIR = new File( BASE, "chunks" );
|
||||
|
||||
JFrame f;
|
||||
|
||||
private int windowWidth = 1200;
|
||||
private int windowHeight = 1000;
|
||||
|
||||
private int centerX = 400; // 600
|
||||
private int centerY = 1000; // 400
|
||||
|
||||
private Graphics g;
|
||||
|
||||
private int scale = 10;
|
||||
|
||||
private List< Polygon > data;
|
||||
|
||||
public static void main( String[] args ) {
|
||||
if ( CHUNK_DIR.exists() && CHUNK_DIR.isDirectory() ) {
|
||||
System.out.println( "Found " + CHUNK_DIR.list().length + " files" );
|
||||
for ( File file : CHUNK_DIR.listFiles() ) {
|
||||
List< Polygon > polys = mesh( file );
|
||||
SwingUtilities.invokeLater( new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new MeshingTest( polys );
|
||||
}
|
||||
} );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
System.err.println( "No such directory exists: " + CHUNK_DIR );
|
||||
}
|
||||
}
|
||||
|
||||
private static List< Polygon > mesh( File file ) {
|
||||
String name = file.getName();
|
||||
String[] split = name.split( "," );
|
||||
ChunkLocation location = new ChunkLocation( split[ 0 ], Integer.parseInt( split[ 1 ] ), Integer.parseInt( split[ 2 ] ) );
|
||||
|
||||
System.out.println( "Parsing chunk " + location );
|
||||
|
||||
// First parse the file to get a list of all bounding boxes that we can use
|
||||
List< AABB > boxes = new ArrayList< AABB >();
|
||||
try ( BufferedReader reader = new BufferedReader( new FileReader( file ) ) ) {
|
||||
String line;
|
||||
while ( ( line = reader.readLine() ) != null ) {
|
||||
if ( !line.isEmpty() ) {
|
||||
String[] values = line.split( "," );
|
||||
double minX = Double.parseDouble( values[ 0 ] );
|
||||
double minY = Double.parseDouble( values[ 1 ] );
|
||||
double minZ = Double.parseDouble( values[ 2 ] );
|
||||
double maxX = Double.parseDouble( values[ 3 ] );
|
||||
double maxY = Double.parseDouble( values[ 4 ] );
|
||||
double maxZ = Double.parseDouble( values[ 5 ] );
|
||||
boxes.add( new AABB( minX, minY, minZ, maxX, maxY, maxZ ) );
|
||||
}
|
||||
}
|
||||
} catch ( FileNotFoundException e ) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
System.out.println( "Found " + boxes.size() + " boxes" );
|
||||
// Now that we have a bunch of bounding boxes, do whatever
|
||||
|
||||
MeshBuilder builder = new MeshBuilder();
|
||||
Plane draw = null;
|
||||
for ( AABB box : boxes ) {
|
||||
for ( Facet facet : generateFacetsFor( box ) ) {
|
||||
builder.addFacet( facet );
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println( "Planes: " + builder.planes.size() );
|
||||
for ( Plane plane : builder.planes ) {
|
||||
if ( plane.polygons.size() > 100 ) {
|
||||
draw = plane;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( Plane plane : builder.planes ) {
|
||||
try {
|
||||
Tess4j< RegionSimple > tess4j = new Tess4j< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||
for ( Polygon poly : plane.polygons ) {
|
||||
tess4j.addPolygon( poly, new WindingRuleSimple() );
|
||||
}
|
||||
tess4j.tessellate();
|
||||
} catch ( IllegalStateException e ) {
|
||||
e.printStackTrace();
|
||||
|
||||
draw = plane;
|
||||
// Tess4j< RegionSimple > tess4j = new Tess4j< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||
// tess4j.setDebug( true );
|
||||
// System.out.println( "Polygon count: " + plane.polygons.size() );
|
||||
// for ( Polygon poly : plane.polygons ) {
|
||||
// tess4j.addPolygon( poly, new WindingRuleSimple() );
|
||||
// }
|
||||
// tess4j.tessellate();
|
||||
}
|
||||
}
|
||||
|
||||
if ( draw != null ) {
|
||||
System.out.println( "Norm:\t" + draw.normal );
|
||||
System.out.println( "Ref:\t" + draw.point );
|
||||
System.out.println( "Size:\t" + draw.polygons.size() );
|
||||
|
||||
Tess4j< RegionSimple > tess4j = new Tess4j< RegionSimple >( () -> { return new RegionSimple( GluWindingRule.ODD ); } );
|
||||
tess4j.setDebug( true );
|
||||
for ( int i = 0; i < draw.polygons.size(); i++ ) {
|
||||
if ( i >= 4 ) {
|
||||
break;
|
||||
}
|
||||
|
||||
Polygon poly = draw.polygons.get( i );
|
||||
|
||||
System.out.println( "Adding polygon " + poly.getPoints().size() );
|
||||
for ( Point point : poly.getPoints() ) {
|
||||
System.out.println( point.getX() + ", " + point.getY() );
|
||||
}
|
||||
|
||||
tess4j.addPolygon( poly, new WindingRuleSimple() );
|
||||
}
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
tess4j.tessellate();
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println( "Took " + ( end - start ) + "ms" );
|
||||
|
||||
return tess4j.getPolygons();
|
||||
} else {
|
||||
System.out.println( "No data!" );
|
||||
}
|
||||
|
||||
return new ArrayList< Polygon >();
|
||||
}
|
||||
|
||||
private static List< Facet > generateFacetsFor( AABB box ) {
|
||||
List< Facet > facets = new ArrayList< Facet >();
|
||||
|
||||
Vector p1 = new Vector( box.xmin, box.ymin, box.zmin );
|
||||
Vector p2 = new Vector( box.xmin, box.ymin, box.zmax );
|
||||
Vector p3 = new Vector( box.xmin, box.ymax, box.zmin );
|
||||
Vector p4 = new Vector( box.xmin, box.ymax, box.zmax );
|
||||
Vector p5 = new Vector( box.xmax, box.ymin, box.zmin );
|
||||
Vector p6 = new Vector( box.xmax, box.ymin, box.zmax );
|
||||
Vector p7 = new Vector( box.xmax, box.ymax, box.zmin );
|
||||
Vector p8 = new Vector( box.xmax, box.ymax, box.zmax );
|
||||
|
||||
{
|
||||
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( p7 );
|
||||
facet.points.add( p8 );
|
||||
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;
|
||||
}
|
||||
|
||||
static class AABB {
|
||||
double xmin, ymin, zmin;
|
||||
double xmax, ymax, zmax;
|
||||
|
||||
AABB( double xmin, double ymin, double zmin, double xmax, double ymax, double zmax ) {
|
||||
this.xmin = xmin;
|
||||
this.ymin = ymin;
|
||||
this.zmin = zmin;
|
||||
|
||||
this.xmax = xmax;
|
||||
this.ymax = ymax;
|
||||
this.zmax = zmax;
|
||||
}
|
||||
|
||||
double getVolume() {
|
||||
return ( xmax - xmin ) * ( ymax - ymin ) * ( zmax - zmin );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format( "(%f, %f, %f) -> (%f, %f, %f)", xmin, ymin, zmin, xmax, ymax, zmax );
|
||||
}
|
||||
}
|
||||
|
||||
public MeshingTest( List< Polygon > polys) {
|
||||
data = polys;
|
||||
|
||||
f = new JFrame( "Drawing Board" );
|
||||
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
|
||||
|
||||
f.add( this );
|
||||
|
||||
f.setSize( windowWidth, windowHeight );
|
||||
f.setVisible( true );
|
||||
f.setResizable( true );
|
||||
|
||||
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
|
||||
}
|
||||
|
||||
public void drawPoint( double x, double y ) {
|
||||
g.fillRect( ( int ) x * scale, ( int ) y * scale, scale, scale );
|
||||
}
|
||||
|
||||
private static Vector2d rotate( Vector2d a, double angle ) {
|
||||
double cos = Math.cos( angle );
|
||||
double sin = Math.sin( angle );
|
||||
double ax = a.getX() * cos - a.getY() * sin;
|
||||
double ay = a.getX() * sin + a.getY() * cos;
|
||||
return new Vector2d( ax, ay );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent( Graphics g ) {
|
||||
super.paintComponent( g );
|
||||
this.g = g;
|
||||
|
||||
// Vertex v = null;
|
||||
// for ( int i = 0; i < 100; i++ ) {
|
||||
// double deg = Math.random() * 360;
|
||||
// double dist = Math.random() * 100 + 100;
|
||||
// double x = dist * Math.cos( Math.toRadians( deg ) );
|
||||
// double y = dist * Math.sin( Math.toRadians( deg ) );
|
||||
// HalfWing edge = new HalfWing();
|
||||
// edge.getDest().setPosition( new Vector2d( x, y ) );
|
||||
// if ( v == null ) {
|
||||
// v = edge.getOrigin();
|
||||
// } else {
|
||||
// HalfWing.splice( edge, v.getWing() );
|
||||
// }
|
||||
// }
|
||||
// v.update();
|
||||
//
|
||||
// HalfWing edge = v.getWing();
|
||||
// int i = 0;
|
||||
// double ic = 0;
|
||||
// do {
|
||||
// Vector2d dest = edge.getDest().getPosition();
|
||||
// g.drawLine( centerX, centerY, ( int ) dest.getX() + centerX, ( int ) dest.getY() + centerY );
|
||||
// dest = dest.normalized();
|
||||
// g.drawString( i++ + "", ( int ) ( dest.x * 200 * ( ic + 1.1 ) ) + centerX, ( int ) ( dest.y * 200 * ( ic + 1.1 ) ) + centerY );
|
||||
// ic = ( ic + 0.07 ) % .7;
|
||||
// edge = edge.getPrev();
|
||||
// } while ( edge != v.getWing() );
|
||||
//
|
||||
// v.sort();
|
||||
//
|
||||
// g.drawLine( centerX + 700, centerY, centerX + 700, centerY - 400 );
|
||||
// edge = v.getWing();
|
||||
// i = 0;
|
||||
// ic = 0;
|
||||
// do {
|
||||
// Vector2d dest = edge.getDest().getPosition();
|
||||
// g.drawLine( centerX + 700, centerY, ( int ) dest.getX() + centerX + 700, ( int ) dest.y + centerY );
|
||||
// dest = dest.normalized();
|
||||
// g.drawString( i++ + "", ( int ) ( dest.x * 200 * ( ic + 1.1 ) ) + centerX + 700, ( int ) ( dest.y * 200 * ( ic + 1.1 ) ) + centerY );
|
||||
// ic = ( ic + 0.07 ) % .7;
|
||||
// edge = edge.getPrev();
|
||||
// } while ( edge != v.getWing() );
|
||||
|
||||
List< Polygon > polygons = data;
|
||||
|
||||
System.out.println( "Polygon count: " + polygons.size() );
|
||||
System.out.println( polygons.size() );
|
||||
for ( Polygon p : polygons ) {
|
||||
List< Point > points = p.getPoints();
|
||||
// System.out.println( points.size() );
|
||||
int size = points.size();
|
||||
int[] xPoints = new int[ size ];
|
||||
int[] yPoints = new int[ size ];
|
||||
|
||||
for ( int i = 0; i < points.size(); i++ ) {
|
||||
Point point = points.get( i );
|
||||
|
||||
// System.out.println( point.getX() + ", " + point.getY() );
|
||||
Vector2d pVec = new Vector2d( point.getX(), point.getY() );
|
||||
pVec = rotate( pVec, 0 );
|
||||
point = new Point( pVec.getX(), pVec.getY() );
|
||||
|
||||
xPoints[ i ] = ( int ) ( point.getX() * scale ) + centerX;
|
||||
yPoints[ i ] = 100 - ( int ) ( point.getY() * scale ) + centerY;
|
||||
}
|
||||
|
||||
g.setColor( new Color( ( int ) ( Math.random() * 0xFFFFFF ) ) );
|
||||
g.fillPolygon( xPoints, yPoints, size );
|
||||
}
|
||||
|
||||
g.setColor( Color.BLACK );
|
||||
for ( Polygon p : polygons ) {
|
||||
for ( Point point : p.getPoints() ) {
|
||||
Vector2d pVec = new Vector2d( point.getX(), point.getY() );
|
||||
pVec = rotate( pVec, 0 );
|
||||
point = new Point( pVec.getX(), pVec.getY() );
|
||||
|
||||
double diff = scale * .05;
|
||||
g.drawRect( ( int ) ( point.getX() * scale ) + centerX - ( int ) diff, 100 - ( int ) ( point.getY() * scale ) + centerY - ( int ) diff, ( int ) ( diff * 2 ), ( int ) ( diff * 2 ) );
|
||||
}
|
||||
}
|
||||
|
||||
g.drawLine( centerX, 0, centerX, 2000 );
|
||||
g.drawLine( 0, centerY + 100, 2000, centerY + 100 );
|
||||
|
||||
// Point[] points = {
|
||||
// new Point( 0, -2 ),
|
||||
// new Point( 1.5, -3.0 ),
|
||||
// new Point( 0.0, -2.0 ),
|
||||
// new Point( 0.9545454545454546, -1.3636363636363638 ),
|
||||
// new Point( -0.8333333333333334, -1.0 ),
|
||||
// new Point( 0.8333333333333334, -1.0 ),
|
||||
// new Point( -0.5, 0.0 ),
|
||||
// new Point( 0.5, 0.0 ),
|
||||
// new Point( -0.16666666666666669, 1.0 ),
|
||||
// new Point( 0.16666666666666669, 1.0 ),
|
||||
// new Point( -0.16666666666666669, 1.0 ),
|
||||
// new Point( 1, 1 ),
|
||||
// new Point( -0.16666666666666669, 1.0 ),
|
||||
// new Point( 0, 1.5 ),
|
||||
// new Point( 0, 1.5 ),
|
||||
// new Point( 0.16666666666666669, 1.0 ),
|
||||
// new Point( -1, 2 ),
|
||||
// new Point( 1, 2 ),
|
||||
// };
|
||||
//
|
||||
// int size = points.length >> 1;
|
||||
// for ( int i = 0; i < size;i++ ) {
|
||||
// Point a = points[ i << 1 ];
|
||||
// Point b = points[ ( i << 1 ) + 1 ];
|
||||
//
|
||||
// g.drawLine( ( int ) ( a.x * scale ) + centerX, ( int ) ( a.y * scale ) + centerY, ( int ) ( b.x * scale ) + centerX, ( int ) ( b.y * scale ) + centerY );
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,768 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
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.apache.commons.lang.SystemUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_21_R4.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_21_R4.block.data.CraftBlockData;
|
||||
import org.bukkit.entity.BlockDisplay;
|
||||
import org.bukkit.entity.Display;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
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.minietest.command.SubCommand;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor.CommandExecutableMessage;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.InputValidatorInt;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender.SenderValidatorPlayer;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.objects.ChunkLocation;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.FileUtil;
|
||||
import com.jme3.bullet.PhysicsSpace;
|
||||
import com.jme3.bullet.PhysicsSpace.BroadphaseType;
|
||||
import com.jme3.bullet.RotationOrder;
|
||||
import com.jme3.bullet.collision.ContactListener;
|
||||
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.PlaneCollisionShape;
|
||||
import com.jme3.bullet.collision.shapes.SphereCollisionShape;
|
||||
import com.jme3.bullet.joints.New6Dof;
|
||||
import com.jme3.bullet.joints.PhysicsJoint;
|
||||
import com.jme3.bullet.joints.motors.MotorParam;
|
||||
import com.jme3.bullet.objects.PhysicsBody;
|
||||
import com.jme3.bullet.objects.PhysicsRigidBody;
|
||||
import com.jme3.math.Matrix3f;
|
||||
import com.jme3.math.Plane;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
import net.minecraft.core.BlockPosition;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
public class MiniePlugin extends JavaPlugin {
|
||||
private static final int TIME_STEPS = 5;
|
||||
private static final float SIMULATION_SPEED = 1f;
|
||||
|
||||
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 Set< PhysicsCollisionObject > isTnt = new HashSet< PhysicsCollisionObject >();
|
||||
|
||||
private Map< PhysicsJoint, JointStruct > joints = new HashMap< PhysicsJoint, JointStruct >();
|
||||
|
||||
private Map< ChunkLocation, PhysicsRigidBody > chunks = new HashMap< ChunkLocation, PhysicsRigidBody >();
|
||||
|
||||
private Map< Vector3f, CollisionShape > collisionShapes = new HashMap< Vector3f, CollisionShape >();
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
FileUtil.saveToFile( getResource( "native/windows/x86_64/bulletjme.dll" ), new File( getDataFolder() + "/lib", "bulletjme.dll" ), false );
|
||||
FileUtil.saveToFile( getResource( "native/osx/x86_64/libbulletjme.dylib" ), new File( getDataFolder() + "/lib", "libbulletjme.dylib" ), false );
|
||||
FileUtil.saveToFile( getResource( "native/linux/x86_64/libbulletjme.so" ), new File( getDataFolder() + "/lib", "libbulletjme.so" ), false );
|
||||
if ( !loadNativeLibraries() ) {
|
||||
getLogger().severe( "Unable to load Bullet JME native libraries! Disabling plugin" );
|
||||
Bukkit.getPluginManager().disablePlugin( this );
|
||||
return;
|
||||
}
|
||||
|
||||
registerCommands();
|
||||
|
||||
space = new PhysicsSpace( BroadphaseType.DBVT );
|
||||
PlaneCollisionShape plane = new PlaneCollisionShape( new Plane( new Vector3f( 0, 1, 0 ), 0 ) );
|
||||
PhysicsRigidBody planeBody = new PhysicsRigidBody( plane, PhysicsBody.massForStatic );
|
||||
planeBody.setPhysicsLocation( new Vector3f( 0, 128, 0 ) );
|
||||
space.addCollisionObject( planeBody );
|
||||
space.setAccuracy( 1f / ( TIME_STEPS * 20f ) );
|
||||
|
||||
space.addContactListener( new ContactListener() {
|
||||
@Override
|
||||
public void onContactEnded( long manifoldId ) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContactProcessed( PhysicsCollisionObject objA, PhysicsCollisionObject objB, long manifoldPointId ) {
|
||||
if ( isTnt.remove( objA ) ) {
|
||||
impulse( objA.getPhysicsLocation(), 30f );
|
||||
if ( linkedDisplays.containsKey( objA ) ) {
|
||||
linkedDisplays.get( objA ).display.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if ( isTnt.remove( objB ) ) {
|
||||
impulse( objB.getPhysicsLocation(), 30f );
|
||||
if ( linkedDisplays.containsKey( objB ) ) {
|
||||
linkedDisplays.get( objB ).display.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContactStarted( long manifoldId ) {
|
||||
|
||||
}
|
||||
} );
|
||||
|
||||
Bukkit.getPluginManager().registerEvents( new Listener() {
|
||||
@EventHandler
|
||||
private void onChunkLoad( ChunkLoadEvent event ) {
|
||||
if ( event.getWorld().getName().equalsIgnoreCase( "world" ) ) {
|
||||
getLogger().info( "Loading chunk..." );
|
||||
// scanAndGenerate( event.getChunk() );
|
||||
saveChunk( event.getChunk() );
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
private void onChunkUnload( ChunkUnloadEvent event ) {
|
||||
if ( event.getWorld().getName().equalsIgnoreCase( "world" ) ) {
|
||||
ChunkLocation loc = new ChunkLocation( event.getChunk() );
|
||||
if ( chunks.containsKey( loc ) ) {
|
||||
space.removeCollisionObject( chunks.get( loc ) );
|
||||
chunks.remove( loc );
|
||||
}
|
||||
}
|
||||
}
|
||||
}, this );
|
||||
|
||||
|
||||
getLogger().info( "There are " + Bukkit.getWorld( "world" ).getLoadedChunks().length + " chunks" );
|
||||
getLogger().info( "Converted " + saveAllChunks( Bukkit.getWorld( "world" ) ) );
|
||||
|
||||
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< PhysicsJoint, JointStruct > > it = joints.entrySet().iterator(); it.hasNext(); ) {
|
||||
Entry< PhysicsJoint, JointStruct > entry = it.next();
|
||||
PhysicsJoint joint = entry.getKey();
|
||||
JointStruct struct = entry.getValue();
|
||||
BlockState state = struct.state;
|
||||
|
||||
if ( state.getBlock().getType() != state.getType() || !state.getChunk().isLoaded() ) {
|
||||
space.removeJoint( joint );
|
||||
space.remove( struct.object );
|
||||
it.remove();
|
||||
} else if ( !joint.isEnabled() ) {
|
||||
Location loc = state.getLocation();
|
||||
BlockData displayData = state.getBlockData();
|
||||
|
||||
// Create the display
|
||||
BlockDisplay display = loc.getWorld().spawn( loc, BlockDisplay.class, d -> {
|
||||
d.setBlock( displayData );
|
||||
} );
|
||||
|
||||
linkedDisplays.put( struct.object, new AuxiliaryDisplayStruct( display, struct.offset ) );
|
||||
|
||||
state.getBlock().setType( Material.AIR );
|
||||
|
||||
struct.object.setProtectGravity( false );
|
||||
Vector3f grav = new Vector3f();
|
||||
space.setGravity( grav );
|
||||
struct.object.setGravity( grav );
|
||||
|
||||
space.removeJoint( joint );
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
active.remove( obj );
|
||||
isTnt.remove( 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" )
|
||||
.defaultTo( ( sender, args, params ) -> {
|
||||
Player player = ( Player ) sender;
|
||||
Location loc = player.getLocation();
|
||||
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();
|
||||
}
|
||||
|
||||
CraftBlockData data = ( CraftBlockData ) displayData;
|
||||
|
||||
BoundingBox[] boxes = convertFrom( data.getState().f( null, null ) );
|
||||
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;
|
||||
}
|
||||
|
||||
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 ) );
|
||||
|
||||
space.addCollisionObject( rigid );
|
||||
|
||||
// Create the display
|
||||
BlockDisplay display = loc.getWorld().spawn( loc, BlockDisplay.class, d -> {
|
||||
d.setBlock( displayData );
|
||||
} );
|
||||
|
||||
linkedDisplays.put( rigid, new AuxiliaryDisplayStruct( display, blockCenter ) );
|
||||
|
||||
if ( displayData.getMaterial() == Material.TNT ) {
|
||||
isTnt.add( rigid );
|
||||
}
|
||||
|
||||
player.sendMessage( "Created display" );
|
||||
} ) )
|
||||
.add( new SubCommand( "constraint" )
|
||||
.defaultTo( ( sender, args, params ) -> {
|
||||
Player player = ( Player ) sender;
|
||||
Location loc = player.getLocation();
|
||||
loc.setPitch( 0 );
|
||||
loc.setDirection( new Vector( 0, 0, 0 ) );
|
||||
|
||||
BlockData displayData = Material.IRON_TRAPDOOR.createBlockData();
|
||||
CraftBlockData data = ( CraftBlockData ) displayData;
|
||||
|
||||
final Vector scale = new Vector( 5, 2, 5 );
|
||||
|
||||
BlockPosition pos = new BlockPosition( loc.getBlockX(), loc.getBlockY(), loc.getBlockZ() );
|
||||
BoundingBox[] boxes = convertFrom( data.getState().f( ( ( CraftWorld ) loc.getWorld() ).getHandle(), pos ) );
|
||||
for ( BoundingBox box : boxes ) {
|
||||
Vector min = box.getMin().multiply( scale );
|
||||
Vector max = box.getMax().multiply( scale );
|
||||
box.resize( min.getX(), min.getY(), min.getZ(), max.getX(), max.getY(), max.getZ() );
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
PhysicsRigidBody rigid = new PhysicsRigidBody( box, 5f );
|
||||
|
||||
// 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 ) );
|
||||
|
||||
space.addCollisionObject( rigid );
|
||||
|
||||
New6Dof constraint = new New6Dof( rigid, new Vector3f( 0, 0, 0 ), rigid.getPhysicsLocation(), Matrix3f.IDENTITY, Matrix3f.IDENTITY, RotationOrder.XYZ );
|
||||
|
||||
constraint.set( MotorParam.UpperLimit, 3, ( float ) Math.PI / 6 );
|
||||
constraint.set( MotorParam.LowerLimit, 3, ( float ) - Math.PI / 6 );
|
||||
constraint.set( MotorParam.UpperLimit, 4, 0 );
|
||||
constraint.set( MotorParam.LowerLimit, 4, 0 );
|
||||
constraint.set( MotorParam.UpperLimit, 5, 0 );
|
||||
constraint.set( MotorParam.LowerLimit, 5, 0 );
|
||||
|
||||
space.addJoint( constraint );
|
||||
|
||||
player.sendMessage( "Location: " + rigid.getPhysicsLocation() );
|
||||
|
||||
// Create the display
|
||||
BlockDisplay display = loc.getWorld().spawn( loc, BlockDisplay.class, d -> {
|
||||
d.setBlock( displayData );
|
||||
} );
|
||||
|
||||
linkedDisplays.put( rigid, new AuxiliaryDisplayStruct( display, blockCenter ).setScale( scale ) );
|
||||
|
||||
player.sendMessage( "Created constraint" );
|
||||
}) )
|
||||
.add( new SubCommand( "fixed" )
|
||||
.defaultTo( ( sender, args, params ) -> {
|
||||
Player player = ( Player ) sender;
|
||||
Block block = player.getTargetBlockExact( 20 );
|
||||
convert( block );
|
||||
|
||||
player.sendMessage( "Fixed" );
|
||||
} ) )
|
||||
.add( new SubCommand( "chunk" )
|
||||
.defaultTo( ( sender, args, params ) -> {
|
||||
Player player = ( Player ) sender;
|
||||
|
||||
player.sendMessage( "Registering chunk..." );
|
||||
player.sendMessage( "Registered " + scanAndGenerate( player.getLocation().getChunk() ) );
|
||||
} ) )
|
||||
.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 int saveAllChunks( World world ) {
|
||||
int total = 0;
|
||||
for ( Chunk chunk : world.getLoadedChunks() ) {
|
||||
total += saveChunk( chunk );
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private int saveChunk( Chunk chunk ) {
|
||||
File saveFile = new File( getDataFolder() + "/chunks", chunk.getWorld().getName() + "," + chunk.getX() + "," + chunk.getZ() );
|
||||
saveFile.getParentFile().mkdirs();
|
||||
saveFile.delete();
|
||||
|
||||
int count = 0;
|
||||
try ( FileWriter writer = new FileWriter( saveFile ) ) {
|
||||
World world = chunk.getWorld();
|
||||
for ( int y = world.getMinHeight(); y < world.getMaxHeight(); 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() ) ) {
|
||||
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 ) {
|
||||
// Save this block
|
||||
for ( BoundingBox box : boxes ) {
|
||||
writer.write( ( box.getMinX() + x ) + "," );
|
||||
writer.write( ( box.getMinY() + y ) + "," );
|
||||
writer.write( ( box.getMinZ() + z ) + "," );
|
||||
writer.write( ( box.getMaxX() + x ) + "," );
|
||||
writer.write( ( box.getMaxY() + y ) + "," );
|
||||
writer.write( ( box.getMaxZ() + z ) + "\n" );
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private int scanAndGenerate( World world ) {
|
||||
int total = 0;
|
||||
for ( Chunk chunk : world.getLoadedChunks() ) {
|
||||
total += scanAndGenerate( chunk );
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private int scanAndGenerate( Chunk chunk ) {
|
||||
World world = chunk.getWorld();
|
||||
CompoundCollisionShape compound = new CompoundCollisionShape();
|
||||
int worldHeight = world.getMaxHeight() - world.getMinHeight();
|
||||
boolean[][][] isSolid = new boolean[ worldHeight ][ 16 ][ 16 ];
|
||||
for ( int y = 0; y < worldHeight; y++ ) {
|
||||
for ( int z = 0; z < 16; z++ ) {
|
||||
for ( int x = 0; x < 16; x++ ) {
|
||||
Block block = chunk.getBlock( x, y + world.getMinHeight(), z );
|
||||
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 == 1 && boxes[ 0 ].getVolume() == 1 ) {
|
||||
isSolid[ y ][ z ][ x ] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( int y = 0; y < worldHeight; y++ ) {
|
||||
for ( int z = 0; z < 16; z++ ) {
|
||||
for ( int x = 0; x < 16; x++ ) {
|
||||
if ( x > 0 && x < 15 && z > 0 && z < 15 && y > 0 && y < worldHeight - 1 ) {
|
||||
// Figure out if this block is surrounded by solid blocks to avoid having to add this block
|
||||
if ( isSolid[ y - 1 ][ z ][ x ]
|
||||
&& 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Block block = chunk.getBlock( x, y + world.getMinHeight(), z );
|
||||
|
||||
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 ) {
|
||||
Vector min = boxes[ 0 ].getMin();
|
||||
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 );
|
||||
if ( shape == null ) {
|
||||
shape = new BoxCollisionShape( halfExtents );
|
||||
collisionShapes.put( halfExtents, shape );
|
||||
}
|
||||
Vector3f shapeCenter = new Vector3f( ( float ) boxes[ 0 ].getCenterX() + x, ( float ) boxes[ 0 ].getCenterY() + y, ( float ) boxes[ 0 ].getCenterZ() + z );
|
||||
compound.addChildShape( shape, shapeCenter );
|
||||
} else {
|
||||
for ( BoundingBox aabb : boxes ) {
|
||||
Vector min = aabb.getMin();
|
||||
Vector center = aabb.getCenter();
|
||||
Vector half = center.clone().subtract( min );
|
||||
Vector3f halfExtents = new Vector3f( ( float ) half.getX(), ( float ) half.getY(), ( float ) half.getZ() );
|
||||
|
||||
CollisionShape shape = collisionShapes.get( halfExtents );
|
||||
if ( shape == null ) {
|
||||
shape = new BoxCollisionShape( halfExtents );
|
||||
collisionShapes.put( halfExtents, shape );
|
||||
}
|
||||
compound.addChildShape( shape, ( float ) center.getX() + x, ( float ) center.getY() + y, ( float ) center.getZ() + z );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getLogger().info( "Chunk has " + compound.countChildren() );
|
||||
|
||||
// Create a rigid body
|
||||
PhysicsRigidBody rigid = new PhysicsRigidBody( compound, PhysicsBody.massForStatic );
|
||||
rigid.setPhysicsLocation( new Vector3f( chunk.getX() << 4, world.getMinHeight(), chunk.getZ() << 4 ) );
|
||||
rigid.setPhysicsRotation( new Quaternion( 0, 0, 0, 1 ) );
|
||||
|
||||
space.addCollisionObject( rigid );
|
||||
|
||||
PhysicsRigidBody old = chunks.put( new ChunkLocation( chunk ), rigid );
|
||||
if ( old != null ) {
|
||||
getLogger().warning( "Old rigid body found!" );
|
||||
space.remove( old );
|
||||
}
|
||||
|
||||
return compound.countChildren();
|
||||
}
|
||||
|
||||
private boolean convert( Block block ) {
|
||||
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 ) loc.getWorld() ).getHandle(), pos ) );
|
||||
Vector blockCenter = calculateCenter( boxes );
|
||||
|
||||
CollisionShape box;
|
||||
if ( boxes.length == 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
PhysicsRigidBody rigid = new PhysicsRigidBody( box, 1f );
|
||||
rigid.setProtectGravity( true );
|
||||
rigid.setGravity( new Vector3f( 0, 0, 0 ) );
|
||||
|
||||
// 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 ) );
|
||||
|
||||
space.addCollisionObject( rigid );
|
||||
|
||||
New6Dof constraint = new New6Dof( rigid, new Vector3f( 0, 0, 0 ), rigid.getPhysicsLocation(), Matrix3f.IDENTITY, Matrix3f.IDENTITY, RotationOrder.XYZ );
|
||||
|
||||
constraint.setBreakingImpulseThreshold( 5 );
|
||||
constraint.set( MotorParam.UpperLimit, 3, 0 );
|
||||
constraint.set( MotorParam.LowerLimit, 3, 0 );
|
||||
constraint.set( MotorParam.UpperLimit, 4, 0 );
|
||||
constraint.set( MotorParam.LowerLimit, 4, 0 );
|
||||
constraint.set( MotorParam.UpperLimit, 5, 0 );
|
||||
constraint.set( MotorParam.LowerLimit, 5, 0 );
|
||||
|
||||
space.addJoint( constraint );
|
||||
|
||||
joints.put( constraint, new JointStruct( state, rigid, blockCenter ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private final boolean loadNativeLibraries() {
|
||||
if ( SystemUtils.IS_OS_MAC ) {
|
||||
System.load( new File( getDataFolder() + "/lib", "libbulletjme.dylib" ).getAbsolutePath() );
|
||||
} else if ( SystemUtils.IS_OS_LINUX ) {
|
||||
System.load( new File( getDataFolder() + "/lib", "libbulletjme.so" ).getAbsolutePath() );
|
||||
} else if ( SystemUtils.IS_OS_WINDOWS ) {
|
||||
System.load( new File( getDataFolder() + "/lib", "bulletjme.dll" ).getAbsolutePath() );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
private static BoundingBox[] convertFrom( VoxelShape shape ) {
|
||||
return shape.e().stream()
|
||||
.map( aabb -> { return new BoundingBox( aabb.a, aabb.b, aabb.c, aabb.d, aabb.e, aabb.f ); } )
|
||||
.toArray( BoundingBox[]::new );
|
||||
}
|
||||
|
||||
private class JointStruct {
|
||||
BlockState state;
|
||||
PhysicsRigidBody object;
|
||||
Vector offset;
|
||||
|
||||
JointStruct( BlockState state, PhysicsRigidBody body, Vector offset ) {
|
||||
this.state = state;
|
||||
this.object = body;
|
||||
this.offset = offset.clone();
|
||||
}
|
||||
}
|
||||
|
||||
private class AuxiliaryDisplayStruct {
|
||||
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;
|
||||
}
|
||||
|
||||
Display display;
|
||||
Vector offset;
|
||||
Vector scale;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest;
|
||||
|
||||
import com.jme3.bullet.PhysicsSpace;
|
||||
import com.jme3.bullet.PhysicsSpace.BroadphaseType;
|
||||
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
|
||||
import com.jme3.bullet.collision.shapes.PlaneCollisionShape;
|
||||
import com.jme3.bullet.objects.PhysicsBody;
|
||||
import com.jme3.bullet.objects.PhysicsRigidBody;
|
||||
import com.jme3.math.Plane;
|
||||
import com.jme3.math.Vector3f;
|
||||
|
||||
public class MinieTest {
|
||||
|
||||
public static void main( String[] args ) {
|
||||
System.loadLibrary( "bulletjme" );
|
||||
|
||||
System.out.println( "Testing a simple PhysicsSpace" );
|
||||
PhysicsSpace space = new PhysicsSpace( BroadphaseType.DBVT );
|
||||
|
||||
PlaneCollisionShape plane = new PlaneCollisionShape( new Plane( new Vector3f( 0, 1, 0 ), 0 ) );
|
||||
PhysicsRigidBody planeBody = new PhysicsRigidBody( plane, PhysicsBody.massForStatic );
|
||||
planeBody.setPhysicsLocation( new Vector3f( 0, 0, 0 ) );
|
||||
|
||||
BoxCollisionShape box = new BoxCollisionShape( 0.5f );
|
||||
PhysicsRigidBody rigid = new PhysicsRigidBody( box, 1f );
|
||||
rigid.setPhysicsLocation( new Vector3f( 0f, 100f, 0f ) );
|
||||
|
||||
space.addCollisionObject( rigid );
|
||||
space.addCollisionObject( planeBody );
|
||||
|
||||
for ( float i = 0; i < 9.6; i += 1 / 256.0 ) {
|
||||
space.update( i );
|
||||
Vector3f loc = rigid.getPhysicsLocation();
|
||||
System.out.println( i + "\t: " + loc.getX() + ", " + loc.getY() + ", " + loc.getZ() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.permissions.Permission;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.util.BukkitUtil;
|
||||
|
||||
public class CommandBase {
|
||||
protected PluginCommand command;
|
||||
|
||||
public CommandBase( String command ) {
|
||||
this.command = BukkitUtil.constructCommand( command );
|
||||
}
|
||||
|
||||
public CommandBase setPermission( String permission ) {
|
||||
command.setPermission( permission );
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBase setDescription( String description ) {
|
||||
command.setDescription( description );
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBase addAliases( String... aliases ) {
|
||||
Set< String > aliasSet = new HashSet< String >( command.getAliases() );
|
||||
for ( String alias : aliases ) {
|
||||
aliasSet.add( alias );
|
||||
}
|
||||
command.setAliases( new ArrayList< String >( aliasSet ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBase addAliases( Collection< String > aliases ) {
|
||||
Set< String > aliasSet = new HashSet< String >( command.getAliases() );
|
||||
aliasSet.addAll( aliases );
|
||||
command.setAliases( new ArrayList< String >( aliasSet ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandBase setPermission( Permission permission ) {
|
||||
return setPermission( permission.toString() );
|
||||
}
|
||||
|
||||
public CommandBase setSubCommand( SubCommand subCommand ) {
|
||||
subCommand.applyTo( command );
|
||||
return this;
|
||||
}
|
||||
|
||||
public PluginCommand build() {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor.CommandExecutable;
|
||||
|
||||
public class CommandOption {
|
||||
protected CommandExecutable exe;
|
||||
protected String[] args;
|
||||
protected CommandParameters parameter;
|
||||
|
||||
public CommandOption( CommandExecutable exe, String[] args, CommandParameters parameter ) {
|
||||
this.exe = exe;
|
||||
this.args = args;
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
public int getArgumentSize() {
|
||||
return args.length;
|
||||
}
|
||||
|
||||
public void execute( CommandSender sender ) {
|
||||
exe.execute( sender, args, parameter );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.primitives.Primitives;
|
||||
|
||||
public class CommandParameters {
|
||||
protected List< Object > parameters = new ArrayList< Object >();
|
||||
|
||||
public CommandParameters() {
|
||||
}
|
||||
|
||||
public CommandParameters( CommandParameters copy ) {
|
||||
parameters.addAll( copy.parameters );
|
||||
}
|
||||
|
||||
public void add( Object object ) {
|
||||
parameters.add( object );
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return parameters.size();
|
||||
}
|
||||
|
||||
public < T > T get( Class < T > clazz, int index ) {
|
||||
clazz = Primitives.wrap( clazz );
|
||||
if ( index < 0 || index >= parameters.size() ) {
|
||||
return null;
|
||||
}
|
||||
Object obj = parameters.get( index );
|
||||
if ( obj != null && clazz.isInstance( obj ) ) {
|
||||
return clazz.cast( obj );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public < T > T getLast( Class< T > clazz ) {
|
||||
clazz = Primitives.wrap( clazz );
|
||||
for ( int i = parameters.size() - 1; i >= 0; i-- ) {
|
||||
Object obj = parameters.get( i );
|
||||
if ( obj != null && clazz.isInstance( obj ) ) {
|
||||
return clazz.cast( obj );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public < T > T getFirst( Class< T > clazz ) {
|
||||
clazz = Primitives.wrap( clazz );
|
||||
for ( int i = 0; i < parameters.size(); i++ ) {
|
||||
Object obj = parameters.get( i );
|
||||
if ( obj != null && clazz.isInstance( obj ) ) {
|
||||
return clazz.cast( obj );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CommandParameters[" + parameters.stream().map( Object::toString ).collect( Collectors.joining( ", " ) ) + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class CommandResult {
|
||||
protected List< CommandOption > options = new ArrayList< CommandOption >();
|
||||
|
||||
public void add( CommandOption option ) {
|
||||
options.add( option );
|
||||
}
|
||||
|
||||
public void addAll( Collection< CommandOption > options ) {
|
||||
this.options.addAll( options );
|
||||
}
|
||||
|
||||
public void add( CommandResult result ) {
|
||||
this.options.addAll( result.getOptions() );
|
||||
}
|
||||
|
||||
public List< CommandOption > getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void execute( CommandSender sender ) {
|
||||
CommandOption lowest = null;
|
||||
for ( CommandOption option : options ) {
|
||||
if ( lowest == null || option.getArgumentSize() < lowest.getArgumentSize() ) {
|
||||
lowest = option;
|
||||
}
|
||||
}
|
||||
if ( lowest != null ) {
|
||||
lowest.execute( sender );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command;
|
||||
|
||||
public class SplitCommand {
|
||||
protected String[] input;
|
||||
protected String[] arguments;
|
||||
|
||||
public SplitCommand( String[] input, String[] arguments ) {
|
||||
this.input = input;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public String[] getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput( String[] input ) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public String[] getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public void setArguments( String[] arguments ) {
|
||||
this.arguments = arguments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.util.StringUtil;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor.CommandExecutable;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.InputValidator;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.InputValidatorString;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender.SenderValidator;
|
||||
|
||||
/**
|
||||
* A build and run command framework for automatic tab completions and easy branching.
|
||||
*
|
||||
* @author BananaPuncher714
|
||||
*/
|
||||
public class SubCommand {
|
||||
protected List< SubCommand > subCommands = new ArrayList< SubCommand >();
|
||||
|
||||
protected InputValidator< ? > validator;
|
||||
protected Set< SenderValidator > senderValidators = new HashSet< SenderValidator >();
|
||||
protected CommandExecutable whenUnknown;
|
||||
protected CommandExecutable whenNone;
|
||||
|
||||
/**
|
||||
* Accept anything as a valid input
|
||||
*/
|
||||
public SubCommand() {
|
||||
}
|
||||
|
||||
// Helped constructor, really belongs in a factory.
|
||||
/**
|
||||
* Create a SubCommand with the string as the input validator.
|
||||
*
|
||||
* @param command
|
||||
* The subcommand value.
|
||||
*/
|
||||
public SubCommand( String command ) {
|
||||
this( new InputValidatorString( command ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a SubCommand with the input validator provided.
|
||||
*
|
||||
* @param validator
|
||||
* Can be null.
|
||||
*/
|
||||
public SubCommand( InputValidator< ? > validator ) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
public SubCommand add( SubCommand builder ) {
|
||||
subCommands.add( builder );
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubCommand addSenderValidator( SenderValidator validator ) {
|
||||
senderValidators.add( validator );
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ran when the arguments provided don't match any SubCommands registered.
|
||||
*
|
||||
* @param executable
|
||||
* An executable where the arguments will start with the unknown subcommand.
|
||||
* @return
|
||||
* Builder pattern return.
|
||||
*/
|
||||
public SubCommand whenUnknown( CommandExecutable executable ) {
|
||||
this.whenUnknown = executable;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Naming by jetp250
|
||||
/**
|
||||
* Ran when there are no arguments provided, or if the executable for when unknown is not set.
|
||||
*
|
||||
* @param executable
|
||||
* If null, nothing will happen.
|
||||
* @return
|
||||
* Builder pattern return.
|
||||
*/
|
||||
public SubCommand defaultTo( CommandExecutable executable ) {
|
||||
this.whenNone = executable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean matches( CommandSender sender ) {
|
||||
for ( SenderValidator validator : senderValidators ) {
|
||||
if ( !validator.isValid( sender ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean matches( CommandSender sender, String input[], String[] args ) {
|
||||
return ( validator == null ? true : validator.isValid( sender, input, args ) ) && matches( sender );
|
||||
}
|
||||
|
||||
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
|
||||
return validator == null ? null : validator.getTabCompletes( sender, input );
|
||||
}
|
||||
|
||||
public List< SubCommand > getSubCommands() {
|
||||
return subCommands;
|
||||
}
|
||||
|
||||
public InputValidator< ? > getInputValidator() {
|
||||
return validator;
|
||||
}
|
||||
|
||||
public Set< SenderValidator > getSenderValidators() {
|
||||
return senderValidators;
|
||||
}
|
||||
|
||||
public CommandResult submit( CommandSender sender, String[] command, String[] args, CommandParameters parameter ) {
|
||||
CommandResult result = new CommandResult();
|
||||
parameter = new CommandParameters( parameter );
|
||||
if ( validator != null ) {
|
||||
parameter.add( validator.get( sender, command ) );
|
||||
} else {
|
||||
parameter.add( null );
|
||||
}
|
||||
if ( args.length > 0 ) {
|
||||
boolean found = false;
|
||||
for ( SubCommand subCommand : subCommands ) {
|
||||
SplitCommand split = split( args, subCommand.getInputValidator().getArgumentCount() );
|
||||
String[] input = split.getInput();
|
||||
String[] newArgs = split.getArguments();
|
||||
if ( subCommand.matches( sender, input, newArgs ) ) {
|
||||
found = true;
|
||||
|
||||
result.add( subCommand.submit( sender, input, newArgs, parameter ) );
|
||||
}
|
||||
}
|
||||
if ( !found ) {
|
||||
if ( whenUnknown != null ) {
|
||||
result.add( new CommandOption( whenUnknown, args, parameter ) );
|
||||
} else if ( whenNone != null ) {
|
||||
result.add( new CommandOption( whenNone, args, parameter ) );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( whenNone != null ) {
|
||||
result.add( new CommandOption( whenNone, args, parameter ) );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Collection< String > getTabCompletions( CommandSender sender, String[] args ) {
|
||||
Set< String > tabs = new HashSet< String >();
|
||||
if ( args.length > 0 ) {
|
||||
for ( SubCommand subCommand : subCommands ) {
|
||||
if ( subCommand.matches( sender ) ) {
|
||||
SplitCommand split = split( args, subCommand.getInputValidator().getArgumentCount() );
|
||||
String[] input = split.getInput();
|
||||
String[] newArgs = split.getArguments();
|
||||
// Check if the subcommand matches the argument, and if it has subcommands of its own
|
||||
if ( subCommand.matches( sender, input, newArgs ) && !subCommand.getSubCommands().isEmpty() ) {
|
||||
tabs.addAll( subCommand.getTabCompletions( sender, newArgs ) );
|
||||
} else if ( newArgs.length == 0 ) {
|
||||
// If not, and this is the last argument, add all possible tab completes
|
||||
// This allows for "recommendations"
|
||||
Collection< String > completions = subCommand.getTabCompletes( sender, input );
|
||||
if ( completions != null ) {
|
||||
tabs.addAll( completions );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
public SubCommand applyTo( PluginCommand command ) {
|
||||
command.setExecutor( this::onCommand );
|
||||
command.setTabCompleter( this::onTabComplete );
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean onCommand( CommandSender sender, Command command, String arg2, String[] args ) {
|
||||
CommandParameters parameters = new CommandParameters();
|
||||
if ( matches( sender ) ) {
|
||||
String[] commandArr = new String[ args.length + 1 ];
|
||||
|
||||
commandArr[ 0 ] = command.getName();
|
||||
for ( int i = 1; i < commandArr.length; i++ ) {
|
||||
commandArr[ i ] = args[ i - 1 ];
|
||||
}
|
||||
|
||||
SplitCommand split = split( commandArr, validator.getArgumentCount() );
|
||||
submit( sender, split.getInput(), split.getArguments(), parameters ).execute( sender );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private List< String > onTabComplete( CommandSender sender, Command command, String arg2, String[] args ) {
|
||||
List< String > completions = new ArrayList< String >();
|
||||
String[] commandArr = new String[ args.length + 1 ];
|
||||
|
||||
commandArr[ 0 ] = command.getName();
|
||||
for ( int i = 1; i < commandArr.length; i++ ) {
|
||||
commandArr[ i ] = args[ i - 1 ];
|
||||
}
|
||||
|
||||
SplitCommand split = split( commandArr, validator.getArgumentCount() );
|
||||
StringUtil.copyPartialMatches( args[ args.length - 1 ], getTabCompletions( sender, split.getArguments() ), completions );
|
||||
Collections.sort( completions );
|
||||
return completions;
|
||||
}
|
||||
|
||||
protected static SplitCommand split( String[] command, int inputSize ) {
|
||||
String[] input = command.length > 0 ? Arrays.copyOfRange( command, 0, Math.min( inputSize, command.length ) ) : new String[ 0 ];
|
||||
String[] args = command.length > inputSize ? Arrays.copyOfRange( command, inputSize, command.length ) : new String[ 0 ];
|
||||
|
||||
return new SplitCommand( input, args );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.CommandParameters;
|
||||
|
||||
public interface CommandExecutable {
|
||||
void execute( CommandSender sender, String[] args, CommandParameters params );
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.command.CommandParameters;
|
||||
|
||||
public class CommandExecutableMessage implements CommandExecutable {
|
||||
protected String message;
|
||||
|
||||
public CommandExecutableMessage( String message ) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute( CommandSender sender, String[] args, CommandParameters params ) {
|
||||
sender.sendMessage( message );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author BananaPuncher714
|
||||
*
|
||||
*/
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.executor;
|
||||
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Classes for building complex command trees.
|
||||
*
|
||||
* @author BananaPuncher714
|
||||
*/
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command;
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public interface InputValidator< T > {
|
||||
Collection< String > getTabCompletes( CommandSender sender, String[] input );
|
||||
boolean isValid( CommandSender sender, String[] input, String[] args );
|
||||
T get( CommandSender sender, String[] input );
|
||||
default int getArgumentCount() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class InputValidatorArguments implements InputValidator< Void > {
|
||||
protected int min;
|
||||
protected int max;
|
||||
|
||||
public InputValidatorArguments( int amount ) {
|
||||
this.min = amount;
|
||||
this.max = amount;
|
||||
}
|
||||
|
||||
public InputValidatorArguments( int min, int max ) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender, String input[], String[] args ) {
|
||||
int len = args.length;
|
||||
return len >= min && len <= max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void get( CommandSender sender, String input[] ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class InputValidatorBoolean implements InputValidator< Boolean > {
|
||||
protected Set< String > trueVals = new HashSet< String >();
|
||||
protected Set< String > falseVals = new HashSet< String >();
|
||||
|
||||
public InputValidatorBoolean( String[] trueVal, String[] falseVal ) {
|
||||
for ( String str : trueVal ) {
|
||||
trueVals.add( str.toLowerCase() );
|
||||
}
|
||||
|
||||
for ( String str : falseVal ) {
|
||||
falseVals.add( str.toLowerCase() );
|
||||
}
|
||||
}
|
||||
|
||||
public InputValidatorBoolean() {
|
||||
trueVals.add( "true" );
|
||||
falseVals.add( "false" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
|
||||
Set< String > combined = new HashSet< String >( trueVals );
|
||||
combined.addAll( falseVals );
|
||||
return combined;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender, String input[], String[] args ) {
|
||||
String lowercase = input[ 0 ].toLowerCase();
|
||||
return trueVals.contains( lowercase ) || falseVals.contains( lowercase );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean get( CommandSender sender, String input[] ) {
|
||||
String lowercase = input[ 0 ].toLowerCase();
|
||||
return trueVals.contains( lowercase );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class InputValidatorChain< T > implements InputValidator< T > {
|
||||
protected InputValidator< T > primaryValidator;
|
||||
protected List< InputValidator< ? > > validators = new ArrayList< InputValidator< ? > >();
|
||||
|
||||
public InputValidatorChain( InputValidator< T > primaryValidator ) {
|
||||
this.primaryValidator = primaryValidator;
|
||||
}
|
||||
|
||||
public InputValidatorChain< T > addValidator( InputValidator< ? > validator ) {
|
||||
validators.add( validator );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
|
||||
return primaryValidator.getTabCompletes( sender, input );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender, String input[], String[] args ) {
|
||||
if ( !primaryValidator.isValid( sender, input, args ) ) {
|
||||
return false;
|
||||
}
|
||||
for ( InputValidator< ? > validator : validators ) {
|
||||
if ( !validator.isValid( sender, input, args ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get( CommandSender sender, String input[] ) {
|
||||
return primaryValidator.get( sender, input );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class InputValidatorInt implements InputValidator< Integer > {
|
||||
protected int min = Integer.MIN_VALUE;
|
||||
protected int max = Integer.MAX_VALUE;
|
||||
|
||||
public InputValidatorInt() {
|
||||
}
|
||||
|
||||
public InputValidatorInt( int min, int max ) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender, String input[], String[] args ) {
|
||||
try {
|
||||
int i = Integer.valueOf( input[ 0 ] );
|
||||
return i >= min && i <= max;
|
||||
} catch ( Exception exception ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get( CommandSender sender, String input[] ) {
|
||||
return Integer.parseInt( input[ 0 ] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class InputValidatorPattern implements InputValidator< String > {
|
||||
protected String pattern;
|
||||
|
||||
public InputValidatorPattern( String pattern ) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender, String input[], String[] args ) {
|
||||
return input[ 0 ].matches( pattern );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get( CommandSender sender, String input[] ) {
|
||||
return input[ 0 ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class InputValidatorPlayer implements InputValidator< Player > {
|
||||
@Override
|
||||
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
|
||||
Set< String > playerNames = new HashSet< String >();
|
||||
for ( Player player : Bukkit.getOnlinePlayers() ) {
|
||||
playerNames.add( player.getName() );
|
||||
}
|
||||
return playerNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender, String input[], String[] args ) {
|
||||
return Bukkit.getPlayerExact( input[ 0 ] ) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player get( CommandSender sender, String input[] ) {
|
||||
return Bukkit.getPlayerExact( input[ 0 ] );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class InputValidatorString implements InputValidator< String > {
|
||||
protected Set< String > values = new HashSet< String >();
|
||||
|
||||
public InputValidatorString( String value ) {
|
||||
values.add( value.toLowerCase() );
|
||||
}
|
||||
|
||||
public InputValidatorString( String... values ) {
|
||||
Validate.isTrue( values.length > 0, "Must provide at least 1 argument!" );
|
||||
for ( String str : values ) {
|
||||
this.values.add( str.toLowerCase() );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection< String > getTabCompletes( CommandSender sender, String[] input ) {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender, String input[], String[] args ) {
|
||||
return values.contains( input[ 0 ].toLowerCase() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get( CommandSender sender, String input[] ) {
|
||||
return input[ 0 ];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author BananaPuncher714
|
||||
*
|
||||
*/
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator;
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public interface SenderValidator {
|
||||
boolean isValid( CommandSender sender );
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SenderValidatorNotPlayer implements SenderValidator {
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender ) {
|
||||
return !( sender instanceof Player );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class SenderValidatorPermission implements SenderValidator {
|
||||
protected Set< String > permissions = new HashSet< String >();
|
||||
|
||||
public SenderValidatorPermission( String... permissions ) {
|
||||
for ( String permission : permissions ) {
|
||||
this.permissions.add( permission );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender ) {
|
||||
for ( String permission : permissions ) {
|
||||
if ( sender.hasPermission( permission ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class SenderValidatorPlayer implements SenderValidator {
|
||||
@Override
|
||||
public boolean isValid( CommandSender sender ) {
|
||||
return sender instanceof Player;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @author BananaPuncher714
|
||||
*
|
||||
*/
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.command.validator.sender;
|
||||
@@ -0,0 +1,286 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.ChunkSnapshot;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
/**
|
||||
* Represents a Bukkit chunk's location.
|
||||
*
|
||||
* @author BananaPuncher714
|
||||
*/
|
||||
public class ChunkLocation {
|
||||
private int x, z;
|
||||
private String worldName;
|
||||
private World world;
|
||||
|
||||
/**
|
||||
* Construct a ChunkLocation from a Location.
|
||||
*
|
||||
* @param location
|
||||
* Cannot be null.
|
||||
*/
|
||||
public ChunkLocation( Location location ) {
|
||||
Validate.notNull( location );
|
||||
world = location.getWorld();
|
||||
worldName = world.getName();
|
||||
x = location.getBlockX() >> 4;
|
||||
z = location.getBlockZ() >> 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a ChunkLocation.
|
||||
*
|
||||
* @param location
|
||||
* Cannot be null.
|
||||
*/
|
||||
public ChunkLocation( ChunkLocation location ) {
|
||||
Validate.notNull( location );
|
||||
x = location.x;
|
||||
z = location.z;
|
||||
worldName = location.worldName;
|
||||
world = location.world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ChunkLocation from chunk coordinates.
|
||||
*
|
||||
* @param world
|
||||
* Cannot be null.
|
||||
* @param x
|
||||
* Chunk coordinate x value.
|
||||
* @param z
|
||||
* Chunk coordinate z value.
|
||||
*/
|
||||
public ChunkLocation( World world, int x, int z ) {
|
||||
Validate.notNull( world );
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.worldName = world.getName();
|
||||
this.world = world;
|
||||
|
||||
}
|
||||
|
||||
public ChunkLocation( String world, int x, int z ) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.worldName = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ChunkLocation from a Bukkit chunk.
|
||||
*
|
||||
* @param chunk
|
||||
* Cannot be null.
|
||||
*/
|
||||
public ChunkLocation( Chunk chunk ) {
|
||||
Validate.notNull( chunk );
|
||||
world = chunk.getWorld();
|
||||
worldName = world.getName();
|
||||
x = chunk.getX();
|
||||
z = chunk.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ChunkLocation from a ChunkSnapshot.
|
||||
*
|
||||
* @param snapshot
|
||||
* Cannot be null. The world will not be cached, only the world name.
|
||||
*/
|
||||
public ChunkLocation( ChunkSnapshot snapshot ) {
|
||||
Validate.notNull( snapshot );
|
||||
worldName = snapshot.getWorldName();
|
||||
x = snapshot.getX();
|
||||
z = snapshot.getZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x coordinate.
|
||||
*
|
||||
* @return
|
||||
* Chunk coordinate x value.
|
||||
*/
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the x coordinate.
|
||||
*
|
||||
* @param x
|
||||
* Chunk coordinate x value.
|
||||
*/
|
||||
public ChunkLocation setX( int x ) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the z coordinate.
|
||||
*
|
||||
* @return
|
||||
* Chunk coordinate z value.
|
||||
*/
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the z coordinate.
|
||||
*
|
||||
* @param z
|
||||
* Chunk coordinate z value.
|
||||
*/
|
||||
public ChunkLocation setZ( int z ) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add coordinates from current coordinates.
|
||||
*
|
||||
* @param x
|
||||
* Chunk x coordinate value.
|
||||
* @param z
|
||||
* Chunk z coordinate value.
|
||||
* @return
|
||||
* This location.
|
||||
*/
|
||||
public ChunkLocation add( int x, int z ) {
|
||||
this.x += x;
|
||||
this.z += z;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract coordinates from current coordinates.
|
||||
*
|
||||
* @param x
|
||||
* Chunk x coordinate value.
|
||||
* @param z
|
||||
* Chunk z coordinate value.
|
||||
* @return
|
||||
* This location.
|
||||
*/
|
||||
public ChunkLocation subtract( int x, int z ) {
|
||||
this.x -= x;
|
||||
this.z -= z;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getWorldName() {
|
||||
return worldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the world.
|
||||
*
|
||||
* @return
|
||||
* A non-null world, will fetch and cache the world if not cached already.
|
||||
*/
|
||||
public World getWorld() {
|
||||
if ( world == null ) {
|
||||
world = Bukkit.getWorld( worldName );
|
||||
}
|
||||
return world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the world.
|
||||
*
|
||||
* @param world
|
||||
* Cannot be null.
|
||||
*/
|
||||
public void setWorld( World world ) {
|
||||
Validate.notNull( world );
|
||||
this.world = world;
|
||||
this.worldName = world.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chunk this location represents.
|
||||
*
|
||||
* @return
|
||||
* May load the chunk.
|
||||
*/
|
||||
public Chunk getChunk() {
|
||||
return world.getChunkAt( x, z );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the chunk that this location represents is loaded.
|
||||
*
|
||||
* @return
|
||||
* If the chunk is loaded. Does not load the chunk.
|
||||
*/
|
||||
public boolean isLoaded() {
|
||||
return getWorld().isChunkLoaded( x, z );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the chunk that this location represents.
|
||||
*/
|
||||
public void load() {
|
||||
getWorld().loadChunk( x, z );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this chunk exists.
|
||||
*
|
||||
* @return
|
||||
* Checks if the chunk exists, does not have to be loaded.
|
||||
*/
|
||||
public boolean exists() {
|
||||
return getWorld().loadChunk( x, z, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ( ( worldName == null ) ? 0 : worldName.hashCode() );
|
||||
result = prime * result + x;
|
||||
result = prime * result + z;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( this == obj ) {
|
||||
return true;
|
||||
}
|
||||
if ( obj == null ) {
|
||||
return false;
|
||||
}
|
||||
if ( getClass() != obj.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunkLocation other = ( ChunkLocation ) obj;
|
||||
|
||||
if ( worldName == null ) {
|
||||
if ( other.worldName != null ) {
|
||||
return false;
|
||||
}
|
||||
} else if ( !worldName.equals( other.worldName ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( x != other.x ) {
|
||||
return false;
|
||||
}
|
||||
if ( z != other.z ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChunkLocation{x:" + x + ",z:" + z + ",world:" + worldName + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class Component {
|
||||
|
||||
|
||||
public Collection< Component > getComponents() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class Facet {
|
||||
public Vector normal;
|
||||
public List< Vector > points = new ArrayList< Vector >();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class LineSegment {
|
||||
public Vector point1, point2;
|
||||
|
||||
public LineSegment( Vector point1, Vector point2 ) {
|
||||
if ( point1.getX() < point2.getX() ) {
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
} else if ( point1.getX() > point2.getX() ) {
|
||||
this.point1 = point2;
|
||||
this.point2 = point1;
|
||||
} else if ( point1.getY() < point2.getY() ) {
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
} else if ( point1.getY() > point2.getY() ) {
|
||||
this.point1 = point2;
|
||||
this.point2 = point1;
|
||||
} else if ( point1.getZ() < point2.getZ() ) {
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
} else if ( point1.getZ() > point2.getZ() ) {
|
||||
this.point1 = point2;
|
||||
this.point2 = point1;
|
||||
} else {
|
||||
// point 1 and 2 are the same, I guess...
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPoint() {
|
||||
return point1.equals( point2 );
|
||||
}
|
||||
|
||||
public double length() {
|
||||
return point1.distance( point2 );
|
||||
}
|
||||
|
||||
public Vector getVector() {
|
||||
return point2.clone().subtract( point1 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class MeshBuilder {
|
||||
public List< Plane > planes = new ArrayList< Plane >();
|
||||
|
||||
public Plane addFacet( Facet facet ) {
|
||||
for ( Plane plane : planes ) {
|
||||
if ( plane.matches( facet.normal, facet.points.get( 0 ) ) ) {
|
||||
plane.addShape( facet );
|
||||
return plane;
|
||||
}
|
||||
}
|
||||
|
||||
Plane plane = new Plane();
|
||||
plane.normal = facet.normal;
|
||||
Optional< Vector > ref = facet.points.stream().filter( v -> v.lengthSquared() > 0.001 && Math.abs( v.clone().normalize().dot( facet.normal ) ) < .999999 ).findAny();
|
||||
if ( ref.isPresent() ) {
|
||||
plane.point = ref.get();
|
||||
} else {
|
||||
System.out.println( "Normal " + facet.normal );
|
||||
for ( Vector point : facet.points ) {
|
||||
System.out.println( point );
|
||||
}
|
||||
System.exit( 1 );
|
||||
}
|
||||
plane.addShape( facet );
|
||||
planes.add( plane );
|
||||
return plane;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.objects.mesh;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
import org.joml.Matrix3d;
|
||||
import org.joml.Vector3d;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.Point;
|
||||
import com.aaaaahhhhhhh.bananapuncher714.tess4j.Polygon;
|
||||
|
||||
public class Plane {
|
||||
public Vector normal;
|
||||
public Vector point;
|
||||
|
||||
public List< Polygon > polygons = new ArrayList< Polygon >();
|
||||
|
||||
public void addShape( Facet facet ) {
|
||||
// TODO Flatten the polygons into 2d points
|
||||
// Get the basis of this plane
|
||||
Vector basis1 = normal.clone().multiply( point.clone().multiply( -1 ).dot( normal ) ).add( point ).normalize();
|
||||
Vector3d b1 = new Vector3d( basis1.getX(), basis1.getY(), basis1.getZ() );
|
||||
Vector3d b3 = new Vector3d( normal.getX(), normal.getY(), normal.getZ() );
|
||||
Vector3d b2 = new Vector3d( b1 ).cross( b3 ).normalize();
|
||||
Matrix3d mat = new Matrix3d( b1, b2, b3 ).transpose();
|
||||
|
||||
List< Point > polygon = new ArrayList< Point >();
|
||||
for ( Vector p : facet.points ) {
|
||||
double t = point.clone().subtract( p ).dot( normal );
|
||||
Vector i = normal.clone().multiply( t ).add( p ).subtract( point );
|
||||
|
||||
Vector3d v = new Vector3d( i.getX(), i.getY(), i.getZ() );
|
||||
|
||||
Vector3d r = v.mul( mat );
|
||||
|
||||
polygon.add( new Point( r.x(), r.y() ) );
|
||||
}
|
||||
|
||||
polygons.add( new Polygon( polygon ) );
|
||||
}
|
||||
|
||||
public boolean matches( Vector normal, Vector point ) {
|
||||
return Math.abs( this.normal.dot( normal ) ) > 0.99 && Math.abs( this.point.clone().subtract( point ).dot( normal ) ) < 0.01;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoader;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.SimplePluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
|
||||
import com.aaaaahhhhhhh.bananapuncher714.minietest.MiniePlugin;
|
||||
|
||||
public class BukkitUtil {
|
||||
private static Constructor< PluginCommand > PLUGINCOMMAND_CONSTRUCTOR;
|
||||
private static Field SIMPLEPLUGINMANAGER_FILEASSOCIATIONS;
|
||||
private static Method JAVAPLUGINLOADER_GETCLASS_1;
|
||||
private static Method JAVAPLUGINLOADER_GETCLASS_2;
|
||||
private static Method JAVAPLUGINLOADER_SETCLASS;
|
||||
private static Method JAVAPLUGINLOADER_REMOVECLASS_1;
|
||||
private static Method JAVAPLUGINLOADER_REMOVECLASS_2;
|
||||
|
||||
static {
|
||||
try {
|
||||
PLUGINCOMMAND_CONSTRUCTOR = PluginCommand.class.getDeclaredConstructor( String.class, Plugin.class );
|
||||
PLUGINCOMMAND_CONSTRUCTOR.setAccessible( true );
|
||||
SIMPLEPLUGINMANAGER_FILEASSOCIATIONS = SimplePluginManager.class.getDeclaredField( "fileAssociations" );
|
||||
SIMPLEPLUGINMANAGER_FILEASSOCIATIONS.setAccessible( true );
|
||||
JAVAPLUGINLOADER_SETCLASS = JavaPluginLoader.class.getDeclaredMethod( "setClass", String.class, Class.class );
|
||||
JAVAPLUGINLOADER_SETCLASS.setAccessible( true );
|
||||
} catch ( NoSuchMethodException | SecurityException | NoSuchFieldException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
JAVAPLUGINLOADER_GETCLASS_1 = JavaPluginLoader.class.getDeclaredMethod( "getClassByName", String.class );
|
||||
JAVAPLUGINLOADER_GETCLASS_1.setAccessible( true );
|
||||
} catch ( NoSuchMethodException | SecurityException e ) {
|
||||
try {
|
||||
JAVAPLUGINLOADER_GETCLASS_2 = JavaPluginLoader.class.getDeclaredMethod( "getClassByName", String.class, boolean.class, PluginDescriptionFile.class );
|
||||
JAVAPLUGINLOADER_GETCLASS_2.setAccessible( true );
|
||||
} catch ( NoSuchMethodException | SecurityException e1 ) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
JAVAPLUGINLOADER_REMOVECLASS_1 = JavaPluginLoader.class.getDeclaredMethod( "removeClass", String.class );
|
||||
JAVAPLUGINLOADER_REMOVECLASS_1.setAccessible( true );
|
||||
} catch ( NoSuchMethodException | SecurityException e ) {
|
||||
try {
|
||||
JAVAPLUGINLOADER_REMOVECLASS_2 = JavaPluginLoader.class.getDeclaredMethod( "removeClass", Class.class );
|
||||
JAVAPLUGINLOADER_REMOVECLASS_2.setAccessible( true );
|
||||
} catch ( NoSuchMethodException | SecurityException e1 ) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static PluginCommand constructCommand( String id ) {
|
||||
PluginCommand command = null;
|
||||
try {
|
||||
command = PLUGINCOMMAND_CONSTRUCTOR.newInstance( id, JavaPlugin.getPlugin( MiniePlugin.class ) );
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call an event synchronously, on the main thread
|
||||
*/
|
||||
public static void callEventSync( Event event ) {
|
||||
if ( Bukkit.getServer().isPrimaryThread() ) {
|
||||
Bukkit.getPluginManager().callEvent( event );
|
||||
} else {
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask( JavaPlugin.getPlugin( MiniePlugin.class ), () -> { callEventSync( event ); } );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the plugin given is loaded
|
||||
*
|
||||
* @param id
|
||||
* case sensitive plugin id
|
||||
* @return
|
||||
* If the plugin is loaded and enabled
|
||||
*/
|
||||
public static boolean isPluginLoaded( String id ) {
|
||||
return Bukkit.getPluginManager().isPluginEnabled( id );
|
||||
}
|
||||
|
||||
public static Class< ? > getClassByName( String name ) {
|
||||
PluginManager manager = Bukkit.getPluginManager();
|
||||
if ( manager instanceof SimplePluginManager ) {
|
||||
SimplePluginManager sManager = ( SimplePluginManager ) manager;
|
||||
try {
|
||||
Map< Pattern, PluginLoader > associations = ( Map< Pattern, PluginLoader > ) SIMPLEPLUGINMANAGER_FILEASSOCIATIONS.get( sManager );
|
||||
for ( PluginLoader loader : associations.values() ) {
|
||||
if ( loader instanceof JavaPluginLoader ) {
|
||||
if ( JAVAPLUGINLOADER_GETCLASS_1 != null ) {
|
||||
return ( Class< ? > ) JAVAPLUGINLOADER_GETCLASS_1.invoke( loader, name );
|
||||
} else {
|
||||
return ( Class< ? > ) JAVAPLUGINLOADER_GETCLASS_2.invoke( loader, name, true, JavaPlugin.getPlugin( MiniePlugin.class ).getDescription() );
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch ( IllegalArgumentException | IllegalAccessException | InvocationTargetException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void setClassToJavaPluginLoader( String name, Class< ? > clazz ) {
|
||||
PluginManager manager = Bukkit.getPluginManager();
|
||||
if ( manager instanceof SimplePluginManager ) {
|
||||
SimplePluginManager sManager = ( SimplePluginManager ) manager;
|
||||
try {
|
||||
Map< Pattern, PluginLoader > associations = ( Map< Pattern, PluginLoader > ) SIMPLEPLUGINMANAGER_FILEASSOCIATIONS.get( sManager );
|
||||
for ( PluginLoader loader : associations.values() ) {
|
||||
if ( loader instanceof JavaPluginLoader ) {
|
||||
JAVAPLUGINLOADER_SETCLASS.invoke( loader, name, clazz );
|
||||
}
|
||||
}
|
||||
} catch ( IllegalArgumentException | IllegalAccessException | InvocationTargetException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean removeClassFromJavaPluginLoader( Class clazz ) {
|
||||
if ( JAVAPLUGINLOADER_REMOVECLASS_2 != null ) {
|
||||
PluginManager manager = Bukkit.getPluginManager();
|
||||
if ( manager instanceof SimplePluginManager ) {
|
||||
SimplePluginManager sManager = ( SimplePluginManager ) manager;
|
||||
try {
|
||||
Map< Pattern, PluginLoader > associations = ( Map< Pattern, PluginLoader > ) SIMPLEPLUGINMANAGER_FILEASSOCIATIONS.get( sManager );
|
||||
for ( PluginLoader loader : associations.values() ) {
|
||||
if ( loader instanceof JavaPluginLoader ) {
|
||||
JAVAPLUGINLOADER_REMOVECLASS_2.invoke( loader, clazz );
|
||||
}
|
||||
}
|
||||
} catch ( IllegalArgumentException | IllegalAccessException | InvocationTargetException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean removeClassFromJavaPluginLoader( String name ) {
|
||||
if ( JAVAPLUGINLOADER_REMOVECLASS_1 != null ) {
|
||||
PluginManager manager = Bukkit.getPluginManager();
|
||||
if ( manager instanceof SimplePluginManager ) {
|
||||
SimplePluginManager sManager = ( SimplePluginManager ) manager;
|
||||
try {
|
||||
Map< Pattern, PluginLoader > associations = ( Map< Pattern, PluginLoader > ) SIMPLEPLUGINMANAGER_FILEASSOCIATIONS.get( sManager );
|
||||
for ( PluginLoader loader : associations.values() ) {
|
||||
if ( loader instanceof JavaPluginLoader ) {
|
||||
JAVAPLUGINLOADER_REMOVECLASS_1.invoke( loader, name );
|
||||
}
|
||||
}
|
||||
} catch ( IllegalArgumentException | IllegalAccessException | InvocationTargetException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.aaaaahhhhhhh.bananapuncher714.minietest.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
/**
|
||||
* Simple file management including YAML updaters
|
||||
*
|
||||
* @author BananaPuncher714
|
||||
*/
|
||||
public final class FileUtil {
|
||||
public static void saveAndUpdate( InputStream stream, File output, boolean trim ) {
|
||||
if ( !output.exists() ) {
|
||||
saveToFile( stream, output, false );
|
||||
}
|
||||
updateConfigFromFile( output, stream, trim );
|
||||
}
|
||||
|
||||
public static void saveToFile( InputStream stream, File output, boolean force ) {
|
||||
if ( force && output.exists() ) {
|
||||
output.delete();
|
||||
}
|
||||
if ( !output.exists() ) {
|
||||
output.getParentFile().mkdirs();
|
||||
try ( OutputStream outStream = new FileOutputStream( output ) ) {
|
||||
byte[] buffer = new byte[ stream.available() ];
|
||||
|
||||
int len;
|
||||
while ( ( len = stream.read( buffer ) ) > 0) {
|
||||
outStream.write( buffer, 0, len );
|
||||
}
|
||||
stream.close();
|
||||
} catch ( FileNotFoundException e ) {
|
||||
e.printStackTrace();
|
||||
} catch ( IOException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void updateConfigFromFile( File toUpdate, InputStream toCopy ) {
|
||||
updateConfigFromFile( toUpdate, toCopy, false );
|
||||
}
|
||||
|
||||
public static void updateConfigFromFile( File toUpdate, InputStream toCopy, boolean trim ) {
|
||||
FileConfiguration config = YamlConfiguration.loadConfiguration( new InputStreamReader( toCopy ) );
|
||||
FileConfiguration old = YamlConfiguration.loadConfiguration( toUpdate );
|
||||
|
||||
for ( String key : config.getKeys( true ) ) {
|
||||
if ( !old.contains( key ) ) {
|
||||
old.set( key, config.get( key ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( trim ) {
|
||||
for ( String key : old.getKeys( true ) ) {
|
||||
if ( !config.contains( key ) ) {
|
||||
old.set( key, null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
old.save( toUpdate );
|
||||
} catch ( Exception exception ) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean move( File original, File dest, boolean force ) {
|
||||
if ( dest.exists() ) {
|
||||
if ( !force ) {
|
||||
return false;
|
||||
} else {
|
||||
recursiveDelete( dest );
|
||||
}
|
||||
}
|
||||
dest.getParentFile().mkdirs();
|
||||
original.renameTo( dest );
|
||||
recursiveDelete( original );
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void recursiveDelete( File file ) {
|
||||
if ( !file.exists() ) {
|
||||
return;
|
||||
}
|
||||
if ( file.isDirectory() ) {
|
||||
for ( File lower : file.listFiles() ) {
|
||||
recursiveDelete( lower );
|
||||
}
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
|
||||
public static < T extends Serializable > T readObject( Class< T > clazz, File file ) throws IOException, ClassNotFoundException {
|
||||
if ( !file.exists() ) {
|
||||
return null;
|
||||
}
|
||||
T head = null;
|
||||
FileInputStream fis = new FileInputStream( file );
|
||||
ObjectInputStream ois = new ObjectInputStream( fis );
|
||||
|
||||
head = ( T ) ois.readObject();
|
||||
|
||||
ois.close();
|
||||
fis.close();
|
||||
return head;
|
||||
}
|
||||
|
||||
public static void writeObject( Serializable object, File file ) {
|
||||
file.getParentFile().mkdirs();
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream( file );
|
||||
ObjectOutputStream oos = new ObjectOutputStream( fos );
|
||||
|
||||
oos.writeObject( object );
|
||||
|
||||
oos.close();
|
||||
fos.close();
|
||||
} catch ( Exception exception ) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static File getImageFile( File dir, String prefix ) {
|
||||
File image = new File( dir + "/" + prefix + ".png" );
|
||||
for ( File file : dir.listFiles() ) {
|
||||
String fileName = file.getName();
|
||||
if ( fileName.equalsIgnoreCase( prefix + ".gif" ) ) {
|
||||
return file;
|
||||
} else if ( fileName.equalsIgnoreCase( prefix + ".png" ) || fileName.equalsIgnoreCase( prefix + ".jpg" ) || fileName.equalsIgnoreCase( prefix + ".jpeg" ) || fileName.equalsIgnoreCase( prefix + ".bmp" ) ) {
|
||||
image = file;
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user