2013-01-24 22:35:28 +01:00
package com.Acrobot.ChestShop.Metadata ;
import com.Acrobot.Breeze.Utils.Encoding.Base62 ;
import com.Acrobot.Breeze.Utils.Encoding.Base64 ;
2019-03-30 15:40:31 +01:00
import com.Acrobot.ChestShop.ChestShop ;
2015-05-22 13:26:07 +02:00
import com.Acrobot.ChestShop.Database.DaoCreator ;
import com.Acrobot.ChestShop.Database.Item ;
2019-03-30 15:40:31 +01:00
import com.j256.ormlite.dao.CloseableIterator ;
2015-05-22 13:26:07 +02:00
import com.j256.ormlite.dao.Dao ;
2019-07-29 19:50:26 +02:00
import com.j256.ormlite.stmt.SelectArg ;
2019-03-30 15:40:31 +01:00
import org.bukkit.Material ;
import org.bukkit.configuration.file.YamlConfiguration ;
2013-01-24 22:35:28 +01:00
import org.bukkit.configuration.file.YamlConstructor ;
import org.bukkit.configuration.file.YamlRepresenter ;
import org.bukkit.inventory.ItemStack ;
2019-03-30 15:40:31 +01:00
import org.bukkit.inventory.meta.ItemMeta ;
2013-01-24 22:35:28 +01:00
import org.yaml.snakeyaml.DumperOptions ;
import org.yaml.snakeyaml.Yaml ;
2019-04-06 19:39:49 +02:00
import org.yaml.snakeyaml.error.YAMLException ;
2015-05-22 13:26:07 +02:00
import org.yaml.snakeyaml.nodes.Tag ;
2013-01-24 22:35:28 +01:00
2019-03-30 15:40:31 +01:00
import java.io.File ;
2013-01-24 22:35:28 +01:00
import java.io.IOException ;
import java.sql.SQLException ;
2019-03-30 15:40:31 +01:00
import java.util.Map ;
import java.util.concurrent.atomic.AtomicInteger ;
import java.util.logging.Level ;
2013-01-24 22:35:28 +01:00
/ * *
* Saves items with Metadata in database , which allows for saving items on signs easily .
2013-07-21 16:49:55 +02:00
*
2013-01-24 22:35:28 +01:00
* @author Acrobot
* /
public class ItemDatabase {
2015-05-22 13:26:07 +02:00
private Dao < Item , Integer > itemDao ;
2013-08-05 02:06:13 +02:00
private final Yaml yaml ;
2013-01-24 22:35:28 +01:00
public ItemDatabase ( ) {
2015-05-22 13:26:07 +02:00
yaml = new Yaml ( new YamlBukkitConstructor ( ) , new YamlRepresenter ( ) , new DumperOptions ( ) ) ;
2013-01-24 22:35:28 +01:00
try {
2015-05-22 13:26:07 +02:00
itemDao = DaoCreator . getDaoAndCreateTable ( Item . class ) ;
2019-03-30 15:40:31 +01:00
handleMetadataUpdate ( ) ;
2013-01-24 22:35:28 +01:00
} catch ( SQLException e ) {
2023-03-01 18:27:04 +01:00
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " Error while loading items database " , e ) ;
2013-01-24 22:35:28 +01:00
}
}
2019-03-30 15:40:31 +01:00
private void handleMetadataUpdate ( ) {
File configFile = ChestShop . loadFile ( " version " ) ;
YamlConfiguration versionConfig = YamlConfiguration . loadConfiguration ( configFile ) ;
int previousVersion = versionConfig . getInt ( " metadata-version " , - 1 ) ;
int newVersion = getCurrentMetadataVersion ( ) ;
if ( previousVersion < newVersion ) {
if ( updateMetadataVersion ( previousVersion , newVersion ) ) {
versionConfig . set ( " metadata-version " , newVersion ) ;
try {
versionConfig . save ( configFile ) ;
} catch ( IOException e ) {
2023-03-01 18:27:04 +01:00
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " Error while updating metadata-version from " + previousVersion + " to " + newVersion , e ) ;
2019-03-30 15:40:31 +01:00
}
} else {
ChestShop . getBukkitLogger ( ) . log ( Level . WARNING , " Error while updating Item Metadata database! While the plugin will still run it will work less efficiently. " ) ;
}
}
}
private int getCurrentMetadataVersion ( ) {
ItemStack item = new ItemStack ( Material . STONE ) ;
ItemMeta meta = item . getItemMeta ( ) ;
2023-03-01 17:42:35 +01:00
if ( meta ! = null ) {
meta . setDisplayName ( " GetCurrentMetadataVersion " ) ;
item . setItemMeta ( meta ) ;
}
2019-03-30 15:40:31 +01:00
Map < String , Object > serialized = item . serialize ( ) ;
return ( int ) serialized . getOrDefault ( " v " , - 1 ) ;
}
private boolean updateMetadataVersion ( int previousVersion , int newVersion ) {
if ( previousVersion > - 1 ) {
ChestShop . getBukkitLogger ( ) . info ( " Data version change detected! Previous version was " + previousVersion ) ;
}
ChestShop . getBukkitLogger ( ) . info ( " Updating Item Metadata database to data version " + newVersion + " ... " ) ;
AtomicInteger i = new AtomicInteger ( ) ;
AtomicInteger updated = new AtomicInteger ( ) ;
CloseableIterator < Item > it = itemDao . iterator ( ) ;
long start = System . currentTimeMillis ( ) ;
try {
itemDao . callBatchTasks ( ( ) - > {
while ( it . hasNext ( ) ) {
i . getAndIncrement ( ) ;
Item item = it . next ( ) ;
try {
String serialized = ( String ) Base64 . decodeToObject ( item . getBase64ItemCode ( ) ) ;
if ( previousVersion < 0 | | ! serialized . contains ( " \ nv: " + newVersion + " \ n " ) ) { // Hacky way to quickly check the version as it's not too big of an issue if some items don't convert
2019-04-06 19:39:49 +02:00
try {
ItemStack itemStack = yaml . loadAs ( serialized , ItemStack . class ) ;
item . setBase64ItemCode ( Base64 . encodeObject ( yaml . dump ( itemStack ) ) ) ;
itemDao . update ( item ) ;
updated . getAndIncrement ( ) ;
} catch ( YAMLException e ) {
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " YAML of the item with ID " + Base62 . encode ( item . getId ( ) ) + " ( " + item . getId ( ) + " ) is corrupted: \ n " + serialized ) ;
}
2019-03-30 15:40:31 +01:00
}
} catch ( IOException | ClassNotFoundException | SQLException e ) {
2019-04-06 19:39:49 +02:00
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " Unable to convert item with ID " + Base62 . encode ( item . getId ( ) ) + " ( " + item . getId ( ) + " ) " , e ) ;
} catch ( StackOverflowError e ) {
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " Item with ID " + Base62 . encode ( item . getId ( ) ) + " ( " + item . getId ( ) + " ) is corrupted. Sorry :( " ) ;
2019-03-30 15:40:31 +01:00
}
if ( i . get ( ) % 1000 = = 0 ) {
ChestShop . getBukkitLogger ( ) . info ( " Checked " + i + " items. Updated " + updated + " ... " ) ;
}
}
return true ;
} ) ;
} catch ( Exception e ) {
2023-03-01 17:42:35 +01:00
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " Unable to update metadata version of all items from " + previousVersion + " to " + newVersion , e ) ;
2019-03-30 15:40:31 +01:00
return false ;
} finally {
it . closeQuietly ( ) ;
}
ChestShop . getBukkitLogger ( ) . info ( " Finished updating database in " + ( System . currentTimeMillis ( ) - start ) / 1000 . 0 + " s. " +
2019-04-06 19:39:49 +02:00
updated + " items out of " + i + " were updated! " ) ;
2019-03-30 15:40:31 +01:00
return true ;
}
2013-01-24 22:35:28 +01:00
/ * *
* Gets the item code for this item
*
* @param item Item
* @return Item code for this item
* /
public String getItemCode ( ItemStack item ) {
try {
2013-10-27 16:50:04 +01:00
ItemStack clone = new ItemStack ( item ) ;
2013-10-01 19:12:40 +02:00
clone . setAmount ( 1 ) ;
2015-05-22 13:26:07 +02:00
clone . setDurability ( ( short ) 0 ) ;
2013-10-01 19:12:40 +02:00
2019-07-08 19:05:50 +02:00
String dumped = yaml . dump ( clone ) ;
ItemStack loadedItem = yaml . loadAs ( dumped , ItemStack . class ) ;
if ( ! loadedItem . isSimilar ( item ) ) {
dumped = yaml . dump ( loadedItem ) ;
2015-05-22 13:26:07 +02:00
}
2019-07-08 19:05:50 +02:00
String code = Base64 . encodeObject ( dumped ) ;
2015-05-22 13:26:07 +02:00
2019-07-29 19:50:26 +02:00
Item itemEntity = itemDao . queryBuilder ( ) . where ( ) . eq ( " code " , new SelectArg ( code ) ) . queryForFirst ( ) ;
2019-07-08 19:05:50 +02:00
if ( itemEntity = = null ) {
itemEntity = new Item ( code ) ;
itemDao . create ( itemEntity ) ;
}
return Base62 . encode ( itemEntity . getId ( ) ) ;
2023-03-01 17:42:35 +01:00
} catch ( SQLException | IOException e ) {
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " Unable to get code of item " + item , e ) ;
2013-01-24 22:35:28 +01:00
}
2015-05-22 13:26:07 +02:00
return null ;
2013-01-24 22:35:28 +01:00
}
/ * *
* Gets an ItemStack from a item code
*
* @param code Item code
* @return ItemStack represented by this code
* /
2016-10-13 18:11:23 +02:00
public ItemStack getFromCode ( String code )
{
// TODO java.lang.StackOverflowError - http://pastebin.com/eRD8wUFM - Corrupt item DB?
2019-04-06 19:39:49 +02:00
int id = Base62 . decode ( code ) ;
2013-01-24 22:35:28 +01:00
try {
2019-07-29 19:50:26 +02:00
Item item = itemDao . queryBuilder ( ) . where ( ) . eq ( " id " , new SelectArg ( id ) ) . queryForFirst ( ) ;
2013-01-24 22:35:28 +01:00
2015-05-22 13:26:07 +02:00
if ( item = = null ) {
2013-01-24 22:35:28 +01:00
return null ;
}
2015-05-22 13:26:07 +02:00
String serialized = item . getBase64ItemCode ( ) ;
2013-08-05 02:06:13 +02:00
2019-04-06 19:39:49 +02:00
try {
return yaml . loadAs ( ( String ) Base64 . decodeToObject ( serialized ) , ItemStack . class ) ;
} catch ( YAMLException e ) {
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " YAML of the item with ID " + Base62 . encode ( item . getId ( ) ) + " ( " + item . getId ( ) + " ) is corrupted: \ n " + serialized ) ;
}
} catch ( IOException | ClassNotFoundException | SQLException | YAMLException e ) {
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " Unable to load item with ID " + code + " ( " + id + " ) " , e ) ;
} catch ( StackOverflowError e ) {
ChestShop . getBukkitLogger ( ) . log ( Level . SEVERE , " Item with ID " + code + " ( " + id + " ) is corrupted. Sorry :( " ) ;
2013-01-24 22:35:28 +01:00
}
2015-05-22 13:26:07 +02:00
return null ;
}
2023-03-01 17:42:35 +01:00
private static class YamlBukkitConstructor extends YamlConstructor {
2015-05-22 13:26:07 +02:00
public YamlBukkitConstructor ( ) {
this . yamlConstructors . put ( new Tag ( Tag . PREFIX + " org.bukkit.inventory.ItemStack " ) , yamlConstructors . get ( Tag . MAP ) ) ;
}
2013-01-24 22:35:28 +01:00
}
}