2018-07-06 15:30:00 +02:00
package com.eu.habbo.habbohotel.achievements ;
import com.eu.habbo.Emulator ;
import com.eu.habbo.habbohotel.items.Item ;
import com.eu.habbo.habbohotel.users.Habbo ;
import com.eu.habbo.habbohotel.users.HabboBadge ;
import com.eu.habbo.habbohotel.users.HabboItem ;
import com.eu.habbo.messages.outgoing.achievements.AchievementProgressComposer ;
import com.eu.habbo.messages.outgoing.achievements.AchievementUnlockedComposer ;
import com.eu.habbo.messages.outgoing.achievements.talenttrack.TalentLevelUpdateComposer ;
import com.eu.habbo.messages.outgoing.inventory.AddHabboItemComposer ;
2018-10-07 00:28:00 +02:00
import com.eu.habbo.messages.outgoing.inventory.InventoryRefreshComposer ;
2018-07-06 15:30:00 +02:00
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer ;
import com.eu.habbo.messages.outgoing.users.AddUserBadgeComposer ;
import com.eu.habbo.messages.outgoing.users.UserBadgesComposer ;
import com.eu.habbo.plugin.Event ;
import com.eu.habbo.plugin.events.users.achievements.UserAchievementLeveledEvent ;
import com.eu.habbo.plugin.events.users.achievements.UserAchievementProgressEvent ;
import gnu.trove.map.hash.THashMap ;
import gnu.trove.procedure.TObjectIntProcedure ;
import java.sql.* ;
import java.util.LinkedHashMap ;
import java.util.Map ;
2019-05-26 20:14:53 +02:00
public class AchievementManager {
2018-11-17 14:28:00 +01:00
public static boolean TALENTTRACK_ENABLED = false ;
2018-07-08 23:32:00 +02:00
2018-07-06 15:30:00 +02:00
private final THashMap < String , Achievement > achievements ;
private final THashMap < TalentTrackType , LinkedHashMap < Integer , TalentTrackLevel > > talentTrackLevels ;
2018-07-08 23:32:00 +02:00
2019-05-26 20:14:53 +02:00
public AchievementManager ( ) {
2018-07-06 15:30:00 +02:00
this . achievements = new THashMap < > ( ) ;
this . talentTrackLevels = new THashMap < > ( ) ;
}
2019-05-26 20:14:53 +02:00
public static void progressAchievement ( int habboId , Achievement achievement ) {
2018-07-06 15:30:00 +02:00
progressAchievement ( habboId , achievement , 1 ) ;
}
2019-05-26 20:14:53 +02:00
public static void progressAchievement ( int habboId , Achievement achievement , int amount ) {
if ( achievement ! = null ) {
2018-07-06 15:30:00 +02:00
Habbo habbo = Emulator . getGameEnvironment ( ) . getHabboManager ( ) . getHabbo ( habboId ) ;
2019-05-26 20:14:53 +02:00
if ( habbo ! = null ) {
2018-07-06 15:30:00 +02:00
progressAchievement ( habbo , achievement , amount ) ;
2019-05-26 20:14:53 +02:00
} else {
2018-07-06 15:30:00 +02:00
try ( Connection connection = Emulator . getDatabase ( ) . getDataSource ( ) . getConnection ( ) ;
PreparedStatement statement = connection . prepareStatement ( " " +
" INSERT INTO users_achievements_queue (user_id, achievement_id, amount) VALUES (?, ?, ?) " +
2019-05-26 20:14:53 +02:00
" ON DUPLICATE KEY UPDATE amount = amount + ? " ) ) {
2018-07-06 15:30:00 +02:00
statement . setInt ( 1 , habboId ) ;
statement . setInt ( 2 , achievement . id ) ;
statement . setInt ( 3 , amount ) ;
statement . setInt ( 4 , amount ) ;
statement . execute ( ) ;
2019-05-26 20:14:53 +02:00
} catch ( SQLException e ) {
2020-05-03 01:46:07 +02:00
logger . error ( " Caught SQL exception " , e ) ;
2018-07-06 15:30:00 +02:00
}
}
}
}
2019-05-26 20:14:53 +02:00
public static void progressAchievement ( Habbo habbo , Achievement achievement ) {
2018-07-06 15:30:00 +02:00
progressAchievement ( habbo , achievement , 1 ) ;
}
2019-05-26 20:14:53 +02:00
public static void progressAchievement ( Habbo habbo , Achievement achievement , int amount ) {
2018-07-06 15:30:00 +02:00
if ( achievement = = null )
return ;
if ( habbo = = null )
return ;
if ( ! habbo . isOnline ( ) )
return ;
int currentProgress = habbo . getHabboStats ( ) . getAchievementProgress ( achievement ) ;
2019-05-26 20:14:53 +02:00
if ( currentProgress = = - 1 ) {
2018-07-06 15:30:00 +02:00
currentProgress = 0 ;
createUserEntry ( habbo , achievement ) ;
habbo . getHabboStats ( ) . setProgress ( achievement , 0 ) ;
}
2019-05-26 20:14:53 +02:00
if ( Emulator . getPluginManager ( ) . isRegistered ( UserAchievementProgressEvent . class , true ) ) {
2018-07-06 15:30:00 +02:00
Event userAchievementProgressedEvent = new UserAchievementProgressEvent ( habbo , achievement , amount ) ;
Emulator . getPluginManager ( ) . fireEvent ( userAchievementProgressedEvent ) ;
2019-05-26 20:14:53 +02:00
if ( userAchievementProgressedEvent . isCancelled ( ) )
2018-07-06 15:30:00 +02:00
return ;
}
AchievementLevel oldLevel = achievement . getLevelForProgress ( currentProgress ) ;
2019-05-26 20:14:53 +02:00
if ( oldLevel ! = null & & ( oldLevel . level = = achievement . levels . size ( ) & & currentProgress > = oldLevel . progress ) ) //Maximum achievement gotten.
2018-07-06 15:30:00 +02:00
return ;
habbo . getHabboStats ( ) . setProgress ( achievement , currentProgress + amount ) ;
AchievementLevel newLevel = achievement . getLevelForProgress ( currentProgress + amount ) ;
2019-05-26 20:14:53 +02:00
if ( AchievementManager . TALENTTRACK_ENABLED ) {
for ( TalentTrackType type : TalentTrackType . values ( ) ) {
if ( Emulator . getGameEnvironment ( ) . getAchievementManager ( ) . talentTrackLevels . containsKey ( type ) ) {
for ( Map . Entry < Integer , TalentTrackLevel > entry : Emulator . getGameEnvironment ( ) . getAchievementManager ( ) . talentTrackLevels . get ( type ) . entrySet ( ) ) {
if ( entry . getValue ( ) . achievements . containsKey ( achievement ) ) {
2018-11-17 14:28:00 +01:00
Emulator . getGameEnvironment ( ) . getAchievementManager ( ) . handleTalentTrackAchievement ( habbo , type , achievement ) ;
break ;
}
2018-10-07 00:28:00 +02:00
}
}
}
}
2019-05-26 20:14:53 +02:00
if ( newLevel = = null | |
( oldLevel ! = null & & ( oldLevel . level = = newLevel . level & & newLevel . level < achievement . levels . size ( ) ) ) ) {
2018-07-06 15:30:00 +02:00
habbo . getClient ( ) . sendResponse ( new AchievementProgressComposer ( habbo , achievement ) ) ;
2019-05-26 20:14:53 +02:00
} else {
if ( Emulator . getPluginManager ( ) . isRegistered ( UserAchievementLeveledEvent . class , true ) ) {
2018-07-06 15:30:00 +02:00
Event userAchievementLeveledEvent = new UserAchievementLeveledEvent ( habbo , achievement , oldLevel , newLevel ) ;
Emulator . getPluginManager ( ) . fireEvent ( userAchievementLeveledEvent ) ;
2019-05-26 20:14:53 +02:00
if ( userAchievementLeveledEvent . isCancelled ( ) )
2018-07-06 15:30:00 +02:00
return ;
}
habbo . getClient ( ) . sendResponse ( new AchievementProgressComposer ( habbo , achievement ) ) ;
habbo . getClient ( ) . sendResponse ( new AchievementUnlockedComposer ( habbo , achievement ) ) ;
//Exception could possibly arise when the user disconnects while being in tour.
//The achievement is then progressed but the user is already disposed so fetching
//the badge would result in an nullpointer exception. This is normal behaviour.
HabboBadge badge = null ;
2018-12-22 11:39:00 +01:00
2019-05-26 20:14:53 +02:00
if ( oldLevel ! = null ) {
try {
2018-12-22 11:39:00 +01:00
badge = habbo . getInventory ( ) . getBadgesComponent ( ) . getBadge ( ( " ACH_ " + achievement . name + oldLevel . level ) . toLowerCase ( ) ) ;
2019-05-26 20:14:53 +02:00
} catch ( Exception e ) {
2020-05-03 01:46:07 +02:00
logger . error ( " Caught exception " , e ) ;
2018-12-22 11:39:00 +01:00
return ;
}
2018-07-06 15:30:00 +02:00
}
2019-05-26 20:14:53 +02:00
if ( badge ! = null ) {
2018-07-06 15:30:00 +02:00
badge . setCode ( " ACH_ " + achievement . name + newLevel . level ) ;
badge . needsInsert ( false ) ;
badge . needsUpdate ( true ) ;
2019-05-26 20:14:53 +02:00
} else {
2018-07-06 15:30:00 +02:00
badge = new HabboBadge ( 0 , " ACH_ " + achievement . name + newLevel . level , 0 , habbo ) ;
habbo . getClient ( ) . sendResponse ( new AddUserBadgeComposer ( badge ) ) ;
badge . needsInsert ( true ) ;
badge . needsUpdate ( true ) ;
habbo . getInventory ( ) . getBadgesComponent ( ) . addBadge ( badge ) ;
}
Emulator . getThreading ( ) . run ( badge ) ;
2019-05-26 20:14:53 +02:00
if ( badge . getSlot ( ) > 0 ) {
if ( habbo . getHabboInfo ( ) . getCurrentRoom ( ) ! = null ) {
2018-07-06 15:30:00 +02:00
habbo . getHabboInfo ( ) . getCurrentRoom ( ) . sendComposer ( new UserBadgesComposer ( habbo . getInventory ( ) . getBadgesComponent ( ) . getWearingBadges ( ) , habbo . getHabboInfo ( ) . getId ( ) ) . compose ( ) ) ;
}
}
2019-05-17 22:07:22 +02:00
habbo . getClient ( ) . sendResponse ( new AddHabboItemComposer ( badge . getId ( ) , AddHabboItemComposer . AddHabboItemCategory . BADGE ) ) ;
2018-07-06 15:30:00 +02:00
habbo . getHabboStats ( ) . addAchievementScore ( newLevel . points ) ;
2019-05-26 20:14:53 +02:00
if ( newLevel . rewardAmount > 0 ) {
2019-04-22 01:42:00 +02:00
habbo . givePoints ( newLevel . rewardType , newLevel . rewardAmount ) ;
}
2019-05-26 20:14:53 +02:00
if ( habbo . getHabboInfo ( ) . getCurrentRoom ( ) ! = null ) {
2018-07-06 15:30:00 +02:00
habbo . getHabboInfo ( ) . getCurrentRoom ( ) . sendComposer ( new RoomUserDataComposer ( habbo ) . compose ( ) ) ;
}
}
}
2019-05-26 20:14:53 +02:00
public static boolean hasAchieved ( Habbo habbo , Achievement achievement ) {
2018-07-06 15:30:00 +02:00
int currentProgress = habbo . getHabboStats ( ) . getAchievementProgress ( achievement ) ;
2019-05-26 20:14:53 +02:00
if ( currentProgress = = - 1 ) {
2018-07-06 15:30:00 +02:00
return false ;
}
AchievementLevel level = achievement . getLevelForProgress ( currentProgress ) ;
2019-05-26 20:14:53 +02:00
if ( level = = null )
2018-07-06 15:30:00 +02:00
return false ;
AchievementLevel nextLevel = achievement . levels . get ( level . level + 1 ) ;
2019-03-18 02:22:00 +01:00
return nextLevel = = null & & currentProgress > = level . progress ;
2018-07-06 15:30:00 +02:00
}
2019-05-26 20:14:53 +02:00
public static void createUserEntry ( Habbo habbo , Achievement achievement ) {
try ( Connection connection = Emulator . getDatabase ( ) . getDataSource ( ) . getConnection ( ) ; PreparedStatement statement = connection . prepareStatement ( " INSERT INTO users_achievements (user_id, achievement_name, progress) VALUES (?, ?, ?) " ) ) {
2018-07-06 15:30:00 +02:00
statement . setInt ( 1 , habbo . getHabboInfo ( ) . getId ( ) ) ;
statement . setString ( 2 , achievement . name ) ;
statement . setInt ( 3 , 1 ) ;
statement . execute ( ) ;
2019-05-26 20:14:53 +02:00
} catch ( SQLException e ) {
2020-05-03 01:46:07 +02:00
logger . error ( " Caught SQL exception " , e ) ;
2018-07-06 15:30:00 +02:00
}
}
2019-05-26 20:14:53 +02:00
public static void saveAchievements ( Habbo habbo ) {
try ( Connection connection = Emulator . getDatabase ( ) . getDataSource ( ) . getConnection ( ) ; PreparedStatement statement = connection . prepareStatement ( " UPDATE users_achievements SET progress = ? WHERE achievement_name = ? AND user_id = ? LIMIT 1 " ) ) {
2018-07-06 15:30:00 +02:00
statement . setInt ( 3 , habbo . getHabboInfo ( ) . getId ( ) ) ;
2019-05-26 20:14:53 +02:00
for ( Map . Entry < Achievement , Integer > map : habbo . getHabboStats ( ) . getAchievementProgress ( ) . entrySet ( ) ) {
2018-07-06 15:30:00 +02:00
statement . setInt ( 1 , map . getValue ( ) ) ;
statement . setString ( 2 , map . getKey ( ) . name ) ;
statement . addBatch ( ) ;
}
statement . executeBatch ( ) ;
2019-05-26 20:14:53 +02:00
} catch ( SQLException e ) {
2020-05-03 01:46:07 +02:00
logger . error ( " Caught SQL exception " , e ) ;
2018-07-06 15:30:00 +02:00
}
}
2019-05-26 20:14:53 +02:00
public static int getAchievementProgressForHabbo ( int userId , Achievement achievement ) {
try ( Connection connection = Emulator . getDatabase ( ) . getDataSource ( ) . getConnection ( ) ; PreparedStatement statement = connection . prepareStatement ( " SELECT progress FROM users_achievements WHERE user_id = ? AND achievement_name = ? LIMIT 1 " ) ) {
2018-12-22 11:39:00 +01:00
statement . setInt ( 1 , userId ) ;
statement . setString ( 2 , achievement . name ) ;
2019-05-26 20:14:53 +02:00
try ( ResultSet set = statement . executeQuery ( ) ) {
if ( set . next ( ) ) {
2018-12-22 11:39:00 +01:00
return set . getInt ( " progress " ) ;
}
}
2019-05-26 20:14:53 +02:00
} catch ( SQLException e ) {
2020-05-03 01:46:07 +02:00
logger . error ( " Caught SQL exception " , e ) ;
2018-12-22 11:39:00 +01:00
}
return 0 ;
}
2019-05-26 20:14:53 +02:00
public void reload ( ) {
long millis = System . currentTimeMillis ( ) ;
synchronized ( this . achievements ) {
for ( Achievement achievement : this . achievements . values ( ) ) {
achievement . clearLevels ( ) ;
}
try ( Connection connection = Emulator . getDatabase ( ) . getDataSource ( ) . getConnection ( ) ) {
try ( Statement statement = connection . createStatement ( ) ; ResultSet set = statement . executeQuery ( " SELECT * FROM achievements " ) ) {
while ( set . next ( ) ) {
if ( ! this . achievements . containsKey ( set . getString ( " name " ) ) ) {
this . achievements . put ( set . getString ( " name " ) , new Achievement ( set ) ) ;
} else {
this . achievements . get ( set . getString ( " name " ) ) . addLevel ( new AchievementLevel ( set ) ) ;
}
}
} catch ( SQLException e ) {
2020-05-03 01:46:07 +02:00
logger . error ( " Caught SQL exception " , e ) ;
2019-05-26 20:14:53 +02:00
} catch ( Exception e ) {
2020-05-03 01:46:07 +02:00
logger . error ( " Caught exception " , e ) ;
2019-05-26 20:14:53 +02:00
}
synchronized ( this . talentTrackLevels ) {
this . talentTrackLevels . clear ( ) ;
try ( Statement statement = connection . createStatement ( ) ; ResultSet set = statement . executeQuery ( " SELECT * FROM achievements_talents ORDER BY level ASC " ) ) {
while ( set . next ( ) ) {
TalentTrackLevel level = new TalentTrackLevel ( set ) ;
if ( ! this . talentTrackLevels . containsKey ( level . type ) ) {
this . talentTrackLevels . put ( level . type , new LinkedHashMap < > ( ) ) ;
}
this . talentTrackLevels . get ( level . type ) . put ( level . level , level ) ;
}
}
}
} catch ( SQLException e ) {
2020-05-03 01:46:07 +02:00
logger . error ( " Caught SQL exception " , e ) ;
2019-05-26 20:14:53 +02:00
Emulator . getLogging ( ) . logErrorLine ( " Achievement Manager -> Failed to load! " ) ;
return ;
}
}
2020-05-03 01:46:07 +02:00
logger . info ( " Achievement Manager -> Loaded! ( " + ( System . currentTimeMillis ( ) - millis ) + " MS) " ) ;
2019-05-26 20:14:53 +02:00
}
public Achievement getAchievement ( String name ) {
return this . achievements . get ( name ) ;
}
public Achievement getAchievement ( int id ) {
synchronized ( this . achievements ) {
for ( Map . Entry < String , Achievement > set : this . achievements . entrySet ( ) ) {
if ( set . getValue ( ) . id = = id ) {
return set . getValue ( ) ;
}
}
}
return null ;
}
public THashMap < String , Achievement > getAchievements ( ) {
return this . achievements ;
}
public LinkedHashMap < Integer , TalentTrackLevel > getTalenTrackLevels ( TalentTrackType type ) {
2018-07-06 15:30:00 +02:00
return this . talentTrackLevels . get ( type ) ;
}
2019-05-26 20:14:53 +02:00
public TalentTrackLevel calculateTalenTrackLevel ( Habbo habbo , TalentTrackType type ) {
2018-07-06 15:30:00 +02:00
TalentTrackLevel level = null ;
2019-05-26 20:14:53 +02:00
for ( Map . Entry < Integer , TalentTrackLevel > entry : this . talentTrackLevels . get ( type ) . entrySet ( ) ) {
2018-07-06 15:30:00 +02:00
final boolean [ ] allCompleted = { true } ;
2019-05-26 20:14:53 +02:00
entry . getValue ( ) . achievements . forEachEntry ( new TObjectIntProcedure < Achievement > ( ) {
2018-07-06 15:30:00 +02:00
@Override
2019-05-26 20:14:53 +02:00
public boolean execute ( Achievement a , int b ) {
if ( habbo . getHabboStats ( ) . getAchievementProgress ( a ) < b ) {
2018-07-06 15:30:00 +02:00
allCompleted [ 0 ] = false ;
}
return allCompleted [ 0 ] ;
}
} ) ;
2019-05-26 20:14:53 +02:00
if ( allCompleted [ 0 ] ) {
if ( level = = null | | level . level < entry . getValue ( ) . level ) {
2018-07-06 15:30:00 +02:00
level = entry . getValue ( ) ;
}
2019-05-26 20:14:53 +02:00
} else {
2018-07-06 15:30:00 +02:00
break ;
}
}
return level ;
}
2019-05-26 20:14:53 +02:00
public void handleTalentTrackAchievement ( Habbo habbo , TalentTrackType type , Achievement achievement ) {
2018-07-06 15:30:00 +02:00
TalentTrackLevel currentLevel = this . calculateTalenTrackLevel ( habbo , type ) ;
2019-05-26 20:14:53 +02:00
if ( currentLevel ! = null ) {
if ( currentLevel . level > habbo . getHabboStats ( ) . talentTrackLevel ( type ) ) {
for ( int i = habbo . getHabboStats ( ) . talentTrackLevel ( type ) ; i < = currentLevel . level ; i + + ) {
2018-10-07 00:28:00 +02:00
TalentTrackLevel level = this . getTalentTrackLevel ( type , i ) ;
2018-07-06 15:30:00 +02:00
2019-05-26 20:14:53 +02:00
if ( level ! = null ) {
if ( level . items ! = null & & ! level . items . isEmpty ( ) ) {
for ( Item item : level . items ) {
2018-12-22 11:39:00 +01:00
HabboItem rewardItem = Emulator . getGameEnvironment ( ) . getItemManager ( ) . createItem ( habbo . getHabboInfo ( ) . getId ( ) , item , 0 , 0 , " " ) ;
habbo . getInventory ( ) . getItemsComponent ( ) . addItem ( rewardItem ) ;
habbo . getClient ( ) . sendResponse ( new AddHabboItemComposer ( rewardItem ) ) ;
habbo . getClient ( ) . sendResponse ( new InventoryRefreshComposer ( ) ) ;
}
2018-10-07 00:28:00 +02:00
}
2019-05-26 20:14:53 +02:00
if ( level . badges ! = null & & level . badges . length > 0 ) {
for ( String badge : level . badges ) {
if ( ! badge . isEmpty ( ) ) {
2018-12-22 11:39:00 +01:00
HabboBadge b = new HabboBadge ( 0 , badge , 0 , habbo ) ;
Emulator . getThreading ( ) . run ( b ) ;
habbo . getInventory ( ) . getBadgesComponent ( ) . addBadge ( b ) ;
habbo . getClient ( ) . sendResponse ( new AddUserBadgeComposer ( b ) ) ;
}
2018-10-07 00:28:00 +02:00
}
2018-07-06 15:30:00 +02:00
}
2019-05-26 20:14:53 +02:00
if ( level . perks ! = null & & level . perks . length > 0 ) {
for ( String perk : level . perks ) {
if ( perk . equalsIgnoreCase ( " TRADE " ) ) {
2018-12-22 11:39:00 +01:00
habbo . getHabboStats ( ) . perkTrade = true ;
}
2018-10-07 00:28:00 +02:00
}
}
habbo . getClient ( ) . sendResponse ( new TalentLevelUpdateComposer ( type , level ) ) ;
}
2018-07-06 15:30:00 +02:00
}
}
2018-10-07 00:28:00 +02:00
habbo . getHabboStats ( ) . setTalentLevel ( type , currentLevel . level ) ;
}
2018-07-06 15:30:00 +02:00
}
2019-05-26 20:14:53 +02:00
public TalentTrackLevel getTalentTrackLevel ( TalentTrackType type , int level ) {
2018-07-06 15:30:00 +02:00
return this . talentTrackLevels . get ( type ) . get ( level ) ;
}
}