6

I'm making a text-based radar for Minecraft. If a player comes within 20 blocks of you, it will say in chat. As of now, it spams the chat. How can I get it to only write to chat about that player ONCE? Even if you don't play the game, it should be easy to understand.

if (Camb.radar)
{
  for (Entity e: (List < Entity > ) mc.theWorld.loadedEntityList)
  {
    if (e instanceof EntityPlayer)
    {
      EntityPlayer player = (EntityPlayer) e;
      if (player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0)
        continue;
      mc.thePlayer.addChatMessage("\2479[CAMB] \247e" + player.getEntityName() + " has entered your 20 block radius!"); //Write to chat, only want this line done once for every player
    }
  }
}
Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
Brad
  • 115
  • 3
  • Would you want it to only ping you once they enter the detection radius, and then only ping again if they leave an re-enter? – StephenTG Aug 01 '13 at 18:50
  • 1. Ever heard of a `boolean variable`? 2. What if the player goes away for 30 minutes and then comes back? Should the player not be alerted then? – Simon Forsberg Aug 01 '13 at 18:50
  • 1
    If there's some sort of MovementListener for players that you can use, I'd suggest moving this entire bit of code into there. – FThompson Aug 01 '13 at 18:52
  • @Vulcan This coder is already probably in a PlayerMoveEvent or similar. Problem for Brad is that it is triggered every time a player moves, even if the player is still inside the player's zone. – Simon Forsberg Aug 01 '13 at 18:53
  • @SimonAndréForsberg I don't believe the code is already in a movement event, judging by how it iterates through every player in the world. When using the MovementListener or similar, it would set a boolean upon entry to the zone, and unset it upon exit from the zone, where it only sends the message when it sets the boolean to true. – FThompson Aug 01 '13 at 18:57
  • @Vulcan Ah, good point about the iterations (or it's possible that Brad just didn't thought about the fact that if he's listening for PlayerMoveEvent, he gets information about which player that moved). Basically he would have to write his own MovementListener then. Because there's nothing in the API that would handle the entries/exits from player zones. – Simon Forsberg Aug 01 '13 at 19:04
  • @Brad What API are you using? Are you using the Minecraft modpack or are you using Bukkit or something else? – Simon Forsberg Aug 01 '13 at 19:04
  • @SimonAndréForsberg MCP, no API. I straight decompiled it. My mod is currently placed in EntityClientPlayerMP, in the function MotionUpdates. The issue is still unsolved – Brad Aug 01 '13 at 19:10
  • @Brad You will have to take care of the implemention details yourself, but the answers you got should get you started in the right direction. Good luck, sounds like a fun Minecraft feature. – Simon Forsberg Aug 01 '13 at 19:57
  • Related wikipedia article: https://en.wikipedia.org/wiki/Hysteresis#In_engineering – Tomáš Zato Jan 12 '16 at 09:55

6 Answers6

15

You'll need to keep track of when the player leaves the range and set a flag, so you'll know when they're transitioning from "out of range" to "in range". Might also want to add a timer so that you can only alert once every N seconds.

Troy
  • 1,599
  • 14
  • 28
2

If you make a class PlayerData, it can contain a hashmap of playernames mapped to booleans. You give each player a PlayerData object and then when somebody enters the radius of that player, you toggle his/her boolean.

public class PlayerData {
    public Player thePlayer;
    public HashMap<String,boolean> inRadius = new HashMap<String,boolean>();

    public PlayerData(Player thePlayer) {
       this.thePlayer = thePlayer;
    }

    public void checkRadius(P Entity player) {
    /**function that checks radius and if a new player is there, notify thePlayer*/
      if(inRadius.get(player.getEntityName()) == true || thePlayer == player || thePlayer.getDistanceToEntity(player) > 20.0) return;
      else {
        thePlayer.addChatMessage("whatever you want to say");
        inRadius.put(player.getEntityName(), true);
      }
      for(Iterator<String> key=inRadius.keySet().Iterator();key.hasNext()) {
        String name = key.next();
        /**Check to see if that player is still within 20 meters. If not, set value to false*/
        /** also be careful to check if player is online*/
      }
    }

}
Kammeot
  • 469
  • 7
  • 18
2

You could try creating a List or Array of nearby players, and add them to that list when they are within 20 blocks. When you find an entity within range, check to see if its in your list. If not, notify and add it to the list, if so, game on :)

