diff --git a/src/main/java/net/minecraft/server/NetServerHandler.java b/src/main/java/net/minecraft/server/NetServerHandler.java index 3329e21972..0e242615eb 100644 --- a/src/main/java/net/minecraft/server/NetServerHandler.java +++ b/src/main/java/net/minecraft/server/NetServerHandler.java @@ -1,7 +1,9 @@ package net.minecraft.server; +import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Random; +import java.util.logging.Level; import java.util.logging.Logger; // CraftBukkit start @@ -1101,4 +1103,31 @@ public class NetServerHandler extends NetHandler implements ICommandListener { public boolean c() { return true; } + + // CraftBukkit start + @Override + public void a(Packet250CustomPayload packet) { + if (packet.tag.equals("REGISTER")) { + try { + String channels = new String(packet.data, "UTF8"); + for (String channel : channels.split("\0")) { + getPlayer().addChannel(channel); + } + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(NetServerHandler.class.getName()).log(Level.SEVERE, "Could not parse REGISTER payload in plugin message packet", ex); + } + } else if (packet.tag.equals("UNREGISTER")) { + try { + String channels = new String(packet.data, "UTF8"); + for (String channel : channels.split("\0")) { + getPlayer().removeChannel(channel); + } + } catch (UnsupportedEncodingException ex) { + Logger.getLogger(NetServerHandler.class.getName()).log(Level.SEVERE, "Could not parse UNREGISTER payload in plugin message packet", ex); + } + } else { + server.getMessenger().dispatchIncomingMessage(player.getPlayer(), packet.tag, packet.data); + } + } + // CraftBukkit end } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index d7e19e847b..4a3b9d784f 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -67,6 +67,7 @@ import org.bukkit.plugin.ServicesManager; import org.bukkit.plugin.SimplePluginManager; import org.bukkit.plugin.SimpleServicesManager; import org.bukkit.plugin.java.JavaPluginLoader; +import org.bukkit.plugin.messaging.Messenger; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe; import org.bukkit.craftbukkit.inventory.CraftRecipe; @@ -81,6 +82,7 @@ import org.bukkit.util.permissions.DefaultPermissions; import org.bukkit.event.world.WorldInitEvent; import org.bukkit.permissions.Permission; import org.bukkit.plugin.PluginLoadOrder; +import org.bukkit.plugin.messaging.StandardMessenger; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.error.MarkedYAMLException; @@ -92,6 +94,7 @@ public final class CraftServer implements Server { private final ServicesManager servicesManager = new SimpleServicesManager(); private final BukkitScheduler scheduler = new CraftScheduler(this); private final SimpleCommandMap commandMap = new SimpleCommandMap(this); + private final StandardMessenger messenger = new StandardMessenger(); private final PluginManager pluginManager = new SimplePluginManager(this, commandMap); protected final MinecraftServer console; protected final ServerConfigurationManager server; @@ -942,4 +945,26 @@ public final class CraftServer implements Server { return players.toArray(new OfflinePlayer[players.size()]); } + + public Messenger getMessenger() { + return messenger; + } + + public void sendPluginMessage(Plugin source, String channel, byte[] message) { + StandardMessenger.validatePluginMessage(getMessenger(), source, channel, message); + + for (Player player : getOnlinePlayers()) { + player.sendPluginMessage(source, channel, message); + } + } + + public Set getListeningPluginChannels() { + Set result = new HashSet(); + + for (Player player : getOnlinePlayers()) { + result.addAll(player.getListeningPluginChannels()); + } + + return result; + } } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 270149d343..e346fba1dc 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -2,11 +2,13 @@ package org.bukkit.craftbukkit; import com.google.common.collect.MapMaker; import java.io.File; +import java.util.Set; import org.bukkit.craftbukkit.entity.*; import org.bukkit.entity.*; import org.bukkit.entity.Entity; import java.util.ArrayList; +import java.util.HashSet; import java.util.concurrent.ConcurrentMap; import java.util.List; import java.util.Random; @@ -25,6 +27,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.entity.Boat; import org.bukkit.Chunk; import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; import org.bukkit.BlockChangeDelegate; import org.bukkit.Bukkit; @@ -38,6 +41,7 @@ import org.bukkit.generator.BlockPopulator; import org.bukkit.Difficulty; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.plugin.messaging.StandardMessenger; public class CraftWorld implements World { private final WorldServer world; @@ -919,4 +923,22 @@ public class CraftWorld implements World { // For example, WOODEN_STAIRS does something with WOOD in this method net.minecraft.server.Block.byId[blockId].wasExploded(this.world, blockX, blockY, blockZ); } + + public void sendPluginMessage(Plugin source, String channel, byte[] message) { + StandardMessenger.validatePluginMessage(server.getMessenger(), source, channel, message); + + for (Player player : getPlayers()) { + player.sendPluginMessage(source, channel, message); + } + } + + public Set getListeningPluginChannels() { + Set result = new HashSet(); + + for (Player player : getPlayers()) { + result.addAll(player.getListeningPluginChannels()); + } + + return result; + } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 2627123ade..e6e233f031 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -1,16 +1,18 @@ package org.bukkit.craftbukkit.entity; +import com.google.common.collect.ImmutableSet; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.util.Calendar; -import java.util.Date; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Set; import net.minecraft.server.EntityPlayer; import net.minecraft.server.NBTTagCompound; import net.minecraft.server.Packet131ItemData; import net.minecraft.server.Packet200Statistic; import net.minecraft.server.Packet201PlayerInfo; +import net.minecraft.server.Packet250CustomPayload; import net.minecraft.server.Packet3Chat; import net.minecraft.server.Packet51MapChunk; import net.minecraft.server.Packet53BlockChange; @@ -39,12 +41,15 @@ import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.map.MapView; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.messaging.StandardMessenger; @DelegateDeserialization(CraftOfflinePlayer.class) public class CraftPlayer extends CraftHumanEntity implements Player { private long firstPlayed = 0; private long lastPlayed = 0; private boolean hasPlayedBefore = false; + private Set channels = new HashSet(); public CraftPlayer(CraftServer server, EntityPlayer entity) { super(server, entity); @@ -616,4 +621,28 @@ public class CraftPlayer extends CraftHumanEntity implements Player { data.setLong("firstPlayed", getFirstPlayed()); data.setLong("lastPlayed", System.currentTimeMillis()); } + + public void sendPluginMessage(Plugin source, String channel, byte[] message) { + StandardMessenger.validatePluginMessage(server.getMessenger(), source, channel, message); + + if (channels.contains(channel)) { + Packet250CustomPayload packet = new Packet250CustomPayload(); + packet.tag = channel; + packet.length = message.length; + packet.data = message; + getHandle().netServerHandler.sendPacket(packet); + } + } + + public void addChannel(String channel) { + channels.add(channel); + } + + public void removeChannel(String channel) { + channels.remove(channel); + } + + public Set getListeningPluginChannels() { + return ImmutableSet.copyOf(channels); + } }