ItemMeta - command and listener - java

How can I use itemmeta in another class?
public class Kart implements CommandExecutor {
#Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
Player p = (Player) sender;
if (label.equalsIgnoreCase("kart")) {
if (p.hasPermission("teamenders.komut.kart")) {
ItemStack kart = new ItemStack(Material.PAPER);
ItemMeta kartM = kart.getItemMeta();
ArrayList<String> tt = new ArrayList<String>();
kartM.setDisplayName(ChatColor.DARK_AQUA + "Yetki Karti");
tt.add(ChatColor.DARK_GREEN + "Giris Yetkisi");
kartM.setLore(tt);
kart.setItemMeta(kartM);
p.getInventory().addItem(new ItemStack(kart));
} else {
p.sendMessage(ChatColor.DARK_RED + "Yetersiz Yetki!!!!!");
}
}
return false;
}
}
My 2nd class:
#EventHandler
public void onPInteract(PlayerInteractEvent e) {
Player p = e.getPlayer();
if (e.getAction() == Action.RIGHT_CLICK_AIR) {
if (p.getItemInHand().getType() == Material.PAPER && p.getItemInHand().hasItemMeta()) {
p.sendMessage(ChatColor.DARK_AQUA + "Yetkiyi aldin.");
}
}
}
I want use first class itemmeta in 2nd class "p.getItemInHand"

Store it using an ArrayList outside of your Kart class, then retrieve the data in your EventHandler.

In your first class, create a global variable (outside any function) and store the value of kart.getItemMeta().
Still in your first class, create a function that returns this variable.
In your second class, create another global variable Kart kart and create a function public *nameOfYourClass*(Kart kart){this.kart = kart}. You should then be able to do kart.*functionOfFirstStep*.
Please tell me if I wasn't clear enough.

Related

Constructor chaining and preparing arguments before calling this(aguments)

I am making a Yahtzee game. I want to supply a constructor for different cases. Suppose you couldn't be bothered to supply the names of the players that you want to create a new game with, I'd like to just create "Unnamed Player 1", "Unnamed Player 2", etc.
Here is how I am trying to do that:
public class YahtzeeGame {
private List<Player> players = new ArrayList<>();
public YahtzeeGame(String[] playerNames) {
for (String playerName : playerNames) {
players.add(new Player(playerName));
}
}
public YahtzeeGame(int numberOfPlayers) {
String[] playerNames = new String[numberOfPlayers];
for (int i = 0; i < numberOfPlayers; i++) {
playerNames[i] = "Unnamed player " + (i+1);
}
this(playerNames); // ERROR: "Constructor call must be the first statement in a constructor.
}
public YahtzeeGame(String playerName) {
this(new String[] {playerName});
}
public YahtzeeGame() {
this("Unnamed player");
}
}
This doesn't work of course, as per the error written in the comment.
Is there a way around this? Do I need a factory pattern for this?
Yes, there's fairly simple way around it, at least in this case: create a static method which will prepare the constructor argument for you. Call that from the this expression:
public YahtzeeGame(int numberOfPlayers) {
this(getUnnamedPlayers(numberOfPlayers));
}
private static String[] getUnnamedPlayers(int numberOfPlayers) {
String[] playerNames = new String[numberOfPlayers];
for (int i = 0; i < numberOfPlayers; i++) {
playerNames[i] = "Unnamed player " + (i+1);
}
return playerNames;
}
Note that it does have to be static, because you can't call any instance methods on this before the chained constructor, either.

JAVA/SPIGOT: How can I make a variable called from non static classes?

