// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.db.archive; import engine.Enum; import engine.objects.Guild; import engine.objects.PlayerCharacter; import engine.workthreads.WarehousePushThread; import org.pmw.tinylog.Logger; import java.sql.*; import java.time.LocalDateTime; import java.util.concurrent.LinkedBlockingQueue; /* * This class warehouses character creation events. It also tracks * updates to summary kills/death data and their promotion class. */ public class CharacterRecord extends DataRecord { // Local object pool for class private static final LinkedBlockingQueue recordPool = new LinkedBlockingQueue<>(); private PlayerCharacter player; private CharacterRecord(PlayerCharacter player) { this.recordType = Enum.DataRecordType.CHARACTER; this.player = player; } public static CharacterRecord borrow(PlayerCharacter player) { CharacterRecord characterRecord; characterRecord = recordPool.poll(); if (characterRecord == null) { characterRecord = new CharacterRecord(player); } else { characterRecord.recordType = Enum.DataRecordType.CHARACTER; characterRecord.player = player; } return characterRecord; } private static PreparedStatement buildCharacterInsertStatement(Connection connection, PlayerCharacter player) throws SQLException { PreparedStatement outStatement = null; String queryString = "INSERT INTO `warehouse_characterhistory` (`char_id`, `char_fname`, `char_lname`, `baseClass`, `race`, `promoteClass`, `startingGuild`, `datetime`) VALUES(?,?,?,?,?,?,?,?)"; Guild charGuild; outStatement = connection.prepareStatement(queryString); charGuild = player.getGuild(); // Bind character data outStatement.setString(1, DataWarehouse.hasher.encrypt(player.getObjectUUID())); outStatement.setString(2, player.getFirstName()); outStatement.setString(3, player.getLastName()); outStatement.setInt(4, player.getBaseClassID()); outStatement.setInt(5, player.getRaceID()); outStatement.setInt(6, player.getPromotionClassID()); outStatement.setString(7, DataWarehouse.hasher.encrypt(charGuild.getObjectUUID())); outStatement.setTimestamp(8, Timestamp.valueOf(LocalDateTime.now())); return outStatement; } public static PreparedStatement buildCharacterPushStatement(Connection connection, ResultSet rs) throws SQLException { PreparedStatement outStatement = null; String queryString = "INSERT INTO `warehouse_characterhistory` (`event_number`, `char_id`, `char_fname`, `char_lname`, `baseClass`, `race`, `promoteClass`, `startingGuild`, `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_fname")); outStatement.setString(4, rs.getString("char_lname")); outStatement.setInt(5, rs.getInt("baseClass")); outStatement.setInt(6, rs.getInt("race")); outStatement.setInt(7, rs.getInt("promoteClass")); outStatement.setString(8, rs.getString("startingGuild")); outStatement.setTimestamp(9, rs.getTimestamp("datetime")); return outStatement; } public static PreparedStatement buildCharacterQueryStatement(Connection connection) throws SQLException { PreparedStatement outStatement = null; String queryString = "SELECT * FROM `warehouse_characterhistory` WHERE `event_number` > ?"; outStatement = connection.prepareStatement(queryString); outStatement.setInt(1, WarehousePushThread.charIndex); return outStatement; } public static void advanceKillCounter(PlayerCharacter player) { try (Connection connection = DataWarehouse.connectionPool.getConnection(); PreparedStatement statement = buildKillCounterStatement(connection, player)) { statement.execute(); } catch (SQLException e) { Logger.error( e.toString()); } } private static PreparedStatement buildKillCounterStatement(Connection connection, PlayerCharacter player) throws SQLException { PreparedStatement outStatement = null; String queryString = "UPDATE `warehouse_characterhistory` SET `kills` = `kills` +1, `dirty` = 1 WHERE `char_id` = ?"; if (player == null) return outStatement; outStatement = connection.prepareStatement(queryString); outStatement.setString(1, player.getHash()); return outStatement; } public static void advanceDeathCounter(PlayerCharacter player) { try (Connection connection = DataWarehouse.connectionPool.getConnection(); PreparedStatement statement = buildDeathCounterStatement(connection, player)) { statement.execute(); } catch (SQLException e) { Logger.error( e.toString()); } } private static PreparedStatement buildDeathCounterStatement(Connection connection, PlayerCharacter player) throws SQLException { PreparedStatement outStatement = null; String queryString = "UPDATE `warehouse_characterhistory` SET `deaths` = `deaths` +1, `dirty` = 1 WHERE `char_id` = ?"; if (player == null) return outStatement; outStatement = connection.prepareStatement(queryString); outStatement.setString(1, player.getHash()); return outStatement; } public static void updatePromotionClass(PlayerCharacter player) { try (Connection connection = DataWarehouse.connectionPool.getConnection(); PreparedStatement statement = buildUpdatePromotionStatement(connection, player)) { statement.execute(); } catch (SQLException e) { Logger.error( e.toString()); } } private static PreparedStatement buildUpdatePromotionStatement(Connection connection, PlayerCharacter player) throws SQLException { PreparedStatement outStatement = null; String queryString = "UPDATE `warehouse_characterhistory` SET `promoteClass` = ?, `dirty` = 1 WHERE `char_id` = ?"; if (player == null) return outStatement; outStatement = connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); outStatement.setInt(1, player.getPromotionClassID()); outStatement.setString(2, player.getHash()); return outStatement; } public static void updateDirtyRecords() { String queryString = "SELECT * FROM `warehouse_characterhistory` where `dirty` = 1"; // Reset character delta WarehousePushThread.charDelta = 0; try (Connection localConnection = DataWarehouse.connectionPool.getConnection(); PreparedStatement statement = localConnection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); // Make this an updatable result set as we'll reset the dirty flag as we go along ResultSet rs = statement.executeQuery()) { while (rs.next()) { // Only update the index and dirty flag // if the remote database update succeeded if (updateDirtyRecord(rs) == true) WarehousePushThread.charDelta++; else continue; // Reset the dirty flag in the local database rs.updateInt("dirty", 0); rs.updateRow(); } } catch (SQLException e) { Logger.error(e.toString()); } } private static boolean updateDirtyRecord(ResultSet rs) { try (Connection remoteConnection = DataWarehouse.remoteConnectionPool.getConnection(); PreparedStatement statement = buildUpdateDirtyStatement(remoteConnection, rs)) { statement.execute(); return true; } catch (SQLException e) { Logger.error(e.toString()); return false; } } private static PreparedStatement buildUpdateDirtyStatement(Connection connection, ResultSet rs) throws SQLException { PreparedStatement outStatement; String queryString = "UPDATE `warehouse_characterhistory` SET `promoteClass` = ?, `kills` = ?, `deaths` = ? WHERE `char_id` = ?"; outStatement = connection.prepareStatement(queryString); // Bind record data outStatement.setInt(1, rs.getInt("promoteClass")); outStatement.setInt(2, rs.getInt("kills")); outStatement.setInt(3, rs.getInt("deaths")); outStatement.setString(4, rs.getString("char_id")); return outStatement; } void reset() { this.player = null; } public void release() { this.reset(); recordPool.add(this); } public void write() { try (Connection connection = DataWarehouse.connectionPool.getConnection(); PreparedStatement statement = buildCharacterInsertStatement(connection, this.player)) { statement.execute(); } catch (SQLException e) { Logger.error( "Error writing character record " + e.toString()); } } }