I want to create a minecraft GUI that use a inventory. I have make all the GUI with the items inside. But when I try to interact with the GUI (like clicking on a item), it's make nothing. So I'm pretty sure that it's the InventoryClickEvent that don't work.
This is my code:
package can.evilestvirus.randomtp;
import java.util.Arrays;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.PluginManager;
public class CommandRtp implements CommandExecutor {
#Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;
Inventory inv = Bukkit.createInventory(null, 9, "Menu de tp aléatoire");
ItemStack goldBlock = new ItemStack(Material.GOLD_BLOCK, 1);
ItemMeta goldBlockM = goldBlock.getItemMeta();
goldBlockM.setDisplayName("§8[§a+§8] §aRandomTP Normal §8[§a+§8]");
goldBlockM.setLore(Arrays.asList("§b- §6Distance de TP: 2500 Blocks", "§b- §6Prix: $0", "§b- §6Cooldown de 60 secondes", "§a§lCliquez ici pour utiliser"));
goldBlockM.addEnchant(Enchantment.DURABILITY, 10, true);
goldBlockM.addItemFlags(ItemFlag.HIDE_ENCHANTS);
goldBlock.setItemMeta(goldBlockM);
inv.setItem(3, goldBlock);
ItemStack diamondBlock = new ItemStack(Material.DIAMOND_BLOCK, 1);
ItemMeta diamondBlockM = diamondBlock.getItemMeta();
diamondBlockM.setDisplayName("§8[§a+§8] §aRandomTP §6§lVIP §8[§a+§8]");
diamondBlockM.setLore(Arrays.asList("§b- §6Distance de TP: 5000 Blocks", "§b- §6Prix: $1000", "§b- §6Cooldown de 5 minutes", "§a§lCliquez ici pour utiliser"));
diamondBlockM.addEnchant(Enchantment.DURABILITY, 10, true);
diamondBlockM.addItemFlags(ItemFlag.HIDE_ENCHANTS);
diamondBlock.setItemMeta(diamondBlockM);
inv.setItem(5, diamondBlock);
player.openInventory(inv);
}
return true;
}
#EventHandler
public void onClick(InventoryClickEvent event) {
Player player = (Player) event.getWhoClicked();
ItemStack current = event.getCurrentItem();
if(current == null) return;
if(event.getInventory().getTitle().equals("Menu de tp aléatoire")) {
event.setCancelled(true);
if(current.getType() == Material.GOLD_BLOCK) {
player.closeInventory();
player.chat("/rtpPlayer");
}
if(current.getType() == Material.DIAMOND_BLOCK) {
player.closeInventory();
player.setFlying(true);
}
}
}
}
The code of my main class is this:
package can.evilestvirus.randomtp;
import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import can.evilestvirus.randomtp.CommandRtpPlayer;
public class Main extends JavaPlugin {
#Override
public void onEnable() {
System.out.println("HELLO PEOPLE!");
this.getCommand("rtpplayer").setExecutor(new CommandRtpPlayer());
this.getCommand("rtp").setExecutor(new CommandRtp());
Bukkit.getPluginManager().registerEvents((Listener) this, Bukkit.getPluginManager().getPlugins()[0]);
Bukkit.getPluginManager().registerEvents((Listener) new CommandRtp(), this);
}
}
You need to implement Listener in your CommandRtp class. Once you do this it should work.
So your class will look like this:
public class CommandRtp implements Listener, CommandExecutor {
// Code
}
Okay, so I have found my error. I have create I new class and I register correctly the new class. After I change the IF that check if my menu is the same than the command menu because the function that I use was not fonctional.
So this is my new code for those that have the same problem that me:
package can.evilestvirus.randomtp;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
public class MenuHandler implements Listener {
#EventHandler
public void onMenuClick(InventoryClickEvent e){
Player player = (Player) e.getWhoClicked();
if(e.getView().getTitle().equalsIgnoreCase("Menu de tp aleatoire")){
e.setCancelled(true);
if (e.getCurrentItem().getType() == Material.GOLD_BLOCK) {
player.closeInventory();
player.chat("/rtpPlayer");
}
if (e.getCurrentItem().getType() == Material.DIAMOND_BLOCK) {
player.closeInventory();
player.setFlying(true);
}
}
}
}
This is the main class:
package can.evilestvirus.randomtp;
import org.bukkit.Bukkit;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin{
#Override
public void onEnable() {
getCommand("rtpplayer").setExecutor(new CommandRtpPlayer());
getCommand("rtp").setExecutor(new CommandRtp());
Bukkit.getPluginManager().registerEvents(new MenuHandler(), this);
}
}
You can use this event:
#EventHandler
public void onInventoryClick(InventoryClickEvent event) {
}
For me it works
Related
Problem:After the ActionEvent is triggered (selecting an account), the comboBox is null. When I run the program, I can see that the ComboBox is populated. I think I'm doing something wrong with the FXML loader. I read through the following document: https://openjfx.io/javadoc/12/javafx.fxml/javafx/fxml/doc-files/introduction_to_fxml.html#controllers
While thrilling (actually learned a lot), the document did not give me an answer to my problem. Please advise.... Referring me to another source for further education would be appreciated. If you need more information to answer the question, let me know.
Caused by: java.lang.NullPointerException: Cannot invoke "javafx.scene.control.ComboBox.setItems(javafx.collections.ObservableList)" because "this.accountComboBox" is null at application.budget/application.budget.Controller.initialize(Controller.java:67)
Line 67 is: accountComboBox.setItems(accountlist);
package application.budget;
import datamodel.Account;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;
import java.io.IOException;
import java.text.NumberFormat;
public class Controller {
public Button detacctinfo;
private Stage stage;
private Scene scene;
private Parent root;
#FXML
private Button createnewacct, Submit;
#FXML
private AnchorPane mainPanel;
#FXML
private ComboBox<Account> accountComboBox;
#FXML
Label acctbalField = new Label();
private NumberFormat fmt;
public void initialize () {
ObservableList<Account> accountlist = FXCollections.observableArrayList();
accountlist.add(new Account("Bank of America", 10010101.32));
accountlist.add(new Account("Prosperity Bank", 10010101.32));
//ComboBox<Account> selectacct = new ComboBox<>();
// Use a StringConverter to configure our ComboBox to display only the film's title
/* accountComboBox.setConverter(new StringConverter<Account>() {
#Override
public String toString(Account account) {
return account.getAccountName();
}
#Override
public Account fromString(String string) {
return accountComboBox.getItems().stream().filter(ap ->
ap.getAccountName().equals(string)).findFirst().orElse(null);
}
});*/
// Finally, set our ComboBox's items to our sample list
accountComboBox.setItems(accountlist);
System.out.println(accountlist);
}
public void OnItemSelected(ActionEvent e ) throws IOException {
root = FXMLLoader.load(getClass().getResource("AccountHome.fxml"));
Stage window = (Stage) Submit.getScene().getWindow();
window.setScene(new Scene(root));
}
}
package datamodel;
public class Account {
private String accountName;
private Double accountBalance;
public Account(String accountName, Double accountBalance) {
this.accountName = accountName;
this.accountBalance = accountBalance;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public Double getAccountBalance() {
return accountBalance;
}
public void setAccountBalance(Double accountBalance) {
this.accountBalance = accountBalance;
}
#Override //Esto dice que cuando un variable se usa, va a dar el valor de abajo
public String toString() {
return accountName;
}
public String getBalance() {
return String.valueOf(accountBalance);
}
}
Caused by: java.lang.NullPointerException: Cannot invoke "javafx.scene.control.ComboBox.setItems(javafx.collections.ObservableList)" because "this.accountComboBox" is null
at application.budget/application.budget.Controller.initialize(Controller.java:67)
Line 67 is: accountComboBox.setItems(accountlist);
After some research, it seems like each FXML document needs it's own controller. Been doing this for about 2 weeks. Excuse the lack of education on my part.
manifest file
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 20.1-b02 (Sun Microsystems Inc.)
SplashScreen-Image: Images/Splash.gif
Permissions: all-permissions
Application-Name: DealEntry Application
The path to the splash screen is correct
On SplashScreen.getSplashScreen() null is returned. Somehow it is not working in my application. Altough I tried a demo where it worked.
import org.apache.log4j.Logger;
import javax.swing.*;
import java.awt.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.event.*;
public class Splash extends Frame implements ActionListener {
static void renderSplashFrame(Graphics2D g, int frame)
{
final String[] comps = {"foo", "bar", "baz"};
g.setComposite(AlphaComposite.Clear);
g.fillRect(120,140,200,40);
g.setPaintMode();
g.setColor(Color.BLACK);
g.drawString("Loading "+comps[(frame/5)%3]+"...", 120, 150);
}
public Splash() {
final SplashScreen splash = SplashScreen.getSplashScreen();
Always returns null when the jar os executed using javaws.
if (splash == null) {
System.out.println("SplashScreen.getSplashScreen() returned
null");
return;
}
Graphics2D g = splash.createGraphics();
if (g == null) {
System.out.println("g is null");
return;
}
}
public void actionPerformed(ActionEvent ae) {
}
private static WindowListener closeWindow = new WindowAdapter(){
public void windowClosing(WindowEvent e){
e.getWindow().dispose();
}
};
public static void main (String args[]) {
Splash test = new Splash();
}
}
I have the following code which works great when I have standard row selection (always single, never multi).
//This is needed to set the X & Y coordinates of the stage for edit.
myTable.setRowFactory(tableView -> {
TableRow<MyDTO> row = new TableRow<MyDTO>();
row.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
lastSelectedRow.set(row);
}
});
return row ;
});
I am using the row to get the bounds in parent so that when a user selects to edit that row, I can pop a modal window up under the row for them to edit this.
However, my table is also editable for the common fields where there is no look up needed, etc. In that case I want to edit in the table. All this is working, however to make it more user friendly, I want to have cell selection turned on, but when I do that, the row.selectedProptery() listener doesn't fire.
How can I accomplish that, without trying to listen to the selectedProperty() of each cell?
Thanks
I don't think there's a way to do this without registering a listener with the selection property of each cell, via a cell factory on each table column.
However, this isn't too difficult, and can be done both generically (i.e. with the same code no matter the type of the table column) and also respecting any other cell factory behavior you need. Here is a SSCCE:
import java.util.Random;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Callback;
public class SelectedTableCellTracking extends Application {
private final ObjectProperty<TableCell<?,?>> selectedCell = new SimpleObjectProperty<>();
#Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>();
TableColumn<Item, String> itemCol = column("Item", Item::nameProperty);
TableColumn<Item, Number> valueCol = column("Value", Item::valueProperty);
table.getColumns().add(itemCol);
table.getColumns().add(valueCol);
Random rng = new Random();
for (int i = 1 ; i <= 100; i++) {
table.getItems().add(new Item("Item "+i, rng.nextInt(1000)));
}
table.getSelectionModel().setCellSelectionEnabled(true);
Rectangle highlight = new Rectangle();
highlight.setManaged(false);
highlight.setHeight(12);
highlight.setFill(Color.CORAL);
StackPane root = new StackPane(table, highlight);
selectedCell.addListener((obs, oldCell, newCell) -> {
if (newCell == null) {
highlight.setVisible(false);
} else {
highlight.setVisible(true);
highlight.setX(newCell.localToScene(newCell.getBoundsInLocal()).getMinX());
highlight.setWidth(newCell.getWidth());
highlight.setY(newCell.localToScene(newCell.getBoundsInLocal()).getMaxY());
}
});
table.getColumns().forEach(this::addCellSelectionListenerToColumn);
Scene scene = new Scene(root, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
private <S,T> void addCellSelectionListenerToColumn(TableColumn<S,T> col) {
Callback<TableColumn<S,T>, TableCell<S,T>> currentCellFactory = col.getCellFactory();
col.setCellFactory(tc -> {
TableCell<S,T> cell = currentCellFactory.call(tc);
cell.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
selectedCell.set(cell);
}
});
return cell ;
});
}
private static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
return col ;
}
public static class Item {
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty value = new SimpleIntegerProperty();
public Item(String name, int value) {
setName(name);
setValue(value);
}
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
public final IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
}
public static void main(String[] args) {
launch(args);
}
}
I could really use some help. I'm having trouble getting my Android Wear device to recognize data changes made by my activity that runs on my Android tablet. I'm relatively new to Android and very new to the Wear APIs so I might be missing something completely obvious or trivial without realizing. I've pieced together a project from a couple of examples from the Android Wear doc pages and from the TwoToasters example on github. I just want to get data communication set up between the devices so that I can then edit the code in order to display images from my tablet on my Wear device. Ultimately, I want to be able to start/stop a slideshow on my Wear device from my tablet but I should be able to get there on my own once I get the data communication protocol set up and working so I'm really just looking for help with that. Here is my code so far:
Mobile:
package com.example.administrator.moto360displaycontrol;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import android.widget.ToggleButton;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.wearable.Asset;
import com.google.android.gms.wearable.DataApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.PutDataMapRequest;
import com.google.android.gms.wearable.PutDataRequest;
import com.google.android.gms.wearable.Wearable;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class MainActivity extends Activity {
private static final long CONNECTION_TIME_OUT_MS = 100;
private static final String ON_MESSAGE = "On!";
private static final String OFF_MESSAGE = "Off!";
private String message = null;
int count = 0;
private GoogleApiClient client;
private String nodeId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initApi();
setupWidgets();
}
/**
* Initializes the GoogleApiClient and gets the Node ID of the connected device.
*/
private void initApi() {
client = getGoogleApiClient(this);
retrieveDeviceNode();
}
/**
* Returns a GoogleApiClient that can access the Wear API.
* #param context
* #return A GoogleApiClient that can make calls to the Wear API
*/
private GoogleApiClient getGoogleApiClient(Context context) {
return new GoogleApiClient.Builder(context)
.addApi(Wearable.API)
.build();
}
/**
* Connects to the GoogleApiClient and retrieves the connected device's Node ID. If there are
* multiple connected devices, the first Node ID is returned.
*/
private void retrieveDeviceNode() {
new Thread(new Runnable() {
#Override
public void run() {
client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
NodeApi.GetConnectedNodesResult result =
Wearable.NodeApi.getConnectedNodes(client).await();
List<Node> nodes = result.getNodes();
if (nodes.size() > 0) {
nodeId = nodes.get(0).getId();
}
client.disconnect();
}
}).start();
}
/**
* Sets up the button for handling click events.`
*/
private void setupWidgets() {
findViewById(R.id.toggleButton).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
Asset asset = createAssetFromBitmap(bitmap);
PutDataRequest request = PutDataRequest.create("/image");
request.putAsset("profileImage", asset);
Wearable.DataApi.putDataItem(client, request);
showToast("SentData");
}
});
}
private static Asset createAssetFromBitmap(Bitmap bitmap) {
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream);
return Asset.createFromBytes(byteStream.toByteArray());
}
public void showToast(String string) {
Toast.makeText(this, string, Toast.LENGTH_LONG).show();
}
}
Wear:
package com.example.administrator.moto360displaycontrol;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.Asset;
import com.google.android.gms.wearable.DataApi;
import com.google.android.gms.wearable.DataEvent;
import com.google.android.gms.wearable.DataEventBuffer;
import com.google.android.gms.wearable.DataMapItem;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
import android.widget.Toast;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class MainActivity extends Activity implements
DataApi.DataListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{
private TextView mTextView;
private static final long CONNECTION_TIME_OUT_MS = 100;
private static final String ON_MESSAGE = "On!";
private static final String OFF_MESSAGE = "Off!";
private static final String TAG = "Moto360DisplayControl";
private GoogleApiClient client;
private String nodeId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initApi();
}
private void initApi() {
client = getGoogleApiClient(this);
retrieveDeviceNode();
}
private GoogleApiClient getGoogleApiClient(Context context) {
return new GoogleApiClient.Builder(context)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
private void retrieveDeviceNode() {
new Thread(new Runnable() {
#Override
public void run() {
client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
NodeApi.GetConnectedNodesResult result =
Wearable.NodeApi.getConnectedNodes(client).await();
List<Node> nodes = result.getNodes();
if (nodes.size() > 0) {
nodeId = nodes.get(0).getId();
}
client.disconnect();
}
}).start();
}
#Override
protected void onStart() {
super.onStart();
client.connect();
}
#Override
public void onConnected(Bundle connectionHint) {
Wearable.DataApi.addListener(client, this);
Toast.makeText(this, "AddedListener!", Toast.LENGTH_LONG).show();
}
#Override
public void onConnectionSuspended(int num) {
Toast.makeText(this, "ConnectionSuspended", Toast.LENGTH_LONG).show();
}
#Override
public void onConnectionFailed(ConnectionResult res) {
Toast.makeText(this, "ConnectionFailed", Toast.LENGTH_LONG).show();
}
#Override
protected void onStop() {
Wearable.DataApi.removeListener(client, this);
client.disconnect();
super.onStop();
}
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
Toast.makeText(this, "DataChanged!", Toast.LENGTH_LONG).show();
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED && event.getDataItem().getUri().getPath().equals("/image")) {
DataMapItem dataMapItem = DataMapItem.fromDataItem(event.getDataItem());
Asset profileAsset = dataMapItem.getDataMap().getAsset("profileImage");
Bitmap bitmap = loadBitmapFromAsset(profileAsset);
// Do something with bitmap
Toast.makeText(this, "DataChanged!", Toast.LENGTH_LONG).show();
}
}
}
public Bitmap loadBitmapFromAsset(Asset asset) {
if (asset == null) {
throw new IllegalArgumentException("Asset must be non-null");
}
ConnectionResult result = client.blockingConnect(CONNECTION_TIME_OUT_MS, TimeUnit.MILLISECONDS);
if (!result.isSuccess()) {
return null;
}
// Convert asset into a file descriptor and block until it's ready
InputStream assetInputStream = Wearable.DataApi.getFdForAsset(client, asset).await().getInputStream();
client.disconnect();
if (assetInputStream == null) {
Log.w(TAG, "Requested an unknown Asset.");
return null;
}
// Decode the stream into a bitmap
return BitmapFactory.decodeStream(assetInputStream);
}
}
Everything "seems" to succeed as far as I can tell but the Toast in the Wear's "onDataChanged" method never shows up on the Wear's display which makes me think it isn't seeing the data change for some reason. Any help would be greatly appreciated!
Try adding a timestamp to your request on the handheld, it did the trick for me back then, and I think Google updated their documentations adding this bit of info
I am getting this error when creating a command for this youtube tutorial, he explains how to make a plugin where when you join fireworks explode and I wanted to make a command for it.
I got the error Syntax error on token "}", { expected. Here is my code:
package me.gecco123.EnterWithABang;
import org.bukkit.Bukkit;
import org.bukkit.Color;
import org.bukkit.FireworkEffect;
import org.bukkit.FireworkEffect.Type;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin implements Listener{
public void onDisable(){
getLogger().info("[EWAB] Disabled");
}
public void onEnable(){
getLogger().info("[EWAB] Enabled");
Bukkit.getServer().getPluginManager().registerEvents(this, this);
}
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
if (sender instanceof Player){
Player player = (Player) sender;
if (cmd.getName().equalsIgnoreCase("forcebang")){
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
public void run(){
PlayerJoinEvent pje;
Firework f = (Firework) pje.getPlayer().getWorld().spawn(pje.getPlayer().getLocation(), Firework.class);
FireworkMeta fm = f.getFireworkMeta();
fm.addEffect(FireworkEffect.builder()
.flicker(false)
.trail(true)
.with(Type.BALL)
.with(Type.BALL_LARGE)
.with(Type.STAR)
.withColor(Color.YELLOW)
.withColor(Color.ORANGE)
.withFade(Color.RED)
.withFade(Color.PURPLE)
.build());
fm.setPower(2);
f.setFireworkMeta(fm);
}
}, 20);
}
}
}
#EventHandler
public void onPlayerJoin (final PlayerJoinEvent pje){
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable(){
public void run(){
Firework f = (Firework) pje.getPlayer().getWorld().spawn(pje.getPlayer().getLocation(), Firework.class);
FireworkMeta fm = f.getFireworkMeta();
fm.addEffect(FireworkEffect.builder()
.flicker(false)
.trail(true)
.with(Type.BALL)
.with(Type.BALL_LARGE)
.with(Type.STAR)
.withColor(Color.YELLOW)
.withColor(Color.ORANGE)
.withFade(Color.RED)
.withFade(Color.PURPLE)
.build());
fm.setPower(2);
f.setFireworkMeta(fm);
}
}, 20);
}
}
}
}
The error is on the 3rd last bracket
Remove the last two brackets. You have 11 opening and 13 closing brackets.