ben cohen
ben cohen

Reputation: 1

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!

Upvotes: 0

Views: 2852

Answers (2)

Ashwin Gupta
Ashwin Gupta

Reputation: 2197

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();
    }

Upvotes: 0

RoccoDev
RoccoDev

Reputation: 526

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!

Upvotes: 1

Related Questions