I'm very new with Java and was introduced to it by creating Minecraft plugins. I am currently using Spigot and want a variable to be accessed through another class. In this plugin, I want players to be able to create a Hero that has certain abilities. The two classes that I use are below.
package me.placerwiz;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
public class Moba extends JavaPlugin {
StompCooldown a;
#Override
public void onEnable() {
getServer().getPluginManager().registerEvents(new MenuClick(this), this);
new PlayerListener(this);
new StompAbility(this);
getLogger().info("This plugin has been enabled!");
a = new StompCooldown(this);
a.runTaskTimer(this, 20, 20);
getCommand("pearl").setExecutor(new WarpAbility());
getCommand("menu").setExecutor(this);
}
#Override
public void onDisable() {
}
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (cmd.getName().equalsIgnoreCase("Menu") && sender instanceof Player) {
Player player = (Player) sender;
player.openInventory(Menu.getMenu());
return true;
}
return false;
}
public static void sircunningham1_1(String args[]) {
SirCunningham_1_1 getLoadout = new SirCunningham_1_1();
getLoadout.heroChosen();
}
public static void sircunningham2_1(String args[]) {
SirCunningham_2_1 getLoadout = new SirCunningham_2_1();
getLoadout.heroChosen();
}
public void gotHero(String heroChoice) {
if (heroChoice == "") {
}
}
public boolean heroTest(CommandSender sender, Command cmd, String label, String[] args) {
if (cmd.getName().equalsIgnoreCase("hero") && sender instanceof Player) {
Player player = (Player) sender;
player.openInventory(Menu.getMenu());
return true;
}
return false;
}}
The code above is my main class, Moba. In this code, a variable called heroChoice is received from the other class. The only problem from this is that I want the code to get what the player has selected as the hero. When it gets the hero, I want it to get the hero that the player has selected. Is there anyway I can get a variable sent to the Moba class after the player clicks on the final inventory item. It might need to use this class where the player selects the final ability for the hero "Sir Cunningham". (See code below)
package me.placerwiz;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
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.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class SirCunningham_2_1{
static String hero;
public static Inventory getMenu(){
Inventory inv = Bukkit.createInventory(null, 18, ChatColor.GREEN + ChatColor.BOLD.toString() + "Choose ultimate ability!");
ItemStack item = new ItemStack(Material.IRON_BOOTS);
ItemMeta meta = item.getItemMeta();
List<String> lore = new ArrayList<String>();
lore.add(" ");
lore.add(ChatColor.YELLOW + "Thoughts of glory inspire your team to");
lore.add(ChatColor.YELLOW + " win this battle! Everyone on your team");
lore.add(ChatColor.YELLOW + " gains a buff!");
meta.setLore(lore);
meta.setDisplayName(ChatColor.GOLD + ChatColor.BOLD.toString() + "Glory");
item.setItemMeta(meta);
inv.addItem(item);
return inv;
}
#EventHandler
public static void onClick(InventoryClickEvent event) {
if (!ChatColor.stripColor(event.getInventory().getName()).equalsIgnoreCase("Choose ultimate ability!"))
return;
Player player = (Player) event.getWhoClicked();
event.setCancelled(true);
if(event.getCurrentItem()==null || event.getCurrentItem().getType()==Material.AIR || !event.getCurrentItem().hasItemMeta()){
player.closeInventory();
return;
}
if(event.getCurrentItem().getType() == Material.IRON_BOOTS){
player.closeInventory();
String hero = "SirCunnigham_2_1";
player.openInventory(Customizer.getMenu());
}
else{
player.sendMessage(ChatColor.GREEN + "[" + ChatColor.YELLOW + "MOBA" + ChatColor.GREEN + "]" + ChatColor.GOLD + "-Under Construction-");
player.closeInventory();
}
}
public static void heroChosen(){
String heroChoice = hero;
Moba sendLoadout = new Moba();
sendLoadout.gotHero(heroChoice);
}
}
All I need to get this to work is to have the String hero (from the if event above) to equal the String heroChoice. Thanks for reading this far and I hope this will get solved. It means a lot to me!
Do not "hide" a variable! You have a static variable named "hero" of type String but you have created another one with the same type and the same name of the static one. So you want to get the name of the hero.
Declaring that variable static you make that variable equal to all of the instances of that class.
Keep reading if you want to know the real solution.
Note, using OOP (Object-Oriented Programming) is a more efficient way to do this.
From what I understood from the question, you want associate an hero name to a player.
You can simply do it with an HashMap.
public static HashMap<Player,String> playerHero = new HashMap<Player,String>();
or if you're using Java 8
public static HashMap<Player,String> playerHero = new HashMap<>();
To add a player AND a hero name do
MyClass.playerHero.put(player, heroName);
To get the heroName from the player:
MyClass.playerHero.get(player);
To get the players from the heroName:
You can make a method:
public static List<Player> getPlayers(String heroName){
List<Player> players = new ArrayList<Player>();
for(Map.Entry<Player,String> e : MyClass.playerHero.entrySet()){
if(e.getValue().equalsIgnoreCase(heroName)){
players.add(e.getKey());
}
}
return players;
}
All these variables are static, so we can access them with MyClass.variableName
All these methods are static, so we can access them with MyClass.method(parameters);
Hope this helped!
You could use the static modifier for heroChoice and all methods that work with your variable, but this is not best practice because in many cases you will not be able to use static and even for this case, you can't make the Bukkit API's EventHandlers static. So what do you do? Its simple.
Use OOP, pass instance of invoking object's variable through constructor
Every object can have constructors, the constructors contain code that will be run when an instance of that object is created. You can also pass paremters to a constructor just like you would a method. As a result, you can simply pass the variable you want from one class into the constructor of the other and store it. For example:
class Car { //my class Car
double topSpeedMPH; //when a Car is created, it needs to get a top speed
public Car(double topSpeedMPH) { //public constructor for Car, requires a double parameter
this.topSpeedMPH = topSpeedMPH; //set the class' topSpeedMPH variable to the local one
}
}
Then in the invoking code:
double speed = 10;
Car fordFusion = new Car(speed);
So for your code specifically:
class Moba {
String heroChoice; //Moba has heroChoice stored
public Moba(String choice) { //Moba constructor, requires a String (which is the choice)
this.heroChoice = choice; //stores the parameter String to use later
}
}
class SirCunningham_2_1 {
public void heroChosen(){
String heroChoice = hero;
Moba sendLoadout = new Moba(heroChoice);
sendLoadout.gotHero(heroChoice);
}
}
Another solution: Use OOP, pass instance of the entire invoking object through constructor using this keyword
The previous solution is great for just one variable, but what if I wanted to be able to access multiple variables from another object? It would be rather inconvenient to make each of them individual parameters. Luckily, there is a good way to do this. Simply pass the entire instance through. The following example (using Car again) shows it:
class Motor {
Car myCar;
double topSpeed;
double accel;
public Motor(Car c) { //require instance of car
this.myCar = c;
this.topSpeed = myCar.topSpeed; //get values from instance
this.accel = myCar.secondsTo60;
}
}
class Car {
Motor m;
double topSpeed = 108;
double secondsTo60 = 8;
int seats = 4;
public Car() {
m = new Motor(this); //use this keyword to pass entire instance
}
void startEngine() {
System.out.println("Vroom Vroom!");
}
}
A big advantage to this solution is that I could even use methods from the other class:
public Motor(Car c) { //require instance of car
this.myCar = c;
this.topSpeed = myCar.topSpeed; //get values from instance
this.accel = myCar.secondsTo60;
myCar.startEngine();
}

