From 9f880af778055a9b3d861b07356cc9974ab27992 Mon Sep 17 00:00:00 2001 From: CeramicTitan Date: Wed, 13 Apr 2016 02:03:30 -0600 Subject: [PATCH 1/2] Added comments explaining what is happening. This is a good way to provide a reference as opposed to people having to go back to your video. --- Resources/HikariExample.java | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Resources/HikariExample.java b/Resources/HikariExample.java index 521ef95..b45bdea 100644 --- a/Resources/HikariExample.java +++ b/Resources/HikariExample.java @@ -8,21 +8,22 @@ import java.util.UUID; public class HikariExample extends JavaPlugin { - + //Create global Hikari instance private HikariDataSource hikari; - + //On server start, we connect to our database @Override public void onEnable() { connectToDatabase(); } - public void connectToDatabase() { + //Database details String address = getConfig().getString("Database.Address"); String name = getConfig().getString("Database.Name"); String username = getConfig().getString("Database.Username"); String password = getConfig().getString("Database.Password"); - + //Initialise hikari instace hikari = new HikariDataSource(); + //Setting Hikari properties hikari.setMaximumPoolSize(10); hikari.setDataSourceClassName("com.mysql.jdbc.jdbc2.optional.MysqlDataSource"); hikari.addDataSourceProperty("serverName", address); @@ -33,24 +34,30 @@ public void connectToDatabase() { } public void runAsyncQuery(UUID playerUUID) { + //Create connection instance Connection connection = null; - + //MySQL query: https://www3.ntu.edu.sg/home/ehchua/programming/sql/MySQL_Beginner.html String update = "INSERT INTO database VALUES(?, ?) ON DUPLICATE KEY UPDATE uuid=?"; PreparedStatement p = null; try { + //Initialise hikari connection, by getting the hikari connect if established connection = hikari.getConnection(); - + //Preparing statement - INSERT INTO... p = connection.prepareStatement(update); + //Setting parameters in MySQL query: i.e the question marks(?), where the first one has the index of 1. p.setString(1, playerUUID.toString()); p.setInt(2, 0); + //ON DUPLICATE UPDATE updates the current uuid, if it exists p.setString(3, playerUUID.toString()); + //Executes the statement p.execute(); } catch (SQLException e) { + //Print out any exception while trying to prepare statement e.printStackTrace(); } finally { - + //After catching the statement, close connection if connection is established if (connection != null) { try { connection.close(); @@ -59,7 +66,7 @@ public void runAsyncQuery(UUID playerUUID) { } } - // Organize + // If connection is established, close connection after query if(p != null) { try { p.close(); From a7604e0452eb4d62c196e59c4ae6c6204a25f708 Mon Sep 17 00:00:00 2001 From: sgtcaze Date: Mon, 9 May 2016 16:07:22 -0700 Subject: [PATCH 2/2] Add new Resource for tutorial --- Resources/PacketAccessor.java | 92 +++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 Resources/PacketAccessor.java diff --git a/Resources/PacketAccessor.java b/Resources/PacketAccessor.java new file mode 100644 index 0000000..73eee86 --- /dev/null +++ b/Resources/PacketAccessor.java @@ -0,0 +1,92 @@ +package example; + +import io.netty.channel.*; +import net.minecraft.server.v1_9_R1.PacketPlayOutPlayerInfo; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.java.JavaPlugin; + +public class PacketAccessor extends JavaPlugin implements Listener { + + @Override + public void onEnable() { + Bukkit.getPluginManager().registerEvents(this, this); + } + + /** + * Inject our custom ChannelDuplexHandler when the player joins the server + */ + @EventHandler + public void onJoin(PlayerJoinEvent event) { + create(event.getPlayer()); + } + + /** + * Remove our custom ChannelDuplexHandler explicitly, NOTE: If they're quitting + * the server this data is cleared anyway. + */ + @EventHandler + public void onQuit(PlayerQuitEvent event) { + remove(event.getPlayer()); + } + + /** + * Submits a request to the pipeline to remove our ChannelDuplexHandler + */ + private void remove(Player player) { + Channel channel = ((CraftPlayer) player).getHandle().playerConnection.networkManager.channel; + channel.eventLoop().submit(() -> { + channel.pipeline().remove(player.getName()); + return null; + }); + } + + /** + * Creates a custom ChannelDuplexHandler for a player, and this serves + * to intercept packets before the packet handler + */ + private void create(Player player) { + ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() { + /** + * Reads packets + */ + @Override + public void channelRead(ChannelHandlerContext context, Object packet) throws Exception { +// getLogger().info("READ>> " + packet.toString()); + super.channelRead(context, packet); + } + + /** + * Writes packets + */ + @Override + public void write(ChannelHandlerContext context, Object packet, ChannelPromise channelPromise) throws Exception { + /** + * If the packet is instance "PacketPlayOutPlayerInfo", we can cast this directly! + */ + if (packet instanceof PacketPlayOutPlayerInfo) { + /** + * We can use reflection to access certain variables as they are + * encapsulated + */ + PacketPlayOutPlayerInfo info = (PacketPlayOutPlayerInfo) packet; + getLogger().info("BLOCKED>> " + info.toString()); + return; + } + super.write(context, packet, channelPromise); + } + }; + + /** + * Take the player's networking channel and add our custom DuplexHandler + */ + ChannelPipeline pipeline = ((CraftPlayer) player).getHandle().playerConnection.networkManager.channel.pipeline(); + pipeline.addBefore("packet_handler", player.getName(), channelDuplexHandler); + } + +}