2013-04-18 23:37:36 +02:00
package com.gmail.nossr50.database ;
import java.sql.Connection ;
import java.sql.DriverManager ;
import java.sql.PreparedStatement ;
import java.sql.ResultSet ;
import java.sql.SQLException ;
2013-06-29 00:02:58 +02:00
import java.sql.Statement ;
2013-04-18 23:37:36 +02:00
import java.util.ArrayList ;
import java.util.Collection ;
import java.util.HashMap ;
2013-06-04 18:14:43 +02:00
import java.util.List ;
2013-04-18 23:37:36 +02:00
import java.util.Map ;
import java.util.Properties ;
import com.gmail.nossr50.mcMMO ;
import com.gmail.nossr50.config.Config ;
2013-06-04 18:14:43 +02:00
import com.gmail.nossr50.datatypes.MobHealthbarType ;
2013-08-22 15:11:33 +02:00
import com.gmail.nossr50.datatypes.database.DatabaseType ;
2013-04-18 23:37:36 +02:00
import com.gmail.nossr50.datatypes.database.DatabaseUpdateType ;
2013-06-04 18:14:43 +02:00
import com.gmail.nossr50.datatypes.database.PlayerStat ;
import com.gmail.nossr50.datatypes.player.PlayerProfile ;
import com.gmail.nossr50.datatypes.skills.AbilityType ;
2013-04-18 23:37:36 +02:00
import com.gmail.nossr50.datatypes.skills.SkillType ;
2013-10-05 23:55:34 +02:00
import com.gmail.nossr50.runnables.database.SQLDatabaseKeepaliveTask ;
2013-10-06 10:25:28 +02:00
import com.gmail.nossr50.runnables.database.SQLReconnectTask ;
2013-04-18 23:37:36 +02:00
import com.gmail.nossr50.util.Misc ;
2013-06-04 18:14:43 +02:00
public final class SQLDatabaseManager implements DatabaseManager {
private String connectionString ;
private String tablePrefix = Config . getInstance ( ) . getMySQLTablePrefix ( ) ;
private Connection connection = null ;
2013-04-18 23:37:36 +02:00
// Scale waiting time by this much per failed attempt
2013-06-04 18:14:43 +02:00
private final double SCALING_FACTOR = 40 . 0 ;
2013-04-18 23:37:36 +02:00
// Minimum wait in nanoseconds (default 500ms)
2013-06-04 18:14:43 +02:00
private final long MIN_WAIT = 500L * 1000000L ;
2013-04-18 23:37:36 +02:00
// Maximum time to wait between reconnects (default 5 minutes)
2013-06-04 18:14:43 +02:00
private final long MAX_WAIT = 5L * 60L * 1000L * 1000000L ;
2013-04-18 23:37:36 +02:00
// How long to wait when checking if connection is valid (default 3 seconds)
2013-06-04 18:14:43 +02:00
private final int VALID_TIMEOUT = 3 ;
2013-04-18 23:37:36 +02:00
// When next to try connecting to Database in nanoseconds
2013-06-04 18:14:43 +02:00
private long nextReconnectTimestamp = 0L ;
2013-04-18 23:37:36 +02:00
// How many connection attempts have failed
2013-06-04 18:14:43 +02:00
private int reconnectAttempt = 0 ;
2013-04-18 23:37:36 +02:00
2013-06-07 00:01:43 +02:00
protected SQLDatabaseManager ( ) {
2013-07-01 07:37:24 +02:00
checkStructure ( ) ;
2013-10-05 23:55:34 +02:00
new SQLDatabaseKeepaliveTask ( this ) . runTaskTimerAsynchronously ( mcMMO . p , 10 , 60L * 60 * Misc . TICK_CONVERSION_FACTOR ) ;
2013-06-04 18:14:43 +02:00
}
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
public void purgePowerlessUsers ( ) {
2013-08-28 17:44:58 +02:00
if ( ! checkConnected ( ) ) {
return ;
}
2013-06-04 18:14:43 +02:00
mcMMO . p . getLogger ( ) . info ( " Purging powerless users... " ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
Collection < ArrayList < String > > usernames = read ( " SELECT u.user FROM " + tablePrefix + " skills AS s, " + tablePrefix + " users AS u WHERE s.user_id = u.id AND (s.taming+s.mining+s.woodcutting+s.repair+s.unarmed+s.herbalism+s.excavation+s.archery+s.swords+s.axes+s.acrobatics+s.fishing) = 0 " ) . values ( ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
write ( " DELETE FROM u, e, h, s, c USING " + tablePrefix + " users u " +
" JOIN " + tablePrefix + " experience e ON (u.id = e.user_id) " +
" JOIN " + tablePrefix + " huds h ON (u.id = h.user_id) " +
" JOIN " + tablePrefix + " skills s ON (u.id = s.user_id) " +
" JOIN " + tablePrefix + " cooldowns c ON (u.id = c.user_id) " +
" WHERE (s.taming+s.mining+s.woodcutting+s.repair+s.unarmed+s.herbalism+s.excavation+s.archery+s.swords+s.axes+s.acrobatics+s.fishing) = 0 " ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
processPurge ( usernames ) ;
mcMMO . p . getLogger ( ) . info ( " Purged " + usernames . size ( ) + " users from the database. " ) ;
}
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
public void purgeOldUsers ( ) {
2013-08-28 17:44:58 +02:00
if ( ! checkConnected ( ) ) {
return ;
}
2013-06-04 18:14:43 +02:00
long currentTime = System . currentTimeMillis ( ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
mcMMO . p . getLogger ( ) . info ( " Purging old users... " ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
Collection < ArrayList < String > > usernames = read ( " SELECT user FROM " + tablePrefix + " users WHERE (( " + currentTime + " - lastlogin * " + Misc . TIME_CONVERSION_FACTOR + " ) > " + PURGE_TIME + " ) " ) . values ( ) ;
write ( " DELETE FROM u, e, h, s, c USING " + tablePrefix + " users u " +
" JOIN " + tablePrefix + " experience e ON (u.id = e.user_id) " +
" JOIN " + tablePrefix + " huds h ON (u.id = h.user_id) " +
" JOIN " + tablePrefix + " skills s ON (u.id = s.user_id) " +
" JOIN " + tablePrefix + " cooldowns c ON (u.id = c.user_id) " +
" WHERE (( " + currentTime + " - lastlogin * " + Misc . TIME_CONVERSION_FACTOR + " ) > " + PURGE_TIME + " ) " ) ;
processPurge ( usernames ) ;
2013-10-06 10:25:28 +02:00
mcMMO . p . getLogger ( ) . info ( " Purged " + usernames . size ( ) + " users from the database. " ) ;
2013-04-18 23:37:36 +02:00
}
2013-06-04 18:14:43 +02:00
public boolean removeUser ( String playerName ) {
2013-08-28 17:44:58 +02:00
if ( ! checkConnected ( ) ) {
return false ;
}
2013-06-04 18:14:43 +02:00
boolean success = update ( " DELETE FROM u, e, h, s, c " +
" USING " + tablePrefix + " users u " +
" JOIN " + tablePrefix + " experience e ON (u.id = e.user_id) " +
" JOIN " + tablePrefix + " huds h ON (u.id = h.user_id) " +
" JOIN " + tablePrefix + " skills s ON (u.id = s.user_id) " +
" JOIN " + tablePrefix + " cooldowns c ON (u.id = c.user_id) " +
" WHERE u.user = ' " + playerName + " ' " ) ! = 0 ;
Misc . profileCleanup ( playerName ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
return success ;
2013-04-18 23:37:36 +02:00
}
2013-10-06 00:18:10 +02:00
public boolean saveUser ( PlayerProfile profile ) {
2013-08-28 17:44:58 +02:00
if ( ! checkConnected ( ) ) {
2013-10-06 00:18:10 +02:00
return false ;
2013-08-28 17:44:58 +02:00
}
2013-06-04 18:14:43 +02:00
int userId = readId ( profile . getPlayerName ( ) ) ;
2013-07-02 18:42:09 +02:00
if ( userId = = - 1 ) {
2013-06-29 00:02:58 +02:00
newUser ( profile . getPlayerName ( ) ) ;
userId = readId ( profile . getPlayerName ( ) ) ;
2013-07-02 18:42:09 +02:00
if ( userId = = - 1 ) {
2013-10-06 00:18:10 +02:00
return false ;
2013-06-29 00:02:58 +02:00
}
}
2013-10-06 00:18:10 +02:00
boolean success = true ;
2013-06-04 18:14:43 +02:00
MobHealthbarType mobHealthbarType = profile . getMobHealthbarType ( ) ;
2013-10-06 00:18:10 +02:00
success & = saveLogin ( userId , ( ( int ) ( System . currentTimeMillis ( ) / Misc . TIME_CONVERSION_FACTOR ) ) ) ;
success & = saveHuds ( userId , ( mobHealthbarType = = null ? Config . getInstance ( ) . getMobHealthbarDefault ( ) . toString ( ) : mobHealthbarType . toString ( ) ) ) ;
success & = saveLongs (
2013-06-04 18:14:43 +02:00
" UPDATE " + tablePrefix + " cooldowns SET "
+ " mining = ?, woodcutting = ?, unarmed = ? "
+ " , herbalism = ?, excavation = ?, swords = ? "
+ " , axes = ?, blast_mining = ? WHERE user_id = ? " ,
userId ,
2013-10-29 14:49:41 +01:00
profile . getAbilityDATS ( AbilityType . SUPER_BREAKER ) ,
profile . getAbilityDATS ( AbilityType . TREE_FELLER ) ,
profile . getAbilityDATS ( AbilityType . BERSERK ) ,
profile . getAbilityDATS ( AbilityType . GREEN_TERRA ) ,
profile . getAbilityDATS ( AbilityType . GIGA_DRILL_BREAKER ) ,
profile . getAbilityDATS ( AbilityType . SERRATED_STRIKES ) ,
profile . getAbilityDATS ( AbilityType . SKULL_SPLITTER ) ,
profile . getAbilityDATS ( AbilityType . BLAST_MINING ) ) ;
2013-10-06 00:18:10 +02:00
success & = saveIntegers (
2013-06-04 18:14:43 +02:00
" UPDATE " + tablePrefix + " skills SET "
+ " taming = ?, mining = ?, repair = ?, woodcutting = ? "
+ " , unarmed = ?, herbalism = ?, excavation = ? "
+ " , archery = ?, swords = ?, axes = ?, acrobatics = ? "
2013-11-16 00:21:00 +01:00
+ " , fishing = ?, alchemy = ? WHERE user_id = ? " ,
2013-06-04 18:14:43 +02:00
profile . getSkillLevel ( SkillType . TAMING ) ,
profile . getSkillLevel ( SkillType . MINING ) ,
profile . getSkillLevel ( SkillType . REPAIR ) ,
profile . getSkillLevel ( SkillType . WOODCUTTING ) ,
profile . getSkillLevel ( SkillType . UNARMED ) ,
profile . getSkillLevel ( SkillType . HERBALISM ) ,
profile . getSkillLevel ( SkillType . EXCAVATION ) ,
profile . getSkillLevel ( SkillType . ARCHERY ) ,
profile . getSkillLevel ( SkillType . SWORDS ) ,
profile . getSkillLevel ( SkillType . AXES ) ,
profile . getSkillLevel ( SkillType . ACROBATICS ) ,
profile . getSkillLevel ( SkillType . FISHING ) ,
2013-11-16 00:21:00 +01:00
profile . getSkillLevel ( SkillType . ALCHEMY ) ,
2013-06-04 18:14:43 +02:00
userId ) ;
2013-10-06 00:18:10 +02:00
success & = saveIntegers (
2013-06-04 18:14:43 +02:00
" UPDATE " + tablePrefix + " experience SET "
+ " taming = ?, mining = ?, repair = ?, woodcutting = ? "
+ " , unarmed = ?, herbalism = ?, excavation = ? "
+ " , archery = ?, swords = ?, axes = ?, acrobatics = ? "
2013-11-16 00:21:00 +01:00
+ " , fishing = ?, alchemy = ? WHERE user_id = ? " ,
2013-06-04 18:14:43 +02:00
profile . getSkillXpLevel ( SkillType . TAMING ) ,
profile . getSkillXpLevel ( SkillType . MINING ) ,
profile . getSkillXpLevel ( SkillType . REPAIR ) ,
profile . getSkillXpLevel ( SkillType . WOODCUTTING ) ,
profile . getSkillXpLevel ( SkillType . UNARMED ) ,
profile . getSkillXpLevel ( SkillType . HERBALISM ) ,
profile . getSkillXpLevel ( SkillType . EXCAVATION ) ,
profile . getSkillXpLevel ( SkillType . ARCHERY ) ,
profile . getSkillXpLevel ( SkillType . SWORDS ) ,
profile . getSkillXpLevel ( SkillType . AXES ) ,
profile . getSkillXpLevel ( SkillType . ACROBATICS ) ,
profile . getSkillXpLevel ( SkillType . FISHING ) ,
2013-11-16 00:21:00 +01:00
profile . getSkillXpLevel ( SkillType . ALCHEMY ) ,
2013-06-04 18:14:43 +02:00
userId ) ;
2013-10-06 00:18:10 +02:00
return success ;
2013-06-04 18:14:43 +02:00
}
2013-04-18 23:37:36 +02:00
2013-09-12 04:42:27 +02:00
public List < PlayerStat > readLeaderboard ( SkillType skill , int pageNumber , int statsPerPage ) {
2013-06-04 18:14:43 +02:00
List < PlayerStat > stats = new ArrayList < PlayerStat > ( ) ;
if ( checkConnected ( ) ) {
2013-11-16 00:21:00 +01:00
String query = skill = = null ? " taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " : skill . name ( ) . toLowerCase ( ) ;
2014-01-20 22:58:40 +01:00
ResultSet resultSet ;
2013-06-04 18:14:43 +02:00
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement ( " SELECT " + query + " , user, NOW() FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON (user_id = id) WHERE " + query + " > 0 ORDER BY " + query + " DESC, user LIMIT ?, ? " ) ;
statement . setInt ( 1 , ( pageNumber * statsPerPage ) - statsPerPage ) ;
statement . setInt ( 2 , statsPerPage ) ;
resultSet = statement . executeQuery ( ) ;
while ( resultSet . next ( ) ) {
ArrayList < String > column = new ArrayList < String > ( ) ;
for ( int i = 1 ; i < = resultSet . getMetaData ( ) . getColumnCount ( ) ; i + + ) {
column . add ( resultSet . getString ( i ) ) ;
}
stats . add ( new PlayerStat ( column . get ( 1 ) , Integer . valueOf ( column . get ( 0 ) ) ) ) ;
}
}
catch ( SQLException ex ) {
2013-05-16 19:37:22 +02:00
printErrors ( ex ) ;
}
2013-06-04 18:14:43 +02:00
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
2013-04-18 23:37:36 +02:00
}
}
}
2013-06-04 18:14:43 +02:00
return stats ;
2013-04-18 23:37:36 +02:00
}
2013-09-12 04:42:27 +02:00
public Map < SkillType , Integer > readRank ( String playerName ) {
Map < SkillType , Integer > skills = new HashMap < SkillType , Integer > ( ) ;
2013-06-04 18:14:43 +02:00
if ( checkConnected ( ) ) {
ResultSet resultSet ;
try {
2013-10-15 19:03:33 +02:00
for ( SkillType skillType : SkillType . NON_CHILD_SKILLS ) {
2013-06-04 18:14:43 +02:00
String skillName = skillType . name ( ) . toLowerCase ( ) ;
String sql = " SELECT COUNT(*) AS rank FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id WHERE " + skillName + " > 0 " +
" AND " + skillName + " > (SELECT " + skillName + " FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id " +
" WHERE user = ?) " ;
PreparedStatement statement = connection . prepareStatement ( sql ) ;
statement . setString ( 1 , playerName ) ;
resultSet = statement . executeQuery ( ) ;
resultSet . next ( ) ;
int rank = resultSet . getInt ( " rank " ) ;
sql = " SELECT user, " + skillName + " FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id WHERE " + skillName + " > 0 " +
" AND " + skillName + " = (SELECT " + skillName + " FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id " +
" WHERE user = ' " + playerName + " ') ORDER BY user " ;
statement . close ( ) ;
statement = connection . prepareStatement ( sql ) ;
resultSet = statement . executeQuery ( ) ;
while ( resultSet . next ( ) ) {
if ( resultSet . getString ( " user " ) . equalsIgnoreCase ( playerName ) ) {
2013-09-12 04:42:27 +02:00
skills . put ( skillType , rank + resultSet . getRow ( ) ) ;
2013-06-04 18:14:43 +02:00
break ;
}
}
statement . close ( ) ;
}
String sql = " SELECT COUNT(*) AS rank FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id " +
2013-11-16 00:21:00 +01:00
" WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > 0 " +
" AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > " +
" (SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " +
2013-06-04 18:14:43 +02:00
" FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id WHERE user = ?) " ;
PreparedStatement statement = connection . prepareStatement ( sql ) ;
statement . setString ( 1 , playerName ) ;
resultSet = statement . executeQuery ( ) ;
resultSet . next ( ) ;
int rank = resultSet . getInt ( " rank " ) ;
statement . close ( ) ;
2013-11-16 00:21:00 +01:00
sql = " SELECT user, taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " +
2013-06-04 18:14:43 +02:00
" FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id " +
2013-11-16 00:21:00 +01:00
" WHERE taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy > 0 " +
" AND taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy = " +
" (SELECT taming+mining+woodcutting+repair+unarmed+herbalism+excavation+archery+swords+axes+acrobatics+fishing+alchemy " +
2013-06-04 18:14:43 +02:00
" FROM " + tablePrefix + " users JOIN " + tablePrefix + " skills ON user_id = id WHERE user = ?) ORDER BY user " ;
statement = connection . prepareStatement ( sql ) ;
statement . setString ( 1 , playerName ) ;
resultSet = statement . executeQuery ( ) ;
while ( resultSet . next ( ) ) {
if ( resultSet . getString ( " user " ) . equalsIgnoreCase ( playerName ) ) {
2013-09-12 04:42:27 +02:00
skills . put ( null , rank + resultSet . getRow ( ) ) ;
2013-06-04 18:14:43 +02:00
break ;
}
}
statement . close ( ) ;
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
2013-04-18 23:37:36 +02:00
}
2013-06-04 18:14:43 +02:00
return skills ;
}
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
public void newUser ( String playerName ) {
2013-08-28 17:44:58 +02:00
if ( ! checkConnected ( ) ) {
return ;
}
2013-04-18 23:37:36 +02:00
PreparedStatement statement = null ;
2013-06-04 18:14:43 +02:00
2013-04-18 23:37:36 +02:00
try {
2013-07-01 05:23:34 +02:00
statement = connection . prepareStatement ( " INSERT INTO " + tablePrefix + " users (user, lastlogin) VALUES (?, ?) " , Statement . RETURN_GENERATED_KEYS ) ;
2013-06-04 18:14:43 +02:00
statement . setString ( 1 , playerName ) ;
statement . setLong ( 2 , System . currentTimeMillis ( ) / Misc . TIME_CONVERSION_FACTOR ) ;
statement . execute ( ) ;
2013-07-02 18:42:09 +02:00
int id = readId ( playerName ) ;
2013-06-29 00:02:58 +02:00
writeMissingRows ( id ) ;
2013-04-18 23:37:36 +02:00
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
2013-06-04 18:14:43 +02:00
// Ignore
2013-04-18 23:37:36 +02:00
}
}
}
}
2013-06-29 00:02:58 +02:00
public PlayerProfile loadPlayerProfile ( String playerName , boolean create ) {
2013-10-07 13:53:42 +02:00
return loadPlayerProfile ( playerName , create , true ) ;
2013-10-06 03:07:11 +02:00
}
2013-10-07 13:53:42 +02:00
private PlayerProfile loadPlayerProfile ( String playerName , boolean create , boolean retry ) {
2013-08-28 17:44:58 +02:00
if ( ! checkConnected ( ) ) {
2013-08-28 19:13:34 +02:00
return new PlayerProfile ( playerName , false ) ; // return fake profile if not connected
2013-08-28 17:44:58 +02:00
}
2013-04-18 23:37:36 +02:00
PreparedStatement statement = null ;
try {
2013-06-04 18:14:43 +02:00
statement = connection . prepareStatement (
" SELECT "
2013-11-16 00:21:00 +01:00
+ " s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, "
+ " e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, "
2013-06-04 18:14:43 +02:00
+ " c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, "
2013-09-18 15:57:28 +02:00
+ " h.mobhealthbar "
2013-06-04 18:14:43 +02:00
+ " FROM " + tablePrefix + " users u "
+ " JOIN " + tablePrefix + " skills s ON (u.id = s.user_id) "
+ " JOIN " + tablePrefix + " experience e ON (u.id = e.user_id) "
+ " JOIN " + tablePrefix + " cooldowns c ON (u.id = c.user_id) "
+ " JOIN " + tablePrefix + " huds h ON (u.id = h.user_id) "
+ " WHERE u.user = ? " ) ;
statement . setString ( 1 , playerName ) ;
2013-06-29 00:02:58 +02:00
ResultSet result = statement . executeQuery ( ) ;
2013-06-04 18:14:43 +02:00
2013-06-29 00:02:58 +02:00
if ( result . next ( ) ) {
try {
PlayerProfile ret = loadFromResult ( playerName , result ) ;
result . close ( ) ;
return ret ;
2013-06-04 18:14:43 +02:00
}
2013-10-06 10:25:28 +02:00
catch ( SQLException e ) {
}
2013-04-18 23:37:36 +02:00
}
2013-06-29 00:02:58 +02:00
result . close ( ) ;
2013-04-18 23:37:36 +02:00
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
2013-06-04 18:14:43 +02:00
// Ignore
2013-04-18 23:37:36 +02:00
}
}
}
2013-06-29 00:02:58 +02:00
// Problem, nothing was returned
2013-06-04 18:14:43 +02:00
2013-10-06 03:07:11 +02:00
// Quit if this is second time around
if ( ! retry ) {
return new PlayerProfile ( playerName , false ) ;
}
2013-06-29 00:02:58 +02:00
// First, read User Id - this is to check for orphans
int id = readId ( playerName ) ;
2013-07-02 18:42:09 +02:00
if ( id = = - 1 ) {
2013-06-29 00:02:58 +02:00
// There is no such user
if ( create ) {
newUser ( playerName ) ;
2013-10-07 13:53:42 +02:00
return loadPlayerProfile ( playerName , false , false ) ;
2013-06-29 00:02:58 +02:00
}
2013-07-11 18:49:01 +02:00
2013-10-06 03:07:11 +02:00
// Return unloaded profile if can't create
return new PlayerProfile ( playerName , false ) ;
2013-06-04 18:14:43 +02:00
}
2013-06-29 00:02:58 +02:00
// There is such a user
writeMissingRows ( id ) ;
// Retry, and abort on re-failure
2013-10-07 13:53:42 +02:00
return loadPlayerProfile ( playerName , create , false ) ;
2013-06-29 00:02:58 +02:00
}
2013-06-04 18:14:43 +02:00
2013-06-29 00:02:58 +02:00
public void convertUsers ( DatabaseManager destination ) {
2013-08-28 17:44:58 +02:00
if ( ! checkConnected ( ) ) {
return ;
}
2013-06-29 00:02:58 +02:00
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement (
" SELECT "
2013-11-16 00:21:00 +01:00
+ " s.taming, s.mining, s.repair, s.woodcutting, s.unarmed, s.herbalism, s.excavation, s.archery, s.swords, s.axes, s.acrobatics, s.fishing, s.alchemy, "
+ " e.taming, e.mining, e.repair, e.woodcutting, e.unarmed, e.herbalism, e.excavation, e.archery, e.swords, e.axes, e.acrobatics, e.fishing, e.alchemy, "
2013-06-29 00:02:58 +02:00
+ " c.taming, c.mining, c.repair, c.woodcutting, c.unarmed, c.herbalism, c.excavation, c.archery, c.swords, c.axes, c.acrobatics, c.blast_mining, "
2013-09-18 15:57:28 +02:00
+ " h.mobhealthbar "
2013-06-29 00:02:58 +02:00
+ " FROM " + tablePrefix + " users u "
+ " JOIN " + tablePrefix + " skills s ON (u.id = s.user_id) "
+ " JOIN " + tablePrefix + " experience e ON (u.id = e.user_id) "
+ " JOIN " + tablePrefix + " cooldowns c ON (u.id = c.user_id) "
+ " JOIN " + tablePrefix + " huds h ON (u.id = h.user_id) "
+ " WHERE u.user = ? " ) ;
List < String > usernames = getStoredUsers ( ) ;
2014-01-20 22:58:40 +01:00
ResultSet resultSet ;
2013-10-16 03:32:54 +02:00
int convertedUsers = 0 ;
long startMillis = System . currentTimeMillis ( ) ;
2013-06-29 00:02:58 +02:00
for ( String playerName : usernames ) {
statement . setString ( 1 , playerName ) ;
try {
2014-01-20 22:58:40 +01:00
resultSet = statement . executeQuery ( ) ;
resultSet . next ( ) ;
destination . saveUser ( loadFromResult ( playerName , resultSet ) ) ;
resultSet . close ( ) ;
2013-06-29 00:02:58 +02:00
}
catch ( SQLException e ) {
// Ignore
}
2013-10-16 03:32:54 +02:00
convertedUsers + + ;
2013-10-18 16:43:37 +02:00
Misc . printProgress ( convertedUsers , progressInterval , startMillis ) ;
2013-06-29 00:02:58 +02:00
}
}
catch ( SQLException e ) {
printErrors ( e ) ;
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
2013-10-06 10:25:28 +02:00
}
catch ( SQLException e ) {
2013-06-29 00:02:58 +02:00
// Ignore
}
}
2013-06-04 18:14:43 +02:00
}
2013-04-18 23:37:36 +02:00
}
2013-10-06 10:25:28 +02:00
2013-04-18 23:37:36 +02:00
/ * *
2013-06-04 18:14:43 +02:00
* Check connection status and re - establish if dead or stale .
*
* If the very first immediate attempt fails , further attempts
* will be made in progressively larger intervals up to MAX_WAIT
* intervals .
*
* This allows for MySQL to time out idle connections as needed by
* server operator , without affecting McMMO , while still providing
* protection against a database outage taking down Bukkit ' s tick
* processing loop due to attempting a database connection each
* time McMMO needs the database .
*
* @return the boolean value for whether or not we are connected
* /
public boolean checkConnected ( ) {
2013-04-18 23:37:36 +02:00
boolean isClosed = true ;
boolean isValid = false ;
boolean exists = ( connection ! = null ) ;
// If we're waiting for server to recover then leave early
if ( nextReconnectTimestamp > 0 & & nextReconnectTimestamp > System . nanoTime ( ) ) {
return false ;
}
if ( exists ) {
try {
isClosed = connection . isClosed ( ) ;
}
catch ( SQLException e ) {
isClosed = true ;
e . printStackTrace ( ) ;
printErrors ( e ) ;
}
if ( ! isClosed ) {
try {
isValid = connection . isValid ( VALID_TIMEOUT ) ;
}
catch ( SQLException e ) {
// Don't print stack trace because it's valid to lose idle connections to the server and have to restart them.
isValid = false ;
}
}
}
// Leave if all ok
if ( exists & & ! isClosed & & isValid ) {
// Housekeeping
nextReconnectTimestamp = 0 ;
reconnectAttempt = 0 ;
return true ;
}
// Cleanup after ourselves for GC and MySQL's sake
if ( exists & & ! isClosed ) {
try {
connection . close ( ) ;
}
catch ( SQLException ex ) {
// This is a housekeeping exercise, ignore errors
}
}
// Try to connect again
connect ( ) ;
// Leave if connection is good
try {
if ( connection ! = null & & ! connection . isClosed ( ) ) {
// Schedule a database save if we really had an outage
if ( reconnectAttempt > 1 ) {
new SQLReconnectTask ( ) . runTaskLater ( mcMMO . p , 5 ) ;
}
nextReconnectTimestamp = 0 ;
reconnectAttempt = 0 ;
return true ;
}
}
catch ( SQLException e ) {
// Failed to check isClosed, so presume connection is bad and attempt later
e . printStackTrace ( ) ;
printErrors ( e ) ;
}
reconnectAttempt + + ;
2013-06-04 18:14:43 +02:00
nextReconnectTimestamp = ( long ) ( System . nanoTime ( ) + Math . min ( MAX_WAIT , ( reconnectAttempt * SCALING_FACTOR * MIN_WAIT ) ) ) ;
2013-04-18 23:37:36 +02:00
return false ;
}
2013-06-29 00:02:58 +02:00
public List < String > getStoredUsers ( ) {
ArrayList < String > users = new ArrayList < String > ( ) ;
2013-08-28 17:44:58 +02:00
if ( checkConnected ( ) ) {
Statement stmt = null ;
try {
stmt = connection . createStatement ( ) ;
ResultSet result = stmt . executeQuery ( " SELECT user FROM " + tablePrefix + " users " ) ;
while ( result . next ( ) ) {
users . add ( result . getString ( " user " ) ) ;
}
result . close ( ) ;
2013-06-29 00:02:58 +02:00
}
2013-08-28 17:44:58 +02:00
catch ( SQLException e ) {
printErrors ( e ) ;
}
finally {
if ( stmt ! = null ) {
try {
stmt . close ( ) ;
2013-10-06 10:25:28 +02:00
}
catch ( SQLException e ) {
2013-08-28 17:44:58 +02:00
// Ignore
}
2013-06-29 00:02:58 +02:00
}
}
}
2013-08-28 17:44:58 +02:00
2013-06-29 00:02:58 +02:00
return users ;
}
2013-04-18 23:37:36 +02:00
/ * *
2013-06-29 00:02:58 +02:00
* Attempt to connect to the mySQL database .
* /
2013-06-04 18:14:43 +02:00
private void connect ( ) {
connectionString = " jdbc:mysql:// " + Config . getInstance ( ) . getMySQLServerName ( ) + " : " + Config . getInstance ( ) . getMySQLServerPort ( ) + " / " + Config . getInstance ( ) . getMySQLDatabaseName ( ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
try {
mcMMO . p . getLogger ( ) . info ( " Attempting connection to MySQL... " ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
// Force driver to load if not yet loaded
Class . forName ( " com.mysql.jdbc.Driver " ) ;
Properties connectionProperties = new Properties ( ) ;
connectionProperties . put ( " user " , Config . getInstance ( ) . getMySQLUserName ( ) ) ;
connectionProperties . put ( " password " , Config . getInstance ( ) . getMySQLUserPassword ( ) ) ;
connectionProperties . put ( " autoReconnect " , " false " ) ;
connection = DriverManager . getConnection ( connectionString , connectionProperties ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
mcMMO . p . getLogger ( ) . info ( " Connection to MySQL was a success! " ) ;
}
catch ( SQLException ex ) {
connection = null ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
if ( reconnectAttempt = = 0 | | reconnectAttempt > = 11 ) {
2013-07-30 21:09:22 +02:00
mcMMO . p . getLogger ( ) . severe ( " Connection to MySQL failed! " ) ;
printErrors ( ex ) ;
2013-04-18 23:37:36 +02:00
}
}
2013-06-04 18:14:43 +02:00
catch ( ClassNotFoundException ex ) {
connection = null ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
if ( reconnectAttempt = = 0 | | reconnectAttempt > = 11 ) {
2013-07-30 21:09:22 +02:00
mcMMO . p . getLogger ( ) . severe ( " MySQL database driver not found! " ) ;
2013-04-18 23:37:36 +02:00
}
}
}
2013-06-04 18:14:43 +02:00
/ * *
2013-07-01 07:37:24 +02:00
* Checks that the database structure is present and correct
2013-06-29 00:02:58 +02:00
* /
2013-07-01 07:37:24 +02:00
private void checkStructure ( ) {
2013-08-28 17:44:58 +02:00
if ( ! checkConnected ( ) ) {
return ;
}
2013-06-04 18:14:43 +02:00
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " users` ( "
+ " `id` int(10) unsigned NOT NULL AUTO_INCREMENT, "
+ " `user` varchar(40) NOT NULL, "
+ " `lastlogin` int(32) unsigned NOT NULL, "
+ " PRIMARY KEY (`id`), "
+ " UNIQUE KEY `user` (`user`)) DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; " ) ;
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " huds` ( "
+ " `user_id` int(10) unsigned NOT NULL, "
+ " `mobhealthbar` varchar(50) NOT NULL DEFAULT ' " + Config . getInstance ( ) . getMobHealthbarDefault ( ) + " ', "
+ " PRIMARY KEY (`user_id`)) "
+ " DEFAULT CHARSET=latin1; " ) ;
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " cooldowns` ( "
+ " `user_id` int(10) unsigned NOT NULL, "
+ " `taming` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `mining` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `woodcutting` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `repair` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `unarmed` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `herbalism` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `excavation` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `archery` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `swords` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `axes` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `acrobatics` int(32) unsigned NOT NULL DEFAULT '0', "
+ " `blast_mining` int(32) unsigned NOT NULL DEFAULT '0', "
+ " PRIMARY KEY (`user_id`)) "
+ " DEFAULT CHARSET=latin1; " ) ;
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " skills` ( "
+ " `user_id` int(10) unsigned NOT NULL, "
+ " `taming` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `mining` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `woodcutting` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `repair` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `unarmed` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `herbalism` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `excavation` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `archery` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `swords` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `axes` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `acrobatics` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `fishing` int(10) unsigned NOT NULL DEFAULT '0', "
2013-11-16 00:21:00 +01:00
+ " `alchemy` int(10) unsigned NOT NULL DEFAULT '0', "
2013-06-04 18:14:43 +02:00
+ " PRIMARY KEY (`user_id`)) "
+ " DEFAULT CHARSET=latin1; " ) ;
write ( " CREATE TABLE IF NOT EXISTS ` " + tablePrefix + " experience` ( "
+ " `user_id` int(10) unsigned NOT NULL, "
+ " `taming` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `mining` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `woodcutting` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `repair` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `unarmed` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `herbalism` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `excavation` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `archery` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `swords` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `axes` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `acrobatics` int(10) unsigned NOT NULL DEFAULT '0', "
+ " `fishing` int(10) unsigned NOT NULL DEFAULT '0', "
2013-11-16 00:21:00 +01:00
+ " `alchemy` int(10) unsigned NOT NULL DEFAULT '0', "
2013-06-04 18:14:43 +02:00
+ " PRIMARY KEY (`user_id`)) "
+ " DEFAULT CHARSET=latin1; " ) ;
2013-04-18 23:37:36 +02:00
2013-06-04 18:14:43 +02:00
for ( DatabaseUpdateType updateType : DatabaseUpdateType . values ( ) ) {
checkDatabaseStructure ( updateType ) ;
2013-04-18 23:37:36 +02:00
}
}
/ * *
2013-06-29 00:02:58 +02:00
* Check database structure for missing values .
*
* @param update Type of data to check updates for
* /
2013-06-04 18:14:43 +02:00
private void checkDatabaseStructure ( DatabaseUpdateType update ) {
String sql = " " ;
2013-04-18 23:37:36 +02:00
switch ( update ) {
case BLAST_MINING :
2013-06-04 18:14:43 +02:00
sql = " SELECT * FROM ` " + tablePrefix + " cooldowns` ORDER BY ` " + tablePrefix + " cooldowns`.`blast_mining` ASC LIMIT 0 , 30 " ;
2013-04-18 23:37:36 +02:00
break ;
case FISHING :
2013-06-04 18:14:43 +02:00
sql = " SELECT * FROM ` " + tablePrefix + " experience` ORDER BY ` " + tablePrefix + " experience`.`fishing` ASC LIMIT 0 , 30 " ;
2013-04-18 23:37:36 +02:00
break ;
2013-11-16 00:21:00 +01:00
case ALCHEMY :
sql = " SELECT * FROM ` " + tablePrefix + " experience` ORDER BY ` " + tablePrefix + " experience`.`alchemy` ASC LIMIT 0 , 30 " ;
break ;
2013-04-18 23:37:36 +02:00
case INDEX :
if ( read ( " SHOW INDEX FROM " + tablePrefix + " skills " ) . size ( ) ! = 13 & & checkConnected ( ) ) {
mcMMO . p . getLogger ( ) . info ( " Indexing tables, this may take a while on larger databases " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " skills` ADD INDEX `idx_taming` (`taming`) USING BTREE, "
+ " ADD INDEX `idx_mining` (`mining`) USING BTREE, "
+ " ADD INDEX `idx_woodcutting` (`woodcutting`) USING BTREE, "
+ " ADD INDEX `idx_repair` (`repair`) USING BTREE, "
+ " ADD INDEX `idx_unarmed` (`unarmed`) USING BTREE, "
+ " ADD INDEX `idx_herbalism` (`herbalism`) USING BTREE, "
+ " ADD INDEX `idx_excavation` (`excavation`) USING BTREE, "
+ " ADD INDEX `idx_archery` (`archery`) USING BTREE, "
+ " ADD INDEX `idx_swords` (`swords`) USING BTREE, "
+ " ADD INDEX `idx_axes` (`axes`) USING BTREE, "
+ " ADD INDEX `idx_acrobatics` (`acrobatics`) USING BTREE, "
+ " ADD INDEX `idx_fishing` (`fishing`) USING BTREE; " ) ;
}
2013-05-17 00:04:14 +02:00
return ;
2013-04-18 23:37:36 +02:00
case MOB_HEALTHBARS :
2013-06-04 18:14:43 +02:00
sql = " SELECT * FROM ` " + tablePrefix + " huds` ORDER BY ` " + tablePrefix + " huds`.`mobhealthbar` ASC LIMIT 0 , 30 " ;
2013-04-18 23:37:36 +02:00
break ;
2013-05-16 19:37:22 +02:00
case PARTY_NAMES :
write ( " ALTER TABLE ` " + tablePrefix + " users` DROP COLUMN `party` ; " ) ;
2013-05-17 00:04:14 +02:00
return ;
2013-05-16 19:37:22 +02:00
2013-09-18 15:57:28 +02:00
case DROPPED_SPOUT :
write ( " ALTER TABLE ` " + tablePrefix + " huds` DROP COLUMN `hudtype` ; " ) ;
return ;
2013-05-16 23:26:16 +02:00
case KILL_ORPHANS :
mcMMO . p . getLogger ( ) . info ( " Killing orphans " ) ;
write (
" DELETE FROM " + tablePrefix + " experience " +
" WHERE NOT EXISTS (SELECT * FROM " +
2013-06-04 18:14:43 +02:00
tablePrefix + " users u WHERE " +
tablePrefix + " experience.user_id = u.id); "
2013-05-16 23:26:16 +02:00
) ;
write (
" DELETE FROM " + tablePrefix + " huds " +
" WHERE NOT EXISTS (SELECT * FROM " +
2013-06-04 18:14:43 +02:00
tablePrefix + " users u WHERE " +
tablePrefix + " huds.user_id = u.id); "
2013-05-16 23:26:16 +02:00
) ;
write (
" DELETE FROM " + tablePrefix + " cooldowns " +
" WHERE NOT EXISTS (SELECT * FROM " +
2013-06-04 18:14:43 +02:00
tablePrefix + " users u WHERE " +
tablePrefix + " cooldowns.user_id = u.id); "
2013-05-16 23:26:16 +02:00
) ;
write (
" DELETE FROM " + tablePrefix + " skills " +
" WHERE NOT EXISTS (SELECT * FROM " +
2013-06-04 18:14:43 +02:00
tablePrefix + " users u WHERE " +
tablePrefix + " skills.user_id = u.id); "
2013-05-16 23:26:16 +02:00
) ;
2013-05-17 00:04:14 +02:00
return ;
2013-05-16 23:26:16 +02:00
2013-04-18 23:37:36 +02:00
default :
break ;
}
2014-01-20 22:58:40 +01:00
ResultSet resultSet ;
2013-04-18 23:37:36 +02:00
PreparedStatement statement = null ;
2013-06-04 18:14:43 +02:00
2013-04-18 23:37:36 +02:00
try {
if ( ! checkConnected ( ) ) {
return ;
}
statement = connection . prepareStatement ( sql ) ;
resultSet = statement . executeQuery ( ) ;
while ( resultSet . next ( ) ) {
2014-02-27 16:56:21 +01:00
// No reason to do anything here... we're just trying to catch exceptions
2013-04-18 23:37:36 +02:00
}
}
catch ( SQLException ex ) {
switch ( update ) {
case BLAST_MINING :
mcMMO . p . getLogger ( ) . info ( " Updating mcMMO MySQL tables for Blast Mining... " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " cooldowns` ADD `blast_mining` int(32) NOT NULL DEFAULT '0' ; " ) ;
break ;
case FISHING :
mcMMO . p . getLogger ( ) . info ( " Updating mcMMO MySQL tables for Fishing... " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " skills` ADD `fishing` int(10) NOT NULL DEFAULT '0' ; " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " experience` ADD `fishing` int(10) NOT NULL DEFAULT '0' ; " ) ;
break ;
case MOB_HEALTHBARS :
mcMMO . p . getLogger ( ) . info ( " Updating mcMMO MySQL tables for mob healthbars... " ) ;
2013-05-14 17:31:21 +02:00
write ( " ALTER TABLE ` " + tablePrefix + " huds` ADD `mobhealthbar` varchar(50) NOT NULL DEFAULT ' " + Config . getInstance ( ) . getMobHealthbarDefault ( ) + " ' ; " ) ;
2013-04-18 23:37:36 +02:00
break ;
2013-11-16 00:21:00 +01:00
case ALCHEMY :
mcMMO . p . getLogger ( ) . info ( " Updating mcMMO MySQL tables for Alchemy... " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " skills` ADD `alchemy` int(10) NOT NULL DEFAULT '0' ; " ) ;
write ( " ALTER TABLE ` " + tablePrefix + " experience` ADD `alchemy` int(10) NOT NULL DEFAULT '0' ; " ) ;
break ;
2013-04-18 23:37:36 +02:00
default :
break ;
}
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore the error, we're leaving
}
}
}
}
2013-06-04 18:14:43 +02:00
/ * *
2013-06-29 00:02:58 +02:00
* Attempt to write the SQL query .
*
* @param sql Query to write .
* @return true if the query was successfully written , false otherwise .
* /
2013-06-04 18:14:43 +02:00
private boolean write ( String sql ) {
if ( ! checkConnected ( ) ) {
return false ;
}
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement ( sql ) ;
statement . executeUpdate ( ) ;
return true ;
}
catch ( SQLException ex ) {
2013-09-20 21:39:20 +02:00
if ( ! sql . contains ( " DROP COLUMN " ) ) {
2013-06-04 18:14:43 +02:00
printErrors ( ex ) ;
}
return false ;
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
/ * *
2013-06-29 00:02:58 +02:00
* Returns the number of rows affected by either a DELETE or UPDATE query
*
* @param sql SQL query to execute
* @return the number of rows affected
* /
2013-06-04 18:14:43 +02:00
private int update ( String sql ) {
int rows = 0 ;
if ( checkConnected ( ) ) {
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement ( sql ) ;
rows = statement . executeUpdate ( ) ;
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
return rows ;
}
/ * *
2013-06-29 00:02:58 +02:00
* Read SQL query .
*
* @param sql SQL query to read
* @return the rows in this SQL query
* /
2013-06-04 18:14:43 +02:00
private HashMap < Integer , ArrayList < String > > read ( String sql ) {
HashMap < Integer , ArrayList < String > > rows = new HashMap < Integer , ArrayList < String > > ( ) ;
if ( checkConnected ( ) ) {
PreparedStatement statement = null ;
ResultSet resultSet ;
try {
statement = connection . prepareStatement ( sql ) ;
resultSet = statement . executeQuery ( ) ;
while ( resultSet . next ( ) ) {
ArrayList < String > column = new ArrayList < String > ( ) ;
for ( int i = 1 ; i < = resultSet . getMetaData ( ) . getColumnCount ( ) ; i + + ) {
column . add ( resultSet . getString ( i ) ) ;
}
rows . put ( resultSet . getRow ( ) , column ) ;
}
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
return rows ;
}
/ * *
2013-06-29 00:02:58 +02:00
* Get the Integer . Only return first row / first field .
*
2013-08-10 20:10:45 +02:00
* @param statement SQL query to execute
2013-06-29 00:02:58 +02:00
* @return the value in the first row / first field
* /
2013-06-04 18:14:43 +02:00
private int readInt ( PreparedStatement statement ) {
2013-07-02 18:42:09 +02:00
int result = - 1 ;
2013-06-04 18:14:43 +02:00
if ( checkConnected ( ) ) {
2014-01-20 22:58:40 +01:00
ResultSet resultSet ;
2013-06-04 18:14:43 +02:00
try {
resultSet = statement . executeQuery ( ) ;
if ( resultSet . next ( ) ) {
result = resultSet . getInt ( 1 ) ;
}
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
return result ;
}
private void writeMissingRows ( int id ) {
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement ( " INSERT IGNORE INTO " + tablePrefix + " experience (user_id) VALUES (?) " ) ;
statement . setInt ( 1 , id ) ;
statement . execute ( ) ;
statement . close ( ) ;
statement = connection . prepareStatement ( " INSERT IGNORE INTO " + tablePrefix + " skills (user_id) VALUES (?) " ) ;
statement . setInt ( 1 , id ) ;
statement . execute ( ) ;
statement . close ( ) ;
statement = connection . prepareStatement ( " INSERT IGNORE INTO " + tablePrefix + " cooldowns (user_id) VALUES (?) " ) ;
statement . setInt ( 1 , id ) ;
statement . execute ( ) ;
statement . close ( ) ;
statement = connection . prepareStatement ( " INSERT IGNORE INTO " + tablePrefix + " huds (user_id, mobhealthbar) VALUES (? ,' " + Config . getInstance ( ) . getMobHealthbarDefault ( ) . name ( ) + " ') " ) ;
statement . setInt ( 1 , id ) ;
statement . execute ( ) ;
statement . close ( ) ;
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
private void processPurge ( Collection < ArrayList < String > > usernames ) {
for ( ArrayList < String > user : usernames ) {
Misc . profileCleanup ( user . get ( 0 ) ) ;
}
}
2013-10-06 00:18:10 +02:00
private boolean saveIntegers ( String sql , int . . . args ) {
2013-06-04 18:14:43 +02:00
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement ( sql ) ;
int i = 1 ;
for ( int arg : args ) {
statement . setInt ( i + + , arg ) ;
}
statement . execute ( ) ;
2013-10-06 00:18:10 +02:00
return true ;
2013-06-04 18:14:43 +02:00
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
2013-10-06 00:18:10 +02:00
return false ;
2013-06-04 18:14:43 +02:00
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
2013-10-06 00:18:10 +02:00
private boolean saveLongs ( String sql , int id , long . . . args ) {
2013-06-04 18:14:43 +02:00
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement ( sql ) ;
int i = 1 ;
for ( long arg : args ) {
statement . setLong ( i + + , arg ) ;
}
statement . setInt ( i + + , id ) ;
statement . execute ( ) ;
2013-10-06 00:18:10 +02:00
return true ;
2013-06-04 18:14:43 +02:00
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
2013-10-06 00:18:10 +02:00
return false ;
2013-06-04 18:14:43 +02:00
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
2013-07-01 07:37:24 +02:00
/ * *
* Retrieve the database id for a player
*
* @param playerName The name of the user to retrieve the id for
2013-07-02 18:42:09 +02:00
* @return the requested id or - 1 if not found
2013-07-01 07:37:24 +02:00
* /
2013-06-04 18:14:43 +02:00
private int readId ( String playerName ) {
2013-07-02 18:42:09 +02:00
int id = - 1 ;
2013-06-04 18:14:43 +02:00
try {
PreparedStatement statement = connection . prepareStatement ( " SELECT id FROM " + tablePrefix + " users WHERE user = ? " ) ;
statement . setString ( 1 , playerName ) ;
id = readInt ( statement ) ;
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
}
return id ;
}
2013-10-06 00:18:10 +02:00
private boolean saveLogin ( int id , long login ) {
2013-06-04 18:14:43 +02:00
PreparedStatement statement = null ;
try {
statement = connection . prepareStatement ( " UPDATE " + tablePrefix + " users SET lastlogin = ? WHERE id = ? " ) ;
statement . setLong ( 1 , login ) ;
statement . setInt ( 2 , id ) ;
statement . execute ( ) ;
2013-10-06 00:18:10 +02:00
return true ;
2013-06-04 18:14:43 +02:00
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
2013-10-06 00:18:10 +02:00
return false ;
2013-06-04 18:14:43 +02:00
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
2013-10-06 00:18:10 +02:00
private boolean saveHuds ( int userId , String mobHealthBar ) {
2013-06-04 18:14:43 +02:00
PreparedStatement statement = null ;
try {
2013-09-18 15:57:28 +02:00
statement = connection . prepareStatement ( " UPDATE " + tablePrefix + " huds SET mobhealthbar = ? WHERE user_id = ? " ) ;
statement . setString ( 1 , mobHealthBar ) ;
statement . setInt ( 2 , userId ) ;
2013-06-04 18:14:43 +02:00
statement . execute ( ) ;
2013-10-06 00:18:10 +02:00
return true ;
2013-06-04 18:14:43 +02:00
}
catch ( SQLException ex ) {
printErrors ( ex ) ;
2013-10-06 00:18:10 +02:00
return false ;
2013-06-04 18:14:43 +02:00
}
finally {
if ( statement ! = null ) {
try {
statement . close ( ) ;
}
catch ( SQLException e ) {
// Ignore
}
}
}
}
2013-06-29 00:02:58 +02:00
private PlayerProfile loadFromResult ( String playerName , ResultSet result ) throws SQLException {
Map < SkillType , Integer > skills = new HashMap < SkillType , Integer > ( ) ; // Skill & Level
Map < SkillType , Float > skillsXp = new HashMap < SkillType , Float > ( ) ; // Skill & XP
Map < AbilityType , Integer > skillsDATS = new HashMap < AbilityType , Integer > ( ) ; // Ability & Cooldown
MobHealthbarType mobHealthbarType ;
final int OFFSET_SKILLS = 0 ; // TODO update these numbers when the query changes (a new skill is added)
2014-01-21 20:16:39 +01:00
final int OFFSET_XP = 13 ;
final int OFFSET_DATS = 26 ;
final int OFFSET_OTHER = 38 ;
2013-06-29 00:02:58 +02:00
skills . put ( SkillType . TAMING , result . getInt ( OFFSET_SKILLS + 1 ) ) ;
skills . put ( SkillType . MINING , result . getInt ( OFFSET_SKILLS + 2 ) ) ;
skills . put ( SkillType . REPAIR , result . getInt ( OFFSET_SKILLS + 3 ) ) ;
skills . put ( SkillType . WOODCUTTING , result . getInt ( OFFSET_SKILLS + 4 ) ) ;
skills . put ( SkillType . UNARMED , result . getInt ( OFFSET_SKILLS + 5 ) ) ;
skills . put ( SkillType . HERBALISM , result . getInt ( OFFSET_SKILLS + 6 ) ) ;
skills . put ( SkillType . EXCAVATION , result . getInt ( OFFSET_SKILLS + 7 ) ) ;
skills . put ( SkillType . ARCHERY , result . getInt ( OFFSET_SKILLS + 8 ) ) ;
skills . put ( SkillType . SWORDS , result . getInt ( OFFSET_SKILLS + 9 ) ) ;
skills . put ( SkillType . AXES , result . getInt ( OFFSET_SKILLS + 10 ) ) ;
skills . put ( SkillType . ACROBATICS , result . getInt ( OFFSET_SKILLS + 11 ) ) ;
skills . put ( SkillType . FISHING , result . getInt ( OFFSET_SKILLS + 12 ) ) ;
2013-11-16 00:21:00 +01:00
skills . put ( SkillType . ALCHEMY , result . getInt ( OFFSET_SKILLS + 13 ) ) ;
2013-06-29 00:02:58 +02:00
skillsXp . put ( SkillType . TAMING , result . getFloat ( OFFSET_XP + 1 ) ) ;
skillsXp . put ( SkillType . MINING , result . getFloat ( OFFSET_XP + 2 ) ) ;
skillsXp . put ( SkillType . REPAIR , result . getFloat ( OFFSET_XP + 3 ) ) ;
skillsXp . put ( SkillType . WOODCUTTING , result . getFloat ( OFFSET_XP + 4 ) ) ;
skillsXp . put ( SkillType . UNARMED , result . getFloat ( OFFSET_XP + 5 ) ) ;
skillsXp . put ( SkillType . HERBALISM , result . getFloat ( OFFSET_XP + 6 ) ) ;
skillsXp . put ( SkillType . EXCAVATION , result . getFloat ( OFFSET_XP + 7 ) ) ;
skillsXp . put ( SkillType . ARCHERY , result . getFloat ( OFFSET_XP + 8 ) ) ;
skillsXp . put ( SkillType . SWORDS , result . getFloat ( OFFSET_XP + 9 ) ) ;
skillsXp . put ( SkillType . AXES , result . getFloat ( OFFSET_XP + 10 ) ) ;
skillsXp . put ( SkillType . ACROBATICS , result . getFloat ( OFFSET_XP + 11 ) ) ;
skillsXp . put ( SkillType . FISHING , result . getFloat ( OFFSET_XP + 12 ) ) ;
2013-11-16 00:21:00 +01:00
skillsXp . put ( SkillType . ALCHEMY , result . getFloat ( OFFSET_XP + 13 ) ) ;
2013-06-29 00:02:58 +02:00
// Taming - Unused - result.getInt(OFFSET_DATS + 1)
skillsDATS . put ( AbilityType . SUPER_BREAKER , result . getInt ( OFFSET_DATS + 2 ) ) ;
// Repair - Unused - result.getInt(OFFSET_DATS + 3)
skillsDATS . put ( AbilityType . TREE_FELLER , result . getInt ( OFFSET_DATS + 4 ) ) ;
skillsDATS . put ( AbilityType . BERSERK , result . getInt ( OFFSET_DATS + 5 ) ) ;
skillsDATS . put ( AbilityType . GREEN_TERRA , result . getInt ( OFFSET_DATS + 6 ) ) ;
skillsDATS . put ( AbilityType . GIGA_DRILL_BREAKER , result . getInt ( OFFSET_DATS + 7 ) ) ;
// Archery - Unused - result.getInt(OFFSET_DATS + 8)
skillsDATS . put ( AbilityType . SERRATED_STRIKES , result . getInt ( OFFSET_DATS + 9 ) ) ;
skillsDATS . put ( AbilityType . SKULL_SPLITTER , result . getInt ( OFFSET_DATS + 10 ) ) ;
// Acrobatics - Unused - result.getInt(OFFSET_DATS + 11)
skillsDATS . put ( AbilityType . BLAST_MINING , result . getInt ( OFFSET_DATS + 12 ) ) ;
try {
mobHealthbarType = MobHealthbarType . valueOf ( result . getString ( OFFSET_OTHER + 2 ) ) ;
}
catch ( Exception e ) {
mobHealthbarType = Config . getInstance ( ) . getMobHealthbarDefault ( ) ;
}
2013-09-16 00:07:40 +02:00
return new PlayerProfile ( playerName , skills , skillsXp , skillsDATS , mobHealthbarType ) ;
2013-06-29 00:02:58 +02:00
}
2013-06-04 18:14:43 +02:00
private void printErrors ( SQLException ex ) {
2013-04-18 23:37:36 +02:00
mcMMO . p . getLogger ( ) . severe ( " SQLException: " + ex . getMessage ( ) ) ;
mcMMO . p . getLogger ( ) . severe ( " SQLState: " + ex . getSQLState ( ) ) ;
mcMMO . p . getLogger ( ) . severe ( " VendorError: " + ex . getErrorCode ( ) ) ;
}
2013-08-22 15:11:33 +02:00
public DatabaseType getDatabaseType ( ) {
return DatabaseType . SQL ;
}
2013-07-01 05:23:34 +02:00
}