Shaped Recipe with specifically named item? - java

I'm trying to create a crafting recipe with bukkit and I want the recipe to ONLY accept a leather helmet with the name "Better Helmet". right now I have this:
public static ItemStack lvl2Head = new ItemStack(Material.LEATHER_HELMET, 1);
{
//removed unnessecary information
lvl2HeadMeta.setDisplayName("Better Helmet 2");
}
public void lvl1ArmorHead() {
ShapedRecipe recipe = new ShapedRecipe(lvl2Head);
recipe.shape("AAA", "ABA", "AAA");
recipe.setIngredient('A', Material.DIAMOND);
//want it to check it under here in place of "LEATHER_HELMET"
recipe.setIngredient('B', Material.LEATHER_HELMET);
this.getServer().addRecipe(recipe);
}
Is there any way I can accomplish this? I tried putting the name of the new ItemStack in place of Material.LEATHER_HELMET but it wants MaterialData not an ItemStack.
update
I'm still able to pull the item out of the crafting table using a regular leather helmet this code created with jojodmo.
Main Class:
public static ShapedRecipe lvl1ArmorHeadRecipe() {
ShapedRecipe recipe = new ShapedRecipe(lvl1Head);
recipe.shape("AAA", "ABA", "AAA");
recipe.setIngredient('A', Material.DIAMOND);
recipe.setIngredient('B', Material.LEATHER_HELMET);
return recipe;
}
public void lvl1ArmorHead(){
this.getServer().addRecipe(lvl1ArmorHeadRecipe());
}
EventHandler class:
#EventHandler
public void craft(CraftItemEvent e){
if(e.getInventory() instanceof CraftingInventory){
CraftingInventory inv = (CraftingInventory) e.getInventory();
if(inv.getSize() != 4 && e.getRecipe().equals(Main.lvl1ArmorHeadRecipe())){
org.bukkit.inventory.ItemStack helm = inv.getMatrix()[5];
if(helm.hasItemMeta()){
if(helm.getItemMeta().getDisplayName().equals("Better Helmet")){
//done.
} else{
e.setCancelled(true);
}
} else {
e.setCancelled(true);
}
}
}
}
Note: This is for Bukkit 1.7.2

I've done this before, It took me so long to figure out how to do it! The only problem is that the result still shows up if you were to use a regular leather helmet, but it just doesn't let you take the result out of the crafting table.
Here's how I did it:
public ShapedRecipie lvl1ArmorHeadRecipie(){
ShapedRecipe recipe = new ShapedRecipe(lvl2Head);
recipe.shape("AAA", "ABA", "AAA");
recipe.setIngredient('A', Material.DIAMOND);
recipe.setIngredient('B', Material.LEATHER_HELMET);
return recipie;
}
public void lvl1ArmorHead(){
this.getServer().addRecipe(lvl1ArmorHeadRecipie());
//do everything in here normally
}
Next, use this. Make sure to make the class that this is in implement Listener
#EventHandler
public void craft(CraftItemEvent e){
if(e.getInventory() instanceof CraftingInventory){
CraftingInventory inv = (CraftingInventory) e.getInventory();
if(inv.getSize() != 4 && e.getRecipe().equals(lvl1ArmorHelmetRecipe())){
ItemStack helm = inv.getMatrix()[4];//get the middle item in the bench, which is the helmet
if(helm.hasItemMeta()){//make sure the helmet has item meta
if(helm.getItemMeta().getDisplayName().equals("Better Helmet")){//make sure the helmet's display name is 'Better Helmet'
//you're done! It works! Do something like tell the player "you have crafted better armor" or something here.
return;
}
}
//the return; above would have been called if the crafting had succeeded. When it got called, the remainder of this method would not run (this part will not be run if the crafting has succeeded)
//send the player a message to make it more realistic here. For my wizardry server I use: 'One of thee items used was incorrect, and unbalanced the energy. The death block hath been destroyed'
e.setCanceled(true);
e.setResult(new ItemStack(Material.AIR));
}
}
}

Look up the PrepareItemCraftEvent, I've answered your question on the bukkit forums, look at my post: http://forums.bukkit.org/threads/resource-no-nms-make-custom-crafting-recipes-ingredients-obey-itemmeta-displayname-e-t-c.280482/

Related

How do you create a custom item in Spigot 1.16.5?