How can a static method change a variable? (Java)

I have this class:
class Inventory {
boolean smallknife = false;
boolean SRLockerkey = false;
void checkinv () {
System.out.println("You have the following items in your inventory: ");
System.out.println(smallknife);
System.out.println(SRLockerkey);
}
}
The Inventory test class
class InvTester {
public static void main(String args[]) {
Inventory TestInv = new Inventory();
System.out.println("This program tests the Inventory");
SKTrue.truth(TestInv.smallknife);
TestInv.checkinv();
}
}
and this class with a method to try to change the inventory
class SKTrue {
static boolean truth(boolean smallknife) {
return true;
}
}
class SKTrue {
static void truth(boolean smallknife) {
smallknife = true;
}
}
I would like to avoid using TestInv.smallknife = SKTrue.truth(TestInv.smallknife) and still change the variable but with a method. Is there a way that this can be done? I want that the truth method does the variable changing and I don't want to do the pass by reference part in the Inventory Test class. Thanks. Is there a way to do this in Java? (I also tried the second version which I think makes more sense)
Assuming you don't want to reference the variables directly (i.e. TestInv.smallknife = blah), the best practice in Java is to declare the variables as private and access them by getters/setters, e.g.:
class Inventory {
private boolean smallknife;
public boolean isSmallknife() {
return smallknife;
}
public void setSmallknife(boolean smallknife) {
this.smallknife = smallknife;
}
}
Now, you can do this:
Inventory TestInv = new Inventory();
TestInv.setSmallknife(SKTrue.truth(blah));
It is called Encapsulation, you can read more about it here.

How to deserialize object from constructor in Java?

