From d2fd433b8bfd4de905dc21272c87fdb5f027205e Mon Sep 17 00:00:00 2001
From: Chris Kearney <chris@kearneymail.com>
Date: Wed, 1 Jul 2015 18:19:29 -0700
Subject: [PATCH] itemdecaymanagerfixes, added sentry

---
 pom.xml                                       |  7 ++
 .../creeper/Items/ForageManager.java          |  2 +
 .../com/comandante/creeper/Items/Item.java    | 11 ++-
 .../creeper/Items/ItemDecayManager.java       | 97 +++++++++++--------
 .../com/comandante/creeper/MyListener.java    |  2 +
 .../creeper/RecentChangesManager.java         |  3 +-
 .../creeper/command/PickUpCommand.java        | 12 ++-
 .../creeper/entity/EntityManager.java         |  8 +-
 .../creeper/managers/GameManager.java         |  2 +-
 .../creeper/managers/SentryManager.java       | 35 +++++++
 .../java/com/comandante/creeper/npc/Npc.java  |  5 +-
 .../com/comandante/creeper/player/Player.java |  3 +
 .../creeper/server/CreeperCommandHandler.java |  2 +
 .../creeper/world/WorldExporter.java          |  2 +
 14 files changed, 140 insertions(+), 51 deletions(-)
 create mode 100644 src/main/java/com/comandante/creeper/managers/SentryManager.java

diff --git a/pom.xml b/pom.xml
index 33b74c9a..311216a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -128,6 +128,13 @@
             <artifactId>ForecastIOLib</artifactId>
             <version>1.5.2</version>
         </dependency>
+
+        <dependency>
+            <groupId>net.kencochrane.raven</groupId>
+            <artifactId>raven</artifactId>
+            <version>4.0</version>
+        </dependency>
+
     </dependencies>
 
     <build>
diff --git a/src/main/java/com/comandante/creeper/Items/ForageManager.java b/src/main/java/com/comandante/creeper/Items/ForageManager.java
index e845777f..d86ed152 100644
--- a/src/main/java/com/comandante/creeper/Items/ForageManager.java
+++ b/src/main/java/com/comandante/creeper/Items/ForageManager.java
@@ -1,6 +1,7 @@
 package com.comandante.creeper.Items;
 
 import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.managers.SentryManager;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.server.Color;
 import com.comandante.creeper.world.Area;
@@ -50,6 +51,7 @@ public class ForageManager {
                 }
             } catch (InterruptedException e) {
                 log.error(e);
+                SentryManager.logSentry(this.getClass(), e, "problem with forage delay!");
             }
         }
     }
diff --git a/src/main/java/com/comandante/creeper/Items/Item.java b/src/main/java/com/comandante/creeper/Items/Item.java
index 96559025..2671babc 100644
--- a/src/main/java/com/comandante/creeper/Items/Item.java
+++ b/src/main/java/com/comandante/creeper/Items/Item.java
@@ -3,6 +3,8 @@ package com.comandante.creeper.Items;
 
 import com.comandante.creeper.player.Equipment;
 import com.comandante.creeper.spells.Effect;
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
 
 import java.io.Serializable;
 import java.util.List;
