// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.db.archive; import engine.gameManager.DbManager; import engine.gameManager.ZoneManager; import engine.math.Vector3fImmutable; import engine.objects.Guild; import engine.objects.PlayerCharacter; import engine.objects.Zone; import engine.workthreads.WarehousePushThread; import org.pmw.tinylog.Logger; import java.sql.*; import java.time.LocalDateTime; import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQueue; import static engine.Enum.DataRecordType; import static engine.Enum.PvpHistoryType; public class PvpRecord extends DataRecord { private static final LinkedBlockingQueue recordPool = new LinkedBlockingQueue<>(); private PlayerCharacter player; private PlayerCharacter victim; private Vector3fImmutable location; private boolean pvpExp; private PvpRecord(PlayerCharacter player, PlayerCharacter victim, Vector3fImmutable location, boolean pvpExp) { this.recordType = DataRecordType.PVP; this.player = player; this.victim = victim; this.location = new Vector3fImmutable(location); this.pvpExp = pvpExp; } public static PvpRecord borrow(PlayerCharacter player, PlayerCharacter victim, Vector3fImmutable location, boolean pvpExp) { PvpRecord pvpRecord; pvpRecord = recordPool.poll(); if (pvpRecord == null) { pvpRecord = new PvpRecord(player, victim, location, pvpExp); } else { pvpRecord.recordType = DataRecordType.PVP; pvpRecord.player = player; pvpRecord.victim = victim; pvpRecord.location = new Vector3fImmutable(location); pvpRecord.pvpExp = pvpExp; } return pvpRecord; } private static PreparedStatement buildHistoryStatement(Connection connection, int charUUID, PvpHistoryType historyType) throws SQLException { PreparedStatement outStatement = null; String queryString = ""; switch (historyType) { case KILLS: queryString = "SELECT DISTINCT `victim_id`, `datetime` FROM warehouse_pvphistory where char_id = ? " + "ORDER BY `datetime` DESC LIMIT 10"; break; case DEATHS: queryString = "SELECT DISTINCT `char_id`,`datetime` FROM warehouse_pvphistory where `victim_id` = ? " + "ORDER BY `datetime` DESC LIMIT 10"; break; } outStatement = connection.prepareStatement(queryString); outStatement.setString(1, DataWarehouse.hasher.encrypt(charUUID)); return outStatement; } public static LinkedList getCharacterPvPHistory(int charUUID, PvpHistoryType historyType) { // Member variable declaration LinkedList outList = new LinkedList<>(); try (Connection connection = DbManager.getConnection(); PreparedStatement statement = buildHistoryStatement(connection, charUUID, historyType); ResultSet rs = statement.executeQuery()) { while (rs.next()) { switch (historyType) { case KILLS: outList.add((int) DataWarehouse.hasher.decrypt(rs.getString("victim_id"))[0]); break; case DEATHS: outList.add((int) DataWarehouse.hasher.decrypt(rs.getString("char_id"))[0]); break; } } } catch (SQLException e) { e.printStackTrace(); } return outList; } private static PreparedStatement buildLuaHistoryQueryStatement(Connection connection, int charUUID) throws SQLException { PreparedStatement outStatement = null; String queryString = "CALL `pvpHistory`(?)"; outStatement = connection.prepareStatement(queryString); outStatement.setString(1, DataWarehouse.hasher.encrypt(charUUID)); return outStatement; } public static String getPvpHistoryString(int charUUID) { String outString; String dividerString; String newLine = System.getProperty("line.separator"); outString = "[LUA_PVP() DATA WAREHOUSE]" + newLine; dividerString = "--------------------------------" + newLine; try (Connection connection = DbManager.getConnection(); PreparedStatement statement = buildLuaHistoryQueryStatement(connection, charUUID); ResultSet rs = statement.executeQuery()) { while (rs.next()) { int killCount; int deathCount; float killRatio; outString += "Total Magicbane murdered souls: " + rs.getInt("TOTALDEATHS") + newLine; outString += dividerString; outString += String.format("%-8s %-8s %-8s %-8s %n", "Period", "Kills", "Deaths", "K/D"); outString += dividerString; killCount = rs.getInt("KILLCOUNT"); deathCount = rs.getInt("DEATHCOUNT"); if (deathCount == 0) killRatio = (float) killCount; else killRatio = (float) killCount / deathCount; try { outString += String.format("%-8s %-8d %-8d %.2f %n", "Total", killCount, deathCount, killRatio); killCount = rs.getInt("DAILYKILLS"); deathCount = rs.getInt("DAILYDEATHS"); if (deathCount == 0) killRatio = (float) killCount; else killRatio = (float) killCount / deathCount; outString += String.format("%-8s %-8d %-8d %.2f %n", "24hrs", killCount, deathCount, killRatio); killCount = rs.getInt("HOURLYKILLS"); deathCount = rs.getInt("HOURLYDEATHS"); if (deathCount == 0) killRatio = (float) killCount; else killRatio = (float) killCount / deathCount; outString += String.format("%-8s %-8d %-8d %.2f %n", "1hr", killCount, deathCount, killRatio); } catch (Exception e) { Logger.error(e.toString()); } } } catch (SQLException e) { e.printStackTrace(); } return outString; } public static PreparedStatement buildPvpPushStatement(Connection connection, ResultSet rs) throws SQLException { PreparedStatement outStatement = null; String queryString = "INSERT INTO `warehouse_pvphistory` (`event_number`, `char_id`, `char_guild_id`, `char_nation_id`, `char_level`," + " `victim_id`, `victim_guild_id`, `victim_nation_id`, `victim_level`," + " `zone_id`, `zone_name`, `loc_x`, `loc_y`, `gave_exp`, `datetime`) " + " VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; outStatement = connection.prepareStatement(queryString); // Bind record data outStatement.setInt(1, rs.getInt("event_number")); outStatement.setString(2, rs.getString("char_id")); outStatement.setString(3, rs.getString("char_guild_id")); outStatement.setString(4, rs.getString("char_nation_id")); outStatement.setInt(5, rs.getInt("char_level")); // Bind victim data outStatement.setString(6, rs.getString("victim_id")); outStatement.setString(7, rs.getString("victim_guild_id")); outStatement.setString(8, rs.getString("victim_nation_id")); outStatement.setInt(9, rs.getInt("victim_level")); outStatement.setString(10, rs.getString("zone_id")); outStatement.setString(11, rs.getString("zone_name")); outStatement.setFloat(12, rs.getFloat("loc_x")); outStatement.setFloat(13, rs.getFloat("loc_y")); outStatement.setBoolean(14, rs.getBoolean("gave_exp")); outStatement.setTimestamp(15, rs.getTimestamp("datetime")); return outStatement; } public static PreparedStatement buildPvpQueryStatement(Connection connection) throws SQLException { PreparedStatement outStatement = null; String queryString = "SELECT * FROM `warehouse_pvphistory` WHERE `event_number` > ?"; outStatement = connection.prepareStatement(queryString); outStatement.setInt(1, WarehousePushThread.pvpIndex); return outStatement; } void reset() { this.player = null; this.victim = null; this.location = Vector3fImmutable.ZERO; pvpExp = false; } public void release() { this.reset(); recordPool.add(this); } private PreparedStatement buildPvPInsertStatement(Connection connection) throws SQLException { Guild charGuild; Guild victimGuild; Zone zone; PreparedStatement outStatement = null; String queryString = "INSERT INTO `warehouse_pvphistory` (`char_id`, `char_guild_id`, `char_nation_id`, `char_level`," + " `victim_id`, `victim_guild_id`, `victim_nation_id`, `victim_level`," + " `zone_id`, `zone_name`, `loc_x`, `loc_y`, `gave_exp`, `datetime`) " + " VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; outStatement = connection.prepareStatement(queryString); charGuild = this.player.getGuild(); victimGuild = this.victim.getGuild(); // Use a proxy in the situation where a char guild is null (errant) // Retrieve the zone name where the PvP event occurred zone = ZoneManager.findSmallestZone(this.location); outStatement.setString(1, DataWarehouse.hasher.encrypt(this.player.getObjectUUID())); outStatement.setString(2, DataWarehouse.hasher.encrypt(charGuild.getObjectUUID())); outStatement.setString(3, DataWarehouse.hasher.encrypt(charGuild.getNation().getObjectUUID())); outStatement.setInt(4, this.player.getLevel()); // Bind victim data outStatement.setString(5, DataWarehouse.hasher.encrypt(this.victim.getObjectUUID())); outStatement.setString(6, DataWarehouse.hasher.encrypt(victimGuild.getObjectUUID())); outStatement.setString(7, DataWarehouse.hasher.encrypt(victimGuild.getNation().getObjectUUID())); outStatement.setInt(8, this.victim.getLevel()); outStatement.setString(9, DataWarehouse.hasher.encrypt(zone.getObjectUUID())); outStatement.setString(10, zone.zoneName); outStatement.setFloat(11, this.location.getX()); outStatement.setFloat(12, -this.location.getZ()); // flip sign on 'y' coordinate outStatement.setBoolean(13, this.pvpExp); outStatement.setTimestamp(14, Timestamp.valueOf(LocalDateTime.now())); return outStatement; } public void write() { try (Connection connection = DbManager.getConnection(); PreparedStatement statement = buildPvPInsertStatement(connection)) { statement.execute(); } catch (SQLException e) { Logger.error(e.toString()); } // Warehouse record for this pvp event written if code path reaches here. // Time to update the respective kill counters. CharacterRecord.advanceKillCounter(this.player); CharacterRecord.advanceDeathCounter(this.victim); } }