I am trying to do some funky stuff which i have never done before.
So what i am trying to do is:
I create an object by doing the following
Player playerVar = new Player(1234);
Players constructor will then look for a player called 1234, if it exists, it will then deserialize and store the loaded object under 'playerVar', if not it'll just follow through and give a'blank'` player object.
I am not sure if its even possible to make the current object an other instance of the same object, so i am posting here.
This is essentially what i am trying to do.
this = deserielizedObject
I know this can all be done by loading the object, then setting all the necessary variables manually, but that is hardly ideal. How can i 'replace' an object with another instance of itself, from within itself
This is the code i currently have
player.java
public class Player implements java.io.Serializable
{
Player(String GUID) // when loading a new player
{
Player player = loadPlayer(GUID);
//i want to set this to player
// something like this = player If you know what i mean....
}
Player()//when creating a new player
{
}
private Player loadPlayer(String GUID)
{
File f = new File("data/players/"+GUID+".ser");
if(!f.exists())
{
Player player = new Player();
return player;
}
Player player = null;
try
{
FileInputStream fileIn = new FileInputStream("data/players/"+GUID+".ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
player = (Player) in.readObject();
in.close();
fileIn.close();
}
catch(IOException i)
{
i.printStackTrace();
return null;
}
catch(ClassNotFoundException c)
{
System.out.println("Cant find Player Class!");
c.printStackTrace();
return null;
}
return player;
}
private int guid;
private String name;
private int bankMoney;
.......
...
.
}
You could use a factory class/method. The simpliest way in your case would probably be to just have loadPlayer as a public static method.
public static Player loadPlayer(String GUID)
{
...
return player;
}
then:
Player playerVar = Player.loadPlayer(1234);
What you describe is not possible. But you could create a (static) factory method instead of the constructor, which either deserializes or creates a new instance.
You cannot assign a value to this, not possible. Why not directly call the loadPlayer method:
Player player = Player.loadPlayer(GUID); //having loadPlayer as public static

HashMap.put causing an infinite loop in Java

So I have a class named MainControl that is ran from another class (The main one) that I am certain only runs once. Inside of MainControl I have a few things that have to be loaded, one of which being a function that populates the HashMap with the key set to the keybind (int) and the values set to a class that holds the information of the specific keybinds function (KeyDetails).
So to populate the hashmap it goes through 2 loops, the first being to loop through the list of functions, the second to check if the key should be bound to the function. If the second loop finds that it should be bound it will run Keybinds.put(KeyCode, new Details(Function, KeyCode, KeyName, false); (Just ignore the false).
For some reason it ends up forcing MainControl(); to run again once it reached Keybinds.put... for no reason at all. There are no functions that should cause MainControl to run and it works when I remove the Keybinds.put line. Just by removing THAT single line it works.
public MainControl()
{
System.out.println("Starting System");
LoadSession("Default");
System.out.println("Ended System - Never Reached");
}
public static void LoadSession(String s)
{
Keybinds = new HashMap();
for (int i = 0; i < FunctionStringList.length; i++)
{
String Key = "";
int KeyVal = 0;
try
{
for (int a = 0; a < KeyBindingList.length; a++)
{
if (KeyBindingList[a].KeyName.equalsIgnoreCase(FunctionStringList[i]))
{
Key = KeyBindingList[a].KeyName
KeyVal = KeyBindingList[a].KeyCode
}
}
Keybinds.put(KeyVal, new Details(FunctionStringList[i], KeyVal, Key, false));
System.out.println("Key: " + Key + " Val: " + KeyVal + " Hack: " + FunctionStringList[i]);
}
catch (Exception E) { E.printStackTrace(); }
}
}
public static String FunctionStringList[] =
{
"Forward", "Backwards", "StrafeLeft", "StrafeRight", "Jump", "Sneak"
};
Details Class:
public class Details extends MainControl
{
public Details(String Name, int KeyCode, String KeyName2, boolean Bool)
{
FunctionName = Name;
Code = KeyCode;
KeyName = KeyName2 != null ? KeyName2 : "None";
State = Bool;
}
public boolean Toggle()
{
State = !State;
return State;
}
public void SendChat(String s)
{
Console.AddChat(s);
}
public String FunctionName;
public String KeyName;
public int Code;
public boolean State;
}
Your Details class is-a MainControl; it's a subclass.
When you extend a class, the child class' constructor is calling the parent object's no-arg constructor which is causing an infinite recursion.
Edit to add from the comment below: Your "offending line" is:
Keybinds.put(KeyVal, new Details(FunctionStringList[i], KeyVal, Key, false));
When the Details constructor executes, it then calls MainControl() ... which then calls LoadSession() ... which then creates a new Details ... which then calls MainControl() .. etc, etc. Infinite recursion until you get a Stack Overflow.

Categories