@@ -24,6 +26,7 @@ public class Item implements Serializable {
     private final Rarity rarity;
     private final int valueInGold;
     private Set<Effect> effects;
+    private final Interner<String> interner = Interners.newWeakInterner();
 
     public static final int CORPSE_ID_RESERVED = 100;
     public static final int EQUIPMENT_ID_RESERVED = 101;
@@ -79,11 +82,15 @@ public class Item implements Serializable {
     }
 
     public boolean isWithPlayer() {
-        return isWithPlayer;
+        synchronized (interner.intern(itemId)) {
+            return isWithPlayer;
+        }
     }
 
     public void setWithPlayer(boolean isWithPlayer) {
-        this.isWithPlayer = isWithPlayer;
+        synchronized (interner.intern(itemId)) {
+            this.isWithPlayer = isWithPlayer;
+        }
     }
 
     public int getNumberOfUses() {
diff --git a/src/main/java/com/comandante/creeper/Items/ItemDecayManager.java b/src/main/java/com/comandante/creeper/Items/ItemDecayManager.java
index bf19bdbc..3a6b8139 100644
--- a/src/main/java/com/comandante/creeper/Items/ItemDecayManager.java
+++ b/src/main/java/com/comandante/creeper/Items/ItemDecayManager.java
@@ -2,6 +2,8 @@ package com.comandante.creeper.Items;
 
 import com.comandante.creeper.entity.CreeperEntity;
 import com.comandante.creeper.entity.EntityManager;
+import com.comandante.creeper.managers.SentryManager;
+import org.apache.log4j.Logger;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -12,17 +14,20 @@ public class ItemDecayManager extends CreeperEntity {
 
     private final ConcurrentHashMap<String, DecayProgress> itemDecayTracker = new ConcurrentHashMap<String, DecayProgress>();
     private final EntityManager entityManager;
+    private static final Logger log = Logger.getLogger(ItemDecayManager.class);
+    private int tickBucket = 0;
 
     public ItemDecayManager(EntityManager entityManager) {
         this.entityManager = entityManager;
     }
 
     public void addItem(Item item) {
+        item.setWithPlayer(false);
         itemDecayTracker.put(item.getItemId(), new DecayProgress(item.getItemHalfLifeTicks()));
     }
 
-    public void removeItem(Item item) {
-        itemDecayTracker.remove(item.getItemId());
+    public void removeItem(String itemId) {
+        itemDecayTracker.remove(itemId);
     }
 
     public ConcurrentHashMap<String, DecayProgress> getItemDecayTracker() {
@@ -31,51 +36,63 @@ public class ItemDecayManager extends CreeperEntity {
 
     @Override
     public void run() {
-        List<String> itemsToRemoveFromDecay = new ArrayList<>();
-        List<String> itemsToDestroy = new ArrayList<>();
-        ConcurrentHashMap<String, DecayProgress> itemDecayTracker1 = getItemDecayTracker();
-        for (Map.Entry<String, DecayProgress> next : itemDecayTracker1.entrySet()) {
-            DecayProgress decayProgress = next.getValue();
-            Item item = entityManager.getItemEntity(next.getKey());
-            if (item.isWithPlayer()) {
-                itemsToRemoveFromDecay.add(item.getItemId());
-                continue;
+        try {
+            if (tickBucket == 10) {
+                List<String> itemsToRemoveFromDecay = new ArrayList<>();
+                List<String> itemsToDestroy = new ArrayList<>();
+                ConcurrentHashMap<String, DecayProgress> itemDecayTracker1 = getItemDecayTracker();
+                for (Map.Entry<String, DecayProgress> next : itemDecayTracker1.entrySet()) {
+                    DecayProgress decayProgress = next.getValue();
+                    Item item = entityManager.getItemEntity(next.getKey());
+                    if (item == null) {
+                        removeItem(next.getKey());
+                        continue;
+                    }
+                    if (item.isWithPlayer()) {
+                        itemsToRemoveFromDecay.add(item.getItemId());
+                        continue;
+                    }
+                    decayProgress.incTick();
+                    if (decayProgress.getCurrentTicks() >= decayProgress.getNumberOfTicks()) {
+                        itemsToDestroy.add(item.getItemId());
+                    }
+                }
+                for (String itemId : itemsToRemoveFromDecay) {
+                    removeItem(itemId);
+                }
+                for (String itemId : itemsToDestroy) {
+                    removeItem(itemId);
+                    entityManager.removeItem(itemId);
+                }
+                tickBucket = 0;
+            } else {
+                tickBucket = tickBucket + 1;
             }
-            decayProgress.incTick();
-            if (decayProgress.getCurrentTicks() >= decayProgress.getNumberOfTicks()) {
-                itemsToDestroy.add(item.getItemId());
-            }
-        }
-        for (String itemId : itemsToRemoveFromDecay) {
-            Item itemEntity = entityManager.getItemEntity(itemId);
-            removeItem(itemEntity);
-        }
-        for (String itemId : itemsToDestroy) {
-            Item itemEntity = entityManager.getItemEntity(itemId);
-            removeItem(itemEntity);
-            entityManager.removeItem(itemEntity);
+        } catch (Exception e) {
+            log.error("Problem with item decay manager!", e);
+            SentryManager.logSentry(this.getClass(), e, "Exception caught in item decay manager!");
         }
     }
+}
 
-    class DecayProgress {
-        private final int numberOfTicks;
-        private int currentTicks = 0;
-
-        DecayProgress(int numberOfTicks) {
-            this.numberOfTicks = numberOfTicks;
-        }
+class DecayProgress {
+    private final int numberOfTicks;
+    private int currentTicks = 0;
 
-        public void incTick() {
-            this.currentTicks++;
-        }
+    DecayProgress(int numberOfTicks) {
+        this.numberOfTicks = numberOfTicks;
+    }
 
-        public int getNumberOfTicks() {
-            return numberOfTicks;
-        }
+    public void incTick() {
+        this.currentTicks++;
+    }
 
-        public int getCurrentTicks() {
-            return currentTicks;
-        }
+    public int getNumberOfTicks() {
+        return numberOfTicks;
     }
 
+    public int getCurrentTicks() {
+        return currentTicks;
+    }
 }
+
diff --git a/src/main/java/com/comandante/creeper/MyListener.java b/src/main/java/com/comandante/creeper/MyListener.java
index 3235d56c..214efe7d 100644
--- a/src/main/java/com/comandante/creeper/MyListener.java
+++ b/src/main/java/com/comandante/creeper/MyListener.java
@@ -2,6 +2,7 @@ package com.comandante.creeper;
 
 import com.comandante.creeper.bot.commands.BotCommand;
 import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.managers.SentryManager;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.player.PlayerManager;
 import com.comandante.creeper.world.Room;
@@ -67,6 +68,7 @@ public class MyListener extends ListenerAdapter {
             }
         } catch (Exception e) {
             e.printStackTrace();
+            SentryManager.logSentry(this.getClass(), e, "IRC Listener Exception!");
         }
     }
 }
diff --git a/src/main/java/com/comandante/creeper/RecentChangesManager.java b/src/main/java/com/comandante/creeper/RecentChangesManager.java
index 3d931476..dbcbabaa 100644
--- a/src/main/java/com/comandante/creeper/RecentChangesManager.java
+++ b/src/main/java/com/comandante/creeper/RecentChangesManager.java
@@ -1,6 +1,7 @@
 package com.comandante.creeper;
 
 
+import com.comandante.creeper.managers.SentryManager;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
@@ -40,7 +41,7 @@ public class RecentChangesManager {
                 i++;
             }
         } catch (IOException e) {
-            e.printStackTrace();
+            SentryManager.logSentry(RecentChangesManager.class, e, "Recent changes problem!");
         }
         return sb.toString();
     }
diff --git a/src/main/java/com/comandante/creeper/command/PickUpCommand.java b/src/main/java/com/comandante/creeper/command/PickUpCommand.java
index e3eb2625..a60b8bea 100644
--- a/src/main/java/com/comandante/creeper/command/PickUpCommand.java
+++ b/src/main/java/com/comandante/creeper/command/PickUpCommand.java
@@ -29,11 +29,13 @@ public class PickUpCommand extends Command {
             String desiredPickUpItem = Joiner.on(" ").join(originalMessageParts);
             for (String next : itemIds) {
                 Item itemEntity = entityManager.getItemEntity(next);
-                if (itemEntity.getItemTriggers().contains(desiredPickUpItem)) {
-                    if (gameManager.acquireItemFromRoom(player, next)) {
-                        String playerName = player.getPlayerName();
-                        gameManager.roomSay(currentRoom.getRoomId(), playerName + " picked up " + itemEntity.getItemName(), playerId);
-                        return;
+                if (itemEntity != null) {
+                    if (itemEntity.getItemTriggers().contains(desiredPickUpItem)) {
+                        if (gameManager.acquireItemFromRoom(player, next)) {
+                            String playerName = player.getPlayerName();
+                            gameManager.roomSay(currentRoom.getRoomId(), playerName + " picked up " + itemEntity.getItemName(), playerId);
+                            return;
+                        }
                     }
                 }
             }
diff --git a/src/main/java/com/comandante/creeper/entity/EntityManager.java b/src/main/java/com/comandante/creeper/entity/EntityManager.java
index a6df1fda..a635b96f 100644
--- a/src/main/java/com/comandante/creeper/entity/EntityManager.java
+++ b/src/main/java/com/comandante/creeper/entity/EntityManager.java
@@ -5,6 +5,7 @@ import com.comandante.creeper.Items.Item;
 import com.comandante.creeper.Items.ItemDecayManager;
 import com.comandante.creeper.Items.ItemSerializer;
 import com.comandante.creeper.Main;
+import com.comandante.creeper.managers.SentryManager;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.player.PlayerManager;
@@ -86,6 +87,10 @@ public class EntityManager {
         items.remove(item.getItemId());
     }
 
+    public void removeItem(String itemId) {
+        items.remove(itemId);
+    }
+
     public void saveEffect(Effect effect) {
         effects.put(effect.getEntityId(), effect);
     }
@@ -150,7 +155,8 @@ public class EntityManager {
                     context.stop();
                     Thread.sleep(500);
                 } catch (Exception e) {
-                   log.error("Problem with ticker!", e);
+                    log.error("Problem with ticker!", e);
+                    SentryManager.logSentry(this.getClass(), e, "Problem with ticker!");
                 }
             }
         }
diff --git a/src/main/java/com/comandante/creeper/managers/GameManager.java b/src/main/java/com/comandante/creeper/managers/GameManager.java
index 837f0b75..82af717c 100644
--- a/src/main/java/com/comandante/creeper/managers/GameManager.java
+++ b/src/main/java/com/comandante/creeper/managers/GameManager.java
@@ -343,9 +343,9 @@ public class GameManager {
         synchronized (interner.intern(itemId)) {
             Stats playerStatsWithEquipmentAndLevel = player.getPlayerStatsWithEquipmentAndLevel();
             if (player.getInventory().size() < playerStatsWithEquipmentAndLevel.getInventorySize()) {
-                player.addInventoryId(itemId);
                 Item itemEntity = entityManager.getItemEntity(itemId);
                 itemEntity.setWithPlayer(true);
+                player.addInventoryId(itemId);
                 entityManager.saveItem(itemEntity);
                 return true;
             } else {
diff --git a/src/main/java/com/comandante/creeper/managers/SentryManager.java b/src/main/java/com/comandante/creeper/managers/SentryManager.java
new file mode 100644
index 00000000..1c4a80f4
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/managers/SentryManager.java
@@ -0,0 +1,35 @@
+package com.comandante.creeper.managers;
+
+import net.kencochrane.raven.Dsn;
+import net.kencochrane.raven.Raven;
+import net.kencochrane.raven.RavenFactory;
+import net.kencochrane.raven.event.Event;
+import net.kencochrane.raven.event.EventBuilder;
+import net.kencochrane.raven.event.interfaces.ExceptionInterface;
+
+public class SentryManager {
+
+    private static Raven raven = RavenFactory.ravenInstance(new Dsn("https://f6888b8b68384ae8a6e5809f8fb08a6d:e2e3dbaaaa8d40639c87d7b16a1539f9@app.getsentry.com/47336"));
+
+    public static void logSentry(Class c, Exception e, String msg) {
+        EventBuilder eventBuilder = new EventBuilder()
+                .setMessage(msg)
+                .setLevel(Event.Level.ERROR)
+                .setLogger(c.getName())
+                .addSentryInterface(new ExceptionInterface(e));
+
+        raven.runBuilderHelpers(eventBuilder);
+        raven.sendEvent(eventBuilder.build());
+    }
+
+    public static void logSentry(Class c, Throwable e, String msg) {
+        EventBuilder eventBuilder = new EventBuilder()
+                .setMessage(msg)
+                .setLevel(Event.Level.ERROR)
+                .setLogger(c.getName())
+                .addSentryInterface(new ExceptionInterface(e));
+
+        raven.runBuilderHelpers(eventBuilder);
+        raven.sendEvent(eventBuilder.build());
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/npc/Npc.java b/src/main/java/com/comandante/creeper/npc/Npc.java
index 098f5088..03f0650d 100644
--- a/src/main/java/com/comandante/creeper/npc/Npc.java
+++ b/src/main/java/com/comandante/creeper/npc/Npc.java
@@ -6,6 +6,7 @@ import com.comandante.creeper.Items.Loot;
 import com.comandante.creeper.Items.Rarity;
 import com.comandante.creeper.entity.CreeperEntity;
 import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.managers.SentryManager;
 import com.comandante.creeper.player.CoolDownType;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.server.Color;
@@ -97,6 +98,7 @@ public class Npc extends CreeperEntity {
                 }
             } catch (Exception e) {
                 e.printStackTrace();
+                SentryManager.logSentry(this.getClass(), e, "NPC Ticker Problem!");
             }
         }
     }
@@ -249,7 +251,8 @@ public class Npc extends CreeperEntity {
                 }
             }
         } catch (Exception e) {
-            e.printStackTrace();
+            SentryManager.logSentry(this.getClass(), e, "Problem processing NPC Stat Change!");
+
         }
     }
 
diff --git a/src/main/java/com/comandante/creeper/player/Player.java b/src/main/java/com/comandante/creeper/player/Player.java
index 8a02b0ec..5155d9b4 100755
--- a/src/main/java/com/comandante/creeper/player/Player.java
+++ b/src/main/java/com/comandante/creeper/player/Player.java
@@ -5,6 +5,7 @@ import com.comandante.creeper.Items.Item;
 import com.comandante.creeper.Items.ItemType;
 import com.comandante.creeper.entity.CreeperEntity;
 import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.managers.SentryManager;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.npc.NpcStatsChangeBuilder;
 import com.comandante.creeper.server.Color;
@@ -61,6 +62,8 @@ public class Player extends CreeperEntity {
             }
         } catch (Exception e) {
             log.error("Player ticker failed! + " + playerName, e);
+            SentryManager.logSentry(this.getClass(), e, "Player ticker problem!");
+
         }
     }
 
diff --git a/src/main/java/com/comandante/creeper/server/CreeperCommandHandler.java b/src/main/java/com/comandante/creeper/server/CreeperCommandHandler.java
index 80e534d4..968074cc 100644
--- a/src/main/java/com/comandante/creeper/server/CreeperCommandHandler.java
+++ b/src/main/java/com/comandante/creeper/server/CreeperCommandHandler.java
@@ -8,6 +8,7 @@ import com.comandante.creeper.command.Command;
 import com.comandante.creeper.command.CommandAuditLog;
 import com.comandante.creeper.command.UnknownCommand;
 import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.managers.SentryManager;
 import com.comandante.creeper.merchant.Merchant;
 import com.comandante.creeper.merchant.MerchantCommandHandler;
 import com.comandante.creeper.merchant.bank.commands.BankCommandHandler;
@@ -76,6 +77,7 @@ public class CreeperCommandHandler extends SimpleChannelUpstreamHandler {
 
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
+        SentryManager.logSentry(this.getClass(), e.getCause(), "Exception caught in command handler!");
         CreeperSession creeperSession = (CreeperSession) e.getChannel().getAttachment();
         log.error("Error in the Command Handler!, last message: \"" + creeperSession.getLastMessage() + "\" - from username:" + creeperSession.getUsername().get(), e.getCause());
         gameManager.getPlayerManager().removePlayer(creeperSession.getUsername().get());
diff --git a/src/main/java/com/comandante/creeper/world/WorldExporter.java b/src/main/java/com/comandante/creeper/world/WorldExporter.java
index 76b42d8d..ef84ab26 100644
--- a/src/main/java/com/comandante/creeper/world/WorldExporter.java
+++ b/src/main/java/com/comandante/creeper/world/WorldExporter.java
@@ -1,6 +1,7 @@
 package com.comandante.creeper.world;
 
 import com.comandante.creeper.entity.EntityManager;
+import com.comandante.creeper.managers.SentryManager;
 import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.collect.Iterators;
@@ -43,6 +44,7 @@ public class WorldExporter {
         try {
             Files.write(worldJson.getBytes(), new File(WORLD_DIR + "world.json"));
         } catch (IOException e) {
+            SentryManager.logSentry(this.getClass(), e, "Save world problem!");
             e.printStackTrace();
         }
     }
-- 
GitLab