For removing items from your list, check the entities in your list and compare them to the players position. If they are out of range, remove them. This may need to happen in a separate loop.

framauro13
  • 797
  • 2
  • 8
  • 18
0

You need to store outside of that method that you have alerted the player already. A Map is perfect for this. Even better a WeakHashMap in case you don't want to leak those Entities

private final Set<EntityPlayer> playersInRange = Collections
        .newSetFromMap(new WeakHashMap<EntityPlayer, Boolean>());

void onMove() {
    if (Camb.radar) {
        for (Entity e : (List<Entity>) mc.theWorld.loadedEntityList) {
            if (e instanceof EntityPlayer) {
                EntityPlayer player = (EntityPlayer) e;

                if (player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0) {
                    // make sure player is (no longer) in set
                    playersInRange.remove(player);
                    continue;
                }

                if (!playersInRange.contains(player)) {
                    playersInRange.add(player);
                    mc.thePlayer.addChatMessage("\2479[CAMB] \247e" + player.getEntityName()
                            + " has entered your 20 block radius!");
                }
            }
        }
    }
}

You could also store a time along with them to re-alert every X time.

private static final long WAIT_BETWEEN_ALERTS = 30000;
private final WeakHashMap<EntityPlayer, Long> map = new WeakHashMap<EntityPlayer, Long>();
void onMove() {
    if (Camb.radar) {
        for (Entity e : (List<Entity>) mc.theWorld.loadedEntityList) {
            if (e instanceof EntityPlayer) {
                EntityPlayer player = (EntityPlayer) e;

                if (player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0) {
                    // clear alerts
                    map.remove(player);
                    continue;
                }

                Long lastTimeAlerted = map.get(player);
                long minimumLastAlert = System.currentTimeMillis() - WAIT_BETWEEN_ALERTS;

                if (lastTimeAlerted == null || lastTimeAlerted < minimumLastAlert) {
                    map.put(player, System.currentTimeMillis());
                    mc.thePlayer.addChatMessage("\2479[CAMB] \247e" + player.getEntityName()
                            + " has entered your 20 block radius!");
                } // else, already alerted recently.
            }
        }
    }
}
zapl
  • 63,179
  • 10
  • 123
  • 154
0

Add a boolean flag to EntityPlayer detected with getter/setter methods.

Inside your loop:

if (Camb.radar) {
    for (....) {
        if (e instanceof EntityPlayer) {
            EntityPlayer player = (EntityPlayer) e;
            if (player.isDetected() || player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0) {
                continue;
            }

            if (!player.isDetected()) {
                mc.thePlayer.addChatMessage(....); 
                player.setDetected(true); // reset this flag when player goes out of radar
            }
        }
    }
}    
c.s.
  • 4,786
  • 18
  • 32
0

I suggest doing as following:

int radius = 0;
if (Camb.radar) for (Entity e : (List <Entity>) mc.theWorld.loadedEntityList)
    if (e instanceof EntityPlayer) {
        EntityPlayer player = (EntityPlayer) e;
        if (player == mc.thePlayer || mc.thePlayer.getDistanceToEntity(e) > 20.0)
            continue;
        while (radius < 1) {
            mc.thePlayer.addChatMessage("\2479[CAMB] \247e" + player.getEntityName() + " has
            entered your 20 block radius!");

        }    
    }
Unihedron
  • 10,902
  • 13
  • 62
  • 72
User
  • 129
  • 2
  • 16