Bukkit Error: event cannot be resolved - java

public void run() {
if(spleggEnabled == 3){
if(player.isBlocking()){
player.sendMessage(ChatColor.GREEN + "Projected Splegg!");
WitherSkull head = (WitherSkull) ((ProjectileSource) player).launchProjectile(WitherSkull.class);
BlockIterator iterator = new BlockIterator(event.getEntity().getWorld(), event.getEntity().getLocation().toVector(), event.getEntity().getVelocity().normalize(), 0.0D, 4);
}
if(player.isDead()){
spleggEnabled = 0;
}
The error is on each event.getEntity(), and the error is event cannot be resolved.
Any ideas?

What it looks like is that event is undefined.
If you are unsure of what event.getEntity() is, try replacing it with head or player in your code.
If you know what it is and what it does, make the event from your listener accessible (define it in the class as public static Event event and set it in your listener.)
You obviously stole some code from online without a single clue as to what it does. Next time, read the whole forum/blog/wiki post instead of blindly copying.

Related

Spawn invisible Bat - convert org.bukkit.Entity to org.bukkit.craftbukkit.v1_8_R3.entity.CraftBat;

I'm creating a Plugin that need some invisible Bats. I therefore have a method that spawns and stores my bats. This is the code, I currently have:
public class BatManager {
private static final List<Entity> bats = new ArrayList<>();
public static void spawnBat(Location location) {
Entity entity = location.getWorld().spawnEntity(location, EntityType.BAT);
try {
CraftBat l = (CraftBat) entity;
l.getHandle().setInvisible(true);
} catch (RuntimeException e) {
e.printStackTrace();
}
bats.add(entity);
}
}
This code does compile, however it does not make the bat invisible. I strongly suspect that I create a copy of the object at some point, and set the invisibility there. I'm not sure however how I can set the invisibility without the conversion to CraftBat, since there are no methods I know of, to make a org.bukkit.Entity invisible on its' own.
How can I correct this?
I'm open for other suggestions concerning the invisibility as well, but I do explicitly not want to use Potion effects, since those leave some particles for the Player to see.
I found a solution without packet. With a quick timer, it's fine :
Entity bat = location.getWorld().spawnEntity(location, EntityType.BAT);
Bukkit.getScheduler().runTaskLater(MyPlugin.getInstance(), () -> {
((CraftBat) bat).getHandle().setInvisible(true);
}, 2);
I've found an alternate solution. It's actually possible to hide the particles per default on bukkit side. I therefore used PotionEffect's, looking like this:
Entity entity = location.getWorld().spawnEntity(location, EntityType.BAT);
LivingEntity livingEntity = (LivingEntity) entity;
PotionEffect effect = new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 1, false, false);
livingEntity.addPotionEffect(effect);
bats.add(livingEntity);

Bukkit - Change player's name above head?

I'm back again.
Today I have a question that many people have asked before. The reason I'm asking again is because in all my ~90 minutes of searching, I couldn't find an updated answer. Many answers tell me to use iTag/TagAPI, but I ran into some problems trying to use that, therefore I would not like to use iTag/TagAPI. I'm trying to use packets, and I found one answer, but it too was outdated.
EntityPlayer entityP = ((CraftPlayer) p).getHandle();
entityP.displayName = args[0];
for (Player a: Bukkit.getOnlinePlayers()) {
if (!p.getUniqueId().equals(a.getUniqueId()))
((CraftPlayer) a).getHandle().playerConnection.sendPacket(new PacketPlayOutNamedEntitySpawn(entityP));
}
Here's that thread I was going off of: https://bukkit.org/threads/change-player-name-above-head.162356/
Any help is appreciated!
It is possible to achieve this in 1.8. For convenience, I used ProtocolLib and PacketWrapper.
Since the 1.8 update, the NamedEntitySpawn packet has been modified and changing player's name by modifying that has been no longer supported.(ref)
But this post gave a reference: we can use packet PlayerInfoData. I did some testing, and here's the result(tested against 1.9.2):
Here's the code:
Player theGuyToChangeNameFor = Bukkit.getPlayer("theguy");
PlayerInfoData pid = new PlayerInfoData(WrappedGameProfile.fromPlayer(theGuyToChangeNameFor), 1,
EnumWrappers.NativeGameMode.SURVIVAL,
WrappedChatComponent.fromText("whatever_string"));
WrapperPlayServerPlayerInfo wpspi = new WrapperPlayServerPlayerInfo();
wpspi.setAction(EnumWrappers.PlayerInfoAction.REMOVE_PLAYER);
wpspi.setData(Collections.singletonList(pid));
for(Player p : Bukkit.getOnlinePlayers())
{
if(p.equals(theGuyToChangeNameFor))
{
continue;
}
p.hidePlayer(theGuyToChangeNameFor);
wpspi.sendPacket(p);
}
ProtocolLibrary.getProtocolManager().addPacketListener(
new PacketAdapter(this, PacketType.Play.Server.PLAYER_INFO)
{
#Override
public void onPacketSending(PacketEvent event)
{
if(event.getPacket().getPlayerInfoAction().read(0) != EnumWrappers.PlayerInfoAction.ADD_PLAYER)
{
return;
}
PlayerInfoData pid = event.getPacket().getPlayerInfoDataLists().read(0).get(0);
if(!pid.getProfile().getName().toLowerCase().equals("theguy")) // Here you can do something to ensure you're changing the name of the correct guy
{
return;
}
PlayerInfoData newPid = new PlayerInfoData(pid.getProfile().withName("HEAD_NAME"), pid.getPing(), pid.getGameMode(),
WrappedChatComponent.fromText("TAB_LIST_NAME"));
event.getPacket().getPlayerInfoDataLists().write(0, Collections.singletonList(newPid));
}
}
);
for(Player p : Bukkit.getOnlinePlayers())
{
if(p.equals(theGuyToChangeNameFor))
{
continue;
}
p.showPlayer(theGuyToChangeNameFor);
}
Explanation:
We use ProtocolLib to modify the PlayerInfoData packets from the server to change the player's display name. (You can see that name tag and tab list name can even be two different values!)
hidePlayer, showPlayer and REMOVE_PLAYER are used to refresh the player's name immediately(otherwise it will require logging out and in again). So far haven't found a better method. If you have one, say it:)