I'm making a plugin that adds some useful items like House Building Wand, Exploding Sword, etc. But how can I add those items using the plugin?
Normally, you would want to make a class for your item.
For example, you can make a class HouseBuildingWand.java and add some Java logic in it.
public class HouseBuildingWand {
public static ItemStack getHouseBuildingWand() {
ItemStack houseBuildingWand = new ItemStack(Material.YOUR_ITEM);
return houseBuildingWand;
}
}
To make the ability, you have to use Java knowledge.
To add enchantments, flags, lore, names, check out https://bukkit.gamepedia.com/Plugin_Tutorial#Item_Manipulation.
To get the item, you would need a command or an event that would give you the item.
To check how the item was clicked, you can use an event listener with the event PlayerInteractEvent. Example:
#EventHandler
public void onRightClick (PlayerInteractEvent event) {
Player p = event.getPlayer();
if (event.getAction() == Action.RIGHT_CLICK_AIR) {
if (event.getItem().getType() == Material.YOUR_ITEM) {
// insert logic
}
}
}

Java download causes lag spike with really small files

EDIT: I've decided to remove the Minecraft tag. While this IS a Minecraft mod's code, the code I'm having trouble with has to do with functions within core Java, and not anything in Minecraft itself.
So, I posted a question last night about me writing a function of a Minecraft mod to allow us to implement our own capes and thanks to some of you I was able to get that working. I've crammed down the code from there and found a way to make it as small as possible while producing the same outcome. I've also found out how to read files directly from a download stream instead of copying the file. Great? Well, no. Now that I'm able to properly test everything and read my files, I've run into another problem. While everything works fine, it causes a lag spike of upwards to 2-4 seconds whenever my code is running. I've looked around and found issues about slow downloads, but nothing about the application completely freezing for a small period of time. Since this is run whenever a player first appears on-screen, this can get repetitive. I'm trying to fix the code and have rearranged it countless times in different ways and it just won't go away.
Here's the code. In short, it checks if the player has an official Mojang cape on their account. If they don't, then instead it runs my code to check if they have one of our custom capes, and exactly when this is run, is when the game has a lag spike. Note that if the player has a cape from Mojang my code is never run and I've tried disabling my code and just running the code that downloads their Mojang cape for use, so I know that part doesn't cause lag, it's specifically just my code. Even if they don't have a custom cape under my code it always causes lag. I can't think of why; the files are very small!
... While writing this, I decided to test something, and so I disabled the player.cloakUrl variable setting lines in my getCustomCapes method. Surely enough the lag still happened so I reckon the lag is caused by the lines that check if the player UUID matches one in the downloaded .txt files. I'm confident the lines of code that check and download from the .txt files are the culprits to the lag here. Note that I'm reading from streamed online files rather than saving them to the computer permanently since they don't need to. They're read every time this code is called and it needs to stay that way.
Without further ado here's the code.
EDIT: I've tried to add .close() commands to the streams with no success.
public static void getSkin(final GameProfile profile, EntityPlayer player) {
final Map<Type, MinecraftProfileTexture> map = Maps.<Type, MinecraftProfileTexture>newHashMap();
// (Here's where some skin-related code would be but I cut it out for easier reading,
// it has nothing to do with this situation so don't worry about that.)
if (map.containsKey(Type.CAPE))
{
MinecraftProfileTexture texture = (MinecraftProfileTexture)map.get(Type.CAPE);
player.cloakUrl = texture.getUrl();
return;
} else {
getCustomCapes(profile, player); //Commenting this fixes the lag, proving it's my code that causes it.
}
}
public static void getCustomCapes(final GameProfile profile, EntityPlayer player) {
InputStream staff;
InputStream contest;
try {
contest = new URL("https://www.dropbox.com/s/kvvkfk6emms3qg5/contest.txt?dl=1").openStream();
StringWriter contestUUIDs = new StringWriter();
IOUtils.copy(contest, contestUUIDs, StandardCharsets.UTF_8);
if (contestUUIDs.toString().contains(profile.getId().toString()))
{
player.cloakUrl = "https://www.dropbox.com/s/a4d3agty57sd4a8/contest.png?dl=1";
// Commenting out the above line doesn't seem to help any, as stated before.
return;
}
staff = new URL("https://www.dropbox.com/s/q6f4729i2zu02nz/staff.txt?dl=1").openStream();
StringWriter staffUUIDs = new StringWriter();
IOUtils.copy(staff, staffUUIDs, StandardCharsets.UTF_8);
if (staffUUIDs.toString().contains(profile.getId().toString()))
{
player.cloakUrl = "https://www.dropbox.com/s/42jn5r7fs6k5f4l/staff.png?dl=1";
// Commenting out the above line doesn't seem to help any, as stated before.
return;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
What an old thread, huh? So, after getting a little more experience I decided to head back to this to say I've found the solution. Here's how I fixed it: Thread magic! ug_ suggested this to me a while ago it seems, but I simply didn't understand at the time. I used some methods to start a thread with special variables that set the player's properties when it's done, removing the lag. Also, I rewrote the way the cape .txts work to be a little more efficient. You may notice there's one file now, and that one controls everything instead of each list having its own file. Here's my code. First, the above get skin methods have been scraped out almost entirely, and I added a new one since creating a GameProfile sends requests to Mojang's API, causing a little bit of lag, so I made it so this thread can also generate profiles:
public static void getSkin(final GameProfile profile, EntityPlayer player) {
ThreadFetchSkins skinThread = new ThreadFetchSkins();
skinThread.start(player, profile, mc);
}
public static void getSkinFromUUIDAndName(UUID uuid, String username, EntityPlayer player) {
ThreadFetchSkins skinThread = new ThreadFetchSkins();
skinThread.start(uuid, username, player, mc);
}
And then, here's the thread.
public class ThreadFetchSkins extends Thread {
public static TreeMap<UUID, String> customCapes = new TreeMap<UUID, String>();
private EntityPlayer thePlayer;
private GameProfile theProfile;
private Minecraft mc;
private boolean createProfile = false;
private UUID id;
private String name;
public ThreadFetchSkins() {
setName("Cape data download thread");
setDaemon(true);
}
public void run() {
if(createProfile) {
theProfile = new GameProfile(id, name);
}
final Map<Type, MinecraftProfileTexture> map = Maps.<Type, MinecraftProfileTexture>newHashMap();
theProfile.getProperties().clear();
theProfile.getProperties().putAll(SkinManager.getProfileProperties(theProfile));
map.putAll(mc.sessionService.getTextures(theProfile, false));
//Removed "secure" textures grab
if (map.containsKey(Type.SKIN))
{
MinecraftProfileTexture texture = (MinecraftProfileTexture)map.get(Type.SKIN);
thePlayer.skinUrl = texture.getUrl();
String grab = texture.getMetadata("model");
// Currently returns null for steve skin
thePlayer.modelAlex = !(grab == null);
thePlayer.worldObj.obtainEntitySkin(thePlayer);
}
if (map.containsKey(Type.CAPE))
{
MinecraftProfileTexture texture = (MinecraftProfileTexture)map.get(Type.CAPE);
thePlayer.cloakUrl = texture.getUrl();
thePlayer.worldObj.obtainEntitySkin(thePlayer);
}
else {
grabCustomCapes();
}
}
public void grabCustomCapes() {
try {
URL capeDownload = new URL("https://www.dropbox.com/s/q6f4729i2zu02nz/capes.txt?dl=1");
String capeFolder = Minecraft.getMinecraftDir().getPath() + "/NFCCapes";
FileUtils.forceMkdir(new File(capeFolder));
FileUtils.copyURLToFile(capeDownload, new File(capeFolder + "/capes.txt"));
InputStream fileOS = new FileInputStream(capeFolder + "/capes.txt");
BufferedReader buf = new BufferedReader(new InputStreamReader(fileOS));
String line = buf.readLine();
customCapes.clear();
while(line != null) {
String[] data = line.split(";");
customCapes.put(UUID.fromString(data[1]), data[2]);
line = buf.readLine();
}
fileOS.close();
FileUtils.getFile(capeFolder).delete();
if(customCapes.get(theProfile.getId()) != null) {
thePlayer.cloakUrl = customCapes.get(theProfile.getId());
thePlayer.worldObj.obtainEntitySkin(thePlayer);
}
} catch (MalformedURLException e) {
e.printStackTrace();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
}
public void start(EntityPlayer player, final GameProfile profile, Minecraft minecraft) {
thePlayer = player;
theProfile = profile;
mc = minecraft;
super.start();
}
public void start(UUID uuid, String username, EntityPlayer player, Minecraft minecraft) {
id = uuid;
name = username;
thePlayer = player;
mc = minecraft;
createProfile = true;
super.start();
}
}

Updating JList by pressing button

first of all I will introduce what I am trying to do. This is an assignment in university we are making Hotel booking system with JAVA. To go straight to the point, all I need to know is how to update JList when I press button.
listModel = new DefaultListModel<Hotel>();
bookingList = new JList(listModel);
class MouseAdapterMod extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if(e.getSource() == searchButton){
for(lists.getRoomsList() p : lists.getRoomsList())
{
listModel.addElement(p);
}
bookingList.setModel(listModel);
}
In this GUI class I have instance variable (lists) of Hotel class, in Hotel class there are methods
public ArrayList<Rooms> getRoomsList()
{
return roomsList.getListRooms();
}
public ArrayList<Suite> getSuitesList()
{
return roomsList.getListSuites();
}
this returns whole ArrayList of Room class objects and also ArrayList of Suite class.
QUESTION would be is how to show whole ArrayList of Rooms when I press button, in other words how to update JList which consists of objects, by pressing button?
I hope I explained alright.
Your for-each loop is wrong. Try this and see:
public void mousePressed(MouseEvent e) {
if(e.getSource().equals(searchButton)){
ArrayList<Rooms> rooms = lists.getRoomsList();
for(Rooms r : rooms) {
listModel.addElement(r);
}
bookingList.setModel(listModel);
}
}
This still looks sorta messy to me though. A more appropriate approach would be to set an event handler on the searchButton, to populate the JList when searchButton is clicked.
Also, are Rooms and Suites sub classes of Hotel? If not, you'll have to create listModel like this (for rooms):
listModel = new DefaultListModel<Rooms>();

Accessing method from different class

I'm trying to call a class's void from a different class. The objects work fine, but for some reason its not completing the action.
I'm making a black jack game, and I need some button to appear when the user enters a correct bet. Here is what I have:
public static void showButtons(Boolean x) { // to show or hide the buttons
if(x) {
hitButton.setVisible(true);
standButton.setVisible(true);
separator.setVisible(true);
}
else {
hitButton.setVisible(false);
standButton.setVisible(false);
separator.setVisible(false);
}
}
Once the bet is verified as an integer, it passes through this:
private void bdButtonActionPerformed(java.awt.event.ActionEvent evt) { //bdButton is the bet button
...
if(validBet(s)) {
bet = Integer.parseInt(s); // parses input string into an int
System.out.println("bet accepted"); // debug to know if it works this far
NewRound nr = new NewRound();
System.out.println("created object");
nr.newHand(bet);
//showButtons(true); // this works, it changes the buttons, but only from here
}
else {
...
}
}
Here is the newHand method:
public static void newHand(int bet) {
System.out.println("In newHand"); // debug
BlackJack b = new BlackJack();
b.showButtons(true);
System.out.println("passed showButtons"); // the code gets to here, but buttons are still not visible
}
The method is declared static, so assuming it is a class called TestClass, the way you would call the method looks like this:
TestClass.newHand(int bet);
If you want to be able to just call
newHand(int bet);
in your current class, you would need to use static import, like this:
import static your.package.TestClass.newHand;
But I would much prefer having it the first way.
Your newHand method is static, so it should be called with the class name.

Android/Java and multiple "view states"

Does anyone recognize this pattern and know of a tidy solution?
I've got a view that can be in certain states. Let's call them Neutral, Success, Error, InProgress. In the view I've got multiple elements (Buttons, TextViews and a ProgressBar) that should either be visible/enabled depending on the state the view is in.
Currently I've got methods that represent the states that do the necessary .setEnabled() and .setVisibility() calls. With 4 states and a couple of elements this becomes messy quite fast.
I also feel that the State Pattern is not necessarily a good solution but is something that personally springs to mind.
I would love to hear what any of you think is a simple and tidy solution.
Sample code:
void setIsRegistering() {
isRegistering = true;
isRegistered = false;
progressBar.setVisibility(View.VISIBLE);
successText.setVisibility(View.GONE);
errorText.setVisibility(View.GONE);
setupFooterButton.setEnabled(false);
setupFooterButton.setText("Adding browser");
}
void setIsRegistered() {
isRegistering = false;
isRegistered = true;
progressBar.setVisibility(View.INVISIBLE);
successText.setVisibility(View.VISIBLE);
errorText.setVisibility(View.GONE);
setupFooterButton.setEnabled(true);
setupFooterButton.setText("Next");
}
void setIsNotRegistered() {
isRegistering = false;
isRegistered = false;
progressBar.setVisibility(View.INVISIBLE);
successText.setVisibility(View.INVISIBLE);
errorText.setVisibility(View.GONE);
setupFooterButton.setEnabled(true);
setupFooterButton.setText("Add browser");
}`
You can use a ViewAnimator for this: (http://developer.android.com/reference/android/widget/ViewAnimator.html)
You can then call viewAnimator.setDisplayedChild() to set the selected item.
setDisplayedChild() takes an integer, so I typically create an enum to hold the states I want:
enum ViewStates {
NEUTRAL, SUCCESS, ERROR
}
setDisplayedChild(ViewStates.Neutral.ordinal());
Or if that's too verbose:
enum ViewStates {
NEUTRAL, SUCCESS, ERROR
public static int neutral = NEUTRAL.ordinal();
public static int success = SUCCESS.ordinal();
public static int error = ERROR.ordinal();
}
setDisplayedChild(neutral);

Categories