diff --git a/src/main/java/com/comandante/creeper/CreeperEvent.java b/src/main/java/com/comandante/creeper/CreeperEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..a50a8fdc46b680d35710ec9e13973dff2cb122d5 --- /dev/null +++ b/src/main/java/com/comandante/creeper/CreeperEvent.java @@ -0,0 +1,5 @@ +package com.comandante.creeper; + +public interface CreeperEvent { + void run(); +} diff --git a/src/main/java/com/comandante/creeper/SingleThreadedCreeperEventProcessor.java b/src/main/java/com/comandante/creeper/SingleThreadedCreeperEventProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..7aaca477438f28c1c5d0e4ab5e62a2f993473567 --- /dev/null +++ b/src/main/java/com/comandante/creeper/SingleThreadedCreeperEventProcessor.java @@ -0,0 +1,47 @@ +package com.comandante.creeper; + +import com.google.api.client.util.Lists; +import com.google.common.util.concurrent.AbstractScheduledService; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class SingleThreadedCreeperEventProcessor extends AbstractScheduledService { + + private final ArrayBlockingQueue<CreeperEvent> creeperEventQueue; + private static final Logger log = Logger.getLogger(SingleThreadedCreeperEventProcessor.class); + + public SingleThreadedCreeperEventProcessor(ArrayBlockingQueue<CreeperEvent> creeperEventQueue) { + this.creeperEventQueue = creeperEventQueue; + } + + @Override + protected void runOneIteration() throws Exception { + ArrayList<CreeperEvent> events = Lists.newArrayList(); + creeperEventQueue.drainTo(events); + events.forEach(this::safeRun); + } + + public void addEvent(CreeperEvent event) { + try { + creeperEventQueue.put(event); + } catch (InterruptedException ex) { + log.error("Problem adding event.", ex); + } + } + + private void safeRun(final CreeperEvent e) { + try { + e.run(); + } catch (Exception ex) { + log.error("Problem executing event.", ex); + } + } + + @Override + protected Scheduler scheduler() { + return Scheduler.newFixedDelaySchedule(0, 50, TimeUnit.MILLISECONDS); + } +} diff --git a/src/main/java/com/comandante/creeper/managers/GameManager.java b/src/main/java/com/comandante/creeper/managers/GameManager.java index 743f940f2884c3ecf1a70d34232dfca03fad7426..5a26337800b7b59cda85493106f5b4613b958d97 100755 --- a/src/main/java/com/comandante/creeper/managers/GameManager.java +++ b/src/main/java/com/comandante/creeper/managers/GameManager.java @@ -5,6 +5,7 @@ import com.comandante.creeper.CreeperConfiguration; import com.comandante.creeper.IrcBotService; import com.comandante.creeper.Items.*; import com.comandante.creeper.Main; +import com.comandante.creeper.SingleThreadedCreeperEventProcessor; import com.comandante.creeper.bot.BotCommandFactory; import com.comandante.creeper.bot.BotCommandManager; import com.comandante.creeper.entity.CreeperEntity; @@ -37,6 +38,7 @@ import org.nocrala.tools.texttablefmt.Table; import java.text.NumberFormat; import java.util.*; +import java.util.concurrent.ArrayBlockingQueue; import static com.comandante.creeper.server.Color.*; @@ -67,6 +69,7 @@ public class GameManager { private final TimeTracker timeTracker; private final ItemUseHandler itemUseHandler; private final NpcMover npcMover; + private final SingleThreadedCreeperEventProcessor eventProcessor = new SingleThreadedCreeperEventProcessor(new ArrayBlockingQueue<>(100000)); public GameManager(CreeperConfiguration creeperConfiguration, RoomManager roomManager, PlayerManager playerManager, EntityManager entityManager, MapsManager mapsManager, ChannelCommunicationUtils channelUtils) { this.roomManager = roomManager; @@ -92,6 +95,7 @@ public class GameManager { this.entityManager.addEntity(itemDecayManager); this.itemUseHandler = new ItemUseHandler(this); this.npcMover = new NpcMover(this); + this.eventProcessor.startAsync(); } public NpcMover getNpcMover() { @@ -166,6 +170,10 @@ public class GameManager { return timeTracker; } + public SingleThreadedCreeperEventProcessor getEventProcessor() { + return eventProcessor; + } + public void placePlayerInLobby(Player player) { Room room = roomManager.getRoom(LOBBY_ID); room.addPresentPlayer(player.getPlayerId()); diff --git a/src/main/java/com/comandante/creeper/npc/Npc.java b/src/main/java/com/comandante/creeper/npc/Npc.java index c79b4912e183b01a27a12b0acc7c6285f9701b8f..76a630d4fdfb6a3a68e8146d9b93968521f50adf 100644 --- a/src/main/java/com/comandante/creeper/npc/Npc.java +++ b/src/main/java/com/comandante/creeper/npc/Npc.java @@ -244,8 +244,8 @@ public class Npc extends CreeperEntity { long xpEarned = (long) (experienceManager.calculateNpcXp(playerLevel, npcLevel) * playerDamagePercentValue); p.addExperience(xpEarned); - p.addNpcKillLog(getName()); gameManager.getChannelUtils().write(p.getPlayerId(), getBattleReport(xpEarned) + "\r\n", true); + p.addNpcKillLog(getName()); } } diff --git a/src/main/java/com/comandante/creeper/player/Player.java b/src/main/java/com/comandante/creeper/player/Player.java index 5a0172536892e379bd8aabc6a993c6bdfb0b7545..24a16bac2ea685c6cc9d6473f92ed1edc6c6f6a5 100755 --- a/src/main/java/com/comandante/creeper/player/Player.java +++ b/src/main/java/com/comandante/creeper/player/Player.java @@ -362,11 +362,13 @@ public class Player extends CreeperEntity { } public void addNpcKillLog(String npcName) { - synchronized (interner.intern(playerId)) { - PlayerMetadata playerMetadata = getPlayerMetadata(); - playerMetadata.addNpcKill(npcName); - savePlayerMetadata(playerMetadata); - } + gameManager.getEventProcessor().addEvent(() -> { + synchronized (interner.intern(playerId)) { + PlayerMetadata playerMetadata = getPlayerMetadata(); + playerMetadata.addNpcKill(npcName); + savePlayerMetadata(playerMetadata); + } + }); } public void transferItemFromLocker(String entityId) { diff --git a/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java b/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java index 07b9908938cdf80bcfd60ddb8310eb7030e63785..b479ec54ef7b5ef6a8170169f99f658b03c3ccb7 100755 --- a/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java +++ b/src/main/java/com/comandante/creeper/spawner/NpcSpawner.java @@ -9,13 +9,12 @@ import com.comandante.creeper.npc.Npc; import com.comandante.creeper.npc.NpcBuilder; import com.comandante.creeper.world.Area; import com.comandante.creeper.world.Room; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterators; -import com.google.common.collect.Lists; -import java.util.ArrayList; +import java.util.List; import java.util.Random; import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; public class NpcSpawner extends CreeperEntity { @@ -69,7 +68,7 @@ public class NpcSpawner extends CreeperEntity { } private void createAndAddItem(Area spawnArea) { - ArrayList<Room> rooms = Lists.newArrayList(Iterators.filter(gameManager.getRoomManager().getRoomsByArea(spawnArea).iterator(), getRoomsWithRoom())); + List<Room> rooms = gameManager.getRoomManager().getRoomsByArea(spawnArea).stream().filter(getRoomsWithRoom()).collect(Collectors.toList()); Room room = rooms.get(random.nextInt(rooms.size())); NpcBuilder npcBuilder = new NpcBuilder(npc); Npc newNpc = npcBuilder.createNpc(); @@ -80,23 +79,30 @@ public class NpcSpawner extends CreeperEntity { Main.metrics.counter(MetricRegistry.name(NpcSpawner.class, npc.getName() + "-spawn")).inc(); } + private Predicate<Room> getRoomsWithRoomNew() { + return room -> { + int count = room.getNpcIds().stream().filter(npcId -> { + Npc npcEntity = gameManager.getEntityManager().getNpcEntity(npcId); + return npcEntity.getName().equals(npc.getName()); + }).collect(Collectors.toList()).size(); + return count < spawnRule.getMaxPerRoom(); + }; + } + private Predicate<Room> getRoomsWithRoom() { - return new Predicate<Room>() { - @Override - public boolean apply(Room room) { - int count = 0; - Set<String> npcIds = room.getNpcIds(); - for (String npcId : npcIds) { - Npc npcEntity = gameManager.getEntityManager().getNpcEntity(npcId); - if (npcEntity.getName().equals(npc.getName())) { - count++; - } - } - if (count < spawnRule.getMaxPerRoom()) { - return true; + return room -> { + int count = 0; + Set<String> npcIds = room.getNpcIds(); + for (String npcId : npcIds) { + Npc npcEntity = gameManager.getEntityManager().getNpcEntity(npcId); + if (npcEntity.getName().equals(npc.getName())) { + count++; } - return false; } + if (count < spawnRule.getMaxPerRoom()) { + return true; + } + return false; }; } } \ No newline at end of file