Delete all box 2D bodies from world in libGDX

Recently I have been trying to delete all my bodies from Box 2D world and I ran into a little bit of a trouble.
Here is my code for deleting all the bodies:
#Override
public boolean keyDown(int keycode) {
if(keycode==Keys.R){
LevelHolder.clearLevel();
}
}
...
public static void clearLevel(){
System.out.println("deleting bodies");
Array<Body> bodies = new Array<Body>();
world.getBodies(bodies);
for(Body bod: bodies){
world.destroyBody(bod);
}
System.out.println("deleted bodies");
}
And it seems like a reasonable peace of code to me however this crashes sometimes (the message "deleted bodies" never gets printed) with error message from native code:
Assertion failed: (m_bodyCount > 0), function DestroyBody, file /Users/badlogic/jenkins/workspace/libgdx-mac/extensions/gdx-box2d/gdx-box2d/jni/Box2D/Dynamics/b2World.cpp, line 133.
When deleting all bodies that I just got from the world Im somehow deleting more bodies than there are in the world. Also it doesn't happen all the time.
The piece of code is completely isolated and my game has no multi threading. So nothing could be deleting bodies while I'm stepping through all the bodies in the world.
What could be happening here? Maybe this is not the right way of deleting all the bodies and someone could give me an insight of how to do it better? Thank you.
Using libGDX 1.5.2 here.
I was using the same code as you to destroy all bodies and ran into a similar problem. I believe the problem is that you are trying to destroy bodies while your box2d.World is locked(you can check with world.isLocked()). During your world.step() your box2d.World is locked. This was my problem, as I was trying to destroy bodies as a result of a beginContact() event and couldn't because this was being handled within world.step().
My solution was to assign a boolean flag to true and just before doing world.step() i would check to see if it was true and if it was, then I destroy all bodies using same code as you did above.
Here is an example i tested:
private boolean destroyAllBodies;
public void clearBodies()
{
destroyAllBodies = true;
}
public void update()
{
if(destroyAllBodies)
{
Array<Body> bodies = new Array<Body>();
world.getBodies(bodies);
for(int i = 0; i < bodies.size; i++)
{
if(!world.isLocked())
world.destroyBody(bodies.get(i));
}
destroyAllBodies = false;
}
...
world.step(1/60f, 6, 2);
...
}
I hope that helped. Cheers!
Try to get the count of bodies first, and then write a for loop that goes through the array using that count, rather than an enumerator. Editing a collection while it's being enumerated can cause issues.
The problem is that you are trying to delete the bodies in the keydown event so the world may be locked.
What you should do is delete them in the render method.
boolean clearLevel=false;
#Override
public boolean keyDown(int keycode) {
if(keycode==Keys.R){
clearLevel=true;
}
}
...
public boolean render(float delta){
world.step(delta, 8, 4);
if(clearLevel){
System.out.println("deleting bodies");
Array<Body> bodies = new Array<Body>();
world.getBodies(bodies);
for(Body bod: bodies){
world.destroyBody(bod);
}
System.out.println("deleted bodies");
clearLevel=false;
}
}

LWJGL Keyboard loop

