diff --git a/src/main/java/com/comandante/creeper/Main.java b/src/main/java/com/comandante/creeper/Main.java index 87a6b65e0f0c1bf4c9afb81199354c2b070eca75..71c4306a599f2253c24efc87e7ddfe68bdc9e045 100644 --- a/src/main/java/com/comandante/creeper/Main.java +++ b/src/main/java/com/comandante/creeper/Main.java @@ -4,6 +4,8 @@ import com.comandante.creeper.managers.GameManager; import com.comandante.creeper.managers.PlayerManager; import com.comandante.creeper.managers.PlayerManagerMapDB; import com.comandante.creeper.managers.RoomManager; +import com.comandante.creeper.model.Npc; +import com.comandante.creeper.model.NpcType; import com.comandante.creeper.model.Player; import com.comandante.creeper.model.PlayerMetadata; import com.comandante.creeper.model.Room; @@ -51,6 +53,9 @@ public class Main { GameManager gameManager = new GameManager(roomManager, playerManager); + Npc derper1 = new Npc(NpcType.DERPER); + gameManager.getNpcManager().saveNpc(derper1); + roomManager.getRoom(1).addPresentNpc(derper1.getNpcId()); CreeperServer creeperServer = new CreeperServer(8080, db); creeperServer.run(gameManager); diff --git a/src/main/java/com/comandante/creeper/command/DefaultCommandType.java b/src/main/java/com/comandante/creeper/command/DefaultCommandType.java index 6ed5aa439106548730fe334426e4e42f30825063..cbca6622e228005f4d92f9f0e605083dde3201b4 100644 --- a/src/main/java/com/comandante/creeper/command/DefaultCommandType.java +++ b/src/main/java/com/comandante/creeper/command/DefaultCommandType.java @@ -6,10 +6,10 @@ import java.util.HashSet; import java.util.Set; public enum DefaultCommandType implements CommandType { - MOVE_NORTH(new HashSet<String>(Arrays.asList("n", "North")), false, "Move north."), - MOVE_SOUTH(new HashSet<String>(Arrays.asList("s", "South")), false, "Move south."), - MOVE_EAST(new HashSet<String>(Arrays.asList("e", "East")), false, "Move east."), - MOVE_WEST(new HashSet<String>(Arrays.asList("w", "West")), false, "Move west."), + MOVE_NORTH(new HashSet<String>(Arrays.asList("n", "north")), false, "Move north."), + MOVE_SOUTH(new HashSet<String>(Arrays.asList("s", "south")), false, "Move south."), + MOVE_EAST(new HashSet<String>(Arrays.asList("e", "east")), false, "Move east."), + MOVE_WEST(new HashSet<String>(Arrays.asList("w", "west")), false, "Move west."), SAY(new HashSet<String>(Arrays.asList("say")), false, "Say something to the current room."), TELL(new HashSet<String>(Arrays.asList("tell", "t")), false, "Tell something to a player in private."), GOSSIP(new HashSet<String>(Arrays.asList("gossip")), false, "Gossip to the entire server."), diff --git a/src/main/java/com/comandante/creeper/managers/GameManager.java b/src/main/java/com/comandante/creeper/managers/GameManager.java index 54fa0a2fd8ef7b8f3afac16f7014ee83f19f1898..21d7343a1e1ac327ce3929cec1d7d18a62fb8b3a 100644 --- a/src/main/java/com/comandante/creeper/managers/GameManager.java +++ b/src/main/java/com/comandante/creeper/managers/GameManager.java @@ -3,16 +3,16 @@ package com.comandante.creeper.managers; import com.comandante.creeper.command.DefaultCommandType; import com.comandante.creeper.model.Movement; +import com.comandante.creeper.model.Npc; +import com.comandante.creeper.model.NpcType; import com.comandante.creeper.model.Player; import com.comandante.creeper.model.Room; import com.comandante.creeper.server.CreeperSession; import com.google.common.base.Optional; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Interners; -import com.google.common.collect.Sets; import org.apache.commons.lang3.StringUtils; import org.fusesource.jansi.Ansi; -import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.MessageEvent; import java.util.ArrayList; @@ -37,6 +37,7 @@ public class GameManager { private final PlayerManager playerManager; private final HelpManager helpManager; private final NewUserRegistrationManager newUserRegistrationManager; + private final NPCManager npcManager; public NewUserRegistrationManager getNewUserRegistrationManager() { return newUserRegistrationManager; @@ -47,6 +48,11 @@ public class GameManager { this.playerManager = playerManager; this.newUserRegistrationManager = new NewUserRegistrationManager(playerManager); this.helpManager = new HelpManager(); + this.npcManager = new NPCManager(roomManager, playerManager); + } + + public NPCManager getNpcManager() { + return npcManager; } public HelpManager getHelpManager() { @@ -77,14 +83,7 @@ public class GameManager { return Optional.absent(); } - public Set<Player> getPresentPlayers(Room room) { - Set<String> presentPlayerIds = room.getPresentPlayerIds(); - Set<Player> players = Sets.newHashSet(); - for (String playerId: presentPlayerIds) { - players.add(playerManager.getPlayer(playerId)); - } - return ImmutableSet.copyOf(players); - } + public void who(Player player) { Set<Player> allPlayers = getAllPlayers(); @@ -142,7 +141,7 @@ public class GameManager { while (rooms.hasNext()) { Map.Entry<Integer, Room> next = rooms.next(); Room room = next.getValue(); - Set<Player> presentPlayers = getPresentPlayers(room); + Set<Player> presentPlayers = playerManager.getPresentPlayers(room); for (Player player : presentPlayers) { builder.add(player); } @@ -162,7 +161,7 @@ public class GameManager { Room sourceRoom = roomManager.getRoom(movement.getSourceRoomId()); Room destinationRoom = roomManager.getRoom(movement.getDestinationRoomId()); sourceRoom.removePresentPlayer(movement.getPlayer().getPlayerId()); - for (Player next : getPresentPlayers(sourceRoom)) { + for (Player next : playerManager.getPresentPlayers(sourceRoom)) { StringBuilder sb = new StringBuilder(); sb.append(movement.getPlayer().getPlayerName()); if (movement.getOriginalMovementCommand().equals(DefaultCommandType.MOVE_NORTH)) { @@ -179,7 +178,7 @@ public class GameManager { sb.append("\r\n"); next.getChannel().write(sb.toString()); } - for (Player next : getPresentPlayers(destinationRoom)) { + for (Player next : playerManager.getPresentPlayers(destinationRoom)) { next.getChannel().write(movement.getPlayer().getPlayerName() + " arrived.\r\n"); } destinationRoom.addPresentPlayer(movement.getPlayer().getPlayerId()); @@ -189,7 +188,7 @@ public class GameManager { public void placePlayerInLobby(Player player) { Room room = roomManager.getRoom(LOBBY_ID); room.addPresentPlayer(player.getPlayerId()); - for (Player next : getPresentPlayers(room)) { + for (Player next : playerManager.getPresentPlayers(room)) { if (next.getPlayerId().equals(player.getPlayerId())) { continue; } @@ -204,7 +203,7 @@ public class GameManager { } Room playerCurrentRoom = playerCurrentRoomOpt.get(); - Set<Player> presentPlayers = getPresentPlayers(playerCurrentRoom); + Set<Player> presentPlayers = playerManager.getPresentPlayers(playerCurrentRoom); for (Player presentPlayer : presentPlayers) { StringBuilder stringBuilder = new StringBuilder(); @@ -235,7 +234,7 @@ public class GameManager { } } - private void printExits(Room room, Channel channel) { + private String getExits(Room room) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("exits: "); stringBuilder.append(new Ansi().fg(Ansi.Color.BLUE).toString()); @@ -251,22 +250,29 @@ public class GameManager { if (room.getWestId().isPresent()) { stringBuilder.append("west "); } - stringBuilder.append(new Ansi().reset().toString()); - channel.write(stringBuilder.toString() + "\r\n"); + stringBuilder.append("\r\n").append(new Ansi().reset().toString()); + return stringBuilder.toString(); } public void currentRoomLogic(CreeperSession creeperSession, MessageEvent e) { final Player player = playerManager.getPlayerByUsername(creeperSession.getUsername().get()); final Room playerCurrentRoom = getPlayerCurrentRoom(player).get(); - e.getChannel().write(playerCurrentRoom.getRoomDescription() + "\r\n"); + StringBuilder sb = new StringBuilder(); + sb.append(playerCurrentRoom.getRoomDescription()).append("\r\n"); for (String searchPlayerId : playerCurrentRoom.getPresentPlayerIds()) { if (searchPlayerId.equals(player.getPlayerId())) { continue; } Player searchPlayer = playerManager.getPlayer(searchPlayerId); - e.getChannel().write(searchPlayer.getPlayerName() + " is here.\r\n"); + sb.append(searchPlayer.getPlayerName()).append(" is here.\r\n"); + } + for (String npcId : playerCurrentRoom.getNpcIds()) { + Npc npc = npcManager.getNpc(npcId); + NpcType npcType = npc.getNpcType(); + sb.append("A ").append(npcType.getNpcName()).append(" is here.\r\n"); } - printExits(playerCurrentRoom, e.getChannel()); + sb.append(getExits(playerCurrentRoom)); + player.getChannel().write(sb.toString()); } } diff --git a/src/main/java/com/comandante/creeper/managers/HelpManager.java b/src/main/java/com/comandante/creeper/managers/HelpManager.java index 2a5c4c9790d15c81640a02257cf82945d19b47c3..a513b6bb9083015ea0da5ab4837e1b8f71ae5bb7 100644 --- a/src/main/java/com/comandante/creeper/managers/HelpManager.java +++ b/src/main/java/com/comandante/creeper/managers/HelpManager.java @@ -10,7 +10,7 @@ public class HelpManager { public void printHelp(Player player, String originalMessage) { StringBuilder sb = new StringBuilder(); DefaultCommandType[] values = DefaultCommandType.values(); - sb.append(new Ansi().bg(Ansi.Color.RED).toString()); + sb.append(new Ansi().fg(Ansi.Color.RED).toString()); for (DefaultCommandType defaultCommandType : values) { if (defaultCommandType.equals(DefaultCommandType.UNKNOWN)) { continue; diff --git a/src/main/java/com/comandante/creeper/managers/NPCManager.java b/src/main/java/com/comandante/creeper/managers/NPCManager.java new file mode 100644 index 0000000000000000000000000000000000000000..fe978792f244aaabd2abfb254cc1f4ca5f707d62 --- /dev/null +++ b/src/main/java/com/comandante/creeper/managers/NPCManager.java @@ -0,0 +1,82 @@ +package com.comandante.creeper.managers; + +import com.comandante.creeper.model.Npc; +import com.comandante.creeper.model.NpcType; +import com.comandante.creeper.model.Player; +import com.comandante.creeper.model.Room; +import com.google.common.base.Optional; + +import java.util.Iterator; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class NPCManager { + + private final ConcurrentHashMap<String, Npc> npcs = new ConcurrentHashMap<>(); + private final RoomManager roomManager; + private final PlayerManager playerManager; + private final ExecutorService phraserService; + + public NPCManager(RoomManager roomManager, PlayerManager playerManager) { + this.roomManager = roomManager; + this.playerManager = playerManager; + this.phraserService = Executors.newSingleThreadExecutor(); + phraserService.submit(new Phraser()); + } + + public void saveNpc(Npc npc) { + npcs.put(npc.getNpcId(), npc); + } + + public Npc getNpc(String npcId) { + return npcs.get(npcId); + } + + public Optional<Room> getNpcCurrentRoom(String npcId) { + Iterator<Map.Entry<Integer, Room>> rooms = roomManager.getRooms(); + while (rooms.hasNext()) { + Map.Entry<Integer, Room> next = rooms.next(); + Room room = next.getValue(); + if (room.getNpcIds().contains(npcId)) { + return Optional.of(room); + } + } + return Optional.absent(); + } + + class Phraser implements Runnable { + private Random randomGenerator = new Random(); + @Override + public void run() { + while (true) { + try { + Thread.sleep(5000); + for (Map.Entry<String, Npc> next : npcs.entrySet()) { + Npc npc = next.getValue(); + NpcType npcType = npc.getNpcType(); + long phraseTimestamp = npc.getPhraseTimestamp(); + long phraseInterval = npcType.getPhrasesIntervalMs(); + long now = System.currentTimeMillis(); + if (now - phraseTimestamp > phraseInterval) { + String phrase = npcType.getPhrases().get(randomGenerator.nextInt(npcType.getPhrases().size())); + Optional<Room> roomOpt = getNpcCurrentRoom(npc.getNpcId()); + if (roomOpt.isPresent()) { + Set<Player> presentPlayers = playerManager.getPresentPlayers(roomOpt.get()); + for (Player player : presentPlayers) { + player.getChannel().write(npcType.getNpcName() + ": " + phrase + "\r\n"); + npc.setPhraseTimestamp(System.currentTimeMillis()); + } + } + } + } + } catch (Exception e) { + System.out.println(e); + } + } + } + } +} diff --git a/src/main/java/com/comandante/creeper/managers/PlayerManager.java b/src/main/java/com/comandante/creeper/managers/PlayerManager.java index c147bce5adcc49447831b348e778bb28ca79aeb9..7c01d8900fdd75bda2cdbbca74836aa129600b73 100644 --- a/src/main/java/com/comandante/creeper/managers/PlayerManager.java +++ b/src/main/java/com/comandante/creeper/managers/PlayerManager.java @@ -2,11 +2,16 @@ package com.comandante.creeper.managers; import com.comandante.creeper.model.Player; import com.comandante.creeper.model.PlayerMetadata; +import com.comandante.creeper.model.Room; import java.util.Iterator; import java.util.Map; +import java.util.Set; public interface PlayerManager { + + public Set<Player> getPresentPlayers(Room room); + PlayerMetadata getPlayerMetadata(String playerId); void savePlayerMetadata(PlayerMetadata playerMetadata); diff --git a/src/main/java/com/comandante/creeper/managers/PlayerManagerMapDB.java b/src/main/java/com/comandante/creeper/managers/PlayerManagerMapDB.java index 2dc61e42570259dd37f113bc1e1f71adade56292..df4adb47eed7e0cde6b0e0eef6b84783d6638077 100644 --- a/src/main/java/com/comandante/creeper/managers/PlayerManagerMapDB.java +++ b/src/main/java/com/comandante/creeper/managers/PlayerManagerMapDB.java @@ -4,11 +4,15 @@ package com.comandante.creeper.managers; import com.comandante.creeper.model.PlayerMetadataSerializer; import com.comandante.creeper.model.Player; import com.comandante.creeper.model.PlayerMetadata; +import com.comandante.creeper.model.Room; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; import org.apache.commons.codec.binary.Base64; import org.mapdb.DB; import org.mapdb.HTreeMap; import java.util.Iterator; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; public class PlayerManagerMapDB implements PlayerManager { @@ -26,6 +30,16 @@ public class PlayerManagerMapDB implements PlayerManager { } } + @Override + public Set<Player> getPresentPlayers(Room room) { + Set<String> presentPlayerIds = room.getPresentPlayerIds(); + Set<Player> players = Sets.newHashSet(); + for (String playerId: presentPlayerIds) { + players.add(getPlayer(playerId)); + } + return ImmutableSet.copyOf(players); + } + @Override public PlayerMetadata getPlayerMetadata(String playerId) { return playerMetadataStore.get(playerId); diff --git a/src/main/java/com/comandante/creeper/model/Npc.java b/src/main/java/com/comandante/creeper/model/Npc.java new file mode 100644 index 0000000000000000000000000000000000000000..00bebb6a60626e8c2a4a28e2528da06b1450d9ab --- /dev/null +++ b/src/main/java/com/comandante/creeper/model/Npc.java @@ -0,0 +1,33 @@ +package com.comandante.creeper.model; + + +import java.util.UUID; + +public class Npc { + + private final String npcId; + private final NpcType npcType; + private long phraseTimestamp; + + public Npc(NpcType npcType) { + npcId = UUID.randomUUID().toString(); + this.npcType = npcType; + this.phraseTimestamp = 0; + } + + public String getNpcId() { + return npcId; + } + + public NpcType getNpcType() { + return npcType; + } + + public long getPhraseTimestamp() { + return phraseTimestamp; + } + + public void setPhraseTimestamp(long phraseTimestamp) { + this.phraseTimestamp = phraseTimestamp; + } +} diff --git a/src/main/java/com/comandante/creeper/model/NpcType.java b/src/main/java/com/comandante/creeper/model/NpcType.java new file mode 100644 index 0000000000000000000000000000000000000000..d87d1239ce42dda1b38976e558b3a73ec3c8276b --- /dev/null +++ b/src/main/java/com/comandante/creeper/model/NpcType.java @@ -0,0 +1,36 @@ +package com.comandante.creeper.model; + +import org.fusesource.jansi.Ansi; + +import java.util.Arrays; +import java.util.List; + + +public enum NpcType { + + DERPER(Arrays.asList( + "Zug zug.", + "Don't provoke me."), 300000, new StringBuilder().append(new Ansi().fg(Ansi.Color.RED).toString()).append("derper").append(new Ansi().reset().toString()).toString()); + + private final List<String> phrases; + private final long phrasesIntervalMs; + private final String npcName; + + NpcType(List<String> phrases, long phrasesIntervalMs, String npcName) { + this.phrases = phrases; + this.phrasesIntervalMs = phrasesIntervalMs; + this.npcName = npcName; + } + + public List<String> getPhrases() { + return phrases; + } + + public long getPhrasesIntervalMs() { + return phrasesIntervalMs; + } + + public String getNpcName() { + return npcName; + } +} diff --git a/src/main/java/com/comandante/creeper/model/Room.java b/src/main/java/com/comandante/creeper/model/Room.java index 5ff0cc33f5fe829586d0ddc123f0c3dbc9a5fb26..04fa6c55694f9150d5589263bf9947a3e1bc60fa 100644 --- a/src/main/java/com/comandante/creeper/model/Room.java +++ b/src/main/java/com/comandante/creeper/model/Room.java @@ -16,6 +16,7 @@ public class Room { public String roomDescription; private Set<String> presentPlayerIds = Sets.<String>newConcurrentHashSet(); private Set<String> afkPlayerIds = Sets.<String>newConcurrentHashSet(); + private Set<String> npcIds = Sets.newConcurrentHashSet(); public Room(Integer roomId, Optional<Integer> northId, Optional<Integer> westId, Optional<Integer> eastId, Optional<Integer> southId, String roomDescription) { this.roomId = roomId; @@ -26,6 +27,18 @@ public class Room { this.roomDescription = roomDescription; } + public void addPresentNpc(String npcId) { + npcIds.add(npcId); + } + + public void removePresentNpc(String npcId) { + npcIds.remove(npcId); + } + + public Set<String> getNpcIds() { + return npcIds; + } + public java.util.Set<String> getPresentPlayerIds() { return presentPlayerIds; }