0

My goals:

  • Have it even more normalized. (more similar wait times - linear growth)
  • Scale up to XXX and maybe even XXXX number of monsters and npcs.
  • Have all of you Java gurus out there give me some ideas :D

My issues are the following:

  • It never hits the second iteration loop(npc)
  • The 'wasted' time is too random; there will be hundreds(if not more) of mobs/npcs to iterate through, this solution will not scale at all
  • I have many other 'events' my server will do in the main loop, some of which use the same HashMaps, hence the use of ConcurrentHashMap(calculate hit damage/etc)

Code: I hope this is SSCCE enough. I tried to trim the fat as much as possible...

import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

public class WaitTime {

    static ConcurrentHashMap<String, Integer> mobInstanceMap = new ConcurrentHashMap<String, Integer>();
    static ConcurrentHashMap<String, Integer> npcInstanceMap = new ConcurrentHashMap<String, Integer>();

    public static void main(String[] args){
        mobInstanceMap.put("mob1", 0);
        mobInstanceMap.put("mob2", 0);
        mobInstanceMap.put("mob3", 0);
        npcInstanceMap.put("npc1", 0);
        npcInstanceMap.put("npc2", 0);
        npcInstanceMap.put("npc3", 0);
        while(true){
            updateEntityLocations();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private static void updateEntityLocations() {
        long entityMovementLoopStartTime = System.nanoTime();
        Iterator<Entry<String, Integer>> it = mobInstanceMap.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, Integer> mobEntity = it.next();
            String mobName = mobEntity.getKey();
            int lastWalkTime = mobEntity.getValue();
            int mobWalkSpeed = 4000;
            long walkWaitTime = lastWalkTime;
            long elapsedTime = (long) ((System.nanoTime() - entityMovementLoopStartTime) / 100.0);
            walkWaitTime += elapsedTime;

            if (walkWaitTime >= mobWalkSpeed){
                System.out.println("Wasted time(walking)(" + mobName + "): " + (walkWaitTime - mobWalkSpeed));

                //mobInstanceMap.put(mobName, 0);
                mobInstanceMap.replace(mobName, 0);
            } else {  //!(walkWaitTime >= walkSpeed)
                //mobInstanceMap.put(mobName, (int) walkWaitTime);
                mobInstanceMap.replace(mobName, (int) walkWaitTime);
            }
        }

        Iterator<Entry<String, Integer>> it1 = npcInstanceMap.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, Integer> npcEntity = it1.next();
            String npcCoords = npcEntity.getKey();
            int lastWalkTime = npcEntity.getValue();
            int npcWalkSpeed = 4000;
            long walkWaitTime = lastWalkTime;
            long elapsedTime = (long) ((System.nanoTime() - entityMovementLoopStartTime) / 100.0);
            walkWaitTime += elapsedTime;

            if (walkWaitTime >= npcWalkSpeed){
                System.out.println("Wasted time(walking)(" + npcCoords + "): " + (walkWaitTime - npcWalkSpeed));

                npcInstanceMap.put(npcCoords, 0);
            } else {  //!(walkWaitTime >= walkSpeed)
                npcInstanceMap.put(npcCoords, (int) walkWaitTime);
            }
        }   
    }
}

Console:

Wasted time(walking)(mob2): 58
Wasted time(walking)(mob1): 1983
Wasted time(walking)(mob3): 2288
Wasted time(walking)(mob3): 266
Wasted time(walking)(mob1): 122
Wasted time(walking)(mob3): 232
Wasted time(walking)(mob2): 23
Wasted time(walking)(mob1): 674
Wasted time(walking)(mob3): 27
Wasted time(walking)(mob1): 159
Wasted time(walking)(mob3): 1723
Wasted time(walking)(mob2): 119
Wasted time(walking)(mob1): 676
Wasted time(walking)(mob3): 1698
Wasted time(walking)(mob3): 3983
Wasted time(walking)(mob1): 182

As you can see if you run it with put(commented out) instead of replace it runs slightly slower and more erratic.

KisnardOnline
  • 653
  • 4
  • 16
  • 42
  • Possible duplicate of: http://stackoverflow.com/questions/1066589/java-iterate-through-hashmap – ktm5124 May 29 '13 at 17:13
  • thanks I am taking a look now, for this instance it looks like the map.entrySet() is what I need... I guess the part I am still weary on is when I remove and add entries mid iteration(in my attacking loop)... – KisnardOnline May 29 '13 at 17:32
  • Even with the new foreach loop the times are so random... any clue? Some in thousands, some 10s, some hundreds... – KisnardOnline May 29 '13 at 17:41
  • Consider using something other than Strings as the map keys. If only mobs end up in the mob-map, get rid of the "mob" part of the key and just use the Integer value. – Ryan May 29 '13 at 18:19
  • The keys in the two maps are coordinates... eg. 20,32 which with the comma is a string. Any ideas? – KisnardOnline May 30 '13 at 16:58
  • @JayAvon Sounds like a new question. I'd make a Point class with an x and y field. Eclipse or Netbeans can generate simple and correct hashCode and equals for you. Building a String from your hash input is wasteful and slow. – Ryan May 31 '13 at 16:44

1 Answers1

2

You'll kick yourself, but the second loop references the first iterator.

Iterator<Entry<String, Integer>> it1 = npcInstanceMap.entrySet().iterator();
while (it.hasNext()) {
    ...
}

Also, as this answer suggests, I propose not using an iterator.

for(String mob : mobInstanceMap.keySet()){
    String mobName = mob;
    int lastWalkTime = mobInstanceMap.get(mob);
    int mobWalkSpeed = 4000;
    long walkWaitTime = lastWalkTime;
    long elapsedTime = (long) ((System.nanoTime() - entityMovementLoopStartTime) / 100.0);
    walkWaitTime += elapsedTime;

    if (walkWaitTime >= mobWalkSpeed){
        System.out.println("Wasted time(walking)(" + mobName + "): " + (walkWaitTime - mobWalkSpeed));

        mobInstanceMap.put(mobName, 0);
    } else {  //!(walkWaitTime >= walkSpeed)
        mobInstanceMap.put(mobName, (int) walkWaitTime);
    }
}
Community
  • 1
  • 1
leon
  • 93
  • 1
  • 3
  • I seem to be kicking myself alot lately... :D Thanks for the help both of you!! – KisnardOnline May 29 '13 at 17:40
  • 1
    Why iterate the keys? The code is going to change the value of the entry. Instead of iterating the keys and doing the lookup twice, iterate the entries and then call entry.setValue(). It avoids rehashing the key. – Ryan May 29 '13 at 18:12