Public Repository for the Magicbane Shadowbane Emulator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
12 KiB

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// 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<PvpRecord> 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<Integer> getCharacterPvPHistory(int charUUID, PvpHistoryType historyType) {
// Member variable declaration
LinkedList<Integer> 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);
}
}