I've created a static Input class, that basicly have a method that I can call, which is this:
public static boolean GetKeyDown(int keyCode) {
while(Keyboard.next()) {
Keyboard.enableRepeatEvents(false);
if (Keyboard.getEventKeyState()) {
if (Keyboard.getEventKey() == keyCode) {
return true;
} else {
return false;
}
}
}
return false;
}
And in my game update loop, I've wanted to use this, instead of having to make a single while-loop:
if(Input.GetKeyDown(KeyCode.S)) {
//Something happens
}
if(Input.GetKeyDown(KeyCode.R)) {
//Something happens
}
//etc..
But it seems that only the first one loaded, will work. In this case 'S'. Is there a way for me to do be able to use the others too?
That is because in your GetKeyDown() method, you call Keyboard.next(), when you call that method it removes the Event of the current key from Keyboard, the only gets refilled with Events, when you call Display.update();
NOTE: This method does not query the operating system for new events. To do that, Display.processMessages() (or Display.update()) must be called first.
Source: LWJGL Docs
You Could
Instead you can use the Keyboard.isKeyDown(int key) method, to achieve what you're trying to do.
Though it returns true/false depending on the following.
Returns: true if the key is down according to the last poll()
But that still doesn't quite fix the problem because it relies on the poll() method.
Fixing The Problem
You can fix the problem by creating some custom methods to use with the Keyboard class, as you already did, though as said the Keyboard Events only gets updated when you call the Display.update(); method.
You already got the right idea about which function to create, though you need to split them into, two different methods. You need a secondary method which you call once each time you want to update your keyboard.
public class MyKeyboard {
/*
* Remember that the index where we store the value,
* is the index of the key. Thereby one key might have
* an index of 400, then your array need to have at least
* the same size, to be able to store it.
*/
public static boolean[] keys = new boolean[100]; // 100 is the amount of keys to remember!
public static void update() {
while(Keyboard.next()) {
if (Keyboard.getEventKey() < keys.length) {
keys[Keyboard.getEventKey()] = Keyboard.getEventKeyState();
}
}
}
public static boolean isKeyDown(int key) {
if ((key > 0) && (key < keys.length)) {
return keys[key];
}
return false;
}
}
Remember to only call the MyKeyboard.update() method once per Display.update() I also renamed your GetKeyDown() method to isKeyDown(), because I think that sounds and describes it better, but you can rename it again in your project if you want to.
The above code was made within this answer, without the use of an IDE, etc. So if there's anything wrong with it I apologize, but just comment and I will fix it.
One problem that arises with this method is the lack of rechecking. Since Keyboard.next() only checks the inputs that have occurred in the current frame. A button which was once pressed will remain "pressed" until it is pressed again. I ran into this problem while trying to implement this solution. The answer to this new problem is here:
public static void update() {
for(int i = 0; i < keys.length; i++) {
keys[i] = false;
}
while(Keyboard.next()) {
keys[Keyboard.getEventKey()] = Keyboard.getEventKeyState();
}
}
You must clear the keypresses of the previous frame by setting everything to false.

How to properly add an ActionListeren to a custom JComponent

I often implement some panels, which provide common functionality like controls. For this I want to be able to add listeners, so that the caller can attach to the control and get notifications about changes.
So far I have simply used my own List where I keep the listeners and when I want to fire an action I loop through the list and call the listeners. From the outside this basically looks like any other Swing controls, however I was wondering if this is really the approach which should be used.
Especcially I was wondering if calling the listeners in a loop is what Swing itself also does, or if there is some kind of queue where you would put the actions, so that Swing decides when to deliver such actions.
When I investiaged this I came across this code:
protected void fireActionPerformed(ActionEvent event)
{
Object[] listeners = listenerList.getListenerList();
ActionEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2)
{
if(listeners[i] instanceof ActionListener)
{
// Lazily create the event:
if (e == null)
{
String actionCommand = event.getActionCommand();
e = new ActionEvent(this,
ActionEvent.ACTION_PERFORMED,
actionCommand,
event.getWhen(),
event.getModifiers());
e.setSource(event.getSource());
}
((ActionListener)listeners[i+1]).actionPerformed(e);
}
}
}
The member listenerList from JComponent is directly accessed, whcih feels a bit strange. However I didn't really find a better way so far. Also when adding a new listener to this, I do it now like shown below, but I'm not sure if this is really the appropriate way:
public void addQueryListener(ActionListener oListener)
{
listenerList.add(ActionListener.class, oListener);
}
public void removeQueryListener(ActionListener oListener)
{
listenerList.remove(ActionListener.class, oListener);
}
So I would like to know, is accessing the listenerList member the correct way to add and remove listeners, so that they behave like any other standard control? Or is there some best practice how this should be done, which I'm missing so far?
Keeping mind the restriction Swings put for Creating the gui. There is no harm accessing the
** listenerlist ** this way. May be this is not best approach.
Swing is Suppose to be Single Threaded and is not Thread Safe.
http://codeidol.com/java/java-concurrency/GUI-Applications/Why-are-GUIs-Single-threaded/
AddListener and RemoveListener needed to be called on EDT(Event Dispatch Thread)
see See http://en.wikipedia.org/wiki/Event_dispatching_thread.
Also See for iteration of Listenere i.e when you call getActionListeners
its creates a copy of ListenersList and returns you back
Below Code from EventListenerList
public <T extends EventListener> T[] getListeners(Class<T> t) {
Object[] lList = listenerList;
int n = getListenerCount(lList, t);
T[] result = (T[])Array.newInstance(t, n);
int j = 0;
for (int i = lList.length-2; i>=0; i-=2) {
if (lList[i] == t) {
result[j++] = (T)lList[i+1];
}
}
return result;
}
There's a good example in the EventListenerList docs, and this Converter example uses its own listenerList in ConverterRangeModel.

Categories

Resources