Single class IdFactory with synchronized static methods.

This commit is contained in:
MobiusDevelopment
2020-02-08 14:34:00 +00:00
parent 29771aa0d8
commit a534cc943c
497 changed files with 4701 additions and 10894 deletions
-20
View File
@@ -1,20 +0,0 @@
# ---------------------------------------------------------------------------
# ID Factory Settings
# ---------------------------------------------------------------------------
# Warning:
# Please take extreme caution when changing anything. Also please understand what you are changing before you do so on a live server.
# ---------------------------------------------------------------------------
# Standard Settings
# ---------------------------------------------------------------------------
# Tell server which IDFactory Class to use:
# BITSET = One non compaction method
# STACK = Another non compaction method
# Default: BITSET
IDFactory = BITSET
# Check for bad ids in the database on server boot up.
# Much faster load time without it, but may cause problems.
# Default: True
BadIdChecking = True
@@ -55,7 +55,6 @@ import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.l2jmobius.commons.enums.IdFactoryType;
import org.l2jmobius.commons.enums.ServerMode; import org.l2jmobius.commons.enums.ServerMode;
import org.l2jmobius.commons.util.IXmlReader; import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.commons.util.PropertiesParser; import org.l2jmobius.commons.util.PropertiesParser;
@@ -96,7 +95,6 @@ public class Config
private static final String GENERAL_CONFIG_FILE = "./config/General.ini"; private static final String GENERAL_CONFIG_FILE = "./config/General.ini";
private static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini"; private static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini";
private static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini"; private static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini";
private static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini";
private static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini"; private static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini";
private static final String NPC_CONFIG_FILE = "./config/NPC.ini"; private static final String NPC_CONFIG_FILE = "./config/NPC.ini";
private static final String PVP_CONFIG_FILE = "./config/PVP.ini"; private static final String PVP_CONFIG_FILE = "./config/PVP.ini";
@@ -802,9 +800,6 @@ public class Config
public static int MAX_REPUTATION; public static int MAX_REPUTATION;
public static int REPUTATION_INCREASE; public static int REPUTATION_INCREASE;
public static IdFactoryType IDFACTORY_TYPE;
public static boolean BAD_ID_CHECKING;
public static int[] ENCHANT_BLACKLIST; public static int[] ENCHANT_BLACKLIST;
public static boolean DISABLE_OVER_ENCHANTING; public static boolean DISABLE_OVER_ENCHANTING;
public static int[] AUGMENTATION_BLACKLIST; public static int[] AUGMENTATION_BLACKLIST;
@@ -1932,12 +1927,6 @@ public class Config
TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0); TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0);
TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0); TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0);
// Load IdFactory config file (if exists)
final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE);
IDFACTORY_TYPE = IdFactory.getEnum("IDFactory", IdFactoryType.class, IdFactoryType.BITSET);
BAD_ID_CHECKING = IdFactory.getBoolean("BadIdChecking", true);
// Load General config file (if exists) // Load General config file (if exists)
final PropertiesParser General = new PropertiesParser(GENERAL_CONFIG_FILE); final PropertiesParser General = new PropertiesParser(GENERAL_CONFIG_FILE);
DEFAULT_ACCESS_LEVEL = General.getInt("DefaultAccessLevel", 0); DEFAULT_ACCESS_LEVEL = General.getInt("DefaultAccessLevel", 0);
@@ -1,26 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.commons.enums;
/**
* @author Mobius
*/
public enum IdFactoryType
{
BITSET,
STACK
}
@@ -205,7 +205,8 @@ public class GameServer
ThreadPool.init(); ThreadPool.init();
printSection("IdFactory"); printSection("IdFactory");
if (!IdFactory.getInstance().isInitialized()) IdFactory.init();
if (!IdFactory.hasInitialized())
{ {
LOGGER.severe(getClass().getSimpleName() + ": Could not read object IDs from database. Please check your configuration."); LOGGER.severe(getClass().getSimpleName() + ": Could not read object IDs from database. Please check your configuration.");
throw new Exception("Could not initialize the ID factory!"); throw new Exception("Could not initialize the ID factory!");
@@ -416,7 +417,7 @@ public class GameServer
Runtime.getRuntime().addShutdownHook(Shutdown.getInstance()); Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.getInstance().size()); LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.size());
if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS) if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
{ {
@@ -188,7 +188,7 @@ public class ClanTable
return null; return null;
} }
final Clan clan = new Clan(IdFactory.getInstance().getNextId(), clanName); final Clan clan = new Clan(IdFactory.getNextId(), clanName);
final ClanMember leader = new ClanMember(clan, player); final ClanMember leader = new ClanMember(clan, player);
clan.setLeader(leader); clan.setLeader(leader);
leader.setPlayerInstance(player); leader.setPlayerInstance(player);
@@ -260,7 +260,7 @@ public class ClanTable
} }
_clans.remove(clanId); _clans.remove(clanId);
IdFactory.getInstance().releaseId(clanId); IdFactory.releaseId(clanId);
try (Connection con = DatabaseFactory.getConnection()) try (Connection con = DatabaseFactory.getConnection())
{ {
@@ -210,7 +210,7 @@ public class ItemTable
public ItemInstance createItem(String process, int itemId, long count, Creature actor, Object reference) public ItemInstance createItem(String process, int itemId, long count, Creature actor, Object reference)
{ {
// Create and Init the ItemInstance corresponding to the Item Identifier // Create and Init the ItemInstance corresponding to the Item Identifier
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), itemId);
if (process.equalsIgnoreCase("loot") && !Config.AUTO_LOOT_ITEM_IDS.contains(itemId)) if (process.equalsIgnoreCase("loot") && !Config.AUTO_LOOT_ITEM_IDS.contains(itemId))
{ {
@@ -328,7 +328,7 @@ public class ItemTable
item.setLastChange(ItemInstance.REMOVED); item.setLastChange(ItemInstance.REMOVED);
World.getInstance().removeObject(item); World.getInstance().removeObject(item);
IdFactory.getInstance().releaseId(item.getObjectId()); IdFactory.releaseId(item.getObjectId());
if (Config.LOG_ITEMS) if (Config.LOG_ITEMS)
{ {
@@ -1,151 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.idfactory;
import java.util.BitSet;
import java.util.concurrent.atomic.AtomicInteger;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.util.PrimeFinder;
/**
* This class ..
* @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
*/
public class BitSetIDFactory extends IdFactory
{
private BitSet _freeIds;
private AtomicInteger _freeIdCount;
private AtomicInteger _nextFreeId;
protected class BitSetCapacityCheck implements Runnable
{
@Override
public void run()
{
synchronized (BitSetIDFactory.this)
{
if (reachingBitSetCapacity())
{
increaseBitSetCapacity();
}
}
}
}
protected BitSetIDFactory()
{
super();
synchronized (BitSetIDFactory.class)
{
ThreadPool.scheduleAtFixedRate(new BitSetCapacityCheck(), 30000, 30000);
initialize();
}
LOGGER.info(getClass().getSimpleName() + ": " + _freeIds.size() + " id's available.");
}
public void initialize()
{
try
{
_freeIds = new BitSet(PrimeFinder.nextPrime(100000));
_freeIds.clear();
_freeIdCount = new AtomicInteger(FREE_OBJECT_ID_SIZE);
for (int usedObjectId : extractUsedObjectIDTable())
{
final int objectID = usedObjectId - FIRST_OID;
if (objectID < 0)
{
LOGGER.warning(getClass().getSimpleName() + ": Object ID " + usedObjectId + " in DB is less than minimum ID of " + FIRST_OID);
continue;
}
_freeIds.set(usedObjectId - FIRST_OID);
_freeIdCount.decrementAndGet();
}
_nextFreeId = new AtomicInteger(_freeIds.nextClearBit(0));
_initialized = true;
}
catch (Exception e)
{
_initialized = false;
LOGGER.severe(getClass().getSimpleName() + ": Could not be initialized properly: " + e.getMessage());
}
}
@Override
public synchronized void releaseId(int objectID)
{
if ((objectID - FIRST_OID) > -1)
{
_freeIds.clear(objectID - FIRST_OID);
_freeIdCount.incrementAndGet();
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Release objectID " + objectID + " failed (< " + FIRST_OID + ")");
}
}
@Override
public synchronized int getNextId()
{
final int newID = _nextFreeId.get();
_freeIds.set(newID);
_freeIdCount.decrementAndGet();
final int nextFree = _freeIds.nextClearBit(newID) < 0 ? _freeIds.nextClearBit(0) : _freeIds.nextClearBit(newID);
if (nextFree < 0)
{
if (_freeIds.size() >= FREE_OBJECT_ID_SIZE)
{
throw new NullPointerException("Ran out of valid Id's.");
}
increaseBitSetCapacity();
}
_nextFreeId.set(nextFree);
return newID + FIRST_OID;
}
@Override
public synchronized int size()
{
return _freeIdCount.get();
}
protected synchronized int usedIdCount()
{
return _freeIdCount.get() - FIRST_OID;
}
protected synchronized boolean reachingBitSetCapacity()
{
return PrimeFinder.nextPrime((usedIdCount() * 11) / 10) > _freeIds.size();
}
protected synchronized void increaseBitSetCapacity()
{
final BitSet newBitSet = new BitSet(PrimeFinder.nextPrime((usedIdCount() * 11) / 10));
newBitSet.or(_freeIds);
_freeIds = newBitSet;
}
}
@@ -19,23 +19,25 @@ package org.l2jmobius.gameserver.idfactory;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.gameserver.util.PrimeFinder;
/** /**
* @version $Revision: 1.3.2.1.2.7 $ $Date: 2005/04/11 10:06:12 $ * @author Mobius (reworked from L2J version)
*/ */
public abstract class IdFactory public abstract class IdFactory
{ {
protected final Logger LOGGER = Logger.getLogger(getClass().getName()); private static final Logger LOGGER = Logger.getLogger(IdFactory.class.getName());
protected static final String[] ID_CHECKS = protected static final String[] ID_CHECKS =
{ {
@@ -64,7 +66,6 @@ public abstract class IdFactory
"SELECT object_id FROM itemsonground WHERE object_id >= ? AND object_id < ?", "SELECT object_id FROM itemsonground WHERE object_id >= ? AND object_id < ?",
"SELECT summonId FROM characters_summons WHERE summonId >= ? AND summonId < ?" "SELECT summonId FROM characters_summons WHERE summonId >= ? AND summonId < ?"
}; };
//@formatter:off //@formatter:off
private static final String[][] ID_EXTRACTS = private static final String[][] ID_EXTRACTS =
{ {
@@ -75,183 +76,121 @@ public abstract class IdFactory
{"messages","messageId"} {"messages","messageId"}
}; };
//@formatter:on //@formatter:on
private static final String[] TIMESTAMPS_CLEAN = private static final String[] TIMESTAMPS_CLEAN =
{ {
"DELETE FROM character_instance_time WHERE time <= ?", "DELETE FROM character_instance_time WHERE time <= ?",
"DELETE FROM character_skills_save WHERE restore_type = 1 AND systime <= ?" "DELETE FROM character_skills_save WHERE restore_type = 1 AND systime <= ?"
}; };
protected boolean _initialized;
public static final int FIRST_OID = 0x10000000; public static final int FIRST_OID = 0x10000000;
public static final int LAST_OID = 0x7FFFFFFF; public static final int LAST_OID = 0x7FFFFFFF;
public static final int FREE_OBJECT_ID_SIZE = LAST_OID - FIRST_OID; public static final int FREE_OBJECT_ID_SIZE = LAST_OID - FIRST_OID;
protected static final IdFactory _instance; private static BitSet _freeIds;
private static AtomicInteger _freeIdCount;
private static AtomicInteger _nextFreeId;
private static boolean _initialized;
protected IdFactory() public static void init()
{
setAllCharacterOffline();
if (Config.DATABASE_CLEAN_UP)
{
cleanUpDB();
}
cleanUpTimeStamps();
}
static
{
switch (Config.IDFACTORY_TYPE)
{
case BITSET:
{
_instance = new BitSetIDFactory();
break;
}
case STACK:
{
_instance = new StackIDFactory();
break;
}
default:
{
_instance = null;
break;
}
}
}
/**
* Sets all character offline
*/
private void setAllCharacterOffline()
{ {
// Update characters online status.
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
Statement s = con.createStatement()) Statement s = con.createStatement())
{ {
s.executeUpdate("UPDATE characters SET online = 0"); s.executeUpdate("UPDATE characters SET online = 0");
LOGGER.info("Updated characters online status."); LOGGER.info("Updated characters online status.");
} }
catch (SQLException e) catch (Exception e)
{ {
LOGGER.log(Level.WARNING, "Could not update characters online status: " + e.getMessage(), e); LOGGER.warning("IdFactory: Could not update characters online status: " + e);
} }
}
// Cleanup database.
/** if (Config.DATABASE_CLEAN_UP)
* Cleans up Database
*/
private void cleanUpDB()
{
try (Connection con = DatabaseFactory.getConnection();
Statement stmt = con.createStatement())
{ {
final long cleanupStart = System.currentTimeMillis(); try (Connection con = DatabaseFactory.getConnection();
int cleanCount = 0; Statement stmt = con.createStatement())
// Misc/Account Related {
// Please read the descriptions above each before uncommenting them. If you are still final long cleanupStart = System.currentTimeMillis();
// unsure of what exactly it does, leave it commented out. This is for those who know int cleanCount = 0;
// what they are doing. :)
// Characters
// Deletes only accounts that HAVE been logged into and have no characters associated cleanCount += stmt.executeUpdate("DELETE FROM account_gsdata WHERE account_gsdata.account_name NOT IN (SELECT account_name FROM characters);");
// with the account. cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.contactId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.lastactive > 0 AND accounts.login NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.friendId NOT IN (SELECT charId FROM characters);");
// Deletes any accounts that don't have characters. Whether or not the player has ever cleanCount += stmt.executeUpdate("DELETE FROM character_hennas WHERE character_hennas.charId NOT IN (SELECT charId FROM characters);");
// logged into the account. cleanCount += stmt.executeUpdate("DELETE FROM character_macroses WHERE character_macroses.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_quests WHERE character_quests.charId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.login NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_recipebook WHERE character_recipebook.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipeshoplist WHERE character_recipeshoplist.charId NOT IN (SELECT charId FROM characters);");
// Deletes banned accounts that have not been logged into for xx amount of days cleanCount += stmt.executeUpdate("DELETE FROM character_shortcuts WHERE character_shortcuts.charId NOT IN (SELECT charId FROM characters);");
// (specified at the end of the script, default is set to 90 days). This prevents cleanCount += stmt.executeUpdate("DELETE FROM character_skills WHERE character_skills.charId NOT IN (SELECT charId FROM characters);");
// accounts from being deleted that were accidentally or temporarily banned. cleanCount += stmt.executeUpdate("DELETE FROM character_skills_save WHERE character_skills_save.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_subclasses WHERE character_subclasses.charId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.accessLevel < 0 AND DATEDIFF(CURRENT_DATE( ) , FROM_UNIXTIME(`lastactive`/1000)) > 90;"); cleanCount += stmt.executeUpdate("DELETE FROM character_instance_time WHERE character_instance_time.charId NOT IN (SELECT charId FROM characters);");
// cleanCount +=
// stmt.executeUpdate("DELETE FROM characters WHERE characters.account_name NOT IN (SELECT login FROM accounts);"); // Items
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id NOT IN (SELECT charId FROM characters) AND items.owner_id NOT IN (SELECT clan_id FROM clan_data) AND items.owner_id != -1;");
// If the character does not exist... cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id = -1 AND loc LIKE 'MAIL' AND loc_data NOT IN (SELECT messageId FROM messages WHERE senderId = -1);");
// Characters cleanCount += stmt.executeUpdate("DELETE FROM item_auction_bid WHERE item_auction_bid.playerObjId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM account_gsdata WHERE account_gsdata.account_name NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_variations WHERE item_variations.itemId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_elementals WHERE item_elementals.itemId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.contactId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_special_abilities WHERE item_special_abilities.objectId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_variables WHERE item_variables.id NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.friendId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_hennas WHERE character_hennas.charId NOT IN (SELECT charId FROM characters);"); // Misc
cleanCount += stmt.executeUpdate("DELETE FROM character_macroses WHERE character_macroses.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM cursed_weapons WHERE cursed_weapons.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_quests WHERE character_quests.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM heroes WHERE heroes.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipebook WHERE character_recipebook.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles WHERE olympiad_nobles.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipeshoplist WHERE character_recipeshoplist.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles_eom WHERE olympiad_nobles_eom.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_shortcuts WHERE character_shortcuts.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM pets WHERE pets.item_obj_id NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_skills WHERE character_skills.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM merchant_lease WHERE merchant_lease.player_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_skills_save WHERE character_skills_save.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_reco_bonus WHERE character_reco_bonus.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_subclasses WHERE character_subclasses.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.leader_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_instance_time WHERE character_instance_time.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.clan_id NOT IN (SELECT clanid FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charOneId NOT IN (SELECT charId FROM characters);");
// Items cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charTwoId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id NOT IN (SELECT charId FROM characters) AND items.owner_id NOT IN (SELECT clan_id FROM clan_data) AND items.owner_id != -1;"); cleanCount += stmt.executeUpdate("DELETE FROM heroes_diary WHERE heroes_diary.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id = -1 AND loc LIKE 'MAIL' AND loc_data NOT IN (SELECT messageId FROM messages WHERE senderId = -1);"); cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade WHERE character_offline_trade.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_auction_bid WHERE item_auction_bid.playerObjId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_variations WHERE item_variations.itemId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_elementals WHERE item_elementals.itemId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_special_abilities WHERE item_special_abilities.objectId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_variables WHERE item_variables.id NOT IN (SELECT object_id FROM items);");
// Clan
// Misc cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM cursed_weapons WHERE cursed_weapons.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_skills WHERE clan_skills.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM heroes WHERE heroes.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_subpledges WHERE clan_subpledges.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles WHERE olympiad_nobles.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan1 NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles_eom WHERE olympiad_nobles_eom.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan2 NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM pets WHERE pets.item_obj_id NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM siege_clans WHERE siege_clans.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM merchant_lease WHERE merchant_lease.player_id NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_notices WHERE clan_notices.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM character_reco_bonus WHERE character_reco_bonus.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM auction_bid WHERE auction_bid.bidderId NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.leader_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.clan_id NOT IN (SELECT clanid FROM characters);"); // Forums
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charOneId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT clan_id FROM clan_data) AND forums.forum_parent=2;");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charTwoId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT charId FROM characters) AND forums.forum_parent=3;");
cleanCount += stmt.executeUpdate("DELETE FROM heroes_diary WHERE heroes_diary.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM posts WHERE posts.post_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade WHERE character_offline_trade.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM topic WHERE topic.topic_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); // Update needed items after cleaning has taken place.
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
// If the clan does not exist... stmt.executeUpdate("UPDATE castle SET side='NEUTRAL' WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_skills WHERE clan_skills.clan_id NOT IN (SELECT clan_id FROM clan_data);"); stmt.executeUpdate("UPDATE fort SET owner=0 WHERE owner NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_subpledges WHERE clan_subpledges.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan1 NOT IN (SELECT clan_id FROM clan_data);"); LOGGER.info("IdFactory: Cleaned " + cleanCount + " elements from database in " + ((System.currentTimeMillis() - cleanupStart) / 1000) + " seconds.");
cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan2 NOT IN (SELECT clan_id FROM clan_data);"); }
cleanCount += stmt.executeUpdate("DELETE FROM siege_clans WHERE siege_clans.clan_id NOT IN (SELECT clan_id FROM clan_data);"); catch (Exception e)
cleanCount += stmt.executeUpdate("DELETE FROM clan_notices WHERE clan_notices.clan_id NOT IN (SELECT clan_id FROM clan_data);"); {
cleanCount += stmt.executeUpdate("DELETE FROM auction_bid WHERE auction_bid.bidderId NOT IN (SELECT clan_id FROM clan_data);"); LOGGER.warning("IdFactory: Could not clean up database: " + e);
}
// Forum Related
cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT clan_id FROM clan_data) AND forums.forum_parent=2;");
cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT charId FROM characters) AND forums.forum_parent=3;");
cleanCount += stmt.executeUpdate("DELETE FROM posts WHERE posts.post_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM topic WHERE topic.topic_forum_id NOT IN (SELECT forum_id FROM forums);");
// Update needed items after cleaning has taken place.
stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
stmt.executeUpdate("UPDATE castle SET side='NEUTRAL' WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");
stmt.executeUpdate("UPDATE fort SET owner=0 WHERE owner NOT IN (SELECT clan_id FROM clan_data);");
LOGGER.info("Cleaned " + cleanCount + " elements from database in " + ((System.currentTimeMillis() - cleanupStart) / 1000) + " s");
} }
catch (SQLException e)
{ // Cleanup timestamps.
LOGGER.log(Level.WARNING, "Could not clean up database: " + e.getMessage(), e);
}
}
private void cleanUpTimeStamps()
{
try (Connection con = DatabaseFactory.getConnection()) try (Connection con = DatabaseFactory.getConnection())
{ {
int cleanCount = 0; int cleanCount = 0;
@@ -263,62 +202,136 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate(); cleanCount += stmt.executeUpdate();
} }
} }
LOGGER.info("Cleaned " + cleanCount + " expired timestamps from database."); LOGGER.info("IdFactory: Cleaned " + cleanCount + " expired timestamps from database.");
} }
catch (SQLException e) catch (Exception e)
{ {
// Ignore. LOGGER.warning("IdFactory: Could not clean expired timestamps from database. " + e);
} }
}
// Initialize.
/** try
* @return
* @throws Exception
* @throws SQLException
*/
protected final Integer[] extractUsedObjectIDTable() throws Exception
{
final List<Integer> temp = new ArrayList<>();
try (Connection con = DatabaseFactory.getConnection();
Statement s = con.createStatement())
{ {
String extractUsedObjectIdsQuery = ""; _freeIds = new BitSet(PrimeFinder.nextPrime(100000));
_freeIds.clear();
_freeIdCount = new AtomicInteger(FREE_OBJECT_ID_SIZE);
for (String[] tblClmn : ID_EXTRACTS) // Collect already used ids.
final List<Integer> usedIds = new ArrayList<>();
try (Connection con = DatabaseFactory.getConnection();
Statement statement = con.createStatement())
{ {
extractUsedObjectIdsQuery += "SELECT " + tblClmn[1] + " FROM " + tblClmn[0] + " UNION "; String extractUsedObjectIdsQuery = "";
} for (String[] tblClmn : ID_EXTRACTS)
extractUsedObjectIdsQuery = extractUsedObjectIdsQuery.substring(0, extractUsedObjectIdsQuery.length() - 7); // Remove the last " UNION "
try (ResultSet rs = s.executeQuery(extractUsedObjectIdsQuery))
{
while (rs.next())
{ {
temp.add(rs.getInt(1)); extractUsedObjectIdsQuery += "SELECT " + tblClmn[1] + " FROM " + tblClmn[0] + " UNION ";
}
extractUsedObjectIdsQuery = extractUsedObjectIdsQuery.substring(0, extractUsedObjectIdsQuery.length() - 7); // Remove the last " UNION "
try (ResultSet result = statement.executeQuery(extractUsedObjectIdsQuery))
{
while (result.next())
{
usedIds.add(result.getInt(1));
}
} }
} }
Collections.sort(usedIds);
// Register used ids.
for (int usedObjectId : usedIds)
{
final int objectId = usedObjectId - FIRST_OID;
if (objectId < 0)
{
LOGGER.warning("IdFactory: Object ID " + usedObjectId + " in DB is less than minimum ID of " + FIRST_OID);
continue;
}
_freeIds.set(usedObjectId - FIRST_OID);
_freeIdCount.decrementAndGet();
}
_nextFreeId = new AtomicInteger(_freeIds.nextClearBit(0));
_initialized = true;
} }
Collections.sort(temp); catch (Exception e)
return temp.toArray(new Integer[temp.size()]); {
_initialized = false;
LOGGER.severe("IdFactory: Could not be initialized properly: " + e.getMessage());
}
// Schedule increase capacity task.
ThreadPool.scheduleAtFixedRate(() ->
{
synchronized (_nextFreeId)
{
if (PrimeFinder.nextPrime((usedIdCount() * 11) / 10) > _freeIds.size())
{
increaseBitSetCapacity();
}
}
}, 30000, 30000);
LOGGER.info("IdFactory: " + _freeIds.size() + " id's available.");
} }
public boolean isInitialized() public synchronized static void releaseId(int objectId)
{
synchronized (_nextFreeId)
{
if ((objectId - FIRST_OID) > -1)
{
_freeIds.clear(objectId - FIRST_OID);
_freeIdCount.incrementAndGet();
}
else
{
LOGGER.warning("IdFactory: Release objectID " + objectId + " failed (< " + FIRST_OID + ")");
}
}
}
public synchronized static int getNextId()
{
synchronized (_nextFreeId)
{
final int newId = _nextFreeId.get();
_freeIds.set(newId);
_freeIdCount.decrementAndGet();
final int nextFree = _freeIds.nextClearBit(newId) < 0 ? _freeIds.nextClearBit(0) : _freeIds.nextClearBit(newId);
if (nextFree < 0)
{
if (_freeIds.size() >= FREE_OBJECT_ID_SIZE)
{
throw new NullPointerException("IdFactory: Ran out of valid ids.");
}
increaseBitSetCapacity();
}
_nextFreeId.set(nextFree);
return newId + FIRST_OID;
}
}
private static void increaseBitSetCapacity()
{
final BitSet newBitSet = new BitSet(PrimeFinder.nextPrime((usedIdCount() * 11) / 10));
newBitSet.or(_freeIds);
_freeIds = newBitSet;
}
private static int usedIdCount()
{
return _freeIdCount.get() - FIRST_OID;
}
public static int size()
{
return _freeIdCount.get();
}
public static boolean hasInitialized()
{ {
return _initialized; return _initialized;
} }
public static IdFactory getInstance()
{
return _instance;
}
public abstract int getNextId();
/**
* return a used Object ID back to the pool
* @param id
*/
public abstract void releaseId(int id);
public abstract int size();
} }
@@ -1,152 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.idfactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Stack;
import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory;
/**
* @version $Revision: 1.3.2.1.2.7 $ $Date: 2005/04/11 10:06:12 $
*/
public class StackIDFactory extends IdFactory
{
private int _curOID;
private int _tempOID;
private final Stack<Integer> _freeOIDStack = new Stack<>();
protected StackIDFactory()
{
super();
_curOID = FIRST_OID;
_tempOID = FIRST_OID;
try (Connection con = DatabaseFactory.getConnection())
{
// con.createStatement().execute("drop table if exists tmp_obj_id");
final Integer[] tmpObjIds = extractUsedObjectIDTable();
if (tmpObjIds.length > 0)
{
_curOID = tmpObjIds[tmpObjIds.length - 1];
}
LOGGER.info("Max Id = " + _curOID);
int n = tmpObjIds.length;
for (int idx = 0; idx < n; idx++)
{
n = insertUntil(tmpObjIds, idx, n, con);
}
_curOID++;
LOGGER.info("IdFactory: Next usable Object ID is: " + _curOID);
_initialized = true;
}
catch (Exception e)
{
LOGGER.severe(getClass().getSimpleName() + ": Could not be initialized properly:" + e.getMessage());
}
}
private int insertUntil(Integer[] tmpObjIds, int idx, int n, Connection con) throws SQLException
{
final int id = tmpObjIds[idx];
if (id == _tempOID)
{
_tempOID++;
return n;
}
// check these IDs not present in DB
if (Config.BAD_ID_CHECKING)
{
for (String check : ID_CHECKS)
{
try (PreparedStatement ps = con.prepareStatement(check))
{
ps.setInt(1, _tempOID);
// ps.setInt(1, _curOID);
ps.setInt(2, id);
try (ResultSet rs = ps.executeQuery())
{
if (rs.next())
{
final int badId = rs.getInt(1);
LOGGER.severe("Bad ID " + badId + " in DB found by: " + check);
throw new RuntimeException();
}
}
}
}
}
// int hole = id - _curOID;
final int hole = (id - _tempOID) > (n - idx) ? n - idx : id - _tempOID;
for (int i = 1; i <= hole; i++)
{
_freeOIDStack.push(_tempOID);
_tempOID++;
}
if (hole < (n - idx))
{
_tempOID++;
}
return n - hole;
}
public static IdFactory getInstance()
{
return _instance;
}
@Override
public synchronized int getNextId()
{
int id;
if (!_freeOIDStack.empty())
{
id = _freeOIDStack.pop();
}
else
{
id = _curOID;
_curOID += 1;
}
return id;
}
/**
* return a used Object ID back to the pool
* @param id
*/
@Override
public synchronized void releaseId(int id)
{
_freeOIDStack.push(id);
}
@Override
public int size()
{
return (FREE_OBJECT_ID_SIZE - _curOID) + FIRST_OID + _freeOIDStack.size();
}
}
@@ -123,7 +123,7 @@ public class AirShipManager
if (_airShips.containsKey(ownerId)) if (_airShips.containsKey(ownerId))
{ {
airShip = _airShips.get(ownerId); airShip = _airShips.get(ownerId);
airShip.refreshID(); airShip.refreshId();
} }
else else
{ {
@@ -282,7 +282,7 @@ public class MailManager
} }
_messages.remove(msgId); _messages.remove(msgId);
IdFactory.getInstance().releaseId(msgId); IdFactory.releaseId(msgId);
} }
/** /**
@@ -47,7 +47,7 @@ public class Petition
public Petition(PlayerInstance petitioner, String petitionText, int petitionType) public Petition(PlayerInstance petitioner, String petitionText, int petitionType)
{ {
_id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
_type = PetitionType.values()[--petitionType]; _type = PetitionType.values()[--petitionType];
_content = petitionText; _content = petitionText;
_petitioner = petitioner; _petitioner = petitioner;
@@ -532,7 +532,7 @@ public class Spawn extends Location implements IIdentifiable, INamable
{ {
if (_doRespawn) if (_doRespawn)
{ {
oldNpc.refreshID(); // oldNpc.refreshID();
initializeNpcInstance(oldNpc); initializeNpcInstance(oldNpc);
// Register NPC back to instance world. // Register NPC back to instance world.
@@ -151,11 +151,11 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return true; return true;
} }
public void refreshID() public void refreshId()
{ {
World.getInstance().removeObject(this); World.getInstance().removeObject(this);
IdFactory.getInstance().releaseId(getObjectId()); IdFactory.releaseId(getObjectId());
_objectId = IdFactory.getInstance().getNextId(); _objectId = IdFactory.getNextId();
} }
@Override @Override
@@ -290,7 +290,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
*/ */
public Creature(CreatureTemplate template) public Creature(CreatureTemplate template)
{ {
this(IdFactory.getInstance().getNextId(), template); this(IdFactory.getNextId(), template);
} }
/** /**
@@ -48,7 +48,7 @@ public class ControllableAirShipInstance extends AirShipInstance
super(template); super(template);
setInstanceType(InstanceType.ControllableAirShipInstance); setInstanceType(InstanceType.ControllableAirShipInstance);
_ownerId = ownerId; _ownerId = ownerId;
_helmId = IdFactory.getInstance().getNextId(); // not forget to release ! _helmId = IdFactory.getNextId(); // not forget to release !
} }
@Override @Override
@@ -281,11 +281,11 @@ public class ControllableAirShipInstance extends AirShipInstance
} }
@Override @Override
public void refreshID() public void refreshId()
{ {
super.refreshID(); super.refreshId();
IdFactory.getInstance().releaseId(_helmId); IdFactory.releaseId(_helmId);
_helmId = IdFactory.getInstance().getNextId(); _helmId = IdFactory.getNextId();
} }
@Override @Override
@@ -44,7 +44,7 @@ public class FenceInstance extends WorldObject
public FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state) public FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
{ {
super(IdFactory.getInstance().getNextId()); super(IdFactory.getNextId());
_xMin = x - (width / 2); _xMin = x - (width / 2);
_xMax = x + (width / 2); _xMax = x + (width / 2);
@@ -62,7 +62,7 @@ public class FenceInstance extends WorldObject
_heightFences = new int[height - 1]; _heightFences = new int[height - 1];
for (int i = 0; i < _heightFences.length; i++) for (int i = 0; i < _heightFences.length; i++)
{ {
_heightFences[i] = IdFactory.getInstance().getNextId(); _heightFences[i] = IdFactory.getNextId();
} }
} }
} }
@@ -1135,7 +1135,7 @@ public class PlayerInstance extends Playable
*/ */
private PlayerInstance(PlayerTemplate template, String accountName, PlayerAppearance app) private PlayerInstance(PlayerTemplate template, String accountName, PlayerAppearance app)
{ {
this(IdFactory.getInstance().getNextId(), template, accountName, app); this(IdFactory.getNextId(), template, accountName, app);
} }
@Override @Override
@@ -164,7 +164,7 @@ public class RaceManagerInstance extends Npc
player.setRace(0, 0); player.setRace(0, 0);
player.setRace(1, 0); player.setRace(1, 0);
ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), 4443); ItemInstance item = new ItemInstance(IdFactory.getNextId(), 4443);
item.setCount(1); item.setCount(1);
item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber()); item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber());
item.setCustomType1(ticket); item.setCustomType1(ticket);
@@ -32,7 +32,7 @@ public class EventAnnouncement implements IAnnouncement
public EventAnnouncement(DateRange range, String content) public EventAnnouncement(DateRange range, String content)
{ {
_id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
_range = range; _range = range;
_content = content; _content = content;
} }
@@ -88,7 +88,7 @@ public class EventAnnouncement implements IAnnouncement
@Override @Override
public boolean deleteMe() public boolean deleteMe()
{ {
IdFactory.getInstance().releaseId(_id); IdFactory.releaseId(_id);
return true; return true;
} }
@@ -34,7 +34,7 @@ public class Couple
{ {
private static final Logger LOGGER = Logger.getLogger(Couple.class.getName()); private static final Logger LOGGER = Logger.getLogger(Couple.class.getName());
private int _Id = 0; private int _id = 0;
private int _player1Id = 0; private int _player1Id = 0;
private int _player2Id = 0; private int _player2Id = 0;
private boolean _maried = false; private boolean _maried = false;
@@ -43,12 +43,12 @@ public class Couple
public Couple(int coupleId) public Couple(int coupleId)
{ {
_Id = coupleId; _id = coupleId;
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM mods_wedding WHERE id = ?")) PreparedStatement ps = con.prepareStatement("SELECT * FROM mods_wedding WHERE id = ?"))
{ {
ps.setInt(1, _Id); ps.setInt(1, _id);
try (ResultSet rs = ps.executeQuery()) try (ResultSet rs = ps.executeQuery())
{ {
while (rs.next()) while (rs.next())
@@ -88,8 +88,8 @@ public class Couple
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO mods_wedding (id, player1Id, player2Id, married, affianceDate, weddingDate) VALUES (?, ?, ?, ?, ?, ?)")) PreparedStatement ps = con.prepareStatement("INSERT INTO mods_wedding (id, player1Id, player2Id, married, affianceDate, weddingDate) VALUES (?, ?, ?, ?, ?, ?)"))
{ {
_Id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
ps.setInt(1, _Id); ps.setInt(1, _id);
ps.setInt(2, _player1Id); ps.setInt(2, _player1Id);
ps.setInt(3, _player2Id); ps.setInt(3, _player2Id);
ps.setBoolean(4, false); ps.setBoolean(4, false);
@@ -111,7 +111,7 @@ public class Couple
ps.setBoolean(1, true); ps.setBoolean(1, true);
_weddingDate = Calendar.getInstance(); _weddingDate = Calendar.getInstance();
ps.setLong(2, _weddingDate.getTimeInMillis()); ps.setLong(2, _weddingDate.getTimeInMillis());
ps.setInt(3, _Id); ps.setInt(3, _id);
ps.execute(); ps.execute();
_maried = true; _maried = true;
} }
@@ -126,7 +126,7 @@ public class Couple
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM mods_wedding WHERE id=?")) PreparedStatement ps = con.prepareStatement("DELETE FROM mods_wedding WHERE id=?"))
{ {
ps.setInt(1, _Id); ps.setInt(1, _id);
ps.execute(); ps.execute();
} }
catch (Exception e) catch (Exception e)
@@ -137,7 +137,7 @@ public class Couple
public int getId() public int getId()
{ {
return _Id; return _id;
} }
public int getPlayer1Id() public int getPlayer1Id()
@@ -99,7 +99,7 @@ public class Message
*/ */
public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena) public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = senderId; _senderId = senderId;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -118,7 +118,7 @@ public class Message
*/ */
public Message(int receiverId, String subject, String content, MailType sendBySystem) public Message(int receiverId, String subject, String content, MailType sendBySystem)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = -1; _senderId = -1;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -138,7 +138,7 @@ public class Message
*/ */
public Message(int senderId, int receiverId, String subject, String content, MailType sendBySystem) public Message(int senderId, int receiverId, String subject, String content, MailType sendBySystem)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = senderId; _senderId = senderId;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -157,7 +157,7 @@ public class Message
*/ */
public Message(Message msg) public Message(Message msg)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = msg.getSenderId(); _senderId = msg.getSenderId();
_receiverId = msg.getSenderId(); _receiverId = msg.getSenderId();
_subject = ""; _subject = "";
@@ -177,7 +177,7 @@ public class Message
public Message(int receiverId, ItemInstance item, MailType mailType) public Message(int receiverId, ItemInstance item, MailType mailType)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = -1; _senderId = -1;
_receiverId = receiverId; _receiverId = receiverId;
_subject = ""; _subject = "";
@@ -79,7 +79,7 @@ public class AuctionItem
public ItemInstance createNewItemInstance() public ItemInstance createNewItemInstance()
{ {
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), _itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), _itemId);
World.getInstance().addObject(item); World.getInstance().addObject(item);
item.setCount(_itemCount); item.setCount(_itemCount);
item.setEnchantLevel(item.getItem().getDefaultEnchantLevel()); item.setEnchantLevel(item.getItem().getDefaultEnchantLevel());
@@ -254,7 +254,7 @@ public class ItemInstance extends WorldObject
*/ */
public ItemInstance(int itemId) public ItemInstance(int itemId)
{ {
this(IdFactory.getInstance().getNextId(), itemId); this(IdFactory.getNextId(), itemId);
} }
/** /**
@@ -50,7 +50,7 @@ public abstract class ZoneForm
protected final void dropDebugItem(int itemId, int num, int x, int y, int z) protected final void dropDebugItem(int itemId, int num, int x, int y, int z)
{ {
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), itemId);
item.setCount(num); item.setCount(num);
item.spawnMe(x, y, z + 5); item.spawnMe(x, y, z + 5);
ZoneManager.getInstance().getDebugItems().add(item); ZoneManager.getInstance().getDebugItems().add(item);
@@ -248,7 +248,7 @@ public class MinionList
// minion can be already spawned or deleted // minion can be already spawned or deleted
if (!_master.isAlikeDead() && _master.isSpawned() && !_minion.isSpawned()) if (!_master.isAlikeDead() && _master.isSpawned() && !_minion.isSpawned())
{ {
_minion.refreshID(); // _minion.refreshId();
initializeNpcInstance(_master, _minion); initializeNpcInstance(_master, _minion);
// assist master // assist master
@@ -1,20 +0,0 @@
# ---------------------------------------------------------------------------
# ID Factory Settings
# ---------------------------------------------------------------------------
# Warning:
# Please take extreme caution when changing anything. Also please understand what you are changing before you do so on a live server.
# ---------------------------------------------------------------------------
# Standard Settings
# ---------------------------------------------------------------------------
# Tell server which IDFactory Class to use:
# BITSET = One non compaction method
# STACK = Another non compaction method
# Default: BITSET
IDFactory = BITSET
# Check for bad ids in the database on server boot up.
# Much faster load time without it, but may cause problems.
# Default: True
BadIdChecking = True
@@ -55,7 +55,6 @@ import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.l2jmobius.commons.enums.IdFactoryType;
import org.l2jmobius.commons.enums.ServerMode; import org.l2jmobius.commons.enums.ServerMode;
import org.l2jmobius.commons.util.IXmlReader; import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.commons.util.PropertiesParser; import org.l2jmobius.commons.util.PropertiesParser;
@@ -97,7 +96,6 @@ public class Config
private static final String GENERAL_CONFIG_FILE = "./config/General.ini"; private static final String GENERAL_CONFIG_FILE = "./config/General.ini";
private static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini"; private static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini";
private static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini"; private static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini";
private static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini";
private static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini"; private static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini";
private static final String NPC_CONFIG_FILE = "./config/NPC.ini"; private static final String NPC_CONFIG_FILE = "./config/NPC.ini";
private static final String PVP_CONFIG_FILE = "./config/PVP.ini"; private static final String PVP_CONFIG_FILE = "./config/PVP.ini";
@@ -809,9 +807,6 @@ public class Config
public static int MAX_REPUTATION; public static int MAX_REPUTATION;
public static int REPUTATION_INCREASE; public static int REPUTATION_INCREASE;
public static IdFactoryType IDFACTORY_TYPE;
public static boolean BAD_ID_CHECKING;
public static int[] ENCHANT_BLACKLIST; public static int[] ENCHANT_BLACKLIST;
public static boolean DISABLE_OVER_ENCHANTING; public static boolean DISABLE_OVER_ENCHANTING;
public static int[] AUGMENTATION_BLACKLIST; public static int[] AUGMENTATION_BLACKLIST;
@@ -1949,12 +1944,6 @@ public class Config
TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0); TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0);
TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0); TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0);
// Load IdFactory config file (if exists)
final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE);
IDFACTORY_TYPE = IdFactory.getEnum("IDFactory", IdFactoryType.class, IdFactoryType.BITSET);
BAD_ID_CHECKING = IdFactory.getBoolean("BadIdChecking", true);
// Load General config file (if exists) // Load General config file (if exists)
final PropertiesParser General = new PropertiesParser(GENERAL_CONFIG_FILE); final PropertiesParser General = new PropertiesParser(GENERAL_CONFIG_FILE);
DEFAULT_ACCESS_LEVEL = General.getInt("DefaultAccessLevel", 0); DEFAULT_ACCESS_LEVEL = General.getInt("DefaultAccessLevel", 0);
@@ -1,26 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.commons.enums;
/**
* @author Mobius
*/
public enum IdFactoryType
{
BITSET,
STACK
}
@@ -209,7 +209,8 @@ public class GameServer
ThreadPool.init(); ThreadPool.init();
printSection("IdFactory"); printSection("IdFactory");
if (!IdFactory.getInstance().isInitialized()) IdFactory.init();
if (!IdFactory.hasInitialized())
{ {
LOGGER.severe(getClass().getSimpleName() + ": Could not read object IDs from database. Please check your configuration."); LOGGER.severe(getClass().getSimpleName() + ": Could not read object IDs from database. Please check your configuration.");
throw new Exception("Could not initialize the ID factory!"); throw new Exception("Could not initialize the ID factory!");
@@ -424,7 +425,7 @@ public class GameServer
Runtime.getRuntime().addShutdownHook(Shutdown.getInstance()); Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.getInstance().size()); LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.size());
if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS) if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
{ {
@@ -188,7 +188,7 @@ public class ClanTable
return null; return null;
} }
final Clan clan = new Clan(IdFactory.getInstance().getNextId(), clanName); final Clan clan = new Clan(IdFactory.getNextId(), clanName);
final ClanMember leader = new ClanMember(clan, player); final ClanMember leader = new ClanMember(clan, player);
clan.setLeader(leader); clan.setLeader(leader);
leader.setPlayerInstance(player); leader.setPlayerInstance(player);
@@ -260,7 +260,7 @@ public class ClanTable
} }
_clans.remove(clanId); _clans.remove(clanId);
IdFactory.getInstance().releaseId(clanId); IdFactory.releaseId(clanId);
try (Connection con = DatabaseFactory.getConnection()) try (Connection con = DatabaseFactory.getConnection())
{ {
@@ -210,7 +210,7 @@ public class ItemTable
public ItemInstance createItem(String process, int itemId, long count, Creature actor, Object reference) public ItemInstance createItem(String process, int itemId, long count, Creature actor, Object reference)
{ {
// Create and Init the ItemInstance corresponding to the Item Identifier // Create and Init the ItemInstance corresponding to the Item Identifier
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), itemId);
if (process.equalsIgnoreCase("loot") && !Config.AUTO_LOOT_ITEM_IDS.contains(itemId)) if (process.equalsIgnoreCase("loot") && !Config.AUTO_LOOT_ITEM_IDS.contains(itemId))
{ {
@@ -328,7 +328,7 @@ public class ItemTable
item.setLastChange(ItemInstance.REMOVED); item.setLastChange(ItemInstance.REMOVED);
World.getInstance().removeObject(item); World.getInstance().removeObject(item);
IdFactory.getInstance().releaseId(item.getObjectId()); IdFactory.releaseId(item.getObjectId());
if (Config.LOG_ITEMS) if (Config.LOG_ITEMS)
{ {
@@ -1,151 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.idfactory;
import java.util.BitSet;
import java.util.concurrent.atomic.AtomicInteger;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.util.PrimeFinder;
/**
* This class ..
* @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
*/
public class BitSetIDFactory extends IdFactory
{
private BitSet _freeIds;
private AtomicInteger _freeIdCount;
private AtomicInteger _nextFreeId;
protected class BitSetCapacityCheck implements Runnable
{
@Override
public void run()
{
synchronized (BitSetIDFactory.this)
{
if (reachingBitSetCapacity())
{
increaseBitSetCapacity();
}
}
}
}
protected BitSetIDFactory()
{
super();
synchronized (BitSetIDFactory.class)
{
ThreadPool.scheduleAtFixedRate(new BitSetCapacityCheck(), 30000, 30000);
initialize();
}
LOGGER.info(getClass().getSimpleName() + ": " + _freeIds.size() + " id's available.");
}
public void initialize()
{
try
{
_freeIds = new BitSet(PrimeFinder.nextPrime(100000));
_freeIds.clear();
_freeIdCount = new AtomicInteger(FREE_OBJECT_ID_SIZE);
for (int usedObjectId : extractUsedObjectIDTable())
{
final int objectID = usedObjectId - FIRST_OID;
if (objectID < 0)
{
LOGGER.warning(getClass().getSimpleName() + ": Object ID " + usedObjectId + " in DB is less than minimum ID of " + FIRST_OID);
continue;
}
_freeIds.set(usedObjectId - FIRST_OID);
_freeIdCount.decrementAndGet();
}
_nextFreeId = new AtomicInteger(_freeIds.nextClearBit(0));
_initialized = true;
}
catch (Exception e)
{
_initialized = false;
LOGGER.severe(getClass().getSimpleName() + ": Could not be initialized properly: " + e.getMessage());
}
}
@Override
public synchronized void releaseId(int objectID)
{
if ((objectID - FIRST_OID) > -1)
{
_freeIds.clear(objectID - FIRST_OID);
_freeIdCount.incrementAndGet();
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Release objectID " + objectID + " failed (< " + FIRST_OID + ")");
}
}
@Override
public synchronized int getNextId()
{
final int newID = _nextFreeId.get();
_freeIds.set(newID);
_freeIdCount.decrementAndGet();
final int nextFree = _freeIds.nextClearBit(newID) < 0 ? _freeIds.nextClearBit(0) : _freeIds.nextClearBit(newID);
if (nextFree < 0)
{
if (_freeIds.size() >= FREE_OBJECT_ID_SIZE)
{
throw new NullPointerException("Ran out of valid Id's.");
}
increaseBitSetCapacity();
}
_nextFreeId.set(nextFree);
return newID + FIRST_OID;
}
@Override
public synchronized int size()
{
return _freeIdCount.get();
}
protected synchronized int usedIdCount()
{
return _freeIdCount.get() - FIRST_OID;
}
protected synchronized boolean reachingBitSetCapacity()
{
return PrimeFinder.nextPrime((usedIdCount() * 11) / 10) > _freeIds.size();
}
protected synchronized void increaseBitSetCapacity()
{
final BitSet newBitSet = new BitSet(PrimeFinder.nextPrime((usedIdCount() * 11) / 10));
newBitSet.or(_freeIds);
_freeIds = newBitSet;
}
}
@@ -19,23 +19,25 @@ package org.l2jmobius.gameserver.idfactory;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.gameserver.util.PrimeFinder;
/** /**
* @version $Revision: 1.3.2.1.2.7 $ $Date: 2005/04/11 10:06:12 $ * @author Mobius (reworked from L2J version)
*/ */
public abstract class IdFactory public abstract class IdFactory
{ {
protected final Logger LOGGER = Logger.getLogger(getClass().getName()); private static final Logger LOGGER = Logger.getLogger(IdFactory.class.getName());
protected static final String[] ID_CHECKS = protected static final String[] ID_CHECKS =
{ {
@@ -64,7 +66,6 @@ public abstract class IdFactory
"SELECT object_id FROM itemsonground WHERE object_id >= ? AND object_id < ?", "SELECT object_id FROM itemsonground WHERE object_id >= ? AND object_id < ?",
"SELECT summonId FROM characters_summons WHERE summonId >= ? AND summonId < ?" "SELECT summonId FROM characters_summons WHERE summonId >= ? AND summonId < ?"
}; };
//@formatter:off //@formatter:off
private static final String[][] ID_EXTRACTS = private static final String[][] ID_EXTRACTS =
{ {
@@ -75,183 +76,121 @@ public abstract class IdFactory
{"messages","messageId"} {"messages","messageId"}
}; };
//@formatter:on //@formatter:on
private static final String[] TIMESTAMPS_CLEAN = private static final String[] TIMESTAMPS_CLEAN =
{ {
"DELETE FROM character_instance_time WHERE time <= ?", "DELETE FROM character_instance_time WHERE time <= ?",
"DELETE FROM character_skills_save WHERE restore_type = 1 AND systime <= ?" "DELETE FROM character_skills_save WHERE restore_type = 1 AND systime <= ?"
}; };
protected boolean _initialized;
public static final int FIRST_OID = 0x10000000; public static final int FIRST_OID = 0x10000000;
public static final int LAST_OID = 0x7FFFFFFF; public static final int LAST_OID = 0x7FFFFFFF;
public static final int FREE_OBJECT_ID_SIZE = LAST_OID - FIRST_OID; public static final int FREE_OBJECT_ID_SIZE = LAST_OID - FIRST_OID;
protected static final IdFactory _instance; private static BitSet _freeIds;
private static AtomicInteger _freeIdCount;
private static AtomicInteger _nextFreeId;
private static boolean _initialized;
protected IdFactory() public static void init()
{
setAllCharacterOffline();
if (Config.DATABASE_CLEAN_UP)
{
cleanUpDB();
}
cleanUpTimeStamps();
}
static
{
switch (Config.IDFACTORY_TYPE)
{
case BITSET:
{
_instance = new BitSetIDFactory();
break;
}
case STACK:
{
_instance = new StackIDFactory();
break;
}
default:
{
_instance = null;
break;
}
}
}
/**
* Sets all character offline
*/
private void setAllCharacterOffline()
{ {
// Update characters online status.
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
Statement s = con.createStatement()) Statement s = con.createStatement())
{ {
s.executeUpdate("UPDATE characters SET online = 0"); s.executeUpdate("UPDATE characters SET online = 0");
LOGGER.info("Updated characters online status."); LOGGER.info("Updated characters online status.");
} }
catch (SQLException e) catch (Exception e)
{ {
LOGGER.log(Level.WARNING, "Could not update characters online status: " + e.getMessage(), e); LOGGER.warning("IdFactory: Could not update characters online status: " + e);
} }
}
// Cleanup database.
/** if (Config.DATABASE_CLEAN_UP)
* Cleans up Database
*/
private void cleanUpDB()
{
try (Connection con = DatabaseFactory.getConnection();
Statement stmt = con.createStatement())
{ {
final long cleanupStart = System.currentTimeMillis(); try (Connection con = DatabaseFactory.getConnection();
int cleanCount = 0; Statement stmt = con.createStatement())
// Misc/Account Related {
// Please read the descriptions above each before uncommenting them. If you are still final long cleanupStart = System.currentTimeMillis();
// unsure of what exactly it does, leave it commented out. This is for those who know int cleanCount = 0;
// what they are doing. :)
// Characters
// Deletes only accounts that HAVE been logged into and have no characters associated cleanCount += stmt.executeUpdate("DELETE FROM account_gsdata WHERE account_gsdata.account_name NOT IN (SELECT account_name FROM characters);");
// with the account. cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.contactId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.lastactive > 0 AND accounts.login NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.friendId NOT IN (SELECT charId FROM characters);");
// Deletes any accounts that don't have characters. Whether or not the player has ever cleanCount += stmt.executeUpdate("DELETE FROM character_hennas WHERE character_hennas.charId NOT IN (SELECT charId FROM characters);");
// logged into the account. cleanCount += stmt.executeUpdate("DELETE FROM character_macroses WHERE character_macroses.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_quests WHERE character_quests.charId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.login NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_recipebook WHERE character_recipebook.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipeshoplist WHERE character_recipeshoplist.charId NOT IN (SELECT charId FROM characters);");
// Deletes banned accounts that have not been logged into for xx amount of days cleanCount += stmt.executeUpdate("DELETE FROM character_shortcuts WHERE character_shortcuts.charId NOT IN (SELECT charId FROM characters);");
// (specified at the end of the script, default is set to 90 days). This prevents cleanCount += stmt.executeUpdate("DELETE FROM character_skills WHERE character_skills.charId NOT IN (SELECT charId FROM characters);");
// accounts from being deleted that were accidentally or temporarily banned. cleanCount += stmt.executeUpdate("DELETE FROM character_skills_save WHERE character_skills_save.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_subclasses WHERE character_subclasses.charId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.accessLevel < 0 AND DATEDIFF(CURRENT_DATE( ) , FROM_UNIXTIME(`lastactive`/1000)) > 90;"); cleanCount += stmt.executeUpdate("DELETE FROM character_instance_time WHERE character_instance_time.charId NOT IN (SELECT charId FROM characters);");
// cleanCount +=
// stmt.executeUpdate("DELETE FROM characters WHERE characters.account_name NOT IN (SELECT login FROM accounts);"); // Items
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id NOT IN (SELECT charId FROM characters) AND items.owner_id NOT IN (SELECT clan_id FROM clan_data) AND items.owner_id != -1;");
// If the character does not exist... cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id = -1 AND loc LIKE 'MAIL' AND loc_data NOT IN (SELECT messageId FROM messages WHERE senderId = -1);");
// Characters cleanCount += stmt.executeUpdate("DELETE FROM item_auction_bid WHERE item_auction_bid.playerObjId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM account_gsdata WHERE account_gsdata.account_name NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_variations WHERE item_variations.itemId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_elementals WHERE item_elementals.itemId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.contactId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_special_abilities WHERE item_special_abilities.objectId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_variables WHERE item_variables.id NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.friendId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_hennas WHERE character_hennas.charId NOT IN (SELECT charId FROM characters);"); // Misc
cleanCount += stmt.executeUpdate("DELETE FROM character_macroses WHERE character_macroses.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM cursed_weapons WHERE cursed_weapons.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_quests WHERE character_quests.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM heroes WHERE heroes.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipebook WHERE character_recipebook.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles WHERE olympiad_nobles.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipeshoplist WHERE character_recipeshoplist.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles_eom WHERE olympiad_nobles_eom.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_shortcuts WHERE character_shortcuts.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM pets WHERE pets.item_obj_id NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_skills WHERE character_skills.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM merchant_lease WHERE merchant_lease.player_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_skills_save WHERE character_skills_save.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_reco_bonus WHERE character_reco_bonus.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_subclasses WHERE character_subclasses.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.leader_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_instance_time WHERE character_instance_time.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.clan_id NOT IN (SELECT clanid FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charOneId NOT IN (SELECT charId FROM characters);");
// Items cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charTwoId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id NOT IN (SELECT charId FROM characters) AND items.owner_id NOT IN (SELECT clan_id FROM clan_data) AND items.owner_id != -1;"); cleanCount += stmt.executeUpdate("DELETE FROM heroes_diary WHERE heroes_diary.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id = -1 AND loc LIKE 'MAIL' AND loc_data NOT IN (SELECT messageId FROM messages WHERE senderId = -1);"); cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade WHERE character_offline_trade.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_auction_bid WHERE item_auction_bid.playerObjId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_variations WHERE item_variations.itemId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_elementals WHERE item_elementals.itemId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_special_abilities WHERE item_special_abilities.objectId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_variables WHERE item_variables.id NOT IN (SELECT object_id FROM items);");
// Clan
// Misc cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM cursed_weapons WHERE cursed_weapons.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_skills WHERE clan_skills.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM heroes WHERE heroes.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_subpledges WHERE clan_subpledges.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles WHERE olympiad_nobles.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan1 NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles_eom WHERE olympiad_nobles_eom.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan2 NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM pets WHERE pets.item_obj_id NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM siege_clans WHERE siege_clans.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM merchant_lease WHERE merchant_lease.player_id NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_notices WHERE clan_notices.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM character_reco_bonus WHERE character_reco_bonus.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM auction_bid WHERE auction_bid.bidderId NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.leader_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.clan_id NOT IN (SELECT clanid FROM characters);"); // Forums
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charOneId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT clan_id FROM clan_data) AND forums.forum_parent=2;");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charTwoId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT charId FROM characters) AND forums.forum_parent=3;");
cleanCount += stmt.executeUpdate("DELETE FROM heroes_diary WHERE heroes_diary.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM posts WHERE posts.post_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade WHERE character_offline_trade.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM topic WHERE topic.topic_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); // Update needed items after cleaning has taken place.
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
// If the clan does not exist... stmt.executeUpdate("UPDATE castle SET side='NEUTRAL' WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_skills WHERE clan_skills.clan_id NOT IN (SELECT clan_id FROM clan_data);"); stmt.executeUpdate("UPDATE fort SET owner=0 WHERE owner NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_subpledges WHERE clan_subpledges.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan1 NOT IN (SELECT clan_id FROM clan_data);"); LOGGER.info("IdFactory: Cleaned " + cleanCount + " elements from database in " + ((System.currentTimeMillis() - cleanupStart) / 1000) + " seconds.");
cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan2 NOT IN (SELECT clan_id FROM clan_data);"); }
cleanCount += stmt.executeUpdate("DELETE FROM siege_clans WHERE siege_clans.clan_id NOT IN (SELECT clan_id FROM clan_data);"); catch (Exception e)
cleanCount += stmt.executeUpdate("DELETE FROM clan_notices WHERE clan_notices.clan_id NOT IN (SELECT clan_id FROM clan_data);"); {
cleanCount += stmt.executeUpdate("DELETE FROM auction_bid WHERE auction_bid.bidderId NOT IN (SELECT clan_id FROM clan_data);"); LOGGER.warning("IdFactory: Could not clean up database: " + e);
}
// Forum Related
cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT clan_id FROM clan_data) AND forums.forum_parent=2;");
cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT charId FROM characters) AND forums.forum_parent=3;");
cleanCount += stmt.executeUpdate("DELETE FROM posts WHERE posts.post_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM topic WHERE topic.topic_forum_id NOT IN (SELECT forum_id FROM forums);");
// Update needed items after cleaning has taken place.
stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
stmt.executeUpdate("UPDATE castle SET side='NEUTRAL' WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");
stmt.executeUpdate("UPDATE fort SET owner=0 WHERE owner NOT IN (SELECT clan_id FROM clan_data);");
LOGGER.info("Cleaned " + cleanCount + " elements from database in " + ((System.currentTimeMillis() - cleanupStart) / 1000) + " s");
} }
catch (SQLException e)
{ // Cleanup timestamps.
LOGGER.log(Level.WARNING, "Could not clean up database: " + e.getMessage(), e);
}
}
private void cleanUpTimeStamps()
{
try (Connection con = DatabaseFactory.getConnection()) try (Connection con = DatabaseFactory.getConnection())
{ {
int cleanCount = 0; int cleanCount = 0;
@@ -263,62 +202,136 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate(); cleanCount += stmt.executeUpdate();
} }
} }
LOGGER.info("Cleaned " + cleanCount + " expired timestamps from database."); LOGGER.info("IdFactory: Cleaned " + cleanCount + " expired timestamps from database.");
} }
catch (SQLException e) catch (Exception e)
{ {
// Ignore. LOGGER.warning("IdFactory: Could not clean expired timestamps from database. " + e);
} }
}
// Initialize.
/** try
* @return
* @throws Exception
* @throws SQLException
*/
protected final Integer[] extractUsedObjectIDTable() throws Exception
{
final List<Integer> temp = new ArrayList<>();
try (Connection con = DatabaseFactory.getConnection();
Statement s = con.createStatement())
{ {
String extractUsedObjectIdsQuery = ""; _freeIds = new BitSet(PrimeFinder.nextPrime(100000));
_freeIds.clear();
_freeIdCount = new AtomicInteger(FREE_OBJECT_ID_SIZE);
for (String[] tblClmn : ID_EXTRACTS) // Collect already used ids.
final List<Integer> usedIds = new ArrayList<>();
try (Connection con = DatabaseFactory.getConnection();
Statement statement = con.createStatement())
{ {
extractUsedObjectIdsQuery += "SELECT " + tblClmn[1] + " FROM " + tblClmn[0] + " UNION "; String extractUsedObjectIdsQuery = "";
} for (String[] tblClmn : ID_EXTRACTS)
extractUsedObjectIdsQuery = extractUsedObjectIdsQuery.substring(0, extractUsedObjectIdsQuery.length() - 7); // Remove the last " UNION "
try (ResultSet rs = s.executeQuery(extractUsedObjectIdsQuery))
{
while (rs.next())
{ {
temp.add(rs.getInt(1)); extractUsedObjectIdsQuery += "SELECT " + tblClmn[1] + " FROM " + tblClmn[0] + " UNION ";
}
extractUsedObjectIdsQuery = extractUsedObjectIdsQuery.substring(0, extractUsedObjectIdsQuery.length() - 7); // Remove the last " UNION "
try (ResultSet result = statement.executeQuery(extractUsedObjectIdsQuery))
{
while (result.next())
{
usedIds.add(result.getInt(1));
}
} }
} }
Collections.sort(usedIds);
// Register used ids.
for (int usedObjectId : usedIds)
{
final int objectId = usedObjectId - FIRST_OID;
if (objectId < 0)
{
LOGGER.warning("IdFactory: Object ID " + usedObjectId + " in DB is less than minimum ID of " + FIRST_OID);
continue;
}
_freeIds.set(usedObjectId - FIRST_OID);
_freeIdCount.decrementAndGet();
}
_nextFreeId = new AtomicInteger(_freeIds.nextClearBit(0));
_initialized = true;
} }
Collections.sort(temp); catch (Exception e)
return temp.toArray(new Integer[temp.size()]); {
_initialized = false;
LOGGER.severe("IdFactory: Could not be initialized properly: " + e.getMessage());
}
// Schedule increase capacity task.
ThreadPool.scheduleAtFixedRate(() ->
{
synchronized (_nextFreeId)
{
if (PrimeFinder.nextPrime((usedIdCount() * 11) / 10) > _freeIds.size())
{
increaseBitSetCapacity();
}
}
}, 30000, 30000);
LOGGER.info("IdFactory: " + _freeIds.size() + " id's available.");
} }
public boolean isInitialized() public synchronized static void releaseId(int objectId)
{
synchronized (_nextFreeId)
{
if ((objectId - FIRST_OID) > -1)
{
_freeIds.clear(objectId - FIRST_OID);
_freeIdCount.incrementAndGet();
}
else
{
LOGGER.warning("IdFactory: Release objectID " + objectId + " failed (< " + FIRST_OID + ")");
}
}
}
public synchronized static int getNextId()
{
synchronized (_nextFreeId)
{
final int newId = _nextFreeId.get();
_freeIds.set(newId);
_freeIdCount.decrementAndGet();
final int nextFree = _freeIds.nextClearBit(newId) < 0 ? _freeIds.nextClearBit(0) : _freeIds.nextClearBit(newId);
if (nextFree < 0)
{
if (_freeIds.size() >= FREE_OBJECT_ID_SIZE)
{
throw new NullPointerException("IdFactory: Ran out of valid ids.");
}
increaseBitSetCapacity();
}
_nextFreeId.set(nextFree);
return newId + FIRST_OID;
}
}
private static void increaseBitSetCapacity()
{
final BitSet newBitSet = new BitSet(PrimeFinder.nextPrime((usedIdCount() * 11) / 10));
newBitSet.or(_freeIds);
_freeIds = newBitSet;
}
private static int usedIdCount()
{
return _freeIdCount.get() - FIRST_OID;
}
public static int size()
{
return _freeIdCount.get();
}
public static boolean hasInitialized()
{ {
return _initialized; return _initialized;
} }
public static IdFactory getInstance()
{
return _instance;
}
public abstract int getNextId();
/**
* return a used Object ID back to the pool
* @param id
*/
public abstract void releaseId(int id);
public abstract int size();
} }
@@ -1,152 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.idfactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Stack;
import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory;
/**
* @version $Revision: 1.3.2.1.2.7 $ $Date: 2005/04/11 10:06:12 $
*/
public class StackIDFactory extends IdFactory
{
private int _curOID;
private int _tempOID;
private final Stack<Integer> _freeOIDStack = new Stack<>();
protected StackIDFactory()
{
super();
_curOID = FIRST_OID;
_tempOID = FIRST_OID;
try (Connection con = DatabaseFactory.getConnection())
{
// con.createStatement().execute("drop table if exists tmp_obj_id");
final Integer[] tmpObjIds = extractUsedObjectIDTable();
if (tmpObjIds.length > 0)
{
_curOID = tmpObjIds[tmpObjIds.length - 1];
}
LOGGER.info("Max Id = " + _curOID);
int n = tmpObjIds.length;
for (int idx = 0; idx < n; idx++)
{
n = insertUntil(tmpObjIds, idx, n, con);
}
_curOID++;
LOGGER.info("IdFactory: Next usable Object ID is: " + _curOID);
_initialized = true;
}
catch (Exception e)
{
LOGGER.severe(getClass().getSimpleName() + ": Could not be initialized properly:" + e.getMessage());
}
}
private int insertUntil(Integer[] tmpObjIds, int idx, int n, Connection con) throws SQLException
{
final int id = tmpObjIds[idx];
if (id == _tempOID)
{
_tempOID++;
return n;
}
// check these IDs not present in DB
if (Config.BAD_ID_CHECKING)
{
for (String check : ID_CHECKS)
{
try (PreparedStatement ps = con.prepareStatement(check))
{
ps.setInt(1, _tempOID);
// ps.setInt(1, _curOID);
ps.setInt(2, id);
try (ResultSet rs = ps.executeQuery())
{
if (rs.next())
{
final int badId = rs.getInt(1);
LOGGER.severe("Bad ID " + badId + " in DB found by: " + check);
throw new RuntimeException();
}
}
}
}
}
// int hole = id - _curOID;
final int hole = (id - _tempOID) > (n - idx) ? n - idx : id - _tempOID;
for (int i = 1; i <= hole; i++)
{
_freeOIDStack.push(_tempOID);
_tempOID++;
}
if (hole < (n - idx))
{
_tempOID++;
}
return n - hole;
}
public static IdFactory getInstance()
{
return _instance;
}
@Override
public synchronized int getNextId()
{
int id;
if (!_freeOIDStack.empty())
{
id = _freeOIDStack.pop();
}
else
{
id = _curOID;
_curOID += 1;
}
return id;
}
/**
* return a used Object ID back to the pool
* @param id
*/
@Override
public synchronized void releaseId(int id)
{
_freeOIDStack.push(id);
}
@Override
public int size()
{
return (FREE_OBJECT_ID_SIZE - _curOID) + FIRST_OID + _freeOIDStack.size();
}
}
@@ -123,7 +123,7 @@ public class AirShipManager
if (_airShips.containsKey(ownerId)) if (_airShips.containsKey(ownerId))
{ {
airShip = _airShips.get(ownerId); airShip = _airShips.get(ownerId);
airShip.refreshID(); airShip.refreshId();
} }
else else
{ {
@@ -282,7 +282,7 @@ public class MailManager
} }
_messages.remove(msgId); _messages.remove(msgId);
IdFactory.getInstance().releaseId(msgId); IdFactory.releaseId(msgId);
} }
/** /**
@@ -47,7 +47,7 @@ public class Petition
public Petition(PlayerInstance petitioner, String petitionText, int petitionType) public Petition(PlayerInstance petitioner, String petitionText, int petitionType)
{ {
_id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
_type = PetitionType.values()[--petitionType]; _type = PetitionType.values()[--petitionType];
_content = petitionText; _content = petitionText;
_petitioner = petitioner; _petitioner = petitioner;
@@ -532,7 +532,7 @@ public class Spawn extends Location implements IIdentifiable, INamable
{ {
if (_doRespawn) if (_doRespawn)
{ {
oldNpc.refreshID(); // oldNpc.refreshID();
initializeNpcInstance(oldNpc); initializeNpcInstance(oldNpc);
// Register NPC back to instance world. // Register NPC back to instance world.
@@ -151,11 +151,11 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return true; return true;
} }
public void refreshID() public void refreshId()
{ {
World.getInstance().removeObject(this); World.getInstance().removeObject(this);
IdFactory.getInstance().releaseId(getObjectId()); IdFactory.releaseId(getObjectId());
_objectId = IdFactory.getInstance().getNextId(); _objectId = IdFactory.getNextId();
} }
@Override @Override
@@ -290,7 +290,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
*/ */
public Creature(CreatureTemplate template) public Creature(CreatureTemplate template)
{ {
this(IdFactory.getInstance().getNextId(), template); this(IdFactory.getNextId(), template);
} }
/** /**
@@ -48,7 +48,7 @@ public class ControllableAirShipInstance extends AirShipInstance
super(template); super(template);
setInstanceType(InstanceType.ControllableAirShipInstance); setInstanceType(InstanceType.ControllableAirShipInstance);
_ownerId = ownerId; _ownerId = ownerId;
_helmId = IdFactory.getInstance().getNextId(); // not forget to release ! _helmId = IdFactory.getNextId(); // not forget to release !
} }
@Override @Override
@@ -281,11 +281,11 @@ public class ControllableAirShipInstance extends AirShipInstance
} }
@Override @Override
public void refreshID() public void refreshId()
{ {
super.refreshID(); super.refreshId();
IdFactory.getInstance().releaseId(_helmId); IdFactory.releaseId(_helmId);
_helmId = IdFactory.getInstance().getNextId(); _helmId = IdFactory.getNextId();
} }
@Override @Override
@@ -44,7 +44,7 @@ public class FenceInstance extends WorldObject
public FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state) public FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
{ {
super(IdFactory.getInstance().getNextId()); super(IdFactory.getNextId());
_xMin = x - (width / 2); _xMin = x - (width / 2);
_xMax = x + (width / 2); _xMax = x + (width / 2);
@@ -62,7 +62,7 @@ public class FenceInstance extends WorldObject
_heightFences = new int[height - 1]; _heightFences = new int[height - 1];
for (int i = 0; i < _heightFences.length; i++) for (int i = 0; i < _heightFences.length; i++)
{ {
_heightFences[i] = IdFactory.getInstance().getNextId(); _heightFences[i] = IdFactory.getNextId();
} }
} }
} }
@@ -1141,7 +1141,7 @@ public class PlayerInstance extends Playable
*/ */
private PlayerInstance(PlayerTemplate template, String accountName, PlayerAppearance app) private PlayerInstance(PlayerTemplate template, String accountName, PlayerAppearance app)
{ {
this(IdFactory.getInstance().getNextId(), template, accountName, app); this(IdFactory.getNextId(), template, accountName, app);
} }
@Override @Override
@@ -164,7 +164,7 @@ public class RaceManagerInstance extends Npc
player.setRace(0, 0); player.setRace(0, 0);
player.setRace(1, 0); player.setRace(1, 0);
ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), 4443); ItemInstance item = new ItemInstance(IdFactory.getNextId(), 4443);
item.setCount(1); item.setCount(1);
item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber()); item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber());
item.setCustomType1(ticket); item.setCustomType1(ticket);
@@ -32,7 +32,7 @@ public class EventAnnouncement implements IAnnouncement
public EventAnnouncement(DateRange range, String content) public EventAnnouncement(DateRange range, String content)
{ {
_id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
_range = range; _range = range;
_content = content; _content = content;
} }
@@ -88,7 +88,7 @@ public class EventAnnouncement implements IAnnouncement
@Override @Override
public boolean deleteMe() public boolean deleteMe()
{ {
IdFactory.getInstance().releaseId(_id); IdFactory.releaseId(_id);
return true; return true;
} }
@@ -34,7 +34,7 @@ public class Couple
{ {
private static final Logger LOGGER = Logger.getLogger(Couple.class.getName()); private static final Logger LOGGER = Logger.getLogger(Couple.class.getName());
private int _Id = 0; private int _id = 0;
private int _player1Id = 0; private int _player1Id = 0;
private int _player2Id = 0; private int _player2Id = 0;
private boolean _maried = false; private boolean _maried = false;
@@ -43,12 +43,12 @@ public class Couple
public Couple(int coupleId) public Couple(int coupleId)
{ {
_Id = coupleId; _id = coupleId;
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM mods_wedding WHERE id = ?")) PreparedStatement ps = con.prepareStatement("SELECT * FROM mods_wedding WHERE id = ?"))
{ {
ps.setInt(1, _Id); ps.setInt(1, _id);
try (ResultSet rs = ps.executeQuery()) try (ResultSet rs = ps.executeQuery())
{ {
while (rs.next()) while (rs.next())
@@ -88,8 +88,8 @@ public class Couple
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO mods_wedding (id, player1Id, player2Id, married, affianceDate, weddingDate) VALUES (?, ?, ?, ?, ?, ?)")) PreparedStatement ps = con.prepareStatement("INSERT INTO mods_wedding (id, player1Id, player2Id, married, affianceDate, weddingDate) VALUES (?, ?, ?, ?, ?, ?)"))
{ {
_Id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
ps.setInt(1, _Id); ps.setInt(1, _id);
ps.setInt(2, _player1Id); ps.setInt(2, _player1Id);
ps.setInt(3, _player2Id); ps.setInt(3, _player2Id);
ps.setBoolean(4, false); ps.setBoolean(4, false);
@@ -111,7 +111,7 @@ public class Couple
ps.setBoolean(1, true); ps.setBoolean(1, true);
_weddingDate = Calendar.getInstance(); _weddingDate = Calendar.getInstance();
ps.setLong(2, _weddingDate.getTimeInMillis()); ps.setLong(2, _weddingDate.getTimeInMillis());
ps.setInt(3, _Id); ps.setInt(3, _id);
ps.execute(); ps.execute();
_maried = true; _maried = true;
} }
@@ -126,7 +126,7 @@ public class Couple
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM mods_wedding WHERE id=?")) PreparedStatement ps = con.prepareStatement("DELETE FROM mods_wedding WHERE id=?"))
{ {
ps.setInt(1, _Id); ps.setInt(1, _id);
ps.execute(); ps.execute();
} }
catch (Exception e) catch (Exception e)
@@ -137,7 +137,7 @@ public class Couple
public int getId() public int getId()
{ {
return _Id; return _id;
} }
public int getPlayer1Id() public int getPlayer1Id()
@@ -99,7 +99,7 @@ public class Message
*/ */
public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena) public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = senderId; _senderId = senderId;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -118,7 +118,7 @@ public class Message
*/ */
public Message(int receiverId, String subject, String content, MailType sendBySystem) public Message(int receiverId, String subject, String content, MailType sendBySystem)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = -1; _senderId = -1;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -138,7 +138,7 @@ public class Message
*/ */
public Message(int senderId, int receiverId, String subject, String content, MailType sendBySystem) public Message(int senderId, int receiverId, String subject, String content, MailType sendBySystem)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = senderId; _senderId = senderId;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -157,7 +157,7 @@ public class Message
*/ */
public Message(Message msg) public Message(Message msg)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = msg.getSenderId(); _senderId = msg.getSenderId();
_receiverId = msg.getSenderId(); _receiverId = msg.getSenderId();
_subject = ""; _subject = "";
@@ -177,7 +177,7 @@ public class Message
public Message(int receiverId, ItemInstance item, MailType mailType) public Message(int receiverId, ItemInstance item, MailType mailType)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = -1; _senderId = -1;
_receiverId = receiverId; _receiverId = receiverId;
_subject = ""; _subject = "";
@@ -79,7 +79,7 @@ public class AuctionItem
public ItemInstance createNewItemInstance() public ItemInstance createNewItemInstance()
{ {
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), _itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), _itemId);
World.getInstance().addObject(item); World.getInstance().addObject(item);
item.setCount(_itemCount); item.setCount(_itemCount);
item.setEnchantLevel(item.getItem().getDefaultEnchantLevel()); item.setEnchantLevel(item.getItem().getDefaultEnchantLevel());
@@ -259,7 +259,7 @@ public class ItemInstance extends WorldObject
*/ */
public ItemInstance(int itemId) public ItemInstance(int itemId)
{ {
this(IdFactory.getInstance().getNextId(), itemId); this(IdFactory.getNextId(), itemId);
} }
/** /**
@@ -50,7 +50,7 @@ public abstract class ZoneForm
protected final void dropDebugItem(int itemId, int num, int x, int y, int z) protected final void dropDebugItem(int itemId, int num, int x, int y, int z)
{ {
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), itemId);
item.setCount(num); item.setCount(num);
item.spawnMe(x, y, z + 5); item.spawnMe(x, y, z + 5);
ZoneManager.getInstance().getDebugItems().add(item); ZoneManager.getInstance().getDebugItems().add(item);
@@ -248,7 +248,7 @@ public class MinionList
// minion can be already spawned or deleted // minion can be already spawned or deleted
if (!_master.isAlikeDead() && _master.isSpawned() && !_minion.isSpawned()) if (!_master.isAlikeDead() && _master.isSpawned() && !_minion.isSpawned())
{ {
_minion.refreshID(); // _minion.refreshId();
initializeNpcInstance(_master, _minion); initializeNpcInstance(_master, _minion);
// assist master // assist master
-20
View File
@@ -1,20 +0,0 @@
# ---------------------------------------------------------------------------
# ID Factory Settings
# ---------------------------------------------------------------------------
# Warning:
# Please take extreme caution when changing anything. Also please understand what you are changing before you do so on a live server.
# ---------------------------------------------------------------------------
# Standard Settings
# ---------------------------------------------------------------------------
# Tell server which IDFactory Class to use:
# BITSET = One non compaction method
# STACK = Another non compaction method
# Default: BITSET
IDFactory = BITSET
# Check for bad ids in the database on server boot up.
# Much faster load time without it, but may cause problems.
# Default: True
BadIdChecking = True
@@ -55,7 +55,6 @@ import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.l2jmobius.commons.enums.IdFactoryType;
import org.l2jmobius.commons.enums.ServerMode; import org.l2jmobius.commons.enums.ServerMode;
import org.l2jmobius.commons.util.IXmlReader; import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.commons.util.PropertiesParser; import org.l2jmobius.commons.util.PropertiesParser;
@@ -97,7 +96,6 @@ public class Config
private static final String GENERAL_CONFIG_FILE = "./config/General.ini"; private static final String GENERAL_CONFIG_FILE = "./config/General.ini";
private static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini"; private static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini";
private static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini"; private static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini";
private static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini";
private static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini"; private static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini";
private static final String NPC_CONFIG_FILE = "./config/NPC.ini"; private static final String NPC_CONFIG_FILE = "./config/NPC.ini";
private static final String PVP_CONFIG_FILE = "./config/PVP.ini"; private static final String PVP_CONFIG_FILE = "./config/PVP.ini";
@@ -810,9 +808,6 @@ public class Config
public static int MAX_REPUTATION; public static int MAX_REPUTATION;
public static int REPUTATION_INCREASE; public static int REPUTATION_INCREASE;
public static IdFactoryType IDFACTORY_TYPE;
public static boolean BAD_ID_CHECKING;
public static int[] ENCHANT_BLACKLIST; public static int[] ENCHANT_BLACKLIST;
public static boolean DISABLE_OVER_ENCHANTING; public static boolean DISABLE_OVER_ENCHANTING;
public static int[] AUGMENTATION_BLACKLIST; public static int[] AUGMENTATION_BLACKLIST;
@@ -1962,12 +1957,6 @@ public class Config
TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0); TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0);
TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0); TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0);
// Load IdFactory config file (if exists)
final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE);
IDFACTORY_TYPE = IdFactory.getEnum("IDFactory", IdFactoryType.class, IdFactoryType.BITSET);
BAD_ID_CHECKING = IdFactory.getBoolean("BadIdChecking", true);
// Load General config file (if exists) // Load General config file (if exists)
final PropertiesParser General = new PropertiesParser(GENERAL_CONFIG_FILE); final PropertiesParser General = new PropertiesParser(GENERAL_CONFIG_FILE);
DEFAULT_ACCESS_LEVEL = General.getInt("DefaultAccessLevel", 0); DEFAULT_ACCESS_LEVEL = General.getInt("DefaultAccessLevel", 0);
@@ -1,26 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.commons.enums;
/**
* @author Mobius
*/
public enum IdFactoryType
{
BITSET,
STACK
}
@@ -209,7 +209,8 @@ public class GameServer
ThreadPool.init(); ThreadPool.init();
printSection("IdFactory"); printSection("IdFactory");
if (!IdFactory.getInstance().isInitialized()) IdFactory.init();
if (!IdFactory.hasInitialized())
{ {
LOGGER.severe(getClass().getSimpleName() + ": Could not read object IDs from database. Please check your configuration."); LOGGER.severe(getClass().getSimpleName() + ": Could not read object IDs from database. Please check your configuration.");
throw new Exception("Could not initialize the ID factory!"); throw new Exception("Could not initialize the ID factory!");
@@ -424,7 +425,7 @@ public class GameServer
Runtime.getRuntime().addShutdownHook(Shutdown.getInstance()); Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.getInstance().size()); LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.size());
if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS) if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
{ {
@@ -189,7 +189,7 @@ public class ClanTable
return null; return null;
} }
final Clan clan = new Clan(IdFactory.getInstance().getNextId(), clanName); final Clan clan = new Clan(IdFactory.getNextId(), clanName);
final ClanMember leader = new ClanMember(clan, player); final ClanMember leader = new ClanMember(clan, player);
clan.setLeader(leader); clan.setLeader(leader);
leader.setPlayerInstance(player); leader.setPlayerInstance(player);
@@ -264,7 +264,7 @@ public class ClanTable
} }
_clans.remove(clanId); _clans.remove(clanId);
IdFactory.getInstance().releaseId(clanId); IdFactory.releaseId(clanId);
try (Connection con = DatabaseFactory.getConnection()) try (Connection con = DatabaseFactory.getConnection())
{ {
@@ -210,7 +210,7 @@ public class ItemTable
public ItemInstance createItem(String process, int itemId, long count, Creature actor, Object reference) public ItemInstance createItem(String process, int itemId, long count, Creature actor, Object reference)
{ {
// Create and Init the ItemInstance corresponding to the Item Identifier // Create and Init the ItemInstance corresponding to the Item Identifier
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), itemId);
if (process.equalsIgnoreCase("loot") && !Config.AUTO_LOOT_ITEM_IDS.contains(itemId)) if (process.equalsIgnoreCase("loot") && !Config.AUTO_LOOT_ITEM_IDS.contains(itemId))
{ {
@@ -328,7 +328,7 @@ public class ItemTable
item.setLastChange(ItemInstance.REMOVED); item.setLastChange(ItemInstance.REMOVED);
World.getInstance().removeObject(item); World.getInstance().removeObject(item);
IdFactory.getInstance().releaseId(item.getObjectId()); IdFactory.releaseId(item.getObjectId());
if (Config.LOG_ITEMS) if (Config.LOG_ITEMS)
{ {
@@ -1,151 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.idfactory;
import java.util.BitSet;
import java.util.concurrent.atomic.AtomicInteger;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.util.PrimeFinder;
/**
* This class ..
* @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
*/
public class BitSetIDFactory extends IdFactory
{
private BitSet _freeIds;
private AtomicInteger _freeIdCount;
private AtomicInteger _nextFreeId;
protected class BitSetCapacityCheck implements Runnable
{
@Override
public void run()
{
synchronized (BitSetIDFactory.this)
{
if (reachingBitSetCapacity())
{
increaseBitSetCapacity();
}
}
}
}
protected BitSetIDFactory()
{
super();
synchronized (BitSetIDFactory.class)
{
ThreadPool.scheduleAtFixedRate(new BitSetCapacityCheck(), 30000, 30000);
initialize();
}
LOGGER.info(getClass().getSimpleName() + ": " + _freeIds.size() + " id's available.");
}
public void initialize()
{
try
{
_freeIds = new BitSet(PrimeFinder.nextPrime(100000));
_freeIds.clear();
_freeIdCount = new AtomicInteger(FREE_OBJECT_ID_SIZE);
for (int usedObjectId : extractUsedObjectIDTable())
{
final int objectID = usedObjectId - FIRST_OID;
if (objectID < 0)
{
LOGGER.warning(getClass().getSimpleName() + ": Object ID " + usedObjectId + " in DB is less than minimum ID of " + FIRST_OID);
continue;
}
_freeIds.set(usedObjectId - FIRST_OID);
_freeIdCount.decrementAndGet();
}
_nextFreeId = new AtomicInteger(_freeIds.nextClearBit(0));
_initialized = true;
}
catch (Exception e)
{
_initialized = false;
LOGGER.severe(getClass().getSimpleName() + ": Could not be initialized properly: " + e.getMessage());
}
}
@Override
public synchronized void releaseId(int objectID)
{
if ((objectID - FIRST_OID) > -1)
{
_freeIds.clear(objectID - FIRST_OID);
_freeIdCount.incrementAndGet();
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Release objectID " + objectID + " failed (< " + FIRST_OID + ")");
}
}
@Override
public synchronized int getNextId()
{
final int newID = _nextFreeId.get();
_freeIds.set(newID);
_freeIdCount.decrementAndGet();
final int nextFree = _freeIds.nextClearBit(newID) < 0 ? _freeIds.nextClearBit(0) : _freeIds.nextClearBit(newID);
if (nextFree < 0)
{
if (_freeIds.size() >= FREE_OBJECT_ID_SIZE)
{
throw new NullPointerException("Ran out of valid Id's.");
}
increaseBitSetCapacity();
}
_nextFreeId.set(nextFree);
return newID + FIRST_OID;
}
@Override
public synchronized int size()
{
return _freeIdCount.get();
}
protected synchronized int usedIdCount()
{
return _freeIdCount.get() - FIRST_OID;
}
protected synchronized boolean reachingBitSetCapacity()
{
return PrimeFinder.nextPrime((usedIdCount() * 11) / 10) > _freeIds.size();
}
protected synchronized void increaseBitSetCapacity()
{
final BitSet newBitSet = new BitSet(PrimeFinder.nextPrime((usedIdCount() * 11) / 10));
newBitSet.or(_freeIds);
_freeIds = newBitSet;
}
}
@@ -19,23 +19,25 @@ package org.l2jmobius.gameserver.idfactory;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.gameserver.util.PrimeFinder;
/** /**
* @version $Revision: 1.3.2.1.2.7 $ $Date: 2005/04/11 10:06:12 $ * @author Mobius (reworked from L2J version)
*/ */
public abstract class IdFactory public abstract class IdFactory
{ {
protected final Logger LOGGER = Logger.getLogger(getClass().getName()); private static final Logger LOGGER = Logger.getLogger(IdFactory.class.getName());
protected static final String[] ID_CHECKS = protected static final String[] ID_CHECKS =
{ {
@@ -64,7 +66,6 @@ public abstract class IdFactory
"SELECT object_id FROM itemsonground WHERE object_id >= ? AND object_id < ?", "SELECT object_id FROM itemsonground WHERE object_id >= ? AND object_id < ?",
"SELECT summonId FROM characters_summons WHERE summonId >= ? AND summonId < ?" "SELECT summonId FROM characters_summons WHERE summonId >= ? AND summonId < ?"
}; };
//@formatter:off //@formatter:off
private static final String[][] ID_EXTRACTS = private static final String[][] ID_EXTRACTS =
{ {
@@ -75,183 +76,121 @@ public abstract class IdFactory
{"messages","messageId"} {"messages","messageId"}
}; };
//@formatter:on //@formatter:on
private static final String[] TIMESTAMPS_CLEAN = private static final String[] TIMESTAMPS_CLEAN =
{ {
"DELETE FROM character_instance_time WHERE time <= ?", "DELETE FROM character_instance_time WHERE time <= ?",
"DELETE FROM character_skills_save WHERE restore_type = 1 AND systime <= ?" "DELETE FROM character_skills_save WHERE restore_type = 1 AND systime <= ?"
}; };
protected boolean _initialized;
public static final int FIRST_OID = 0x10000000; public static final int FIRST_OID = 0x10000000;
public static final int LAST_OID = 0x7FFFFFFF; public static final int LAST_OID = 0x7FFFFFFF;
public static final int FREE_OBJECT_ID_SIZE = LAST_OID - FIRST_OID; public static final int FREE_OBJECT_ID_SIZE = LAST_OID - FIRST_OID;
protected static final IdFactory _instance; private static BitSet _freeIds;
private static AtomicInteger _freeIdCount;
private static AtomicInteger _nextFreeId;
private static boolean _initialized;
protected IdFactory() public static void init()
{
setAllCharacterOffline();
if (Config.DATABASE_CLEAN_UP)
{
cleanUpDB();
}
cleanUpTimeStamps();
}
static
{
switch (Config.IDFACTORY_TYPE)
{
case BITSET:
{
_instance = new BitSetIDFactory();
break;
}
case STACK:
{
_instance = new StackIDFactory();
break;
}
default:
{
_instance = null;
break;
}
}
}
/**
* Sets all character offline
*/
private void setAllCharacterOffline()
{ {
// Update characters online status.
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
Statement s = con.createStatement()) Statement s = con.createStatement())
{ {
s.executeUpdate("UPDATE characters SET online = 0"); s.executeUpdate("UPDATE characters SET online = 0");
LOGGER.info("Updated characters online status."); LOGGER.info("Updated characters online status.");
} }
catch (SQLException e) catch (Exception e)
{ {
LOGGER.log(Level.WARNING, "Could not update characters online status: " + e.getMessage(), e); LOGGER.warning("IdFactory: Could not update characters online status: " + e);
} }
}
// Cleanup database.
/** if (Config.DATABASE_CLEAN_UP)
* Cleans up Database
*/
private void cleanUpDB()
{
try (Connection con = DatabaseFactory.getConnection();
Statement stmt = con.createStatement())
{ {
final long cleanupStart = System.currentTimeMillis(); try (Connection con = DatabaseFactory.getConnection();
int cleanCount = 0; Statement stmt = con.createStatement())
// Misc/Account Related {
// Please read the descriptions above each before uncommenting them. If you are still final long cleanupStart = System.currentTimeMillis();
// unsure of what exactly it does, leave it commented out. This is for those who know int cleanCount = 0;
// what they are doing. :)
// Characters
// Deletes only accounts that HAVE been logged into and have no characters associated cleanCount += stmt.executeUpdate("DELETE FROM account_gsdata WHERE account_gsdata.account_name NOT IN (SELECT account_name FROM characters);");
// with the account. cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.contactId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.lastactive > 0 AND accounts.login NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.friendId NOT IN (SELECT charId FROM characters);");
// Deletes any accounts that don't have characters. Whether or not the player has ever cleanCount += stmt.executeUpdate("DELETE FROM character_hennas WHERE character_hennas.charId NOT IN (SELECT charId FROM characters);");
// logged into the account. cleanCount += stmt.executeUpdate("DELETE FROM character_macroses WHERE character_macroses.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_quests WHERE character_quests.charId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.login NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_recipebook WHERE character_recipebook.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipeshoplist WHERE character_recipeshoplist.charId NOT IN (SELECT charId FROM characters);");
// Deletes banned accounts that have not been logged into for xx amount of days cleanCount += stmt.executeUpdate("DELETE FROM character_shortcuts WHERE character_shortcuts.charId NOT IN (SELECT charId FROM characters);");
// (specified at the end of the script, default is set to 90 days). This prevents cleanCount += stmt.executeUpdate("DELETE FROM character_skills WHERE character_skills.charId NOT IN (SELECT charId FROM characters);");
// accounts from being deleted that were accidentally or temporarily banned. cleanCount += stmt.executeUpdate("DELETE FROM character_skills_save WHERE character_skills_save.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_subclasses WHERE character_subclasses.charId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.accessLevel < 0 AND DATEDIFF(CURRENT_DATE( ) , FROM_UNIXTIME(`lastactive`/1000)) > 90;"); cleanCount += stmt.executeUpdate("DELETE FROM character_instance_time WHERE character_instance_time.charId NOT IN (SELECT charId FROM characters);");
// cleanCount +=
// stmt.executeUpdate("DELETE FROM characters WHERE characters.account_name NOT IN (SELECT login FROM accounts);"); // Items
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id NOT IN (SELECT charId FROM characters) AND items.owner_id NOT IN (SELECT clan_id FROM clan_data) AND items.owner_id != -1;");
// If the character does not exist... cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id = -1 AND loc LIKE 'MAIL' AND loc_data NOT IN (SELECT messageId FROM messages WHERE senderId = -1);");
// Characters cleanCount += stmt.executeUpdate("DELETE FROM item_auction_bid WHERE item_auction_bid.playerObjId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM account_gsdata WHERE account_gsdata.account_name NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_variations WHERE item_variations.itemId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_elementals WHERE item_elementals.itemId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.contactId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_special_abilities WHERE item_special_abilities.objectId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_variables WHERE item_variables.id NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.friendId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_hennas WHERE character_hennas.charId NOT IN (SELECT charId FROM characters);"); // Misc
cleanCount += stmt.executeUpdate("DELETE FROM character_macroses WHERE character_macroses.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM cursed_weapons WHERE cursed_weapons.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_quests WHERE character_quests.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM heroes WHERE heroes.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipebook WHERE character_recipebook.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles WHERE olympiad_nobles.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipeshoplist WHERE character_recipeshoplist.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles_eom WHERE olympiad_nobles_eom.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_shortcuts WHERE character_shortcuts.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM pets WHERE pets.item_obj_id NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_skills WHERE character_skills.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM merchant_lease WHERE merchant_lease.player_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_skills_save WHERE character_skills_save.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_reco_bonus WHERE character_reco_bonus.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_subclasses WHERE character_subclasses.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.leader_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_instance_time WHERE character_instance_time.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.clan_id NOT IN (SELECT clanid FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charOneId NOT IN (SELECT charId FROM characters);");
// Items cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charTwoId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id NOT IN (SELECT charId FROM characters) AND items.owner_id NOT IN (SELECT clan_id FROM clan_data) AND items.owner_id != -1;"); cleanCount += stmt.executeUpdate("DELETE FROM heroes_diary WHERE heroes_diary.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id = -1 AND loc LIKE 'MAIL' AND loc_data NOT IN (SELECT messageId FROM messages WHERE senderId = -1);"); cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade WHERE character_offline_trade.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_auction_bid WHERE item_auction_bid.playerObjId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_variations WHERE item_variations.itemId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_elementals WHERE item_elementals.itemId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_special_abilities WHERE item_special_abilities.objectId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_variables WHERE item_variables.id NOT IN (SELECT object_id FROM items);");
// Clan
// Misc cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM cursed_weapons WHERE cursed_weapons.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_skills WHERE clan_skills.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM heroes WHERE heroes.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_subpledges WHERE clan_subpledges.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles WHERE olympiad_nobles.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan1 NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles_eom WHERE olympiad_nobles_eom.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan2 NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM pets WHERE pets.item_obj_id NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM siege_clans WHERE siege_clans.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM merchant_lease WHERE merchant_lease.player_id NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_notices WHERE clan_notices.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM character_reco_bonus WHERE character_reco_bonus.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM auction_bid WHERE auction_bid.bidderId NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.leader_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.clan_id NOT IN (SELECT clanid FROM characters);"); // Forums
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charOneId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT clan_id FROM clan_data) AND forums.forum_parent=2;");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charTwoId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT charId FROM characters) AND forums.forum_parent=3;");
cleanCount += stmt.executeUpdate("DELETE FROM heroes_diary WHERE heroes_diary.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM posts WHERE posts.post_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade WHERE character_offline_trade.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM topic WHERE topic.topic_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); // Update needed items after cleaning has taken place.
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
// If the clan does not exist... stmt.executeUpdate("UPDATE castle SET side='NEUTRAL' WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_skills WHERE clan_skills.clan_id NOT IN (SELECT clan_id FROM clan_data);"); stmt.executeUpdate("UPDATE fort SET owner=0 WHERE owner NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_subpledges WHERE clan_subpledges.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan1 NOT IN (SELECT clan_id FROM clan_data);"); LOGGER.info("IdFactory: Cleaned " + cleanCount + " elements from database in " + ((System.currentTimeMillis() - cleanupStart) / 1000) + " seconds.");
cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan2 NOT IN (SELECT clan_id FROM clan_data);"); }
cleanCount += stmt.executeUpdate("DELETE FROM siege_clans WHERE siege_clans.clan_id NOT IN (SELECT clan_id FROM clan_data);"); catch (Exception e)
cleanCount += stmt.executeUpdate("DELETE FROM clan_notices WHERE clan_notices.clan_id NOT IN (SELECT clan_id FROM clan_data);"); {
cleanCount += stmt.executeUpdate("DELETE FROM auction_bid WHERE auction_bid.bidderId NOT IN (SELECT clan_id FROM clan_data);"); LOGGER.warning("IdFactory: Could not clean up database: " + e);
}
// Forum Related
cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT clan_id FROM clan_data) AND forums.forum_parent=2;");
cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT charId FROM characters) AND forums.forum_parent=3;");
cleanCount += stmt.executeUpdate("DELETE FROM posts WHERE posts.post_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM topic WHERE topic.topic_forum_id NOT IN (SELECT forum_id FROM forums);");
// Update needed items after cleaning has taken place.
stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
stmt.executeUpdate("UPDATE castle SET side='NEUTRAL' WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");
stmt.executeUpdate("UPDATE fort SET owner=0 WHERE owner NOT IN (SELECT clan_id FROM clan_data);");
LOGGER.info("Cleaned " + cleanCount + " elements from database in " + ((System.currentTimeMillis() - cleanupStart) / 1000) + " s");
} }
catch (SQLException e)
{ // Cleanup timestamps.
LOGGER.log(Level.WARNING, "Could not clean up database: " + e.getMessage(), e);
}
}
private void cleanUpTimeStamps()
{
try (Connection con = DatabaseFactory.getConnection()) try (Connection con = DatabaseFactory.getConnection())
{ {
int cleanCount = 0; int cleanCount = 0;
@@ -263,62 +202,136 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate(); cleanCount += stmt.executeUpdate();
} }
} }
LOGGER.info("Cleaned " + cleanCount + " expired timestamps from database."); LOGGER.info("IdFactory: Cleaned " + cleanCount + " expired timestamps from database.");
} }
catch (SQLException e) catch (Exception e)
{ {
// Ignore. LOGGER.warning("IdFactory: Could not clean expired timestamps from database. " + e);
} }
}
// Initialize.
/** try
* @return
* @throws Exception
* @throws SQLException
*/
protected final Integer[] extractUsedObjectIDTable() throws Exception
{
final List<Integer> temp = new ArrayList<>();
try (Connection con = DatabaseFactory.getConnection();
Statement s = con.createStatement())
{ {
String extractUsedObjectIdsQuery = ""; _freeIds = new BitSet(PrimeFinder.nextPrime(100000));
_freeIds.clear();
_freeIdCount = new AtomicInteger(FREE_OBJECT_ID_SIZE);
for (String[] tblClmn : ID_EXTRACTS) // Collect already used ids.
final List<Integer> usedIds = new ArrayList<>();
try (Connection con = DatabaseFactory.getConnection();
Statement statement = con.createStatement())
{ {
extractUsedObjectIdsQuery += "SELECT " + tblClmn[1] + " FROM " + tblClmn[0] + " UNION "; String extractUsedObjectIdsQuery = "";
} for (String[] tblClmn : ID_EXTRACTS)
extractUsedObjectIdsQuery = extractUsedObjectIdsQuery.substring(0, extractUsedObjectIdsQuery.length() - 7); // Remove the last " UNION "
try (ResultSet rs = s.executeQuery(extractUsedObjectIdsQuery))
{
while (rs.next())
{ {
temp.add(rs.getInt(1)); extractUsedObjectIdsQuery += "SELECT " + tblClmn[1] + " FROM " + tblClmn[0] + " UNION ";
}
extractUsedObjectIdsQuery = extractUsedObjectIdsQuery.substring(0, extractUsedObjectIdsQuery.length() - 7); // Remove the last " UNION "
try (ResultSet result = statement.executeQuery(extractUsedObjectIdsQuery))
{
while (result.next())
{
usedIds.add(result.getInt(1));
}
} }
} }
Collections.sort(usedIds);
// Register used ids.
for (int usedObjectId : usedIds)
{
final int objectId = usedObjectId - FIRST_OID;
if (objectId < 0)
{
LOGGER.warning("IdFactory: Object ID " + usedObjectId + " in DB is less than minimum ID of " + FIRST_OID);
continue;
}
_freeIds.set(usedObjectId - FIRST_OID);
_freeIdCount.decrementAndGet();
}
_nextFreeId = new AtomicInteger(_freeIds.nextClearBit(0));
_initialized = true;
} }
Collections.sort(temp); catch (Exception e)
return temp.toArray(new Integer[temp.size()]); {
_initialized = false;
LOGGER.severe("IdFactory: Could not be initialized properly: " + e.getMessage());
}
// Schedule increase capacity task.
ThreadPool.scheduleAtFixedRate(() ->
{
synchronized (_nextFreeId)
{
if (PrimeFinder.nextPrime((usedIdCount() * 11) / 10) > _freeIds.size())
{
increaseBitSetCapacity();
}
}
}, 30000, 30000);
LOGGER.info("IdFactory: " + _freeIds.size() + " id's available.");
} }
public boolean isInitialized() public synchronized static void releaseId(int objectId)
{
synchronized (_nextFreeId)
{
if ((objectId - FIRST_OID) > -1)
{
_freeIds.clear(objectId - FIRST_OID);
_freeIdCount.incrementAndGet();
}
else
{
LOGGER.warning("IdFactory: Release objectID " + objectId + " failed (< " + FIRST_OID + ")");
}
}
}
public synchronized static int getNextId()
{
synchronized (_nextFreeId)
{
final int newId = _nextFreeId.get();
_freeIds.set(newId);
_freeIdCount.decrementAndGet();
final int nextFree = _freeIds.nextClearBit(newId) < 0 ? _freeIds.nextClearBit(0) : _freeIds.nextClearBit(newId);
if (nextFree < 0)
{
if (_freeIds.size() >= FREE_OBJECT_ID_SIZE)
{
throw new NullPointerException("IdFactory: Ran out of valid ids.");
}
increaseBitSetCapacity();
}
_nextFreeId.set(nextFree);
return newId + FIRST_OID;
}
}
private static void increaseBitSetCapacity()
{
final BitSet newBitSet = new BitSet(PrimeFinder.nextPrime((usedIdCount() * 11) / 10));
newBitSet.or(_freeIds);
_freeIds = newBitSet;
}
private static int usedIdCount()
{
return _freeIdCount.get() - FIRST_OID;
}
public static int size()
{
return _freeIdCount.get();
}
public static boolean hasInitialized()
{ {
return _initialized; return _initialized;
} }
public static IdFactory getInstance()
{
return _instance;
}
public abstract int getNextId();
/**
* return a used Object ID back to the pool
* @param id
*/
public abstract void releaseId(int id);
public abstract int size();
} }
@@ -1,152 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.idfactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Stack;
import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory;
/**
* @version $Revision: 1.3.2.1.2.7 $ $Date: 2005/04/11 10:06:12 $
*/
public class StackIDFactory extends IdFactory
{
private int _curOID;
private int _tempOID;
private final Stack<Integer> _freeOIDStack = new Stack<>();
protected StackIDFactory()
{
super();
_curOID = FIRST_OID;
_tempOID = FIRST_OID;
try (Connection con = DatabaseFactory.getConnection())
{
// con.createStatement().execute("drop table if exists tmp_obj_id");
final Integer[] tmpObjIds = extractUsedObjectIDTable();
if (tmpObjIds.length > 0)
{
_curOID = tmpObjIds[tmpObjIds.length - 1];
}
LOGGER.info("Max Id = " + _curOID);
int n = tmpObjIds.length;
for (int idx = 0; idx < n; idx++)
{
n = insertUntil(tmpObjIds, idx, n, con);
}
_curOID++;
LOGGER.info("IdFactory: Next usable Object ID is: " + _curOID);
_initialized = true;
}
catch (Exception e)
{
LOGGER.severe(getClass().getSimpleName() + ": Could not be initialized properly:" + e.getMessage());
}
}
private int insertUntil(Integer[] tmpObjIds, int idx, int n, Connection con) throws SQLException
{
final int id = tmpObjIds[idx];
if (id == _tempOID)
{
_tempOID++;
return n;
}
// check these IDs not present in DB
if (Config.BAD_ID_CHECKING)
{
for (String check : ID_CHECKS)
{
try (PreparedStatement ps = con.prepareStatement(check))
{
ps.setInt(1, _tempOID);
// ps.setInt(1, _curOID);
ps.setInt(2, id);
try (ResultSet rs = ps.executeQuery())
{
if (rs.next())
{
final int badId = rs.getInt(1);
LOGGER.severe("Bad ID " + badId + " in DB found by: " + check);
throw new RuntimeException();
}
}
}
}
}
// int hole = id - _curOID;
final int hole = (id - _tempOID) > (n - idx) ? n - idx : id - _tempOID;
for (int i = 1; i <= hole; i++)
{
_freeOIDStack.push(_tempOID);
_tempOID++;
}
if (hole < (n - idx))
{
_tempOID++;
}
return n - hole;
}
public static IdFactory getInstance()
{
return _instance;
}
@Override
public synchronized int getNextId()
{
int id;
if (!_freeOIDStack.empty())
{
id = _freeOIDStack.pop();
}
else
{
id = _curOID;
_curOID += 1;
}
return id;
}
/**
* return a used Object ID back to the pool
* @param id
*/
@Override
public synchronized void releaseId(int id)
{
_freeOIDStack.push(id);
}
@Override
public int size()
{
return (FREE_OBJECT_ID_SIZE - _curOID) + FIRST_OID + _freeOIDStack.size();
}
}
@@ -123,7 +123,7 @@ public class AirShipManager
if (_airShips.containsKey(ownerId)) if (_airShips.containsKey(ownerId))
{ {
airShip = _airShips.get(ownerId); airShip = _airShips.get(ownerId);
airShip.refreshID(); airShip.refreshId();
} }
else else
{ {
@@ -282,7 +282,7 @@ public class MailManager
} }
_messages.remove(msgId); _messages.remove(msgId);
IdFactory.getInstance().releaseId(msgId); IdFactory.releaseId(msgId);
} }
/** /**
@@ -47,7 +47,7 @@ public class Petition
public Petition(PlayerInstance petitioner, String petitionText, int petitionType) public Petition(PlayerInstance petitioner, String petitionText, int petitionType)
{ {
_id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
_type = PetitionType.values()[--petitionType]; _type = PetitionType.values()[--petitionType];
_content = petitionText; _content = petitionText;
_petitioner = petitioner; _petitioner = petitioner;
@@ -532,7 +532,7 @@ public class Spawn extends Location implements IIdentifiable, INamable
{ {
if (_doRespawn) if (_doRespawn)
{ {
oldNpc.refreshID(); // oldNpc.refreshID();
initializeNpcInstance(oldNpc); initializeNpcInstance(oldNpc);
// Register NPC back to instance world. // Register NPC back to instance world.
@@ -151,11 +151,11 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return true; return true;
} }
public void refreshID() public void refreshId()
{ {
World.getInstance().removeObject(this); World.getInstance().removeObject(this);
IdFactory.getInstance().releaseId(getObjectId()); IdFactory.releaseId(getObjectId());
_objectId = IdFactory.getInstance().getNextId(); _objectId = IdFactory.getNextId();
} }
@Override @Override
@@ -290,7 +290,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
*/ */
public Creature(CreatureTemplate template) public Creature(CreatureTemplate template)
{ {
this(IdFactory.getInstance().getNextId(), template); this(IdFactory.getNextId(), template);
} }
/** /**
@@ -48,7 +48,7 @@ public class ControllableAirShipInstance extends AirShipInstance
super(template); super(template);
setInstanceType(InstanceType.ControllableAirShipInstance); setInstanceType(InstanceType.ControllableAirShipInstance);
_ownerId = ownerId; _ownerId = ownerId;
_helmId = IdFactory.getInstance().getNextId(); // not forget to release ! _helmId = IdFactory.getNextId(); // not forget to release !
} }
@Override @Override
@@ -281,11 +281,11 @@ public class ControllableAirShipInstance extends AirShipInstance
} }
@Override @Override
public void refreshID() public void refreshId()
{ {
super.refreshID(); super.refreshId();
IdFactory.getInstance().releaseId(_helmId); IdFactory.releaseId(_helmId);
_helmId = IdFactory.getInstance().getNextId(); _helmId = IdFactory.getNextId();
} }
@Override @Override
@@ -44,7 +44,7 @@ public class FenceInstance extends WorldObject
public FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state) public FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
{ {
super(IdFactory.getInstance().getNextId()); super(IdFactory.getNextId());
_xMin = x - (width / 2); _xMin = x - (width / 2);
_xMax = x + (width / 2); _xMax = x + (width / 2);
@@ -62,7 +62,7 @@ public class FenceInstance extends WorldObject
_heightFences = new int[height - 1]; _heightFences = new int[height - 1];
for (int i = 0; i < _heightFences.length; i++) for (int i = 0; i < _heightFences.length; i++)
{ {
_heightFences[i] = IdFactory.getInstance().getNextId(); _heightFences[i] = IdFactory.getNextId();
} }
} }
} }
@@ -1143,7 +1143,7 @@ public class PlayerInstance extends Playable
*/ */
private PlayerInstance(PlayerTemplate template, String accountName, PlayerAppearance app) private PlayerInstance(PlayerTemplate template, String accountName, PlayerAppearance app)
{ {
this(IdFactory.getInstance().getNextId(), template, accountName, app); this(IdFactory.getNextId(), template, accountName, app);
} }
@Override @Override
@@ -164,7 +164,7 @@ public class RaceManagerInstance extends Npc
player.setRace(0, 0); player.setRace(0, 0);
player.setRace(1, 0); player.setRace(1, 0);
ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), 4443); ItemInstance item = new ItemInstance(IdFactory.getNextId(), 4443);
item.setCount(1); item.setCount(1);
item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber()); item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber());
item.setCustomType1(ticket); item.setCustomType1(ticket);
@@ -32,7 +32,7 @@ public class EventAnnouncement implements IAnnouncement
public EventAnnouncement(DateRange range, String content) public EventAnnouncement(DateRange range, String content)
{ {
_id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
_range = range; _range = range;
_content = content; _content = content;
} }
@@ -88,7 +88,7 @@ public class EventAnnouncement implements IAnnouncement
@Override @Override
public boolean deleteMe() public boolean deleteMe()
{ {
IdFactory.getInstance().releaseId(_id); IdFactory.releaseId(_id);
return true; return true;
} }
@@ -34,7 +34,7 @@ public class Couple
{ {
private static final Logger LOGGER = Logger.getLogger(Couple.class.getName()); private static final Logger LOGGER = Logger.getLogger(Couple.class.getName());
private int _Id = 0; private int _id = 0;
private int _player1Id = 0; private int _player1Id = 0;
private int _player2Id = 0; private int _player2Id = 0;
private boolean _maried = false; private boolean _maried = false;
@@ -43,12 +43,12 @@ public class Couple
public Couple(int coupleId) public Couple(int coupleId)
{ {
_Id = coupleId; _id = coupleId;
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM mods_wedding WHERE id = ?")) PreparedStatement ps = con.prepareStatement("SELECT * FROM mods_wedding WHERE id = ?"))
{ {
ps.setInt(1, _Id); ps.setInt(1, _id);
try (ResultSet rs = ps.executeQuery()) try (ResultSet rs = ps.executeQuery())
{ {
while (rs.next()) while (rs.next())
@@ -88,8 +88,8 @@ public class Couple
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO mods_wedding (id, player1Id, player2Id, married, affianceDate, weddingDate) VALUES (?, ?, ?, ?, ?, ?)")) PreparedStatement ps = con.prepareStatement("INSERT INTO mods_wedding (id, player1Id, player2Id, married, affianceDate, weddingDate) VALUES (?, ?, ?, ?, ?, ?)"))
{ {
_Id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
ps.setInt(1, _Id); ps.setInt(1, _id);
ps.setInt(2, _player1Id); ps.setInt(2, _player1Id);
ps.setInt(3, _player2Id); ps.setInt(3, _player2Id);
ps.setBoolean(4, false); ps.setBoolean(4, false);
@@ -111,7 +111,7 @@ public class Couple
ps.setBoolean(1, true); ps.setBoolean(1, true);
_weddingDate = Calendar.getInstance(); _weddingDate = Calendar.getInstance();
ps.setLong(2, _weddingDate.getTimeInMillis()); ps.setLong(2, _weddingDate.getTimeInMillis());
ps.setInt(3, _Id); ps.setInt(3, _id);
ps.execute(); ps.execute();
_maried = true; _maried = true;
} }
@@ -126,7 +126,7 @@ public class Couple
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM mods_wedding WHERE id=?")) PreparedStatement ps = con.prepareStatement("DELETE FROM mods_wedding WHERE id=?"))
{ {
ps.setInt(1, _Id); ps.setInt(1, _id);
ps.execute(); ps.execute();
} }
catch (Exception e) catch (Exception e)
@@ -137,7 +137,7 @@ public class Couple
public int getId() public int getId()
{ {
return _Id; return _id;
} }
public int getPlayer1Id() public int getPlayer1Id()
@@ -99,7 +99,7 @@ public class Message
*/ */
public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena) public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = senderId; _senderId = senderId;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -118,7 +118,7 @@ public class Message
*/ */
public Message(int receiverId, String subject, String content, MailType sendBySystem) public Message(int receiverId, String subject, String content, MailType sendBySystem)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = -1; _senderId = -1;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -138,7 +138,7 @@ public class Message
*/ */
public Message(int senderId, int receiverId, String subject, String content, MailType sendBySystem) public Message(int senderId, int receiverId, String subject, String content, MailType sendBySystem)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = senderId; _senderId = senderId;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -157,7 +157,7 @@ public class Message
*/ */
public Message(Message msg) public Message(Message msg)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = msg.getSenderId(); _senderId = msg.getSenderId();
_receiverId = msg.getSenderId(); _receiverId = msg.getSenderId();
_subject = ""; _subject = "";
@@ -177,7 +177,7 @@ public class Message
public Message(int receiverId, ItemInstance item, MailType mailType) public Message(int receiverId, ItemInstance item, MailType mailType)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = -1; _senderId = -1;
_receiverId = receiverId; _receiverId = receiverId;
_subject = ""; _subject = "";
@@ -79,7 +79,7 @@ public class AuctionItem
public ItemInstance createNewItemInstance() public ItemInstance createNewItemInstance()
{ {
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), _itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), _itemId);
World.getInstance().addObject(item); World.getInstance().addObject(item);
item.setCount(_itemCount); item.setCount(_itemCount);
item.setEnchantLevel(item.getItem().getDefaultEnchantLevel()); item.setEnchantLevel(item.getItem().getDefaultEnchantLevel());
@@ -259,7 +259,7 @@ public class ItemInstance extends WorldObject
*/ */
public ItemInstance(int itemId) public ItemInstance(int itemId)
{ {
this(IdFactory.getInstance().getNextId(), itemId); this(IdFactory.getNextId(), itemId);
} }
/** /**
@@ -50,7 +50,7 @@ public abstract class ZoneForm
protected final void dropDebugItem(int itemId, int num, int x, int y, int z) protected final void dropDebugItem(int itemId, int num, int x, int y, int z)
{ {
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), itemId);
item.setCount(num); item.setCount(num);
item.spawnMe(x, y, z + 5); item.spawnMe(x, y, z + 5);
ZoneManager.getInstance().getDebugItems().add(item); ZoneManager.getInstance().getDebugItems().add(item);
@@ -248,7 +248,7 @@ public class MinionList
// minion can be already spawned or deleted // minion can be already spawned or deleted
if (!_master.isAlikeDead() && _master.isSpawned() && !_minion.isSpawned()) if (!_master.isAlikeDead() && _master.isSpawned() && !_minion.isSpawned())
{ {
_minion.refreshID(); // _minion.refreshId();
initializeNpcInstance(_master, _minion); initializeNpcInstance(_master, _minion);
// assist master // assist master
@@ -1,20 +0,0 @@
# ---------------------------------------------------------------------------
# ID Factory Settings
# ---------------------------------------------------------------------------
# Warning:
# Please take extreme caution when changing anything. Also please understand what you are changing before you do so on a live server.
# ---------------------------------------------------------------------------
# Standard Settings
# ---------------------------------------------------------------------------
# Tell server which IDFactory Class to use:
# BITSET = One non compaction method
# STACK = Another non compaction method
# Default: BITSET
IDFactory = BITSET
# Check for bad ids in the database on server boot up.
# Much faster load time without it, but may cause problems.
# Default: True
BadIdChecking = True
@@ -55,7 +55,6 @@ import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.l2jmobius.commons.enums.IdFactoryType;
import org.l2jmobius.commons.enums.ServerMode; import org.l2jmobius.commons.enums.ServerMode;
import org.l2jmobius.commons.util.IXmlReader; import org.l2jmobius.commons.util.IXmlReader;
import org.l2jmobius.commons.util.PropertiesParser; import org.l2jmobius.commons.util.PropertiesParser;
@@ -97,7 +96,6 @@ public class Config
private static final String GENERAL_CONFIG_FILE = "./config/General.ini"; private static final String GENERAL_CONFIG_FILE = "./config/General.ini";
private static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini"; private static final String GRACIASEEDS_CONFIG_FILE = "./config/GraciaSeeds.ini";
private static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini"; private static final String GRANDBOSS_CONFIG_FILE = "./config/GrandBoss.ini";
private static final String IDFACTORY_CONFIG_FILE = "./config/IdFactory.ini";
private static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini"; private static final String LOGIN_CONFIG_FILE = "./config/LoginServer.ini";
private static final String NPC_CONFIG_FILE = "./config/NPC.ini"; private static final String NPC_CONFIG_FILE = "./config/NPC.ini";
private static final String PVP_CONFIG_FILE = "./config/PVP.ini"; private static final String PVP_CONFIG_FILE = "./config/PVP.ini";
@@ -797,9 +795,6 @@ public class Config
public static int MAX_REPUTATION; public static int MAX_REPUTATION;
public static int REPUTATION_INCREASE; public static int REPUTATION_INCREASE;
public static IdFactoryType IDFACTORY_TYPE;
public static boolean BAD_ID_CHECKING;
public static int[] ENCHANT_BLACKLIST; public static int[] ENCHANT_BLACKLIST;
public static boolean DISABLE_OVER_ENCHANTING; public static boolean DISABLE_OVER_ENCHANTING;
public static int[] AUGMENTATION_BLACKLIST; public static int[] AUGMENTATION_BLACKLIST;
@@ -1942,12 +1937,6 @@ public class Config
TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0); TRAINING_CAMP_EXP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampExpMultiplier", 1.0);
TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0); TRAINING_CAMP_SP_MULTIPLIER = trainingCampSettings.getDouble("TrainingCampSpMultiplier", 1.0);
// Load IdFactory config file (if exists)
final PropertiesParser IdFactory = new PropertiesParser(IDFACTORY_CONFIG_FILE);
IDFACTORY_TYPE = IdFactory.getEnum("IDFactory", IdFactoryType.class, IdFactoryType.BITSET);
BAD_ID_CHECKING = IdFactory.getBoolean("BadIdChecking", true);
// Load General config file (if exists) // Load General config file (if exists)
final PropertiesParser General = new PropertiesParser(GENERAL_CONFIG_FILE); final PropertiesParser General = new PropertiesParser(GENERAL_CONFIG_FILE);
DEFAULT_ACCESS_LEVEL = General.getInt("DefaultAccessLevel", 0); DEFAULT_ACCESS_LEVEL = General.getInt("DefaultAccessLevel", 0);
@@ -1,26 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.commons.enums;
/**
* @author Mobius
*/
public enum IdFactoryType
{
BITSET,
STACK
}
@@ -209,7 +209,8 @@ public class GameServer
ThreadPool.init(); ThreadPool.init();
printSection("IdFactory"); printSection("IdFactory");
if (!IdFactory.getInstance().isInitialized()) IdFactory.init();
if (!IdFactory.hasInitialized())
{ {
LOGGER.severe(getClass().getSimpleName() + ": Could not read object IDs from database. Please check your configuration."); LOGGER.severe(getClass().getSimpleName() + ": Could not read object IDs from database. Please check your configuration.");
throw new Exception("Could not initialize the ID factory!"); throw new Exception("Could not initialize the ID factory!");
@@ -424,7 +425,7 @@ public class GameServer
Runtime.getRuntime().addShutdownHook(Shutdown.getInstance()); Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.getInstance().size()); LOGGER.info("IdFactory: Free ObjectID's remaining: " + IdFactory.size());
if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS) if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
{ {
@@ -189,7 +189,7 @@ public class ClanTable
return null; return null;
} }
final Clan clan = new Clan(IdFactory.getInstance().getNextId(), clanName); final Clan clan = new Clan(IdFactory.getNextId(), clanName);
final ClanMember leader = new ClanMember(clan, player); final ClanMember leader = new ClanMember(clan, player);
clan.setLeader(leader); clan.setLeader(leader);
leader.setPlayerInstance(player); leader.setPlayerInstance(player);
@@ -264,7 +264,7 @@ public class ClanTable
} }
_clans.remove(clanId); _clans.remove(clanId);
IdFactory.getInstance().releaseId(clanId); IdFactory.releaseId(clanId);
try (Connection con = DatabaseFactory.getConnection()) try (Connection con = DatabaseFactory.getConnection())
{ {
@@ -210,7 +210,7 @@ public class ItemTable
public ItemInstance createItem(String process, int itemId, long count, Creature actor, Object reference) public ItemInstance createItem(String process, int itemId, long count, Creature actor, Object reference)
{ {
// Create and Init the ItemInstance corresponding to the Item Identifier // Create and Init the ItemInstance corresponding to the Item Identifier
final ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), itemId); final ItemInstance item = new ItemInstance(IdFactory.getNextId(), itemId);
if (process.equalsIgnoreCase("loot") && !Config.AUTO_LOOT_ITEM_IDS.contains(itemId)) if (process.equalsIgnoreCase("loot") && !Config.AUTO_LOOT_ITEM_IDS.contains(itemId))
{ {
@@ -328,7 +328,7 @@ public class ItemTable
item.setLastChange(ItemInstance.REMOVED); item.setLastChange(ItemInstance.REMOVED);
World.getInstance().removeObject(item); World.getInstance().removeObject(item);
IdFactory.getInstance().releaseId(item.getObjectId()); IdFactory.releaseId(item.getObjectId());
if (Config.LOG_ITEMS) if (Config.LOG_ITEMS)
{ {
@@ -1,151 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.idfactory;
import java.util.BitSet;
import java.util.concurrent.atomic.AtomicInteger;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.util.PrimeFinder;
/**
* This class ..
* @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
*/
public class BitSetIDFactory extends IdFactory
{
private BitSet _freeIds;
private AtomicInteger _freeIdCount;
private AtomicInteger _nextFreeId;
protected class BitSetCapacityCheck implements Runnable
{
@Override
public void run()
{
synchronized (BitSetIDFactory.this)
{
if (reachingBitSetCapacity())
{
increaseBitSetCapacity();
}
}
}
}
protected BitSetIDFactory()
{
super();
synchronized (BitSetIDFactory.class)
{
ThreadPool.scheduleAtFixedRate(new BitSetCapacityCheck(), 30000, 30000);
initialize();
}
LOGGER.info(getClass().getSimpleName() + ": " + _freeIds.size() + " id's available.");
}
public void initialize()
{
try
{
_freeIds = new BitSet(PrimeFinder.nextPrime(100000));
_freeIds.clear();
_freeIdCount = new AtomicInteger(FREE_OBJECT_ID_SIZE);
for (int usedObjectId : extractUsedObjectIDTable())
{
final int objectID = usedObjectId - FIRST_OID;
if (objectID < 0)
{
LOGGER.warning(getClass().getSimpleName() + ": Object ID " + usedObjectId + " in DB is less than minimum ID of " + FIRST_OID);
continue;
}
_freeIds.set(usedObjectId - FIRST_OID);
_freeIdCount.decrementAndGet();
}
_nextFreeId = new AtomicInteger(_freeIds.nextClearBit(0));
_initialized = true;
}
catch (Exception e)
{
_initialized = false;
LOGGER.severe(getClass().getSimpleName() + ": Could not be initialized properly: " + e.getMessage());
}
}
@Override
public synchronized void releaseId(int objectID)
{
if ((objectID - FIRST_OID) > -1)
{
_freeIds.clear(objectID - FIRST_OID);
_freeIdCount.incrementAndGet();
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Release objectID " + objectID + " failed (< " + FIRST_OID + ")");
}
}
@Override
public synchronized int getNextId()
{
final int newID = _nextFreeId.get();
_freeIds.set(newID);
_freeIdCount.decrementAndGet();
final int nextFree = _freeIds.nextClearBit(newID) < 0 ? _freeIds.nextClearBit(0) : _freeIds.nextClearBit(newID);
if (nextFree < 0)
{
if (_freeIds.size() >= FREE_OBJECT_ID_SIZE)
{
throw new NullPointerException("Ran out of valid Id's.");
}
increaseBitSetCapacity();
}
_nextFreeId.set(nextFree);
return newID + FIRST_OID;
}
@Override
public synchronized int size()
{
return _freeIdCount.get();
}
protected synchronized int usedIdCount()
{
return _freeIdCount.get() - FIRST_OID;
}
protected synchronized boolean reachingBitSetCapacity()
{
return PrimeFinder.nextPrime((usedIdCount() * 11) / 10) > _freeIds.size();
}
protected synchronized void increaseBitSetCapacity()
{
final BitSet newBitSet = new BitSet(PrimeFinder.nextPrime((usedIdCount() * 11) / 10));
newBitSet.or(_freeIds);
_freeIds = newBitSet;
}
}
@@ -19,23 +19,25 @@ package org.l2jmobius.gameserver.idfactory;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.commons.database.DatabaseFactory; import org.l2jmobius.commons.database.DatabaseFactory;
import org.l2jmobius.gameserver.util.PrimeFinder;
/** /**
* @version $Revision: 1.3.2.1.2.7 $ $Date: 2005/04/11 10:06:12 $ * @author Mobius (reworked from L2J version)
*/ */
public abstract class IdFactory public abstract class IdFactory
{ {
protected final Logger LOGGER = Logger.getLogger(getClass().getName()); private static final Logger LOGGER = Logger.getLogger(IdFactory.class.getName());
protected static final String[] ID_CHECKS = protected static final String[] ID_CHECKS =
{ {
@@ -64,7 +66,6 @@ public abstract class IdFactory
"SELECT object_id FROM itemsonground WHERE object_id >= ? AND object_id < ?", "SELECT object_id FROM itemsonground WHERE object_id >= ? AND object_id < ?",
"SELECT summonId FROM characters_summons WHERE summonId >= ? AND summonId < ?" "SELECT summonId FROM characters_summons WHERE summonId >= ? AND summonId < ?"
}; };
//@formatter:off //@formatter:off
private static final String[][] ID_EXTRACTS = private static final String[][] ID_EXTRACTS =
{ {
@@ -75,183 +76,121 @@ public abstract class IdFactory
{"messages","messageId"} {"messages","messageId"}
}; };
//@formatter:on //@formatter:on
private static final String[] TIMESTAMPS_CLEAN = private static final String[] TIMESTAMPS_CLEAN =
{ {
"DELETE FROM character_instance_time WHERE time <= ?", "DELETE FROM character_instance_time WHERE time <= ?",
"DELETE FROM character_skills_save WHERE restore_type = 1 AND systime <= ?" "DELETE FROM character_skills_save WHERE restore_type = 1 AND systime <= ?"
}; };
protected boolean _initialized;
public static final int FIRST_OID = 0x10000000; public static final int FIRST_OID = 0x10000000;
public static final int LAST_OID = 0x7FFFFFFF; public static final int LAST_OID = 0x7FFFFFFF;
public static final int FREE_OBJECT_ID_SIZE = LAST_OID - FIRST_OID; public static final int FREE_OBJECT_ID_SIZE = LAST_OID - FIRST_OID;
protected static final IdFactory _instance; private static BitSet _freeIds;
private static AtomicInteger _freeIdCount;
private static AtomicInteger _nextFreeId;
private static boolean _initialized;
protected IdFactory() public static void init()
{
setAllCharacterOffline();
if (Config.DATABASE_CLEAN_UP)
{
cleanUpDB();
}
cleanUpTimeStamps();
}
static
{
switch (Config.IDFACTORY_TYPE)
{
case BITSET:
{
_instance = new BitSetIDFactory();
break;
}
case STACK:
{
_instance = new StackIDFactory();
break;
}
default:
{
_instance = null;
break;
}
}
}
/**
* Sets all character offline
*/
private void setAllCharacterOffline()
{ {
// Update characters online status.
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
Statement s = con.createStatement()) Statement s = con.createStatement())
{ {
s.executeUpdate("UPDATE characters SET online = 0"); s.executeUpdate("UPDATE characters SET online = 0");
LOGGER.info("Updated characters online status."); LOGGER.info("Updated characters online status.");
} }
catch (SQLException e) catch (Exception e)
{ {
LOGGER.log(Level.WARNING, "Could not update characters online status: " + e.getMessage(), e); LOGGER.warning("IdFactory: Could not update characters online status: " + e);
} }
}
// Cleanup database.
/** if (Config.DATABASE_CLEAN_UP)
* Cleans up Database
*/
private void cleanUpDB()
{
try (Connection con = DatabaseFactory.getConnection();
Statement stmt = con.createStatement())
{ {
final long cleanupStart = System.currentTimeMillis(); try (Connection con = DatabaseFactory.getConnection();
int cleanCount = 0; Statement stmt = con.createStatement())
// Misc/Account Related {
// Please read the descriptions above each before uncommenting them. If you are still final long cleanupStart = System.currentTimeMillis();
// unsure of what exactly it does, leave it commented out. This is for those who know int cleanCount = 0;
// what they are doing. :)
// Characters
// Deletes only accounts that HAVE been logged into and have no characters associated cleanCount += stmt.executeUpdate("DELETE FROM account_gsdata WHERE account_gsdata.account_name NOT IN (SELECT account_name FROM characters);");
// with the account. cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.contactId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.lastactive > 0 AND accounts.login NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.friendId NOT IN (SELECT charId FROM characters);");
// Deletes any accounts that don't have characters. Whether or not the player has ever cleanCount += stmt.executeUpdate("DELETE FROM character_hennas WHERE character_hennas.charId NOT IN (SELECT charId FROM characters);");
// logged into the account. cleanCount += stmt.executeUpdate("DELETE FROM character_macroses WHERE character_macroses.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_quests WHERE character_quests.charId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.login NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_recipebook WHERE character_recipebook.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipeshoplist WHERE character_recipeshoplist.charId NOT IN (SELECT charId FROM characters);");
// Deletes banned accounts that have not been logged into for xx amount of days cleanCount += stmt.executeUpdate("DELETE FROM character_shortcuts WHERE character_shortcuts.charId NOT IN (SELECT charId FROM characters);");
// (specified at the end of the script, default is set to 90 days). This prevents cleanCount += stmt.executeUpdate("DELETE FROM character_skills WHERE character_skills.charId NOT IN (SELECT charId FROM characters);");
// accounts from being deleted that were accidentally or temporarily banned. cleanCount += stmt.executeUpdate("DELETE FROM character_skills_save WHERE character_skills_save.charId NOT IN (SELECT charId FROM characters);");
// cleanCount += cleanCount += stmt.executeUpdate("DELETE FROM character_subclasses WHERE character_subclasses.charId NOT IN (SELECT charId FROM characters);");
// stmt.executeUpdate("DELETE FROM accounts WHERE accounts.accessLevel < 0 AND DATEDIFF(CURRENT_DATE( ) , FROM_UNIXTIME(`lastactive`/1000)) > 90;"); cleanCount += stmt.executeUpdate("DELETE FROM character_instance_time WHERE character_instance_time.charId NOT IN (SELECT charId FROM characters);");
// cleanCount +=
// stmt.executeUpdate("DELETE FROM characters WHERE characters.account_name NOT IN (SELECT login FROM accounts);"); // Items
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id NOT IN (SELECT charId FROM characters) AND items.owner_id NOT IN (SELECT clan_id FROM clan_data) AND items.owner_id != -1;");
// If the character does not exist... cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id = -1 AND loc LIKE 'MAIL' AND loc_data NOT IN (SELECT messageId FROM messages WHERE senderId = -1);");
// Characters cleanCount += stmt.executeUpdate("DELETE FROM item_auction_bid WHERE item_auction_bid.playerObjId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM account_gsdata WHERE account_gsdata.account_name NOT IN (SELECT account_name FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_variations WHERE item_variations.itemId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_elementals WHERE item_elementals.itemId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_contacts WHERE character_contacts.contactId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_special_abilities WHERE item_special_abilities.objectId NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM item_variables WHERE item_variables.id NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_friends WHERE character_friends.friendId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_hennas WHERE character_hennas.charId NOT IN (SELECT charId FROM characters);"); // Misc
cleanCount += stmt.executeUpdate("DELETE FROM character_macroses WHERE character_macroses.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM cursed_weapons WHERE cursed_weapons.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_quests WHERE character_quests.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM heroes WHERE heroes.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipebook WHERE character_recipebook.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles WHERE olympiad_nobles.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_recipeshoplist WHERE character_recipeshoplist.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles_eom WHERE olympiad_nobles_eom.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_shortcuts WHERE character_shortcuts.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM pets WHERE pets.item_obj_id NOT IN (SELECT object_id FROM items);");
cleanCount += stmt.executeUpdate("DELETE FROM character_skills WHERE character_skills.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM merchant_lease WHERE merchant_lease.player_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_skills_save WHERE character_skills_save.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_reco_bonus WHERE character_reco_bonus.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_subclasses WHERE character_subclasses.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.leader_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_instance_time WHERE character_instance_time.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.clan_id NOT IN (SELECT clanid FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charOneId NOT IN (SELECT charId FROM characters);");
// Items cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charTwoId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id NOT IN (SELECT charId FROM characters) AND items.owner_id NOT IN (SELECT clan_id FROM clan_data) AND items.owner_id != -1;"); cleanCount += stmt.executeUpdate("DELETE FROM heroes_diary WHERE heroes_diary.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM items WHERE items.owner_id = -1 AND loc LIKE 'MAIL' AND loc_data NOT IN (SELECT messageId FROM messages WHERE senderId = -1);"); cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade WHERE character_offline_trade.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_auction_bid WHERE item_auction_bid.playerObjId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_variations WHERE item_variations.itemId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_elementals WHERE item_elementals.itemId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_special_abilities WHERE item_special_abilities.objectId NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM item_variables WHERE item_variables.id NOT IN (SELECT object_id FROM items);");
// Clan
// Misc cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM cursed_weapons WHERE cursed_weapons.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_skills WHERE clan_skills.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM heroes WHERE heroes.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_subpledges WHERE clan_subpledges.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles WHERE olympiad_nobles.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan1 NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_nobles_eom WHERE olympiad_nobles_eom.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan2 NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM pets WHERE pets.item_obj_id NOT IN (SELECT object_id FROM items);"); cleanCount += stmt.executeUpdate("DELETE FROM siege_clans WHERE siege_clans.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM merchant_lease WHERE merchant_lease.player_id NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM clan_notices WHERE clan_notices.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM character_reco_bonus WHERE character_reco_bonus.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM auction_bid WHERE auction_bid.bidderId NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.leader_id NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_data WHERE clan_data.clan_id NOT IN (SELECT clanid FROM characters);"); // Forums
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charOneId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT clan_id FROM clan_data) AND forums.forum_parent=2;");
cleanCount += stmt.executeUpdate("DELETE FROM olympiad_fights WHERE olympiad_fights.charTwoId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT charId FROM characters) AND forums.forum_parent=3;");
cleanCount += stmt.executeUpdate("DELETE FROM heroes_diary WHERE heroes_diary.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM posts WHERE posts.post_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade WHERE character_offline_trade.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM topic WHERE topic.topic_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); // Update needed items after cleaning has taken place.
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
// If the clan does not exist... stmt.executeUpdate("UPDATE castle SET side='NEUTRAL' WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_skills WHERE clan_skills.clan_id NOT IN (SELECT clan_id FROM clan_data);"); stmt.executeUpdate("UPDATE fort SET owner=0 WHERE owner NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_subpledges WHERE clan_subpledges.clan_id NOT IN (SELECT clan_id FROM clan_data);");
cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan1 NOT IN (SELECT clan_id FROM clan_data);"); LOGGER.info("IdFactory: Cleaned " + cleanCount + " elements from database in " + ((System.currentTimeMillis() - cleanupStart) / 1000) + " seconds.");
cleanCount += stmt.executeUpdate("DELETE FROM clan_wars WHERE clan_wars.clan2 NOT IN (SELECT clan_id FROM clan_data);"); }
cleanCount += stmt.executeUpdate("DELETE FROM siege_clans WHERE siege_clans.clan_id NOT IN (SELECT clan_id FROM clan_data);"); catch (Exception e)
cleanCount += stmt.executeUpdate("DELETE FROM clan_notices WHERE clan_notices.clan_id NOT IN (SELECT clan_id FROM clan_data);"); {
cleanCount += stmt.executeUpdate("DELETE FROM auction_bid WHERE auction_bid.bidderId NOT IN (SELECT clan_id FROM clan_data);"); LOGGER.warning("IdFactory: Could not clean up database: " + e);
}
// Forum Related
cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT clan_id FROM clan_data) AND forums.forum_parent=2;");
cleanCount += stmt.executeUpdate("DELETE FROM forums WHERE forums.forum_owner_id NOT IN (SELECT charId FROM characters) AND forums.forum_parent=3;");
cleanCount += stmt.executeUpdate("DELETE FROM posts WHERE posts.post_forum_id NOT IN (SELECT forum_id FROM forums);");
cleanCount += stmt.executeUpdate("DELETE FROM topic WHERE topic.topic_forum_id NOT IN (SELECT forum_id FROM forums);");
// Update needed items after cleaning has taken place.
stmt.executeUpdate("UPDATE clan_data SET auction_bid_at = 0 WHERE auction_bid_at NOT IN (SELECT auctionId FROM auction_bid);");
stmt.executeUpdate("UPDATE clan_data SET new_leader_id = 0 WHERE new_leader_id <> 0 AND new_leader_id NOT IN (SELECT charId FROM characters);");
stmt.executeUpdate("UPDATE clan_subpledges SET leader_id=0 WHERE clan_subpledges.leader_id NOT IN (SELECT charId FROM characters) AND leader_id > 0;");
stmt.executeUpdate("UPDATE castle SET side='NEUTRAL' WHERE castle.id NOT IN (SELECT hasCastle FROM clan_data);");
stmt.executeUpdate("UPDATE characters SET clanid=0, clan_privs=0, wantspeace=0, subpledge=0, lvl_joined_academy=0, apprentice=0, sponsor=0, clan_join_expiry_time=0, clan_create_expiry_time=0 WHERE characters.clanid > 0 AND characters.clanid NOT IN (SELECT clan_id FROM clan_data);");
stmt.executeUpdate("UPDATE fort SET owner=0 WHERE owner NOT IN (SELECT clan_id FROM clan_data);");
LOGGER.info("Cleaned " + cleanCount + " elements from database in " + ((System.currentTimeMillis() - cleanupStart) / 1000) + " s");
} }
catch (SQLException e)
{ // Cleanup timestamps.
LOGGER.log(Level.WARNING, "Could not clean up database: " + e.getMessage(), e);
}
}
private void cleanUpTimeStamps()
{
try (Connection con = DatabaseFactory.getConnection()) try (Connection con = DatabaseFactory.getConnection())
{ {
int cleanCount = 0; int cleanCount = 0;
@@ -263,62 +202,136 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate(); cleanCount += stmt.executeUpdate();
} }
} }
LOGGER.info("Cleaned " + cleanCount + " expired timestamps from database."); LOGGER.info("IdFactory: Cleaned " + cleanCount + " expired timestamps from database.");
} }
catch (SQLException e) catch (Exception e)
{ {
// Ignore. LOGGER.warning("IdFactory: Could not clean expired timestamps from database. " + e);
} }
}
// Initialize.
/** try
* @return
* @throws Exception
* @throws SQLException
*/
protected final Integer[] extractUsedObjectIDTable() throws Exception
{
final List<Integer> temp = new ArrayList<>();
try (Connection con = DatabaseFactory.getConnection();
Statement s = con.createStatement())
{ {
String extractUsedObjectIdsQuery = ""; _freeIds = new BitSet(PrimeFinder.nextPrime(100000));
_freeIds.clear();
_freeIdCount = new AtomicInteger(FREE_OBJECT_ID_SIZE);
for (String[] tblClmn : ID_EXTRACTS) // Collect already used ids.
final List<Integer> usedIds = new ArrayList<>();
try (Connection con = DatabaseFactory.getConnection();
Statement statement = con.createStatement())
{ {
extractUsedObjectIdsQuery += "SELECT " + tblClmn[1] + " FROM " + tblClmn[0] + " UNION "; String extractUsedObjectIdsQuery = "";
} for (String[] tblClmn : ID_EXTRACTS)
extractUsedObjectIdsQuery = extractUsedObjectIdsQuery.substring(0, extractUsedObjectIdsQuery.length() - 7); // Remove the last " UNION "
try (ResultSet rs = s.executeQuery(extractUsedObjectIdsQuery))
{
while (rs.next())
{ {
temp.add(rs.getInt(1)); extractUsedObjectIdsQuery += "SELECT " + tblClmn[1] + " FROM " + tblClmn[0] + " UNION ";
}
extractUsedObjectIdsQuery = extractUsedObjectIdsQuery.substring(0, extractUsedObjectIdsQuery.length() - 7); // Remove the last " UNION "
try (ResultSet result = statement.executeQuery(extractUsedObjectIdsQuery))
{
while (result.next())
{
usedIds.add(result.getInt(1));
}
} }
} }
Collections.sort(usedIds);
// Register used ids.
for (int usedObjectId : usedIds)
{
final int objectId = usedObjectId - FIRST_OID;
if (objectId < 0)
{
LOGGER.warning("IdFactory: Object ID " + usedObjectId + " in DB is less than minimum ID of " + FIRST_OID);
continue;
}
_freeIds.set(usedObjectId - FIRST_OID);
_freeIdCount.decrementAndGet();
}
_nextFreeId = new AtomicInteger(_freeIds.nextClearBit(0));
_initialized = true;
} }
Collections.sort(temp); catch (Exception e)
return temp.toArray(new Integer[temp.size()]); {
_initialized = false;
LOGGER.severe("IdFactory: Could not be initialized properly: " + e.getMessage());
}
// Schedule increase capacity task.
ThreadPool.scheduleAtFixedRate(() ->
{
synchronized (_nextFreeId)
{
if (PrimeFinder.nextPrime((usedIdCount() * 11) / 10) > _freeIds.size())
{
increaseBitSetCapacity();
}
}
}, 30000, 30000);
LOGGER.info("IdFactory: " + _freeIds.size() + " id's available.");
} }
public boolean isInitialized() public synchronized static void releaseId(int objectId)
{
synchronized (_nextFreeId)
{
if ((objectId - FIRST_OID) > -1)
{
_freeIds.clear(objectId - FIRST_OID);
_freeIdCount.incrementAndGet();
}
else
{
LOGGER.warning("IdFactory: Release objectID " + objectId + " failed (< " + FIRST_OID + ")");
}
}
}
public synchronized static int getNextId()
{
synchronized (_nextFreeId)
{
final int newId = _nextFreeId.get();
_freeIds.set(newId);
_freeIdCount.decrementAndGet();
final int nextFree = _freeIds.nextClearBit(newId) < 0 ? _freeIds.nextClearBit(0) : _freeIds.nextClearBit(newId);
if (nextFree < 0)
{
if (_freeIds.size() >= FREE_OBJECT_ID_SIZE)
{
throw new NullPointerException("IdFactory: Ran out of valid ids.");
}
increaseBitSetCapacity();
}
_nextFreeId.set(nextFree);
return newId + FIRST_OID;
}
}
private static void increaseBitSetCapacity()
{
final BitSet newBitSet = new BitSet(PrimeFinder.nextPrime((usedIdCount() * 11) / 10));
newBitSet.or(_freeIds);
_freeIds = newBitSet;
}
private static int usedIdCount()
{
return _freeIdCount.get() - FIRST_OID;
}
public static int size()
{
return _freeIdCount.get();
}
public static boolean hasInitialized()
{ {
return _initialized; return _initialized;
} }
public static IdFactory getInstance()
{
return _instance;
}
public abstract int getNextId();
/**
* return a used Object ID back to the pool
* @param id
*/
public abstract void releaseId(int id);
public abstract int size();
} }
@@ -1,152 +0,0 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.l2jmobius.gameserver.idfactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Stack;
import org.l2jmobius.Config;
import org.l2jmobius.commons.database.DatabaseFactory;
/**
* @version $Revision: 1.3.2.1.2.7 $ $Date: 2005/04/11 10:06:12 $
*/
public class StackIDFactory extends IdFactory
{
private int _curOID;
private int _tempOID;
private final Stack<Integer> _freeOIDStack = new Stack<>();
protected StackIDFactory()
{
super();
_curOID = FIRST_OID;
_tempOID = FIRST_OID;
try (Connection con = DatabaseFactory.getConnection())
{
// con.createStatement().execute("drop table if exists tmp_obj_id");
final Integer[] tmpObjIds = extractUsedObjectIDTable();
if (tmpObjIds.length > 0)
{
_curOID = tmpObjIds[tmpObjIds.length - 1];
}
LOGGER.info("Max Id = " + _curOID);
int n = tmpObjIds.length;
for (int idx = 0; idx < n; idx++)
{
n = insertUntil(tmpObjIds, idx, n, con);
}
_curOID++;
LOGGER.info("IdFactory: Next usable Object ID is: " + _curOID);
_initialized = true;
}
catch (Exception e)
{
LOGGER.severe(getClass().getSimpleName() + ": Could not be initialized properly:" + e.getMessage());
}
}
private int insertUntil(Integer[] tmpObjIds, int idx, int n, Connection con) throws SQLException
{
final int id = tmpObjIds[idx];
if (id == _tempOID)
{
_tempOID++;
return n;
}
// check these IDs not present in DB
if (Config.BAD_ID_CHECKING)
{
for (String check : ID_CHECKS)
{
try (PreparedStatement ps = con.prepareStatement(check))
{
ps.setInt(1, _tempOID);
// ps.setInt(1, _curOID);
ps.setInt(2, id);
try (ResultSet rs = ps.executeQuery())
{
if (rs.next())
{
final int badId = rs.getInt(1);
LOGGER.severe("Bad ID " + badId + " in DB found by: " + check);
throw new RuntimeException();
}
}
}
}
}
// int hole = id - _curOID;
final int hole = (id - _tempOID) > (n - idx) ? n - idx : id - _tempOID;
for (int i = 1; i <= hole; i++)
{
_freeOIDStack.push(_tempOID);
_tempOID++;
}
if (hole < (n - idx))
{
_tempOID++;
}
return n - hole;
}
public static IdFactory getInstance()
{
return _instance;
}
@Override
public synchronized int getNextId()
{
int id;
if (!_freeOIDStack.empty())
{
id = _freeOIDStack.pop();
}
else
{
id = _curOID;
_curOID += 1;
}
return id;
}
/**
* return a used Object ID back to the pool
* @param id
*/
@Override
public synchronized void releaseId(int id)
{
_freeOIDStack.push(id);
}
@Override
public int size()
{
return (FREE_OBJECT_ID_SIZE - _curOID) + FIRST_OID + _freeOIDStack.size();
}
}
@@ -123,7 +123,7 @@ public class AirShipManager
if (_airShips.containsKey(ownerId)) if (_airShips.containsKey(ownerId))
{ {
airShip = _airShips.get(ownerId); airShip = _airShips.get(ownerId);
airShip.refreshID(); airShip.refreshId();
} }
else else
{ {
@@ -282,7 +282,7 @@ public class MailManager
} }
_messages.remove(msgId); _messages.remove(msgId);
IdFactory.getInstance().releaseId(msgId); IdFactory.releaseId(msgId);
} }
/** /**
@@ -47,7 +47,7 @@ public class Petition
public Petition(PlayerInstance petitioner, String petitionText, int petitionType) public Petition(PlayerInstance petitioner, String petitionText, int petitionType)
{ {
_id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
_type = PetitionType.values()[--petitionType]; _type = PetitionType.values()[--petitionType];
_content = petitionText; _content = petitionText;
_petitioner = petitioner; _petitioner = petitioner;
@@ -532,7 +532,7 @@ public class Spawn extends Location implements IIdentifiable, INamable
{ {
if (_doRespawn) if (_doRespawn)
{ {
oldNpc.refreshID(); // oldNpc.refreshID();
initializeNpcInstance(oldNpc); initializeNpcInstance(oldNpc);
// Register NPC back to instance world. // Register NPC back to instance world.
@@ -151,11 +151,11 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return true; return true;
} }
public void refreshID() public void refreshId()
{ {
World.getInstance().removeObject(this); World.getInstance().removeObject(this);
IdFactory.getInstance().releaseId(getObjectId()); IdFactory.releaseId(getObjectId());
_objectId = IdFactory.getInstance().getNextId(); _objectId = IdFactory.getNextId();
} }
@Override @Override
@@ -290,7 +290,7 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe
*/ */
public Creature(CreatureTemplate template) public Creature(CreatureTemplate template)
{ {
this(IdFactory.getInstance().getNextId(), template); this(IdFactory.getNextId(), template);
} }
/** /**
@@ -48,7 +48,7 @@ public class ControllableAirShipInstance extends AirShipInstance
super(template); super(template);
setInstanceType(InstanceType.ControllableAirShipInstance); setInstanceType(InstanceType.ControllableAirShipInstance);
_ownerId = ownerId; _ownerId = ownerId;
_helmId = IdFactory.getInstance().getNextId(); // not forget to release ! _helmId = IdFactory.getNextId(); // not forget to release !
} }
@Override @Override
@@ -281,11 +281,11 @@ public class ControllableAirShipInstance extends AirShipInstance
} }
@Override @Override
public void refreshID() public void refreshId()
{ {
super.refreshID(); super.refreshId();
IdFactory.getInstance().releaseId(_helmId); IdFactory.releaseId(_helmId);
_helmId = IdFactory.getInstance().getNextId(); _helmId = IdFactory.getNextId();
} }
@Override @Override
@@ -44,7 +44,7 @@ public class FenceInstance extends WorldObject
public FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state) public FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
{ {
super(IdFactory.getInstance().getNextId()); super(IdFactory.getNextId());
_xMin = x - (width / 2); _xMin = x - (width / 2);
_xMax = x + (width / 2); _xMax = x + (width / 2);
@@ -62,7 +62,7 @@ public class FenceInstance extends WorldObject
_heightFences = new int[height - 1]; _heightFences = new int[height - 1];
for (int i = 0; i < _heightFences.length; i++) for (int i = 0; i < _heightFences.length; i++)
{ {
_heightFences[i] = IdFactory.getInstance().getNextId(); _heightFences[i] = IdFactory.getNextId();
} }
} }
} }
@@ -1156,7 +1156,7 @@ public class PlayerInstance extends Playable
*/ */
private PlayerInstance(PlayerTemplate template, String accountName, PlayerAppearance app) private PlayerInstance(PlayerTemplate template, String accountName, PlayerAppearance app)
{ {
this(IdFactory.getInstance().getNextId(), template, accountName, app); this(IdFactory.getNextId(), template, accountName, app);
} }
@Override @Override
@@ -164,7 +164,7 @@ public class RaceManagerInstance extends Npc
player.setRace(0, 0); player.setRace(0, 0);
player.setRace(1, 0); player.setRace(1, 0);
ItemInstance item = new ItemInstance(IdFactory.getInstance().getNextId(), 4443); ItemInstance item = new ItemInstance(IdFactory.getNextId(), 4443);
item.setCount(1); item.setCount(1);
item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber()); item.setEnchantLevel(MonsterRace.getInstance().getRaceNumber());
item.setCustomType1(ticket); item.setCustomType1(ticket);
@@ -32,7 +32,7 @@ public class EventAnnouncement implements IAnnouncement
public EventAnnouncement(DateRange range, String content) public EventAnnouncement(DateRange range, String content)
{ {
_id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
_range = range; _range = range;
_content = content; _content = content;
} }
@@ -88,7 +88,7 @@ public class EventAnnouncement implements IAnnouncement
@Override @Override
public boolean deleteMe() public boolean deleteMe()
{ {
IdFactory.getInstance().releaseId(_id); IdFactory.releaseId(_id);
return true; return true;
} }
@@ -34,7 +34,7 @@ public class Couple
{ {
private static final Logger LOGGER = Logger.getLogger(Couple.class.getName()); private static final Logger LOGGER = Logger.getLogger(Couple.class.getName());
private int _Id = 0; private int _id = 0;
private int _player1Id = 0; private int _player1Id = 0;
private int _player2Id = 0; private int _player2Id = 0;
private boolean _maried = false; private boolean _maried = false;
@@ -43,12 +43,12 @@ public class Couple
public Couple(int coupleId) public Couple(int coupleId)
{ {
_Id = coupleId; _id = coupleId;
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM mods_wedding WHERE id = ?")) PreparedStatement ps = con.prepareStatement("SELECT * FROM mods_wedding WHERE id = ?"))
{ {
ps.setInt(1, _Id); ps.setInt(1, _id);
try (ResultSet rs = ps.executeQuery()) try (ResultSet rs = ps.executeQuery())
{ {
while (rs.next()) while (rs.next())
@@ -88,8 +88,8 @@ public class Couple
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO mods_wedding (id, player1Id, player2Id, married, affianceDate, weddingDate) VALUES (?, ?, ?, ?, ?, ?)")) PreparedStatement ps = con.prepareStatement("INSERT INTO mods_wedding (id, player1Id, player2Id, married, affianceDate, weddingDate) VALUES (?, ?, ?, ?, ?, ?)"))
{ {
_Id = IdFactory.getInstance().getNextId(); _id = IdFactory.getNextId();
ps.setInt(1, _Id); ps.setInt(1, _id);
ps.setInt(2, _player1Id); ps.setInt(2, _player1Id);
ps.setInt(3, _player2Id); ps.setInt(3, _player2Id);
ps.setBoolean(4, false); ps.setBoolean(4, false);
@@ -111,7 +111,7 @@ public class Couple
ps.setBoolean(1, true); ps.setBoolean(1, true);
_weddingDate = Calendar.getInstance(); _weddingDate = Calendar.getInstance();
ps.setLong(2, _weddingDate.getTimeInMillis()); ps.setLong(2, _weddingDate.getTimeInMillis());
ps.setInt(3, _Id); ps.setInt(3, _id);
ps.execute(); ps.execute();
_maried = true; _maried = true;
} }
@@ -126,7 +126,7 @@ public class Couple
try (Connection con = DatabaseFactory.getConnection(); try (Connection con = DatabaseFactory.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM mods_wedding WHERE id=?")) PreparedStatement ps = con.prepareStatement("DELETE FROM mods_wedding WHERE id=?"))
{ {
ps.setInt(1, _Id); ps.setInt(1, _id);
ps.execute(); ps.execute();
} }
catch (Exception e) catch (Exception e)
@@ -137,7 +137,7 @@ public class Couple
public int getId() public int getId()
{ {
return _Id; return _id;
} }
public int getPlayer1Id() public int getPlayer1Id()
@@ -99,7 +99,7 @@ public class Message
*/ */
public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena) public Message(int senderId, int receiverId, boolean isCod, String subject, String text, long reqAdena)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = senderId; _senderId = senderId;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -118,7 +118,7 @@ public class Message
*/ */
public Message(int receiverId, String subject, String content, MailType sendBySystem) public Message(int receiverId, String subject, String content, MailType sendBySystem)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = -1; _senderId = -1;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -138,7 +138,7 @@ public class Message
*/ */
public Message(int senderId, int receiverId, String subject, String content, MailType sendBySystem) public Message(int senderId, int receiverId, String subject, String content, MailType sendBySystem)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = senderId; _senderId = senderId;
_receiverId = receiverId; _receiverId = receiverId;
_subject = subject; _subject = subject;
@@ -157,7 +157,7 @@ public class Message
*/ */
public Message(Message msg) public Message(Message msg)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = msg.getSenderId(); _senderId = msg.getSenderId();
_receiverId = msg.getSenderId(); _receiverId = msg.getSenderId();
_subject = ""; _subject = "";
@@ -177,7 +177,7 @@ public class Message
public Message(int receiverId, ItemInstance item, MailType mailType) public Message(int receiverId, ItemInstance item, MailType mailType)
{ {
_messageId = IdFactory.getInstance().getNextId(); _messageId = IdFactory.getNextId();
_senderId = -1; _senderId = -1;
_receiverId = receiverId; _receiverId = receiverId;
_subject = ""; _subject = "";

Some files were not shown because too many files have changed in this diff Show More