I want to make a player Invunerable to damage and all knockback for a certain period of time (except for fall damage). My rpoblem is that the bukkit runable is not wroking as intended:
public class WeaponEvents implements Listener {
private Elemental_weapons plugin;
ArrayList<UUID> forceFieldArray = new ArrayList<UUID>();
#EventHandler
public void onplayercrouchevent(PlayerToggleSneakEvent event) {
boolean issneaking = event.isSneaking();
Player player = event.getPlayer();
if (issneaking==true) {
if (player.getInventory().getChestplate().equals(Weapons.chestplate)) {
forceFieldArray.add(player.getUniqueId());
Bukkit.broadcastMessage(String.valueOf(forceFieldArray));
new BukkitRunnable() {
#Override
public void run() {
Bukkit.broadcastMessage("no more");
forceFieldArray.remove(player.getUniqueId());
}
}.runTaskLater( plugin, 200L);
while (forceFieldArray.contains(player.getUniqueId())) {
}
}
}
}
I'd do this by having an array, say
ArrayList<UUID> forceFieldArray = new ArrayList<UUID>();
then whenever you want to activate your player's forcefield use a BukkitRunnable to set a delayed task.
forceFieldArray.add(player.getUniqueId());
new BukkitRunnable() {
#Override
public void run() {
forceFieldArray.remove(player.getUniqueId());
}
}.runTaskLater(plugin, 200L);
Just remember that the '200L' in there is ticks, 20 ticks to a second so 200L is 10 seconds. This adds the player to the array, then in ten seconds it'll remove the player. Using this you can now use that array to check if players have the force field active.
public void onPlayerDamage(EntityDamageEvent e) {
//Check if entity is player
//Create player variable
if(e.getCause() == DamageCause./*[Damage type you want to cancel]*/) {
if(forceFieldArray.contains(player.getUniqueId())) {
e.setCancelled(true);
}
}
}
This way you could even make a config with a list in there, have all the types of damage you want the forcefield to block then just above the ifs bring that data into an Array and say if(configArray.contains(e.getCause()) { //Do stuff
Hope this helped!
Related
I'm trying to add some custom ability to this plugin by using it own API. I have some trouble adding items to players when they got a kill. I have tried a lot of different methods to add potion to the killer by using .addItem(). There is no wiki for this plugin and on their page, there is some information about the API. Here is my code
public class ChemistryAbility extends Ability{
//Return name of ability
#Override
public String getName() {
return "Chemistry";
}
//Get the data form config file.
#Override
public void load(FileConfiguration file) {
// TODO Auto-generated method stub
}
//Get the activate Material
#Override
public Material getActivationMaterial() {
return null;
}
//Get the activate projectile
#Override
public EntityType getActivationProjectile() {
return null;
}
//Will this ability activate when player attack another player
#Override
public boolean isAttackActivated() {
return true;
}
//Will this ability activate when player get attacked by another player
#Override
public boolean isAttackReceiveActivated() {
return false;
}
//Will this ability activate when player get damage
#Override
public boolean isDamageActivated() {
return false;
}
//Will this ability activate when player interact with another player
#Override
public boolean isEntityInteractionActivated() {
return false;
}
#Override
public boolean execute(final Player p, final PlayerData PD, final Event e) {
ItemStack potion = new ItemStack(Material.SPLASH_POTION, 3);
PotionMeta pmeta = (PotionMeta) potion.getItemMeta();
pmeta.addCustomEffect(new PotionEffect(PotionEffectType.HARM, 1, 2), true);
potion.setItemMeta(pmeta);
Player killer = p.getKiller();
if (p.isDead()) {
p.getKiller();
if (p.getKiller() instanceof Player) {
killer.getInventory().addItem(potion);
}
}
return false;
}
}
K, So i don't know that much about plugin dev, but here is my best shot with 15 min of research. Not sure about the API, but if u can implement this outside the event, try this
#EventHandler
public void onKill(PlayerDeathEvent e) {
if (e.getEntity().getKiller() != null) { // to check if there was actually a killer
Entity killer = e.getEntity.getKiller(); // stores killer instance
if (killer.hasMetadata("Chemistry")) { // checks if has class
killer.getInventory().addItem(new ItemStack(Material.BOOK));
}
}
}
i think. i honestly dont know
Potions have always been a pain in Minecraft. Mojang changes how item data works.
I have some Deprecated code that I made. This should work for a few of the upcoming updates.
public ItemStack getPotionItem(Color c, PotionEffectType type, PotionType pType, boolean splash, int time, int level) {
Potion p = new Potion(pType);
p.setSplash(splash);
p.setType(pType);
ItemStack pot = new ItemStack(Material.SPLASH_POTION);
PotionMeta im = (PotionMeta) pot.getItemMeta();
List<String> lores = new ArrayList<String>();
lores.add(getLore());
im.setDisplayName(getName());
im.addCustomEffect(new PotionEffect(type, time, level - 1), true);
im.setLore(lores);
im.setColor(getColor());
im.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS);
im.addItemFlags(ItemFlag.HIDE_ATTRIBUTES);
pot.setItemMeta(im);
p.apply(pot);
return pot;
}
I'm making a basic card game that human user can play with computer or computer play with computer in java. I wanna take a selection as a random number from a selection function in the Computer Player class that extends my Player class. But I wanna take answer after 5 seconds from calling selection function. Also I must take a answer from selection function in Human Player class with mouse listener.
I create a waiter timer that start when calling my selection function.
Timer waiter = new Timer(5000,this);
boolean is_waiting;
public int select_cart() {
waiter.start();
is_waiting = true;
Random r = new Random();
int random = r.nextInt(getCartNumber()) + 1;
int selection = random;
while(is_waiting){
System.out.println("Computer is selecting...");
}
return selection;
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == waiter){
is_waiting = false;
waiter.stop();
}
}
I expect that select_cart function return a value after 5 second but this code print "Computer is selecting..." to console in endless loop.
If select_cart is been called from the Event Dispatching Thread
Then you need to change your approach, as the while-loop is blocking the Event Dispatching Thread, meaning that the Timer's actionPerformed method will never be called.
In this case, a better approach would be to allow the actionPerformed method to actually trigger the result, but, you'll need to employ a observer pattern to make it work
Start by defining a callback interface, something like...
public interface CartSelection {
public void cartSelection(int value);
}
Then you need to change the code to make use of this callback and move the core functionality to actionPerformed, for example...
Timer waiter = new Timer(5000,this);
CartSelection callback;
public void select_cart(CartSelection callback) {
this.callback = callback;
waiter.start();
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == waiter){
waiter.stop();
Random r = new Random();
int random = r.nextInt(getCartNumber()) + 1;
int selection = random;
callback(selection)
}
}
Then you could call select_cart something like...
select_cart(new CartSelection() {
#Override
public void cartSelection(int value) {
// Carry on...
}
});
as an example.
If the cart is been filled by some other process, then you might consider using different approaches, such as using Lock objects to "wait" till the filling process completed.
Equally, you could use a SwingWorker to fill the cart and when it's completed, publish the results to be consumed via some other mechanism.
If select_cart is been called from another thread
Now, if you're calling select_cart from a different thread (other then the EDT), then you don't actually need the Timer at all and could just do ...
public int select_cart() {
Random r = new Random();
int random = r.nextInt(getCartNumber()) + 1;
int selection = random;
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
}
return selection;
}
I've managed to code everything and debug everything on my own which is an accomplishment, well everything except one thing..
I need help figuring out how to check the name of an item and if the item has that specific name, THEN the event will happen. I'm trying to check if a chicken egg has a specific mob name, like creeper, or spider, and if so, that mob will spawn out of the egg. (I know they have mob eggs for that but I'm messing around with my abilities atm.)
Here's the code for the command:
public class EggCommands implements CommandExecutor {
#Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
Player player = (Player) sender;
if (cmd.getName().equalsIgnoreCase("egg") && sender instanceof Player) {
if (args.length == 0) {
player.sendMessage("Usage: /egg <mob>");
return true;
}
if (args[0].equals("creeper")) {
if (player.getInventory().getSize() == -1) {
player.sendMessage(ChatColor.DARK_RED + "You're inventory is full");
return true;
} else {
ItemStack item = new ItemStack(Material.EGG, 1);
ItemMeta meta = item.getItemMeta();
meta.setDisplayName(ChatColor.DARK_GREEN + "Creeper");
ArrayList<String> lore = new ArrayList<String>();
lore.add(ChatColor.RED + "Spawns A Charged Creeper With Lightning Effect");
meta.setLore(lore);
item.setItemMeta(meta);
player.getInventory().addItem(item);
return true;
}
}
}
return true;
}
}
Here's the code for the Event Listener:
public class EggListener implements Listener {
public EggListener(EggMain plugin) {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
#EventHandler
public void Eggs(PlayerEggThrowEvent e) {
if (e.getEgg().getCustomName().equals(ChatColor.DARK_GREEN + "Creeper")) {
e.setHatchingType(EntityType.CREEPER);
e.setNumHatches((byte) 1);
e.setHatching(true);
}
}
}
Reason why your code won't work is that you're comparing two different names. You set the name of an ItemStack to "Creeper", but then in the PlayerEggThrowEvent you check if the Egg's name is the same as the ItemStack, it is not.
An egg is an entity, its name is the same as a nametag over a zombie's or a player's head, not the same as an ItemStack. The egg will infact have no name unless you set one.
I experimented a while and came up with this structure, it's not working but might give you a head start:
private HashMap<UUID, ItemStack> eggThrown = new HashMap<UUID, ItemStack>();
#EventHandler
public void eggthrown(PlayerEggThrowEvent event) {
if(eggThrown.containsKey(event.getPlayer().getUniqueId())) {
ItemStack egg = eggThrown.get(event.getPlayer().getUniqueId());
}
}
#EventHandler(priority = EventPriority.HIGHEST)
public void storeEgg(PlayerInteractEvent event) {
if(event.getAction().equals(Action.RIGHT_CLICK_AIR) || event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
if(event.hasItem() && event.getItem().getType().equals(Material.EGG)) {
eggThrown.put(event.getPlayer().getUniqueId(), event.getItem());
}
}
}
What I do is use PlayerInteractEvent to retrieve the egg's ItemStack, this event is called only when a player right clicks (throws an egg) thanks to the if statements. I then put the ItemStack into a hashmap we can use in the PlayerEggThrowEvent. When we have the ItemStack we can compare the names.
Another solution would be cancel whatever event that gets called when the egg is spawned into the world and give it a custom name.
I am trying to create a simple game using JavaFX. The game consists in a main game and sub-games, which the player may have to play, depending on the result of the main game. In the end, the main game has to update it's state (p.e.: score) depending on the sub-games result.
I made a simplified and generalized version of how I have implemented the game logic:
Result play(Player p) {
Result r = p.play(this);
for(SubGame game : r.getSubGames())
{
p.play(game);
}
update(r);
return r;
}
This game works perfectly in the terminal, since it has a linear execution.
But using JavaFX (implemented in the Player), I cannot control the flow of the program properly, because of the game loop.
I have followed this tutorial to handle multiple screens for the main game and sub-games. The Player class can successfully change the screen to a sub-game, using the handler. But the update no longer waits for the sub-games to be played, and this function returns while the player is mid-game.
I am trying to keep the game logic separate from UI, so changes to the code showed above shouldn't be dependent on the interface framework.
Any help?
Use an event-driven approach, setting the values of observable properties, and responding when they change.
For example, you might encapsulate the state of the game with
public class GameState {
private ObservableList<SubGame> currentGames = FXCollections.observableArrayList();
public ObservableList<SubGame> getCurrentGames() {
return currentGames();
}
private ReadOnlyObjectWrapper<SubGame> currentGame = new ReadOnlyObjectProperty<>();
public ReadOnlyObjectProperty<SubGame> currentGameProperty() {
return currentGame.getReadOnlyProperty() ;
}
public final SubGame getCurrentGame() {
return currentGameProperty().get();
}
public GameState() {
// initialize sub game list...
}
public void nextGame() {
int index = currentGames.indexOf(currentGame.get());
if (index < currentGames.size() - 1) {
currentGame.set(currentGames.get(index + 1));
}
}
public void start() {
currentGame.set(currentGames().get(0));
}
public boolean hasMoreGames() {
return currentGames.indexOf(currentGame.get()) < currentGames.size() - 1 ;
}
}
And similarly you might have some observable state in your SubGame class:
public class SubGame {
private final BooleanProperty finished = new SimpleBooleanProperty();
public BooleanProperty finishedProperty() {
return finished ;
}
public final boolean isFinished() {
return finishedProperty().get();
}
public final void setFinished(boolean finished) {
finishedProperty().set(finished) ;
}
// ...
}
Now your game logic is just implemented with listeners:
void play(Player p) {
Result r = p.play(this);
GameState gameState = new GameState();
gameState.currentGameProperty().addListener((obs, oldGame, newGame) -> {
newGame.finishedProperty().addListener((obs, wasFinished, isNowFinished) -> {
if (isNowFinished) {
// maybe update score etc based on state of newGame...
if (gameState.hasMoreGames()) {
gameState.nextGame();
} else {
// logic here for "all games are finished...
}
}
});
});
gameState.start();
}
Obviously the details of how you implement this depend on your requirements etc, but this general approach should work for anything you need.
I'm using RxVertx which is a sort of RxJava along with Java8 and I have a compilation error.
Here is my code:
public rx.Observable<Game> findGame(long templateId, GameModelType game_model, GameStateType state) {
return context.findGame(templateId, state)
.flatMap(new Func1<RxMessage<byte[]>, rx.Observable<Game>>() {
#Override
public Observable<Game> call(RxMessage<byte[]> gameRawReply) {
Game game = null;
switch(game_model) {
case SINGLE: {
ebs.subscribe(new Action1<RxMessage<byte[]>>() {
#Override
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game = new Game(); // ERROR is at this line
singleGames.put(0, game);
} else {
game = singleGames.get(0); // ERROR is at this line
}
}
});
}
}
return rx.Observable.from(game);
}
});
}
The compilation error is:
"Local variable game defined in an enclosing scope must be final or effectively final"
I cannot define 'game' as final since I do allocation\set and return it at the end of the function.
How can I make this code compile??
Thanks.
I have a Holder class that I use for situations like this.
/**
* Make a final one of these to hold non-final things in.
*
* #param <T>
*/
public class Holder<T> {
private T held = null;
public Holder() {
}
public Holder(T it) {
held = it;
}
public void hold(T it) {
held = it;
}
public T held() {
return held;
}
public boolean isEmpty() {
return held == null;
}
#Override
public String toString() {
return String.valueOf(held);
}
}
You can then do stuff like:
final Holder<Game> theGame = new Holder<>();
...
theGame.hold(myGame);
...
{
// Access the game through the `final Holder`
theGame.held() ....
Since you need to not modify the reference of the object you can wrap the Game in something else.
The quickest (but ugly) fix is to use an array of size 1, then set the content of the array later. This works because the the array is effectively final, what is contained in the array doesn't have to be.
#Override
public Observable<Game> call(RxMessage<byte[]> gameRawReply) {
Game[] game = new Game[1];
switch(game_model) {
case SINGLE: {
ebs.subscribe(new Action1<RxMessage<byte[]>>() {
#Override
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game[0] = new Game();
singleGames.put(0, game[0]);
} else {
game[0] = singleGames.get(0);
}
}
});
}
}
return rx.Observable.from(game[0]);
}
Another similar option is to make a new class that has a Game field and you then set that field later.
Cyclops has Mutable, and LazyImmutable objects for handling this use case. Mutable is fully mutable, and LazyImmutable is set once.
Mutable<Game> game = Mutable.of(null);
public void call(RxMessage<byte[]> t1) {
if(!singleGame.contains(0) {
game.mutate(g -> new Game());
singleGames.put(0, game.get());
} else {
game[0] = game.mutate(g->singleGames.get(0));
}
}
LazyImmutable can be used to set a value, lazily, once :
LazyImmutable<Game> game = LazyImmutable.def();
public void call(RxMessage<byte[]> t1) {
//new Game() is only ever called once
Game g = game.computeIfAbsent(()->new Game());
}
You cant. At least not directly. U can use a wrapper class however: just define a class "GameContainer" with game as its property and foward a final reference to this container instead.
#dkatzel's suggestion is a good one, but there's another option: extract everything about retrieving/creating the Game into a helper method, and then declare final Game game = getOrCreateGame();. I think that's cleaner than the final array approach, though the final array approach will certainly work.
Although the other approaches look acceptable, I'd like to mention that you can't be sure subscribing to ebs will be synchronous and you may end up always returning null from the inner function. Since you depend on another Observable, you could just simply compose it through:
public rx.Observable<Game> findGame(
long templateId,
GameModelType game_model,
GameStateType state) {
return context.findGame(templateId, state)
.flatMap(gameRawReply -> {
switch(game_model) {
case SINGLE: {
return ebs.map(t1 -> {
Game game;
if (!singleGame.contains(0) {
game = new Game();
singleGames.put(0, game);
} else {
game = singleGames.get(0);
}
return game;
});
}
}
return rx.Observable.just(null);
});
}