actual freya branch

This commit is contained in:
2026-09-12 15:41:31 +00:00
parent 8049e0a882
commit 68c1cd27d4
3510 changed files with 336689 additions and 302906 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,336 @@
/*
* 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 com.l2jserver;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class L2DatabaseFactory
{
static Logger _log = Logger.getLogger(L2DatabaseFactory.class.getName());
public static enum ProviderType
{
MySql,
MsSql
}
// =========================================================
// Data Field
private static L2DatabaseFactory _instance;
private static ScheduledExecutorService _executor;
private ProviderType _providerType;
private ComboPooledDataSource _source;
// =========================================================
// Constructor
public L2DatabaseFactory() throws SQLException
{
try
{
if (Config.DATABASE_MAX_CONNECTIONS < 2)
{
Config.DATABASE_MAX_CONNECTIONS = 2;
_log.warning("A minimum of " + Config.DATABASE_MAX_CONNECTIONS + " db connections are required.");
}
_source = new ComboPooledDataSource();
_source.setAutoCommitOnClose(true);
_source.setInitialPoolSize(10);
_source.setMinPoolSize(10);
_source.setMaxPoolSize(Math.max(10, Config.DATABASE_MAX_CONNECTIONS));
_source.setAcquireRetryAttempts(0); // try to obtain connections indefinitely (0 = never quit)
_source.setAcquireRetryDelay(500); // 500 milliseconds wait before try to acquire connection again
_source.setCheckoutTimeout(0); // 0 = wait indefinitely for new connection
// if pool is exhausted
_source.setAcquireIncrement(5); // if pool is exhausted, get 5 more connections at a time
// cause there is a "long" delay on acquire connection
// so taking more than one connection at once will make connection pooling
// more effective.
// this "connection_test_table" is automatically created if not already there
_source.setAutomaticTestTable("connection_test_table");
_source.setTestConnectionOnCheckin(false);
// testing OnCheckin used with IdleConnectionTestPeriod is faster than testing on checkout
_source.setIdleConnectionTestPeriod(3600); // test idle connection every 60 sec
_source.setMaxIdleTime(Config.DATABASE_MAX_IDLE_TIME); // 0 = idle connections never expire
// *THANKS* to connection testing configured above
// but I prefer to disconnect all connections not used
// for more than 1 hour
// enables statement caching, there is a "semi-bug" in c3p0 0.9.0 but in 0.9.0.2 and later it's fixed
_source.setMaxStatementsPerConnection(100);
_source.setBreakAfterAcquireFailure(false); // never fail if any way possible
// setting this to true will make
// c3p0 "crash" and refuse to work
// till restart thus making acquire
// errors "FATAL" ... we don't want that
// it should be possible to recover
_source.setDriverClass(Config.DATABASE_DRIVER);
_source.setJdbcUrl(Config.DATABASE_URL);
_source.setUser(Config.DATABASE_LOGIN);
_source.setPassword(Config.DATABASE_PASSWORD);
/* Test the connection */
_source.getConnection().close();
if (Config.DEBUG)
{
_log.fine("Database Connection Working");
}
if (Config.DATABASE_DRIVER.toLowerCase().contains("microsoft"))
{
_providerType = ProviderType.MsSql;
}
else
{
_providerType = ProviderType.MySql;
}
}
catch (SQLException x)
{
if (Config.DEBUG)
{
_log.fine("Database Connection FAILED");
}
// re-throw the exception
throw x;
}
catch (Exception e)
{
if (Config.DEBUG)
{
_log.fine("Database Connection FAILED");
}
throw new SQLException("Could not init DB connection:" + e.getMessage());
}
}
// =========================================================
// Method - Public
public final String prepQuerySelect(String[] fields, String tableName, String whereClause, boolean returnOnlyTopRecord)
{
String msSqlTop1 = "";
String mySqlTop1 = "";
if (returnOnlyTopRecord)
{
if (getProviderType() == ProviderType.MsSql)
{
msSqlTop1 = " Top 1 ";
}
if (getProviderType() == ProviderType.MySql)
{
mySqlTop1 = " Limit 1 ";
}
}
String query = "SELECT " + msSqlTop1 + safetyString(fields) + " FROM " + tableName + " WHERE " + whereClause + mySqlTop1;
return query;
}
public void shutdown()
{
try
{
_source.close();
}
catch (Exception e)
{
_log.log(Level.INFO, "", e);
}
try
{
_source = null;
}
catch (Exception e)
{
_log.log(Level.INFO, "", e);
}
}
public final String safetyString(String... whatToCheck)
{
// NOTE: Use brace as a safty precaution just incase name is a reserved word
final char braceLeft;
final char braceRight;
if (getProviderType() == ProviderType.MsSql)
{
braceLeft = '[';
braceRight = ']';
}
else
{
braceLeft = '`';
braceRight = '`';
}
int length = 0;
for (String word : whatToCheck)
{
length += word.length() + 4;
}
final StringBuilder sbResult = new StringBuilder(length);
for (String word : whatToCheck)
{
if (sbResult.length() > 0)
{
sbResult.append(", ");
}
sbResult.append(braceLeft);
sbResult.append(word);
sbResult.append(braceRight);
}
return sbResult.toString();
}
// =========================================================
// Property - Public
public static L2DatabaseFactory getInstance() throws SQLException
{
synchronized (L2DatabaseFactory.class)
{
if (_instance == null)
{
_instance = new L2DatabaseFactory();
}
}
return _instance;
}
public Connection getConnection() // throws SQLException
{
Connection con = null;
while (con == null)
{
try
{
con = _source.getConnection();
if (Server.serverMode == Server.MODE_GAMESERVER)
{
ThreadPoolManager.getInstance().scheduleGeneral(new ConnectionCloser(con, new RuntimeException()), Config.CONNECTION_CLOSE_TIME);
}
else
{
getExecutor().schedule(new ConnectionCloser(con, new RuntimeException()), 60, TimeUnit.SECONDS);
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, "L2DatabaseFactory: getConnection() failed, trying again " + e.getMessage(), e);
}
}
return con;
}
private static class ConnectionCloser implements Runnable
{
private final Connection c;
private final RuntimeException exp;
public ConnectionCloser(Connection con, RuntimeException e)
{
c = con;
exp = e;
}
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
try
{
if (!c.isClosed())
{
_log.log(Level.WARNING, "Unclosed connection! Trace: " + exp.getStackTrace()[1], exp);
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, "", e);
}
}
}
public static void close(Connection con)
{
if (con == null)
{
return;
}
try
{
con.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Failed to close database connection!", e);
}
}
private static ScheduledExecutorService getExecutor()
{
if (_executor == null)
{
synchronized (L2DatabaseFactory.class)
{
if (_executor == null)
{
_executor = Executors.newSingleThreadScheduledExecutor();
}
}
}
return _executor;
}
public int getBusyConnectionCount() throws SQLException
{
return _source.getNumBusyConnectionsDefaultUser();
}
public int getIdleConnectionCount() throws SQLException
{
return _source.getNumIdleConnectionsDefaultUser();
}
public final ProviderType getProviderType()
{
return _providerType;
}
}
+28
View File
@@ -0,0 +1,28 @@
/*
* 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 com.l2jserver;
/**
* This class used to be the starter class, since LS/GS split, it only retains server mode
*/
public class Server
{
// constants for the server mode
public static final int MODE_NONE = 0;
public static final int MODE_GAMESERVER = 1;
public static final int MODE_LOGINSERVER = 2;
public static int serverMode = MODE_NONE;
}
@@ -0,0 +1,475 @@
/*
* 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 com.l2jserver.accountmanager;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Base64;
import javolution.util.FastList;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.Server;
/**
* This class SQL Account Manager
* @author netimperia
* @version $Revision: 2.3.2.1.2.3 $ $Date: 2005/08/08 22:47:12 $
*/
public class SQLAccountManager
{
private static String _uname = "";
private static String _pass = "";
private static String _level = "";
private static String _mode = "";
public static void main(String[] args) throws SQLException, IOException, NoSuchAlgorithmException
{
Server.serverMode = Server.MODE_LOGINSERVER;
Config.load();
while (true)
{
System.out.println("Please choose an option:");
System.out.println("");
System.out.println("1 - Create new account or update existing one (change pass and access level).");
System.out.println("2 - Change access level.");
System.out.println("3 - Delete existing account.");
System.out.println("4 - List accounts & access levels.");
System.out.println("5 - Exit.");
LineNumberReader _in = new LineNumberReader(new InputStreamReader(System.in));
while (!(_mode.equals("1") || _mode.equals("2") || _mode.equals("3") || _mode.equals("4") || _mode.equals("5")))
{
System.out.print("Your choice: ");
_mode = _in.readLine();
}
if (_mode.equals("1") || _mode.equals("2") || _mode.equals("3"))
{
if (_mode.equals("1") || _mode.equals("2"))
{
while (_uname.trim().length() == 0)
{
System.out.print("Username: ");
_uname = _in.readLine().toLowerCase();
}
}
else if (_mode.equals("3"))
{
while (_uname.trim().length() == 0)
{
System.out.print("Account name: ");
_uname = _in.readLine().toLowerCase();
}
}
if (_mode.equals("1"))
{
while (_pass.trim().length() == 0)
{
System.out.print("Password: ");
_pass = _in.readLine();
}
}
if (_mode.equals("1") || _mode.equals("2"))
{
while (_level.trim().length() == 0)
{
System.out.print("Access level: ");
_level = _in.readLine();
}
}
}
if (_mode.equals("1"))
{
// Add or Update
addOrUpdateAccount(_uname.trim(), _pass.trim(), _level.trim());
}
else if (_mode.equals("2"))
{
// Change Level
changeAccountLevel(_uname.trim(), _level.trim());
}
else if (_mode.equals("3"))
{
// Delete
System.out.print("Do you really want to delete this account ? Y/N : ");
String yesno = _in.readLine();
if (yesno.equalsIgnoreCase("Y"))
{
deleteAccount(_uname.trim());
}
else
{
System.out.println("Deletion cancelled");
}
}
else if (_mode.equals("4"))
{
// List
_mode = "";
System.out.println("");
System.out.println("Please choose a listing mode:");
System.out.println("");
System.out.println("1 - Banned accounts only (accessLevel < 0)");
System.out.println("2 - GM/privileged accounts (accessLevel > 0)");
System.out.println("3 - Regular accounts only (accessLevel = 0)");
System.out.println("4 - List all");
while (!(_mode.equals("1") || _mode.equals("2") || _mode.equals("3") || _mode.equals("4")))
{
System.out.print("Your choice: ");
_mode = _in.readLine();
}
System.out.println("");
printAccInfo(_mode);
}
else if (_mode.equals("5"))
{
System.exit(0);
}
_uname = "";
_pass = "";
_level = "";
_mode = "";
System.out.println();
}
}
private static void printAccInfo(String m) throws SQLException
{
int count = 0;
Connection con = null;
con = L2DatabaseFactory.getInstance().getConnection();
String q = "SELECT login, accessLevel FROM accounts ";
if (m.equals("1"))
{
q = q.concat("WHERE accessLevel < 0");
}
else if (m.equals("2"))
{
q = q.concat("WHERE accessLevel > 0");
}
else if (m.equals("3"))
{
q = q.concat("WHERE accessLevel = 0");
}
q = q.concat(" ORDER BY login ASC");
PreparedStatement statement = con.prepareStatement(q);
ResultSet rset = statement.executeQuery();
while (rset.next())
{
System.out.println(rset.getString("login") + " -> " + rset.getInt("accessLevel"));
count++;
}
rset.close();
statement.close();
L2DatabaseFactory.close(con);
System.out.println("Displayed accounts: " + count + ".");
}
private static void addOrUpdateAccount(String account, String password, String level) throws IOException, SQLException, NoSuchAlgorithmException
{
// Encode Password
MessageDigest md = MessageDigest.getInstance("SHA");
byte[] newpass;
newpass = password.getBytes("UTF-8");
newpass = md.digest(newpass);
// Add to Base
Connection con = null;
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("REPLACE accounts (login, password, accessLevel) VALUES (?,?,?)");
statement.setString(1, account);
statement.setString(2, Base64.getEncoder().encodeToString(newpass));
statement.setString(3, level);
statement.executeUpdate();
statement.close();
L2DatabaseFactory.close(con);
}
private static void changeAccountLevel(String account, String level) throws SQLException
{
Connection con = null;
con = L2DatabaseFactory.getInstance().getConnection();
// Check Account Exist
PreparedStatement statement = con.prepareStatement("SELECT COUNT(*) FROM accounts WHERE login=?;");
statement.setString(1, account);
ResultSet rset = statement.executeQuery();
if (!rset.next())
{
System.out.println("False");
}
else if (rset.getInt(1) > 0)
{
// Exist
// Update
statement = con.prepareStatement("UPDATE accounts SET accessLevel=? WHERE login=?;");
statement.setEscapeProcessing(true);
statement.setString(1, level);
statement.setString(2, account);
statement.executeUpdate();
System.out.println("Account " + account + " has been updated.");
}
else
{
// Not Exist
System.out.println("Account " + account + " does not exist.");
}
rset.close();
statement.close();
L2DatabaseFactory.close(con);
}
private static void deleteAccount(String account) throws SQLException
{
Connection con = null;
con = L2DatabaseFactory.getInstance().getConnection();
// Check Account Exist
PreparedStatement statement = con.prepareStatement("SELECT COUNT(*) FROM accounts WHERE login=?;");
statement.setString(1, account);
ResultSet rset = statement.executeQuery();
if (!rset.next())
{
System.out.println("False");
rset.close();
}
else if (rset.getInt(1) > 0)
{
rset.close();
// Account exist
// Get Accounts ID
ResultSet rcln;
statement = con.prepareStatement("SELECT charId, char_name, clanid FROM characters WHERE account_name=?;");
statement.setEscapeProcessing(true);
statement.setString(1, account);
rset = statement.executeQuery();
FastList<String> objIds = new FastList<>();
FastList<String> charNames = new FastList<>();
FastList<String> clanIds = new FastList<>();
while (rset.next())
{
objIds.add(rset.getString("charId"));
charNames.add(rset.getString("char_name"));
clanIds.add(rset.getString("clanid"));
}
rset.close();
for (int index = 0; index < objIds.size(); index++)
{
System.out.println("Deleting character " + charNames.get(index) + ".");
// Check If clan leader Remove Clan and remove all from it
statement.close();
statement = con.prepareStatement("SELECT COUNT(*) FROM clan_data WHERE leader_id=?;");
statement.setString(1, clanIds.get(index));
rcln = statement.executeQuery();
rcln.next();
if (rcln.getInt(1) > 0)
{
rcln.close();
// Clan Leader
// Get Clan Name
statement.close();
statement = con.prepareStatement("SELECT clan_name FROM clan_data WHERE leader_id=?;");
statement.setString(1, clanIds.get(index));
rcln = statement.executeQuery();
rcln.next();
String clanName = rcln.getString("clan_name");
System.out.println("Deleting clan " + clanName + ".");
// Delete Clan Wars
statement.close();
statement = con.prepareStatement("DELETE FROM clan_wars WHERE clan1=? OR clan2=?;");
statement.setEscapeProcessing(true);
statement.setString(1, clanName);
statement.setString(2, clanName);
statement.executeUpdate();
rcln.close();
// Remove All From clan
statement.close();
statement = con.prepareStatement("UPDATE characters SET clanid=0 WHERE clanid=?;");
statement.setString(1, clanIds.get(index));
statement.executeUpdate();
// Free Clan Halls
statement.close();
statement = con.prepareStatement("UPDATE clanhall SET ownerId=0, paidUntil=0, paid=0 WHERE ownerId=?;");
statement.setString(1, clanIds.get(index));
statement.executeUpdate();
// Delete Clan
statement.close();
statement = con.prepareStatement("DELETE FROM clan_data WHERE clan_id=?;");
statement.setString(1, clanIds.get(index));
statement.executeUpdate();
// Clan privileges
statement.close();
statement = con.prepareStatement("DELETE FROM clan_privs WHERE clan_id=?;");
statement.setString(1, clanIds.get(index));
statement.executeUpdate();
// Clan subpledges
statement.close();
statement = con.prepareStatement("DELETE FROM clan_subpledges WHERE clan_id=?;");
statement.setString(1, clanIds.get(index));
statement.executeUpdate();
// Clan skills
statement.close();
statement = con.prepareStatement("DELETE FROM clan_skills WHERE clan_id=?;");
statement.setString(1, clanIds.get(index));
statement.executeUpdate();
}
else
{
rcln.close();
}
// skills
statement.close();
statement = con.prepareStatement("DELETE FROM character_skills WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// skills save
statement.close();
statement = con.prepareStatement("DELETE FROM character_skills_save WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// subclasses
statement.close();
statement = con.prepareStatement("DELETE FROM character_subclasses WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// shortcuts
statement.close();
statement = con.prepareStatement("DELETE FROM character_shortcuts WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// items
statement.close();
statement = con.prepareStatement("DELETE FROM items WHERE owner_id=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// recipebook
statement.close();
statement = con.prepareStatement("DELETE FROM character_recipebook WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// quests
statement.close();
statement = con.prepareStatement("DELETE FROM character_quests WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// macroses
statement.close();
statement = con.prepareStatement("DELETE FROM character_macroses WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// friends
statement.close();
statement = con.prepareStatement("DELETE FROM character_friends WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// merchant_lease
statement.close();
statement = con.prepareStatement("DELETE FROM merchant_lease WHERE player_id=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// boxaccess
statement.close();
statement = con.prepareStatement("DELETE FROM boxaccess WHERE charname=?;");
statement.setString(1, charNames.get(index));
statement.executeUpdate();
// hennas
statement.close();
statement = con.prepareStatement("DELETE FROM character_hennas WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// recommends
statement.close();
statement = con.prepareStatement("DELETE FROM character_reco_bonus WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// ui categories
statement.close();
statement = con.prepareStatement("DELETE FROM character_ui_categories WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// ui keys
statement.close();
statement = con.prepareStatement("DELETE FROM character_ui_keys WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// characters
statement.close();
statement = con.prepareStatement("DELETE FROM characters WHERE charId=?;");
statement.setString(1, objIds.get(index));
statement.executeUpdate();
// TODO: delete pets, olympiad/noble/hero stuff
}
// Delete Account
statement.close();
statement = con.prepareStatement("DELETE FROM accounts WHERE login=?;");
statement.setEscapeProcessing(true);
statement.setString(1, account);
statement.executeUpdate();
System.out.println("Account " + account + " has been deleted.");
}
else
{
// Not Exist
System.out.println("Account " + account + " does not exist.");
}
// Close Connection
statement.close();
L2DatabaseFactory.close(con);
}
}
@@ -0,0 +1,771 @@
/*
* 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 com.l2jserver.configurator;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javolution.util.FastList;
import com.l2jserver.configurator.ConfigUserInterface.ConfigFile.ConfigComment;
import com.l2jserver.configurator.ConfigUserInterface.ConfigFile.ConfigProperty;
import com.l2jserver.i18n.LanguageControl;
import com.l2jserver.images.ImagesTable;
/**
* @author KenM
*/
public class ConfigUserInterface extends JFrame implements ActionListener
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
private final JTabbedPane _tabPane = new JTabbedPane();
private List<ConfigFile> _configs = new FastList<>();
private ResourceBundle _bundle;
/**
* @param args
*/
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e)
{
// couldn't care less
}
final ResourceBundle bundle = ResourceBundle.getBundle("configurator.Configurator", Locale.getDefault(), LanguageControl.INSTANCE);
SwingUtilities.invokeLater(() ->
{
ConfigUserInterface cui = new ConfigUserInterface(bundle);
cui.setVisible(true);
});
}
public ConfigUserInterface(ResourceBundle bundle)
{
setBundle(bundle);
setTitle(bundle.getString("toolName"));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(750, 500);
setLayout(new GridBagLayout());
setDefaultLookAndFeelDecorated(true);
setIconImage(ImagesTable.getImage("l2j.png").getImage());
GridBagConstraints cons = new GridBagConstraints();
cons.fill = GridBagConstraints.HORIZONTAL;
cons.gridx = 0;
cons.gridy = 0;
cons.weighty = 0;
cons.weightx = 1;
JMenuBar menubar = new JMenuBar();
JMenu fileMenu = new JMenu(bundle.getString("fileMenu"));
JMenu helpMenu = new JMenu(bundle.getString("helpMenu"));
JMenuItem exitItem = new JMenuItem(bundle.getString("exitItem"));
exitItem.setActionCommand("exit");
exitItem.addActionListener(this);
fileMenu.add(exitItem);
JMenuItem aboutItem = new JMenuItem(bundle.getString("aboutItem"));
aboutItem.setActionCommand("about");
aboutItem.addActionListener(this);
helpMenu.add(aboutItem);
menubar.add(fileMenu);
menubar.add(helpMenu);
setJMenuBar(menubar);
JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false);
toolBar.setRollover(true);
toolBar.add(createToolButton("disk.png", bundle.getString("save"), "save"));
this.add(toolBar, cons);
cons.gridy++;
cons.fill = GridBagConstraints.BOTH;
cons.weighty = 1;
loadConfigs();
buildInterface();
this.add(_tabPane, cons);
}
private JButton createToolButton(String image, String text, String action)
{
JButton button = new JButton(text, ImagesTable.getImage(image));
button.setActionCommand(action);
button.addActionListener(this);
return button;
}
private void buildInterface()
{
ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE);
ToolTipManager.sharedInstance().setInitialDelay(0);
ToolTipManager.sharedInstance().setReshowDelay(0);
GridBagConstraints cons = new GridBagConstraints();
cons.fill = GridBagConstraints.NONE;
cons.anchor = GridBagConstraints.FIRST_LINE_START;
cons.insets = new Insets(2, 2, 2, 2);
for (ConfigFile cf : getConfigs())
{
JPanel panel = new JPanel()
{
/**
*
*/
private static final long serialVersionUID = -6580868086294343672L;
@Override
public void scrollRectToVisible(Rectangle r)
{
}
};
panel.setLayout(new GridBagLayout());
cons.gridy = 0;
cons.weighty = 0;
for (ConfigComment cc : cf.getConfigProperties())
{
if (!(cc instanceof ConfigProperty))
{
continue;
}
ConfigProperty cp = (ConfigProperty) cc;
cons.gridx = 0;
JLabel keyLabel = new JLabel(cp.getDisplayName() + ':', ImagesTable.getImage("help.png"), SwingConstants.LEFT);
String comments = "<b>" + cp.getName() + ":</b><br>" + cp.getComments();
comments = comments.replace("\r\n", "<br>");
comments = "<html>" + comments + "</html>";
keyLabel.setToolTipText(comments);
cons.weightx = 0;
panel.add(keyLabel, cons);
cons.gridx++;
JComponent valueComponent = cp.getValueComponent();
valueComponent.setToolTipText(comments);
cons.weightx = 1;
panel.add(valueComponent, cons);
cons.gridx++;
cons.gridy++;
}
cons.gridy++;
cons.weighty = 1;
panel.add(new JLabel(), cons); // filler
_tabPane.addTab(cf.getName(), new JScrollPane(panel));
}
}
/**
*
*/
private void loadConfigs()
{
File configsDir = new File("config");
for (File file : configsDir.listFiles())
{
if (file.getName().endsWith(".properties") && file.isFile() && file.canWrite())
{
try
{
parsePropertiesFile(file);
}
catch (IOException e)
{
JOptionPane.showMessageDialog(ConfigUserInterface.this, getBundle().getString("errorReading") + file.getName(), getBundle().getString("error"), JOptionPane.ERROR_MESSAGE);
System.exit(3);
// e.printStackTrace();
}
}
}
}
/**
* @param file
* @throws IOException
*/
private void parsePropertiesFile(File file) throws IOException
{
LineNumberReader lnr = new LineNumberReader(new InputStreamReader(new FileInputStream(file)));
String line;
StringBuilder commentBuffer = new StringBuilder();
ConfigFile cf = new ConfigFile(file);
while ((line = lnr.readLine()) != null)
{
line = line.trim();
if (line.startsWith("#"))
{
if (commentBuffer.length() > 0)
{
commentBuffer.append("\r\n");
}
commentBuffer.append(line.substring(1));
}
else if (line.length() == 0)
{
// blank line, reset comments
if (commentBuffer.length() > 0)
{
cf.addConfigComment(commentBuffer.toString());
}
commentBuffer.setLength(0);
}
else if (line.indexOf('=') >= 0)
{
String[] kv = line.split("=");
String key = kv[0].trim();
String value = "";
if (kv.length > 1)
{
value = kv[1].trim();
}
if (line.indexOf('\\') >= 0)
{
while (((line = lnr.readLine()) != null) && (line.indexOf('\\') >= 0))
{
value += "\r\n" + line;
}
value += "\r\n" + line;
}
String comments = commentBuffer.toString();
commentBuffer.setLength(0); // reset
cf.addConfigProperty(key, parseValue(value), comments);
}
}
getConfigs().add(cf);
lnr.close();
}
/**
* @param value
*/
private Object parseValue(String value)
{
if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("true"))
{
return Boolean.parseBoolean(value);
}
/*
* try { double parseDouble = Double.parseDouble(value); return parseDouble; } catch (NumberFormatException e) { // not a double, ignore }
*/
// localhost -> 127.0.0.1
if (value.equals("localhost"))
{
value = "127.0.0.1";
}
String[] parts = value.split("\\.");
if (parts.length == 4)
{
boolean ok = true;
for (int i = 0; (i < 4) && ok; i++)
{
try
{
int parseInt = Integer.parseInt(parts[i]);
if ((parseInt < 0) || (parseInt > 255))
{
ok = false;
}
}
catch (NumberFormatException e)
{
ok = false;
}
}
if (ok)
{
try
{
InetAddress address = InetAddress.getByName(value);
return address;
}
catch (UnknownHostException e)
{
// ignore
}
}
}
return value;
}
static class ConfigFile
{
private final File _file;
private String _name;
private final List<ConfigComment> _configs = new FastList<>();
public ConfigFile(File file)
{
_file = file;
int lastIndex = file.getName().lastIndexOf('.');
setName(file.getName().substring(0, lastIndex));
}
public void addConfigProperty(String name, Object value, ValueType type, String comments)
{
_configs.add(new ConfigProperty(name, value, type, comments));
}
public void addConfigComment(String comment)
{
_configs.add(new ConfigComment(comment));
}
public void addConfigProperty(String name, Object value, String comments)
{
this.addConfigProperty(name, value, ValueType.firstTypeMatch(value), comments);
}
public List<ConfigComment> getConfigProperties()
{
return _configs;
}
/**
* @param name The name to set.
*/
public void setName(String name)
{
_name = name;
}
/**
* @return Returns the name.
*/
public String getName()
{
return _name;
}
public void save() throws IOException
{
BufferedWriter bufWriter = null;
try
{
bufWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(_file)));
for (ConfigComment cc : _configs)
{
cc.save(bufWriter);
}
}
finally
{
if (bufWriter != null)
{
bufWriter.close();
}
}
}
class ConfigComment
{
private String _comments;
/**
* @param comments
*/
public ConfigComment(String comments)
{
_comments = comments;
}
/**
* @return Returns the comments.
*/
public String getComments()
{
return _comments;
}
/**
* @param comments The comments to set.
*/
public void setComments(String comments)
{
_comments = comments;
}
public void save(Writer writer) throws IOException
{
StringBuilder sb = new StringBuilder();
sb.append('#');
sb.append(getComments().replace("\r\n", "\r\n#"));
sb.append("\r\n\r\n");
writer.write(sb.toString());
}
}
class ConfigProperty extends ConfigComment
{
private String _propname;
private Object _value;
private ValueType _type;
private JComponent _component;
/**
* @param name
* @param value
* @param type
* @param comments
*/
public ConfigProperty(String name, Object value, ValueType type, String comments)
{
super(comments);
if (!type.getType().isAssignableFrom(value.getClass()))
{
throw new IllegalArgumentException("Value Instance Type doesn't match the type argument.");
}
_propname = name;
_type = type;
_value = value;
}
/**
* @return Returns the name.
*/
public String getName()
{
return _propname;
}
/**
* @return Returns the name.
*/
public String getDisplayName()
{
return unCamelize(_propname);
}
/**
* @param name The name to set.
*/
public void setName(String name)
{
_propname = name;
}
/**
* @return Returns the value.
*/
public Object getValue()
{
return _value;
}
/**
* @param value The value to set.
*/
public void setValue(String value)
{
_value = value;
}
/**
* @return Returns the type.
*/
public ValueType getType()
{
return _type;
}
/**
* @param type The type to set.
*/
public void setType(ValueType type)
{
_type = type;
}
public JComponent getValueComponent()
{
if (_component == null)
{
_component = createValueComponent();
}
return _component;
}
public JComponent createValueComponent()
{
switch (getType())
{
case BOOLEAN:
boolean bool = (Boolean) getValue();
JCheckBox checkBox = new JCheckBox();
checkBox.setSelected(bool);
return checkBox;
case IPv4:
return new JIPTextField((Inet4Address) getValue());
case DOUBLE:
case INTEGER:
case STRING:
default:
String val = getValue().toString();
JTextArea textArea = new JTextArea(val);
textArea.setFont(UIManager.getFont("TextField.font"));
int rows = 1;
for (int i = 0; i < val.length(); i++)
{
if (val.charAt(i) == '\\')
{
rows++;
}
}
textArea.setRows(rows);
textArea.setColumns(Math.max(val.length() / rows, 20));
return textArea;
}
}
@Override
public void save(Writer writer) throws IOException
{
String value;
if (getValueComponent() instanceof JCheckBox)
{
value = Boolean.toString(((JCheckBox) getValueComponent()).isSelected());
value = value.substring(0, 1).toUpperCase() + value.substring(1);
}
else if (getValueComponent() instanceof JIPTextField)
{
value = ((JIPTextField) getValueComponent()).getText();
}
else if (getValueComponent() instanceof JTextArea)
{
value = ((JTextArea) getValueComponent()).getText();
}
else
{
throw new IllegalStateException("Unhandled component value");
}
StringBuilder sb = new StringBuilder();
sb.append('#');
sb.append(getComments().replace("\r\n", "\r\n#"));
sb.append("\r\n");
sb.append(getName());
sb.append(" = ");
sb.append(value);
sb.append("\r\n");
sb.append("\r\n");
writer.write(sb.toString());
}
}
}
public static enum ValueType
{
BOOLEAN(Boolean.class),
DOUBLE(Double.class),
INTEGER(Integer.class),
IPv4(Inet4Address.class),
STRING(String.class);
private final Class<?> _type;
private ValueType(Class<?> type)
{
_type = type;
}
/**
* @return Returns the type.
*/
public Class<?> getType()
{
return _type;
}
public static ValueType firstTypeMatch(Object value)
{
for (ValueType vt : ValueType.values())
{
if (vt.getType() == value.getClass())
{
return vt;
}
}
throw new NoSuchElementException("No match for: " + value.getClass().getName());
}
}
/**
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent e)
{
String cmd = e.getActionCommand();
StringBuilder errors = new StringBuilder();
if (cmd.equals("save"))
{
for (ConfigFile cf : ConfigUserInterface.this.getConfigs())
{
try
{
cf.save();
}
catch (Exception e1)
{
e1.printStackTrace();
errors.append(getBundle().getString("errorSaving") + cf.getName() + ".properties. " + getBundle().getString("reason") + e1.getLocalizedMessage() + "\r\n");
}
}
if (errors.length() == 0)
{
JOptionPane.showMessageDialog(ConfigUserInterface.this, getBundle().getString("success"), "OK", JOptionPane.INFORMATION_MESSAGE);
}
else
{
JOptionPane.showMessageDialog(ConfigUserInterface.this, errors, getBundle().getString("error"), JOptionPane.ERROR_MESSAGE);
System.exit(2);
}
}
else if (cmd.equals("exit"))
{
System.exit(0);
}
else if (cmd.equals("about"))
{
JOptionPane.showMessageDialog(ConfigUserInterface.this, getBundle().getString("credits") + "\nhttp://www.l2jserver.com\n\n" + getBundle().getString("icons") + "\n\n" + getBundle().getString("language") + '\n' + getBundle().getString("translation"), getBundle().getString("aboutItem"), JOptionPane.INFORMATION_MESSAGE, ImagesTable.getImage("l2jserverlogo.png"));
}
}
/**
* @param configs The configuration to set.
*/
public void setConfigs(List<ConfigFile> configs)
{
_configs = configs;
}
/**
* @return Returns the configuration.
*/
public List<ConfigFile> getConfigs()
{
return _configs;
}
/**
* @return Returns the configuration setting name in a human readable form.
*/
public static String unCamelize(final String keyName)
{
Pattern p = Pattern.compile("\\p{Lu}");
Matcher m = p.matcher(keyName);
StringBuffer sb = new StringBuffer();
int last = 0;
while (m.find())
{
if (m.start() != (last + 1))
{
m.appendReplacement(sb, " " + m.group());
}
last = m.start();
}
m.appendTail(sb);
return sb.toString().trim();
}
/**
* @param bundle The bundle to set.
*/
public void setBundle(ResourceBundle bundle)
{
_bundle = bundle;
}
/**
* @return Returns the bundle.
*/
public ResourceBundle getBundle()
{
return _bundle;
}
}
@@ -0,0 +1,323 @@
/*
* 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 com.l2jserver.configurator;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
/**
* @author KenM
*/
public class JIPTextField extends JPanel implements FocusListener
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
private JTextField[] _textFields;
private List<FocusListener> _focusListeners;
public JIPTextField(String textIp)
{
super.addFocusListener(this);
initIPTextField(textIp);
for (JTextField _textField : _textFields)
{
_textField.addFocusListener(this);
}
}
public JIPTextField()
{
this("...");
}
/**
* @param value
*/
public JIPTextField(Inet4Address value)
{
this(value.getHostAddress());
}
private void initIPTextField(String textIp)
{
final ActionListener nextfocusaction = evt -> ((Component) evt.getSource()).transferFocus();
setLayout(new GridBagLayout());
_textFields = new JTextField[4];
GridBagConstraints cons = new GridBagConstraints();
cons.anchor = GridBagConstraints.PAGE_START;
cons.fill = GridBagConstraints.HORIZONTAL;
cons.insets = new Insets(1, 1, 1, 1);
cons.gridx = 0;
cons.gridy = 0;
MaxLengthDocument previous = null;
String[] parts = textIp.split("\\.");
for (int i = 0; i < 4; i++)
{
String str = parts[i];
if (i > 0)
{
JLabel dot = new JLabel(".");
cons.weightx = 0;
add(dot, cons);
cons.gridx++;
}
MaxLengthDocument maxDoc = new MaxLengthDocument(3);
_textFields[i] = new JTextField(maxDoc, str, 3);
if (previous != null)
{
previous.setNext(_textFields[i]);
}
previous = maxDoc;
// ic.weightx = 1;
add(_textFields[i], cons);
_textFields[i].addActionListener(nextfocusaction);
cons.gridx++;
}
}
@Override
public void addFocusListener(FocusListener fl)
{
if (_focusListeners == null)
{
_focusListeners = new LinkedList<>();
}
if ((fl != null) && !_focusListeners.contains(fl))
{
_focusListeners.add(fl);
}
}
@Override
public void removeFocusListener(FocusListener fl)
{
if (_focusListeners != null)
{
_focusListeners.remove(fl);
}
}
public String getText()
{
String str = "";
for (int i = 0; i < 4; i++)
{
if (_textFields[i].getText().length() == 0)
{
str += "0";
}
else
{
str += _textFields[i].getText();
}
if (i < 3)
{
str += ".";
}
}
return str;
}
public void setText(String str)
{
try
{
// make sure string is not null; throw a NullPointerException otherwise
str.length();
InetAddress ip = InetAddress.getByName(str);
byte b[] = ip.getAddress();
for (int i = 0; i < 4; i++)
{
// byte always have a sign in Java, IP addresses aren't
if (b[i] >= 0)
{
_textFields[i].setText(Byte.toString(b[i]));
}
else
{
_textFields[i].setText(Integer.toString(b[i] + 256));
}
}
return;
}
catch (UnknownHostException ex)
{
}
catch (NullPointerException npe)
{
}
for (int i = 0; i < 4; i++)
{
_textFields[i].setText("");
}
}
@Override
public void setEnabled(boolean enabled)
{
for (JTextField _textField : _textFields)
{
if (_textField != null)
{
_textField.setEnabled(enabled);
}
}
}
public boolean isEmpty()
{
for (int i = 0; i < 4; i++)
{
if (_textFields[i].getText().length() != 0)
{
return false;
}
}
return true;
}
public boolean isCorrect()
{
for (int i = 0; i < 4; i++)
{
if (_textFields[i].getText().length() == 0)
{
return false;
}
}
return true;
}
@Override
public void focusGained(FocusEvent event)
{
if (_focusListeners != null)
{
for (FocusListener fl : _focusListeners)
{
fl.focusGained(event);
}
}
}
@Override
public void focusLost(FocusEvent event)
{
if (isCorrect() || isEmpty())
{
if (_focusListeners != null)
{
for (FocusListener fl : _focusListeners)
{
fl.focusLost(event);
}
}
}
}
public class MaxLengthDocument extends PlainDocument
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
private final int _max;
private JTextField _next;
public MaxLengthDocument(int maxLength)
{
this(maxLength, null);
}
public MaxLengthDocument(int maxLength, JTextField next)
{
_max = maxLength;
setNext(next);
}
@Override
public void insertString(int offset, String str, AttributeSet a) throws BadLocationException
{
if ((getLength() + str.length()) > _max)
{
if (getNext() != null)
{
if (getNext().getText().length() > 0)
{
getNext().select(0, getNext().getText().length());
}
else
{
getNext().getDocument().insertString(0, str, a);
}
getNext().requestFocusInWindow();
}
else
{
Toolkit.getDefaultToolkit().beep();
}
}
else
{
super.insertString(offset, str, a);
}
}
/**
* @param next The next to set.
*/
public void setNext(JTextField next)
{
_next = next;
}
/**
* @return Returns the next.
*/
public JTextField getNext()
{
return _next;
}
}
}
@@ -0,0 +1,237 @@
/*
* 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 com.l2jserver.gameserver;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jserver.Config;
import com.l2jserver.gameserver.cache.HtmCache;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.clientpackets.Say2;
import com.l2jserver.gameserver.network.serverpackets.CreatureSay;
import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.script.DateRange;
import com.l2jserver.gameserver.util.Broadcast;
import com.l2jserver.util.StringUtil;
/**
* This class ...
* @version $Revision: 1.5.2.1.2.7 $ $Date: 2005/03/29 23:15:14 $
*/
public class Announcements
{
private static Logger _log = Logger.getLogger(Announcements.class.getName());
private final List<String> _announcements = new FastList<>();
private final List<List<Object>> _eventAnnouncements = new FastList<>();
private Announcements()
{
loadAnnouncements();
}
public static Announcements getInstance()
{
return SingletonHolder._instance;
}
public void loadAnnouncements()
{
_announcements.clear();
File file = new File(Config.DATAPACK_ROOT, "data/announcements.txt");
if (file.exists())
{
readFromDisk(file);
}
else
{
_log.warning("data/announcements.txt doesn't exist");
}
}
public void showAnnouncements(L2PcInstance activeChar)
{
for (int i = 0; i < _announcements.size(); i++)
{
CreatureSay cs = new CreatureSay(0, Say2.ANNOUNCEMENT, activeChar.getName(), _announcements.get(i));
activeChar.sendPacket(cs);
}
for (int i = 0; i < _eventAnnouncements.size(); i++)
{
List<Object> entry = _eventAnnouncements.get(i);
DateRange validDateRange = (DateRange) entry.get(0);
String[] msg = (String[]) entry.get(1);
Date currentDate = new Date();
if (!validDateRange.isValid() || validDateRange.isWithinRange(currentDate))
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1);
for (String element : msg)
{
sm.addString(element);
}
activeChar.sendPacket(sm);
}
}
}
public void addEventAnnouncement(DateRange validDateRange, String[] msg)
{
List<Object> entry = new FastList<>();
entry.add(validDateRange);
entry.add(msg);
_eventAnnouncements.add(entry);
}
public void listAnnouncements(L2PcInstance activeChar)
{
String content = HtmCache.getInstance().getHtmForce(activeChar.getHtmlPrefix(), "data/html/admin/announce.htm");
NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
adminReply.setHtml(content);
final StringBuilder replyMSG = StringUtil.startAppend(500, "<br>");
for (int i = 0; i < _announcements.size(); i++)
{
StringUtil.append(replyMSG, "<table width=260><tr><td width=220>", _announcements.get(i), "</td><td width=40>" + "<button value=\"Delete\" action=\"bypass -h admin_del_announcement ", String.valueOf(i), "\" width=60 height=20 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td></tr></table>");
}
adminReply.replace("%announces%", replyMSG.toString());
activeChar.sendPacket(adminReply);
}
public void addAnnouncement(String text)
{
_announcements.add(text);
saveToDisk();
}
public void delAnnouncement(int line)
{
_announcements.remove(line);
saveToDisk();
}
private void readFromDisk(File file)
{
try (LineNumberReader lnr = new LineNumberReader(new FileReader(file));)
{
int i = 0;
String line = null;
while ((line = lnr.readLine()) != null)
{
StringTokenizer st = new StringTokenizer(line, "\n\r");
if (st.hasMoreTokens())
{
String announcement = st.nextToken();
_announcements.add(announcement);
i++;
}
}
if (Config.DEBUG)
{
_log.info("Announcements: Loaded " + i + " Announcements.");
}
}
catch (IOException e1)
{
_log.log(Level.SEVERE, "Error reading announcements: ", e1);
}
}
private void saveToDisk()
{
File file = new File("data/announcements.txt");
FileWriter save = null;
try
{
save = new FileWriter(file);
for (int i = 0; i < _announcements.size(); i++)
{
save.write(_announcements.get(i));
save.write("\r\n");
}
}
catch (IOException e)
{
_log.log(Level.SEVERE, "Saving to the announcements file has failed: ", e);
}
finally
{
try
{
save.close();
}
catch (Exception e)
{
}
}
}
public void announceToAll(String text)
{
Broadcast.announceToOnlinePlayers(text);
}
public void announceToAll(SystemMessage sm)
{
Broadcast.toAllOnlinePlayers(sm);
}
public void announceToInstance(SystemMessage sm, int instanceId)
{
Broadcast.toPlayersInInstance(sm, instanceId);
}
// Method for handling announcements from admin
public void handleAnnounce(String command, int lengthToTrim)
{
try
{
// Announce string to everyone on server
String text = command.substring(lengthToTrim);
SingletonHolder._instance.announceToAll(text);
}
// No body cares!
catch (StringIndexOutOfBoundsException e)
{
// empty message.. ignore
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final Announcements _instance = new Announcements();
}
}
@@ -0,0 +1,72 @@
/*
* 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 com.l2jserver.gameserver;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.gameserver.instancemanager.CastleManager;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.entity.Castle;
import com.l2jserver.gameserver.model.itemcontainer.ItemContainer;
/**
* Thorgrim - 2005 Class managing periodical events with castle
*/
public class CastleUpdater implements Runnable
{
protected static final Logger _log = Logger.getLogger(CastleUpdater.class.getName());
private final L2Clan _clan;
private int _runCount = 0;
public CastleUpdater(L2Clan clan, int runCount)
{
_clan = clan;
_runCount = runCount;
}
@Override
public void run()
{
try
{
// Move current castle treasury to clan warehouse every 2 hour
ItemContainer warehouse = _clan.getWarehouse();
if ((warehouse != null) && (_clan.getHasCastle() > 0))
{
Castle castle = CastleManager.getInstance().getCastleById(_clan.getHasCastle());
if (!Config.ALT_MANOR_SAVE_ALL_ACTIONS)
{
if ((_runCount % Config.ALT_MANOR_SAVE_PERIOD_RATE) == 0)
{
castle.saveSeedData();
castle.saveCropData();
if (Config.DEBUG)
{
_log.info("Manor System: all data for " + castle.getName() + " saved");
}
}
}
CastleUpdater cu = new CastleUpdater(_clan, ++_runCount);
ThreadPoolManager.getInstance().scheduleGeneral(cu, 3600000);
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
}
}
}
@@ -0,0 +1,104 @@
/* 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 com.l2jserver.gameserver;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.gameserver.instancemanager.CastleManager;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.entity.Fort;
/**
* Class managing periodical events with castle
* @author Vice - 2008
*/
public class FortUpdater implements Runnable
{
protected static Logger _log = Logger.getLogger(FortUpdater.class.getName());
private final L2Clan _clan;
private final Fort _fort;
private int _runCount;
private final UpdaterType _updaterType;
public enum UpdaterType
{
MAX_OWN_TIME, // gives fort back to NPC clan
PERIODIC_UPDATE // raise blood oath/supply level
}
public FortUpdater(Fort fort, L2Clan clan, int runCount, UpdaterType ut)
{
_fort = fort;
_clan = clan;
_runCount = runCount;
_updaterType = ut;
}
@Override
public void run()
{
try
{
switch (_updaterType)
{
case PERIODIC_UPDATE:
_runCount++;
if ((_fort.getOwnerClan() == null) || (_fort.getOwnerClan() != _clan))
{
return;
}
_fort.setBloodOathReward(_fort.getBloodOathReward() + Config.FS_BLOOD_OATH_COUNT);
if (_fort.getFortState() == 2)
{
if (_clan.getWarehouse().getAdena() >= Config.FS_FEE_FOR_CASTLE)
{
_clan.getWarehouse().destroyItemByItemId("FS_fee_for_Castle", 57, Config.FS_FEE_FOR_CASTLE, null, null);
CastleManager.getInstance().getCastleById(_fort.getCastleId()).addToTreasuryNoTax(Config.FS_FEE_FOR_CASTLE);
_fort.raiseSupplyLvL();
}
else
{
_fort.setFortState(1, 0);
}
}
_fort.saveFortVariables();
break;
case MAX_OWN_TIME:
if ((_fort.getOwnerClan() == null) || (_fort.getOwnerClan() != _clan))
{
return;
}
if (_fort.getOwnedTime() > (Config.FS_MAX_OWN_TIME * 3600))
{
_fort.removeOwner(true);
_fort.setFortState(0, 0);
}
break;
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
}
}
public int getRunCount()
{
return _runCount;
}
}
@@ -0,0 +1,514 @@
/*
* 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 com.l2jserver.gameserver;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import org.mmocore.network.SelectorConfig;
import org.mmocore.network.SelectorThread;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.Server;
import com.l2jserver.gameserver.cache.CrestCache;
import com.l2jserver.gameserver.cache.HtmCache;
import com.l2jserver.gameserver.datatables.AccessLevels;
import com.l2jserver.gameserver.datatables.AdminCommandAccessRights;
import com.l2jserver.gameserver.datatables.ArmorSetsTable;
import com.l2jserver.gameserver.datatables.AugmentationData;
import com.l2jserver.gameserver.datatables.CharNameTable;
import com.l2jserver.gameserver.datatables.CharTemplateTable;
import com.l2jserver.gameserver.datatables.ClanTable;
import com.l2jserver.gameserver.datatables.DoorTable;
import com.l2jserver.gameserver.datatables.EnchantGroupsTable;
import com.l2jserver.gameserver.datatables.EnchantHPBonusData;
import com.l2jserver.gameserver.datatables.EventDroplist;
import com.l2jserver.gameserver.datatables.FishTable;
import com.l2jserver.gameserver.datatables.GMSkillTable;
import com.l2jserver.gameserver.datatables.HelperBuffTable;
import com.l2jserver.gameserver.datatables.HennaTable;
import com.l2jserver.gameserver.datatables.HennaTreeTable;
import com.l2jserver.gameserver.datatables.HerbDropTable;
import com.l2jserver.gameserver.datatables.HeroSkillTable;
import com.l2jserver.gameserver.datatables.ItemTable;
import com.l2jserver.gameserver.datatables.LevelUpData;
import com.l2jserver.gameserver.datatables.MapRegionTable;
import com.l2jserver.gameserver.datatables.MerchantPriceConfigTable;
import com.l2jserver.gameserver.datatables.MultiSell;
import com.l2jserver.gameserver.datatables.NobleSkillTable;
import com.l2jserver.gameserver.datatables.NpcBufferTable;
import com.l2jserver.gameserver.datatables.NpcTable;
import com.l2jserver.gameserver.datatables.NpcWalkerRoutesTable;
import com.l2jserver.gameserver.datatables.OfflineTradersTable;
import com.l2jserver.gameserver.datatables.PetDataTable;
import com.l2jserver.gameserver.datatables.SkillTable;
import com.l2jserver.gameserver.datatables.SkillTreesData;
import com.l2jserver.gameserver.datatables.SpawnTable;
import com.l2jserver.gameserver.datatables.StaticObjects;
import com.l2jserver.gameserver.datatables.SummonItemsData;
import com.l2jserver.gameserver.datatables.SummonSkillsTable;
import com.l2jserver.gameserver.datatables.TeleportLocationTable;
import com.l2jserver.gameserver.datatables.UITable;
import com.l2jserver.gameserver.geoeditorcon.GeoEditorListener;
import com.l2jserver.gameserver.handler.AdminCommandHandler;
import com.l2jserver.gameserver.handler.ChatHandler;
import com.l2jserver.gameserver.handler.ItemHandler;
import com.l2jserver.gameserver.handler.SkillHandler;
import com.l2jserver.gameserver.handler.UserCommandHandler;
import com.l2jserver.gameserver.handler.VoicedCommandHandler;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.instancemanager.AirShipManager;
import com.l2jserver.gameserver.instancemanager.AntiFeedManager;
import com.l2jserver.gameserver.instancemanager.AuctionManager;
import com.l2jserver.gameserver.instancemanager.BoatManager;
import com.l2jserver.gameserver.instancemanager.CastleManager;
import com.l2jserver.gameserver.instancemanager.CastleManorManager;
import com.l2jserver.gameserver.instancemanager.ClanHallManager;
import com.l2jserver.gameserver.instancemanager.CoupleManager;
import com.l2jserver.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jserver.gameserver.instancemanager.DayNightSpawnManager;
import com.l2jserver.gameserver.instancemanager.DimensionalRiftManager;
import com.l2jserver.gameserver.instancemanager.FortManager;
import com.l2jserver.gameserver.instancemanager.FortSiegeManager;
import com.l2jserver.gameserver.instancemanager.FourSepulchersManager;
import com.l2jserver.gameserver.instancemanager.GlobalVariablesManager;
import com.l2jserver.gameserver.instancemanager.GraciaSeedsManager;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.instancemanager.HellboundManager;
import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.instancemanager.ItemAuctionManager;
import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jserver.gameserver.instancemanager.MailManager;
import com.l2jserver.gameserver.instancemanager.MercTicketManager;
import com.l2jserver.gameserver.instancemanager.PetitionManager;
import com.l2jserver.gameserver.instancemanager.QuestManager;
import com.l2jserver.gameserver.instancemanager.RaidBossPointsManager;
import com.l2jserver.gameserver.instancemanager.RaidBossSpawnManager;
import com.l2jserver.gameserver.instancemanager.SiegeManager;
import com.l2jserver.gameserver.instancemanager.TerritoryWarManager;
import com.l2jserver.gameserver.instancemanager.TransformationManager;
import com.l2jserver.gameserver.instancemanager.ZoneManager;
import com.l2jserver.gameserver.model.AutoChatHandler;
import com.l2jserver.gameserver.model.AutoSpawnHandler;
import com.l2jserver.gameserver.model.L2Manor;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.PartyMatchRoomList;
import com.l2jserver.gameserver.model.PartyMatchWaitingList;
import com.l2jserver.gameserver.model.entity.Hero;
import com.l2jserver.gameserver.model.entity.TvTManager;
import com.l2jserver.gameserver.model.olympiad.Olympiad;
import com.l2jserver.gameserver.network.L2GameClient;
import com.l2jserver.gameserver.network.L2GamePacketHandler;
import com.l2jserver.gameserver.network.communityserver.CommunityServerThread;
import com.l2jserver.gameserver.pathfinding.PathFinding;
import com.l2jserver.gameserver.script.faenor.FaenorScriptEngine;
import com.l2jserver.gameserver.scripting.CompiledScriptCache;
import com.l2jserver.gameserver.scripting.L2ScriptEngineManager;
import com.l2jserver.gameserver.taskmanager.AutoAnnounceTaskManager;
import com.l2jserver.gameserver.taskmanager.KnownListUpdateTaskManager;
import com.l2jserver.gameserver.taskmanager.TaskManager;
import com.l2jserver.status.Status;
import com.l2jserver.util.DeadLockDetector;
import com.l2jserver.util.IPv4Filter;
/**
* This class ...
* @version $Revision: 1.29.2.15.2.19 $ $Date: 2005/04/05 19:41:23 $
*/
public class GameServer
{
private static final Logger _log = Logger.getLogger(GameServer.class.getName());
private final SelectorThread<L2GameClient> _selectorThread;
private final L2GamePacketHandler _gamePacketHandler;
private final DeadLockDetector _deadDetectThread;
private final IdFactory _idFactory;
public static GameServer gameServer;
private final LoginServerThread _loginThread;
private static Status _statusServer;
public static final Calendar dateTimeServerStarted = Calendar.getInstance();
public long getUsedMemoryMB()
{
return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1048576; // ;
}
public SelectorThread<L2GameClient> getSelectorThread()
{
return _selectorThread;
}
public L2GamePacketHandler getL2GamePacketHandler()
{
return _gamePacketHandler;
}
public DeadLockDetector getDeadLockDetectorThread()
{
return _deadDetectThread;
}
public GameServer() throws Exception
{
long serverLoadStart = System.currentTimeMillis();
gameServer = this;
_log.finest("Used memory:" + getUsedMemoryMB() + "MB");
_idFactory = IdFactory.getInstance();
if (!_idFactory.isInitialized())
{
_log.severe("Could not read object IDs from DB. Please Check Your Data.");
throw new Exception("Could not initialize the ID factory");
}
ThreadPoolManager.getInstance();
new File(Config.DATAPACK_ROOT, "data/crests").mkdirs();
new File("log/game").mkdirs();
// load script engines
printSection("Engines");
L2ScriptEngineManager.getInstance();
printSection("World");
// start game time control early
GameTimeController.getInstance();
InstanceManager.getInstance();
L2World.getInstance();
MapRegionTable.getInstance();
Announcements.getInstance();
GlobalVariablesManager.getInstance();
printSection("Skills");
EnchantGroupsTable.getInstance();
SkillTable.getInstance();
SkillTreesData.getInstance();
NobleSkillTable.getInstance();
GMSkillTable.getInstance();
HeroSkillTable.getInstance();
SummonSkillsTable.getInstance();
printSection("Items");
ItemTable.getInstance();
SummonItemsData.getInstance();
EnchantHPBonusData.getInstance();
MerchantPriceConfigTable.getInstance().loadInstances();
TradeController.getInstance();
MultiSell.getInstance();
RecipeController.getInstance();
ArmorSetsTable.getInstance();
FishTable.getInstance();
printSection("Characters");
CharTemplateTable.getInstance();
CharNameTable.getInstance();
LevelUpData.getInstance();
AccessLevels.getInstance();
AdminCommandAccessRights.getInstance();
GmListTable.getInstance();
RaidBossPointsManager.getInstance();
PetDataTable.getInstance();
printSection("Clans");
ClanTable.getInstance();
ClanHallManager.getInstance();
AuctionManager.getInstance();
printSection("Geodata");
GeoData.getInstance();
if (Config.GEODATA == 2)
{
PathFinding.getInstance();
}
printSection("NPCs");
HerbDropTable.getInstance();
NpcTable.getInstance();
NpcWalkerRoutesTable.getInstance();
ZoneManager.getInstance();
DoorTable.getInstance();
StaticObjects.getInstance();
ItemAuctionManager.getInstance();
CastleManager.getInstance().loadInstances();
FortManager.getInstance().loadInstances();
NpcBufferTable.getInstance();
SpawnTable.getInstance();
RaidBossSpawnManager.getInstance();
DayNightSpawnManager.getInstance().trim().notifyChangeMode();
GrandBossManager.getInstance().initZones();
FourSepulchersManager.getInstance().init();
DimensionalRiftManager.getInstance();
EventDroplist.getInstance();
printSection("Siege");
SiegeManager.getInstance().getSieges();
FortSiegeManager.getInstance();
TerritoryWarManager.getInstance();
CastleManorManager.getInstance();
MercTicketManager.getInstance();
L2Manor.getInstance();
printSection("Olympiad");
Olympiad.getInstance();
Hero.getInstance();
// Call to load caches
printSection("Cache");
HtmCache.getInstance();
CrestCache.getInstance();
TeleportLocationTable.getInstance();
UITable.getInstance();
PartyMatchWaitingList.getInstance();
PartyMatchRoomList.getInstance();
PetitionManager.getInstance();
HennaTable.getInstance();
HennaTreeTable.getInstance();
HelperBuffTable.getInstance();
AugmentationData.getInstance();
CursedWeaponsManager.getInstance();
printSection("Scripts");
QuestManager.getInstance();
TransformationManager.getInstance();
BoatManager.getInstance();
AirShipManager.getInstance();
GraciaSeedsManager.getInstance();
try
{
_log.info("Loading Server Scripts");
File scripts = new File(Config.DATAPACK_ROOT + "/data/scripts.cfg");
if (!Config.ALT_DEV_NO_HANDLERS || !Config.ALT_DEV_NO_QUESTS)
{
L2ScriptEngineManager.getInstance().executeScriptList(scripts);
}
}
catch (IOException ioe)
{
_log.severe("Failed loading scripts.cfg, no script going to be loaded");
}
try
{
CompiledScriptCache compiledScriptCache = L2ScriptEngineManager.getInstance().getCompiledScriptCache();
if (compiledScriptCache == null)
{
_log.info("Compiled Scripts Cache is disabled.");
}
else
{
compiledScriptCache.purge();
if (compiledScriptCache.isModified())
{
compiledScriptCache.save();
_log.info("Compiled Scripts Cache was saved.");
}
else
{
_log.info("Compiled Scripts Cache is up-to-date.");
}
}
}
catch (IOException e)
{
_log.log(Level.SEVERE, "Failed to store Compiled Scripts Cache.", e);
}
QuestManager.getInstance().report();
TransformationManager.getInstance().report();
if (Config.SAVE_DROPPED_ITEM)
{
ItemsOnGroundManager.getInstance();
}
if ((Config.AUTODESTROY_ITEM_AFTER > 0) || (Config.HERB_AUTO_DESTROY_TIME > 0))
{
ItemsAutoDestroy.getInstance();
}
MonsterRace.getInstance();
SevenSigns.getInstance().spawnSevenSignsNPC();
SevenSignsFestival.getInstance();
AutoSpawnHandler.getInstance();
AutoChatHandler.getInstance();
FaenorScriptEngine.getInstance();
// Init of a cursed weapon manager
_log.info("AutoChatHandler: Loaded " + AutoChatHandler.getInstance().size() + " handlers in total.");
_log.info("AutoSpawnHandler: Loaded " + AutoSpawnHandler.getInstance().size() + " handlers in total.");
AdminCommandHandler.getInstance();
ChatHandler.getInstance();
ItemHandler.getInstance();
SkillHandler.getInstance();
UserCommandHandler.getInstance();
VoicedCommandHandler.getInstance();
if (Config.L2JMOD_ALLOW_WEDDING)
{
CoupleManager.getInstance();
}
TaskManager.getInstance();
AntiFeedManager.getInstance().registerEvent(AntiFeedManager.GAME_ID);
MerchantPriceConfigTable.getInstance().updateReferences();
CastleManager.getInstance().activateInstances();
FortManager.getInstance().activateInstances();
HellboundManager.getInstance();
if (Config.ALLOW_MAIL)
{
MailManager.getInstance();
}
if (Config.ACCEPT_GEOEDITOR_CONN)
{
GeoEditorListener.getInstance();
}
Runtime.getRuntime().addShutdownHook(Shutdown.getInstance());
_log.info("IdFactory: Free ObjectID's remaining: " + IdFactory.getInstance().size());
TvTManager.getInstance();
KnownListUpdateTaskManager.getInstance();
if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
{
OfflineTradersTable.restoreOfflineTraders();
}
if (Config.DEADLOCK_DETECTOR)
{
_deadDetectThread = new DeadLockDetector();
_deadDetectThread.setDaemon(true);
_deadDetectThread.start();
}
else
{
_deadDetectThread = null;
}
System.gc();
// maxMemory is the upper limit the jvm can use, totalMemory the size of
// the current allocation pool, freeMemory the unused memory in the
// allocation pool
long freeMem = ((Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory()) + Runtime.getRuntime().freeMemory()) / 1048576;
long totalMem = Runtime.getRuntime().maxMemory() / 1048576;
_log.info("GameServer Started, free memory " + freeMem + " Mb of " + totalMem + " Mb");
_loginThread = LoginServerThread.getInstance();
_loginThread.start();
CommunityServerThread.initialize();
final SelectorConfig sc = new SelectorConfig();
sc.MAX_READ_PER_PASS = Config.MMO_MAX_READ_PER_PASS;
sc.MAX_SEND_PER_PASS = Config.MMO_MAX_SEND_PER_PASS;
sc.SLEEP_TIME = Config.MMO_SELECTOR_SLEEP_TIME;
sc.HELPER_BUFFER_COUNT = Config.MMO_HELPER_BUFFER_COUNT;
_gamePacketHandler = new L2GamePacketHandler();
_selectorThread = new SelectorThread<>(sc, _gamePacketHandler, _gamePacketHandler, _gamePacketHandler, new IPv4Filter());
InetAddress bindAddress = null;
if (!Config.GAMESERVER_HOSTNAME.equals("*"))
{
try
{
bindAddress = InetAddress.getByName(Config.GAMESERVER_HOSTNAME);
}
catch (UnknownHostException e1)
{
_log.log(Level.SEVERE, "WARNING: The GameServer bind address is invalid, using all avaliable IPs. Reason: " + e1.getMessage(), e1);
}
}
try
{
_selectorThread.openServerSocket(bindAddress, Config.PORT_GAME);
}
catch (IOException e)
{
_log.log(Level.SEVERE, "FATAL: Failed to open server socket. Reason: " + e.getMessage(), e);
System.exit(1);
}
_selectorThread.start();
_log.info("Maximum Numbers of Connected Players: " + Config.MAXIMUM_ONLINE_USERS);
long serverLoadEnd = System.currentTimeMillis();
_log.info("Server Loaded in " + ((serverLoadEnd - serverLoadStart) / 1000) + " seconds");
AutoAnnounceTaskManager.getInstance();
}
public static void main(String[] args) throws Exception
{
Server.serverMode = Server.MODE_GAMESERVER;
// Local Constants
final String LOG_FOLDER = "log"; // Name of folder for log file
final String LOG_NAME = "./log.cfg"; // Name of log file
/*** Main ***/
// Create log folder
File logFolder = new File(Config.DATAPACK_ROOT, LOG_FOLDER);
logFolder.mkdir();
// Create input stream for log file -- or store file data into memory
InputStream is = new FileInputStream(new File(LOG_NAME));
LogManager.getLogManager().readConfiguration(is);
is.close();
// Initialize config
Config.load();
printSection("Database");
L2DatabaseFactory.getInstance();
gameServer = new GameServer();
if (Config.IS_TELNET_ENABLED)
{
_statusServer = new Status(Server.serverMode);
_statusServer.start();
}
else
{
_log.info("Telnet server is currently disabled.");
}
}
public static void printSection(String s)
{
s = "=[ " + s + " ]";
while (s.length() < 78)
{
s = "-" + s;
}
_log.info(s);
}
}
@@ -0,0 +1,259 @@
/*
* 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 com.l2jserver.gameserver;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.gameserver.ai.CtrlEvent;
import com.l2jserver.gameserver.instancemanager.DayNightSpawnManager;
import com.l2jserver.gameserver.model.actor.L2Character;
/**
* Removed TimerThread watcher [DrHouse]
* @version $Date: 2010/02/02 22:43:00 $
*/
public class GameTimeController
{
protected static final Logger _log = Logger.getLogger(GameTimeController.class.getName());
public static final int TICKS_PER_SECOND = 10; // not able to change this without checking through code
public static final int MILLIS_IN_TICK = 1000 / TICKS_PER_SECOND;
protected static int _gameTicks;
protected static long _gameStartTime;
protected static boolean _isNight = false;
protected static boolean _interruptRequest = false;
private static final FastMap<Integer, L2Character> _movingObjects = new FastMap<Integer, L2Character>().shared();
protected static TimerThread _timer;
/**
* one ingame day is 240 real minutes
*/
public static GameTimeController getInstance()
{
return SingletonHolder._instance;
}
private GameTimeController()
{
_gameStartTime = System.currentTimeMillis() - 3600000; // offset so that the server starts a day begin
_gameTicks = 3600000 / MILLIS_IN_TICK; // offset so that the server starts a day begin
_timer = new TimerThread();
_timer.start();
ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new BroadcastSunState(), 0, 600000);
}
public boolean isNowNight()
{
return _isNight;
}
public int getGameTime()
{
return (_gameTicks / (TICKS_PER_SECOND * 10));
}
public static int getGameTicks()
{
return _gameTicks;
}
/**
* Add a L2Character to movingObjects of GameTimeController.<BR>
* <BR>
* <B><U> Concept</U> :</B><BR>
* <BR>
* All L2Character in movement are identified in <B>movingObjects</B> of GameTimeController.<BR>
* <BR>
* @param cha The L2Character to add to movingObjects of GameTimeController
*/
public void registerMovingObject(L2Character cha)
{
if (cha == null)
{
return;
}
_movingObjects.putIfAbsent(cha.getObjectId(), cha);
}
/**
* Move all L2Characters contained in movingObjects of GameTimeController.<BR>
* <BR>
* <B><U> Concept</U> :</B><BR>
* <BR>
* All L2Character in movement are identified in <B>movingObjects</B> of GameTimeController.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Update the position of each L2Character</li> <li>If movement is finished, the L2Character is removed from movingObjects</li> <li>Create a task to update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object then notify AI with
* EVT_ARRIVED</li><BR>
* <BR>
*/
protected void moveObjects()
{
// Go throw the table containing L2Character in movement
Iterator<Map.Entry<Integer, L2Character>> it = _movingObjects.entrySet().iterator();
while (it.hasNext())
{
// If movement is finished, the L2Character is removed from
// movingObjects and added to the ArrayList ended
L2Character ch = it.next().getValue();
if (ch.updatePosition(_gameTicks))
{
it.remove();
ThreadPoolManager.getInstance().executeTask(new MovingObjectArrived(ch));
}
}
}
public void stopTimer()
{
_interruptRequest = true;
_timer.interrupt();
}
class TimerThread extends Thread
{
public TimerThread()
{
super("GameTimeController");
setDaemon(true);
setPriority(MAX_PRIORITY);
}
@Override
public void run()
{
int oldTicks;
long runtime;
int sleepTime;
for (;;)
{
try
{
oldTicks = _gameTicks; // save old ticks value to avoid moving objects 2x in same tick
runtime = System.currentTimeMillis() - _gameStartTime; // from server boot to now
_gameTicks = (int) (runtime / MILLIS_IN_TICK); // new ticks value (ticks now)
if (oldTicks != _gameTicks)
{
moveObjects(); // Runs possibly too often
}
runtime = (System.currentTimeMillis() - _gameStartTime) - runtime;
// calculate sleep time... time needed to next tick minus time it takes to call moveObjects()
sleepTime = (1 + MILLIS_IN_TICK) - (((int) runtime) % MILLIS_IN_TICK);
// _log.finest("TICK: "+_gameTicks);
if (sleepTime > 0)
{
Thread.sleep(sleepTime);
}
}
catch (InterruptedException ie)
{
if (_interruptRequest)
{
return;
}
_log.log(Level.WARNING, "", ie);
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
}
}
}
}
/**
* Update the _knownObject and _knowPlayers of each L2Character that finished its movement and of their already known L2Object then notify AI with EVT_ARRIVED.<BR>
* <BR>
*/
private static class MovingObjectArrived implements Runnable
{
private final L2Character _ended;
MovingObjectArrived(L2Character ended)
{
_ended = ended;
}
@Override
public void run()
{
try
{
if (_ended.hasAI()) // AI could be just disabled due to region turn off
{
if (Config.MOVE_BASED_KNOWNLIST)
{
_ended.getKnownList().findObjects();
}
_ended.getAI().notifyEvent(CtrlEvent.EVT_ARRIVED);
}
}
catch (NullPointerException e)
{
_log.log(Level.WARNING, "", e);
}
}
}
/**
* @param rise
*/
class BroadcastSunState implements Runnable
{
int h;
boolean tempIsNight;
@Override
public void run()
{
h = ((getGameTime() + 29) / 60) % 24; // Time in hour (+ 29 is to round 60)
tempIsNight = (h < 6);
if (tempIsNight != _isNight)
{ // If diff day/night state
_isNight = tempIsNight; // Set current day/night varible to value of temp varible
DayNightSpawnManager.getInstance().notifyChangeMode();
}
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final GameTimeController _instance = new GameTimeController();
}
}
@@ -0,0 +1,196 @@
/*
* 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 com.l2jserver.gameserver;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.util.Point3D;
/**
* @author -Nemesiss-
*/
public class GeoData
{
private static Logger _log = Logger.getLogger(GeoData.class.getName());
protected GeoData()
{
}
private GeoData(final boolean disabled)
{
if (disabled)
{
_log.info("Geodata Engine: Disabled.");
}
}
public static GeoData getInstance()
{
return SingletonHolder._instance;
}
// Public Methods
/**
* @param x
* @param y
* @return Geo Block Type
*/
public short getType(int x, int y)
{
return 0;
}
/**
* @param x
* @param y
* @param z
* @return Nearles Z
*/
public short getHeight(int x, int y, int z)
{
return (short) z;
}
/**
* @param x
* @param y
* @param zmin
* @param zmax
* @param spawnid
* @return
*/
public short getSpawnHeight(int x, int y, int zmin, int zmax, L2Spawn spawn)
{
return (short) zmin;
}
/**
* @param x
* @param y
* @return
*/
public String geoPosition(int x, int y)
{
return "";
}
/**
* @param cha
* @param target
* @return True if cha can see target (LOS)
*/
public boolean canSeeTarget(L2Object cha, L2Object target)
{
// If geo is off do simple check :]
// Don't allow casting on players on different dungeon lvls etc
return (Math.abs(target.getZ() - cha.getZ()) < 1000);
}
public boolean canSeeTarget(L2Object cha, Point3D worldPosition)
{
// If geo is off do simple check :]
// Don't allow casting on players on different dungeon lvls etc
return Math.abs(worldPosition.getZ() - cha.getZ()) < 1000;
}
public boolean canSeeTarget(int x, int y, int z, int tx, int ty, int tz)
{
// If geo is off do simple check :]
// Don't allow casting on players on different dungeon lvls etc
return (Math.abs(z - tz) < 1000);
}
/**
* @param cha
* @param target
* @return True if cha can see target (LOS) and send usful info to PC
*/
public boolean canSeeTargetDebug(L2PcInstance gm, L2Object target)
{
return true;
}
/**
* @param x
* @param y
* @param z
* @return Geo NSWE (0-15)
*/
public short getNSWE(int x, int y, int z)
{
return 15;
}
public short getHeightAndNSWE(int x, int y, int z)
{
return (short) ((z << 1) | 15);
}
/**
* @param x
* @param y
* @param z
* @param tx
* @param ty
* @param tz
* @param instanceId
* @return Last Location (x,y,z) where player can walk - just before wall
*/
public Location moveCheck(int x, int y, int z, int tx, int ty, int tz, int instanceId)
{
return new Location(tx, ty, tz);
}
public boolean canMoveFromToTarget(int x, int y, int z, int tx, int ty, int tz, int instanceId)
{
return true;
}
/**
* @param gm
* @param comment
*/
public void addGeoDataBug(L2PcInstance gm, String comment)
{
// Do Nothing
}
public static void unloadGeodata(byte rx, byte ry)
{
}
public static boolean loadGeodataFile(byte rx, byte ry)
{
return false;
}
public boolean hasGeo(int x, int y)
{
return false;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final GeoData _instance = Config.GEODATA > 0 ? GeoEngine.getInstance() : new GeoData(true);
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,184 @@
/*
* 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 com.l2jserver.gameserver;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.L2GameServerPacket;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
/**
* This class stores references to all online game masters. (access level > 100)
* @version $Revision: 1.2.2.1.2.7 $ $Date: 2005/04/05 19:41:24 $
*/
public class GmListTable
{
private static Logger _log = Logger.getLogger(GmListTable.class.getName());
/** Set(L2PcInstance>) containing all the GM in game */
private final FastMap<L2PcInstance, Boolean> _gmList;
public static GmListTable getInstance()
{
return SingletonHolder._instance;
}
public FastList<L2PcInstance> getAllGms(boolean includeHidden)
{
FastList<L2PcInstance> tmpGmList = new FastList<>();
for (FastMap.Entry<L2PcInstance, Boolean> n = _gmList.head(), end = _gmList.tail(); (n = n.getNext()) != end;)
{
if (includeHidden || !n.getValue())
{
tmpGmList.add(n.getKey());
}
}
return tmpGmList;
}
public FastList<String> getAllGmNames(boolean includeHidden)
{
FastList<String> tmpGmList = new FastList<>();
for (FastMap.Entry<L2PcInstance, Boolean> n = _gmList.head(), end = _gmList.tail(); (n = n.getNext()) != end;)
{
if (!n.getValue())
{
tmpGmList.add(n.getKey().getName());
}
else if (includeHidden)
{
tmpGmList.add(n.getKey().getName() + " (invis)");
}
}
return tmpGmList;
}
private GmListTable()
{
_gmList = new FastMap<L2PcInstance, Boolean>().shared();
}
/**
* Add a L2PcInstance player to the Set _gmList
*/
public void addGm(L2PcInstance player, boolean hidden)
{
if (Config.DEBUG)
{
_log.fine("added gm: " + player.getName());
}
_gmList.put(player, hidden);
}
public void deleteGm(L2PcInstance player)
{
if (Config.DEBUG)
{
_log.fine("deleted gm: " + player.getName());
}
_gmList.remove(player);
}
/**
* GM will be displayed on clients gmlist
* @param player
*/
public void showGm(L2PcInstance player)
{
FastMap.Entry<L2PcInstance, Boolean> gm = _gmList.getEntry(player);
if (gm != null)
{
gm.setValue(false);
}
}
/**
* GM will no longer be displayed on clients gmlist
* @param player
*/
public void hideGm(L2PcInstance player)
{
FastMap.Entry<L2PcInstance, Boolean> gm = _gmList.getEntry(player);
if (gm != null)
{
gm.setValue(true);
}
}
public boolean isGmOnline(boolean includeHidden)
{
for (FastMap.Entry<L2PcInstance, Boolean> n = _gmList.head(), end = _gmList.tail(); (n = n.getNext()) != end;)
{
if (includeHidden || !n.getValue())
{
return true;
}
}
return false;
}
public void sendListToPlayer(L2PcInstance player)
{
if (isGmOnline(player.isGM()))
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.GM_LIST));
for (String name : getAllGmNames(player.isGM()))
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.GM_C1);
sm.addString(name);
player.sendPacket(sm);
}
}
else
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.NO_GM_PROVIDING_SERVICE_NOW));
}
}
public static void broadcastToGMs(L2GameServerPacket packet)
{
for (L2PcInstance gm : getInstance().getAllGms(true))
{
gm.sendPacket(packet);
}
}
public static void broadcastMessageToGMs(String message)
{
for (L2PcInstance gm : getInstance().getAllGms(true))
{
gm.sendMessage(message);
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final GmListTable _instance = new GmListTable();
}
}
@@ -0,0 +1,24 @@
package com.l2jserver.gameserver;
/**
* Interface for managers of list of instances.
* @author fordfrog
*/
public interface InstanceListManager
{
/**
* Loads instances with their data from persistant format. This method has no side effect as calling methods of another instance manager.
*/
void loadInstances();
/**
* For each loaded instance, updates references to related instances.
*/
void updateReferences();
/**
* Activates instances so their setup is performed.
*/
void activateInstances();
}
@@ -0,0 +1,44 @@
/*
* $Header: Item.java, 2/08/2005 00:49:12 luisantonioa Exp $
*
* $Author: luisantonioa $ $Date: 2/08/2005 00:49:12 $ $Revision: 1 $ $Log:
* Item.java,v $ Revision 1 2/08/2005 00:49:12 luisantonioa Added copyright
* notice
*
*
* 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 com.l2jserver.gameserver;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.templates.item.L2Item;
/**
* This class ...
* @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $
*/
public class Item
{
public int id;
public String type;
public String name;
public StatsSet set;
public int currentLevel;
public L2Item item;
}
@@ -0,0 +1,124 @@
/*
* 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 com.l2jserver.gameserver;
import java.util.List;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jserver.Config;
import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.templates.item.L2EtcItemType;
public class ItemsAutoDestroy
{
protected static final Logger _log = Logger.getLogger(ItemsAutoDestroy.class.getName());
protected List<L2ItemInstance> _items = null;
protected static long _sleep;
private ItemsAutoDestroy()
{
_log.info("Initializing ItemsAutoDestroy.");
_items = new FastList<>();
_sleep = Config.AUTODESTROY_ITEM_AFTER * 1000;
if (_sleep == 0)
{
_sleep = 3600000;
}
ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new CheckItemsForDestroy(), 5000, 5000);
}
public static ItemsAutoDestroy getInstance()
{
return SingletonHolder._instance;
}
public synchronized void addItem(L2ItemInstance item)
{
item.setDropTime(System.currentTimeMillis());
_items.add(item);
}
public synchronized void removeItems()
{
if (Config.DEBUG)
{
_log.info("[ItemsAutoDestroy] : " + _items.size() + " items to check.");
}
if (_items.isEmpty())
{
return;
}
long curtime = System.currentTimeMillis();
for (L2ItemInstance item : _items)
{
if ((item == null) || (item.getDropTime() == 0) || (item.getLocation() != L2ItemInstance.ItemLocation.VOID))
{
_items.remove(item);
}
else
{
if (item.getItemType() == L2EtcItemType.HERB)
{
if ((curtime - item.getDropTime()) > Config.HERB_AUTO_DESTROY_TIME)
{
L2World.getInstance().removeVisibleObject(item, item.getWorldRegion());
L2World.getInstance().removeObject(item);
_items.remove(item);
if (Config.SAVE_DROPPED_ITEM)
{
ItemsOnGroundManager.getInstance().removeObject(item);
}
}
}
else if ((curtime - item.getDropTime()) > _sleep)
{
L2World.getInstance().removeVisibleObject(item, item.getWorldRegion());
L2World.getInstance().removeObject(item);
_items.remove(item);
if (Config.SAVE_DROPPED_ITEM)
{
ItemsOnGroundManager.getInstance().removeObject(item);
}
}
}
}
if (Config.DEBUG)
{
_log.info("[ItemsAutoDestroy] : " + _items.size() + " items remaining.");
}
}
protected class CheckItemsForDestroy extends Thread
{
@Override
public void run()
{
removeItems();
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ItemsAutoDestroy _instance = new ItemsAutoDestroy();
}
}
@@ -0,0 +1,702 @@
/*
* 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 com.l2jserver.gameserver;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAKeyGenParameterSpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.L2GameClient;
import com.l2jserver.gameserver.network.L2GameClient.GameClientState;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.gameserverpackets.AuthRequest;
import com.l2jserver.gameserver.network.gameserverpackets.BlowFishKey;
import com.l2jserver.gameserver.network.gameserverpackets.ChangeAccessLevel;
import com.l2jserver.gameserver.network.gameserverpackets.PlayerAuthRequest;
import com.l2jserver.gameserver.network.gameserverpackets.PlayerInGame;
import com.l2jserver.gameserver.network.gameserverpackets.PlayerLogout;
import com.l2jserver.gameserver.network.gameserverpackets.PlayerTracert;
import com.l2jserver.gameserver.network.gameserverpackets.ServerStatus;
import com.l2jserver.gameserver.network.loginserverpackets.AuthResponse;
import com.l2jserver.gameserver.network.loginserverpackets.InitLS;
import com.l2jserver.gameserver.network.loginserverpackets.KickPlayer;
import com.l2jserver.gameserver.network.loginserverpackets.LoginServerFail;
import com.l2jserver.gameserver.network.loginserverpackets.PlayerAuthResponse;
import com.l2jserver.gameserver.network.serverpackets.CharSelectionInfo;
import com.l2jserver.gameserver.network.serverpackets.LoginFail;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.util.Util;
import com.l2jserver.util.crypt.NewCrypt;
import com.l2jserver.util.network.BaseSendablePacket;
public class LoginServerThread extends Thread
{
protected static final Logger _log = Logger.getLogger(LoginServerThread.class.getName());
protected static final Logger _logAccounting = Logger.getLogger("accounting");
/** {@see com.l2jserver.loginserver.LoginServer#PROTOCOL_REV } */
private static final int REVISION = 0x0104;
private RSAPublicKey _publicKey;
private final String _hostname;
private final int _port;
private final int _gamePort;
private Socket _loginSocket;
private InputStream _in;
private OutputStream _out;
/**
* The BlowFish engine used to encrypt packets<br>
* It is first initialized with a unified key:<br>
* "_;v.]05-31!|+-%xT!^[$\00"<br>
* <br>
* and then after handshake, with a new key sent by<br>
* loginserver during the handshake. This new key is stored<br>
* in {@link #_blowfishKey}
*/
private NewCrypt _blowfish;
private byte[] _blowfishKey;
private byte[] _hexID;
private final boolean _acceptAlternate;
private int _requestID;
private int _serverID;
private final boolean _reserveHost;
private int _maxPlayer;
private final List<WaitingClient> _waitingClients;
private final Map<String, L2GameClient> _accountsInGameServer;
private int _status;
private String _serverName;
private final String[] _subnets;
private final String[] _hosts;
private LoginServerThread()
{
super("LoginServerThread");
_port = Config.GAME_SERVER_LOGIN_PORT;
_gamePort = Config.PORT_GAME;
_hostname = Config.GAME_SERVER_LOGIN_HOST;
_hexID = Config.HEX_ID;
if (_hexID == null)
{
_requestID = Config.REQUEST_ID;
_hexID = Util.generateHex(16);
}
else
{
_requestID = Config.SERVER_ID;
}
_acceptAlternate = Config.ACCEPT_ALTERNATE_ID;
_reserveHost = Config.RESERVE_HOST_ON_LOGIN;
_subnets = Config.GAME_SERVER_SUBNETS;
_hosts = Config.GAME_SERVER_HOSTS;
_waitingClients = new FastList<>();
_accountsInGameServer = new FastMap<String, L2GameClient>().shared();
_maxPlayer = Config.MAXIMUM_ONLINE_USERS;
}
public static LoginServerThread getInstance()
{
return SingletonHolder._instance;
}
@Override
public void run()
{
while (!isInterrupted())
{
int lengthHi = 0;
int lengthLo = 0;
int length = 0;
boolean checksumOk = false;
try
{
// Connection
_log.info("Connecting to login on " + _hostname + ":" + _port);
_loginSocket = new Socket(_hostname, _port);
_in = _loginSocket.getInputStream();
_out = new BufferedOutputStream(_loginSocket.getOutputStream());
// init Blowfish
_blowfishKey = Util.generateHex(40);
_blowfish = new NewCrypt("_;v.]05-31!|+-%xT!^[$\00");
while (!isInterrupted())
{
lengthLo = _in.read();
lengthHi = _in.read();
length = (lengthHi * 256) + lengthLo;
if (lengthHi < 0)
{
_log.finer("LoginServerThread: Login terminated the connection.");
break;
}
byte[] incoming = new byte[length - 2];
int receivedBytes = 0;
int newBytes = 0;
int left = length - 2;
while ((newBytes != -1) && (receivedBytes < (length - 2)))
{
newBytes = _in.read(incoming, receivedBytes, left);
receivedBytes = receivedBytes + newBytes;
left -= newBytes;
}
if (receivedBytes != (length - 2))
{
_log.warning("Incomplete Packet is sent to the server, closing connection.(LS)");
break;
}
// decrypt if we have a key
byte[] decrypt = _blowfish.decrypt(incoming);
checksumOk = NewCrypt.verifyChecksum(decrypt);
if (!checksumOk)
{
_log.warning("Incorrect packet checksum, ignoring packet (LS)");
break;
}
if (Config.DEBUG)
{
_log.warning("[C]\n" + Util.printData(decrypt));
}
int packetType = decrypt[0] & 0xff;
switch (packetType)
{
case 0x00:
InitLS init = new InitLS(decrypt);
if (Config.DEBUG)
{
_log.info("Init received");
}
if (init.getRevision() != REVISION)
{
// TODO: revision mismatch
_log.warning("/!\\ Revision mismatch between LS and GS /!\\");
break;
}
try
{
KeyFactory kfac = KeyFactory.getInstance("RSA");
BigInteger modulus = new BigInteger(init.getRSAKey());
RSAPublicKeySpec kspec1 = new RSAPublicKeySpec(modulus, RSAKeyGenParameterSpec.F4);
_publicKey = (RSAPublicKey) kfac.generatePublic(kspec1);
if (Config.DEBUG)
{
_log.info("RSA key set up");
}
}
catch (GeneralSecurityException e)
{
_log.warning("Troubles while init the public key send by login");
break;
}
// send the blowfish key through the rsa encryption
BlowFishKey bfk = new BlowFishKey(_blowfishKey, _publicKey);
sendPacket(bfk);
if (Config.DEBUG)
{
_log.info("Sent new blowfish key");
}
// now, only accept paket with the new encryption
_blowfish = new NewCrypt(_blowfishKey);
if (Config.DEBUG)
{
_log.info("Changed blowfish key");
}
AuthRequest ar = new AuthRequest(_requestID, _acceptAlternate, _hexID, _gamePort, _reserveHost, _maxPlayer, _subnets, _hosts);
sendPacket(ar);
if (Config.DEBUG)
{
_log.info("Sent AuthRequest to login");
}
break;
case 0x01:
LoginServerFail lsf = new LoginServerFail(decrypt);
_log.info("Damn! Registeration Failed: " + lsf.getReasonString());
// login will close the connection here
break;
case 0x02:
AuthResponse aresp = new AuthResponse(decrypt);
_serverID = aresp.getServerId();
_serverName = aresp.getServerName();
Config.saveHexid(_serverID, hexToString(_hexID));
_log.info("Registered on login as Server " + _serverID + " : " + _serverName);
ServerStatus st = new ServerStatus();
if (Config.SERVER_LIST_BRACKET)
{
st.addAttribute(ServerStatus.SERVER_LIST_SQUARE_BRACKET, ServerStatus.ON);
}
else
{
st.addAttribute(ServerStatus.SERVER_LIST_SQUARE_BRACKET, ServerStatus.OFF);
}
st.addAttribute(ServerStatus.SERVER_TYPE, Config.SERVER_LIST_TYPE);
if (Config.SERVER_GMONLY)
{
st.addAttribute(ServerStatus.SERVER_LIST_STATUS, ServerStatus.STATUS_GM_ONLY);
}
else
{
st.addAttribute(ServerStatus.SERVER_LIST_STATUS, ServerStatus.STATUS_AUTO);
}
if (Config.SERVER_LIST_AGE == 15)
{
st.addAttribute(ServerStatus.SERVER_AGE, ServerStatus.SERVER_AGE_15);
}
else if (Config.SERVER_LIST_AGE == 18)
{
st.addAttribute(ServerStatus.SERVER_AGE, ServerStatus.SERVER_AGE_18);
}
else
{
st.addAttribute(ServerStatus.SERVER_AGE, ServerStatus.SERVER_AGE_ALL);
}
sendPacket(st);
if (L2World.getInstance().getAllPlayersCount() > 0)
{
FastList<String> playerList = new FastList<>();
Collection<L2PcInstance> pls = L2World.getInstance().getAllPlayers().values();
// synchronized (L2World.getInstance().getAllPlayers())
{
for (L2PcInstance player : pls)
{
playerList.add(player.getAccountName());
}
}
PlayerInGame pig = new PlayerInGame(playerList);
sendPacket(pig);
}
break;
case 0x03:
PlayerAuthResponse par = new PlayerAuthResponse(decrypt);
String account = par.getAccount();
WaitingClient wcToRemove = null;
synchronized (_waitingClients)
{
for (WaitingClient wc : _waitingClients)
{
if (wc.account.equals(account))
{
wcToRemove = wc;
}
}
}
if (wcToRemove != null)
{
if (par.isAuthed())
{
if (Config.DEBUG)
{
_log.info("Login accepted player " + wcToRemove.account + " waited(" + (GameTimeController.getGameTicks() - wcToRemove.timestamp) + "ms)");
}
PlayerInGame pig = new PlayerInGame(par.getAccount());
sendPacket(pig);
wcToRemove.gameClient.setState(GameClientState.AUTHED);
wcToRemove.gameClient.setSessionId(wcToRemove.session);
CharSelectionInfo cl = new CharSelectionInfo(wcToRemove.account, wcToRemove.gameClient.getSessionId().playOkID1);
wcToRemove.gameClient.getConnection().sendPacket(cl);
wcToRemove.gameClient.setCharSelection(cl.getCharInfo());
}
else
{
_log.warning("Session key is not correct. Closing connection for account " + wcToRemove.account + ".");
// wcToRemove.gameClient.getConnection().sendPacket(new LoginFail(LoginFail.SYSTEM_ERROR_LOGIN_LATER));
wcToRemove.gameClient.close(new LoginFail(LoginFail.SYSTEM_ERROR_LOGIN_LATER));
_accountsInGameServer.remove(wcToRemove.account);
}
_waitingClients.remove(wcToRemove);
}
break;
case 0x04:
KickPlayer kp = new KickPlayer(decrypt);
doKickPlayer(kp.getAccount());
break;
}
}
}
catch (UnknownHostException e)
{
if (Config.DEBUG)
{
_log.log(Level.WARNING, "", e);
}
}
catch (IOException e)
{
_log.log(Level.WARNING, "Disconnected from Login, Trying to reconnect: " + e.getMessage(), e);
}
finally
{
try
{
_loginSocket.close();
if (isInterrupted())
{
return;
}
}
catch (Exception e)
{
}
}
try
{
Thread.sleep(5000); // 5 seconds tempo.
}
catch (InterruptedException e)
{
return; // never swallow an interrupt!
}
}
}
public void addWaitingClientAndSendRequest(String acc, L2GameClient client, SessionKey key)
{
if (Config.DEBUG)
{
_log.info(String.valueOf(key));
}
WaitingClient wc = new WaitingClient(acc, client, key);
synchronized (_waitingClients)
{
_waitingClients.add(wc);
}
PlayerAuthRequest par = new PlayerAuthRequest(acc, key);
try
{
sendPacket(par);
}
catch (IOException e)
{
_log.warning("Error while sending player auth request");
if (Config.DEBUG)
{
_log.log(Level.WARNING, "", e);
}
}
}
public void removeWaitingClient(L2GameClient client)
{
WaitingClient toRemove = null;
synchronized (_waitingClients)
{
for (WaitingClient c : _waitingClients)
{
if (c.gameClient == client)
{
toRemove = c;
}
}
if (toRemove != null)
{
_waitingClients.remove(toRemove);
}
}
}
public void sendLogout(String account)
{
if (account == null)
{
return;
}
PlayerLogout pl = new PlayerLogout(account);
try
{
sendPacket(pl);
}
catch (IOException e)
{
_log.warning("Error while sending logout packet to login");
if (Config.DEBUG)
{
_log.log(Level.WARNING, "", e);
}
}
finally
{
_accountsInGameServer.remove(account);
}
}
public void addGameServerLogin(String account, L2GameClient client)
{
_accountsInGameServer.put(account, client);
}
public void sendAccessLevel(String account, int level)
{
ChangeAccessLevel cal = new ChangeAccessLevel(account, level);
try
{
sendPacket(cal);
}
catch (IOException e)
{
if (Config.DEBUG)
{
_log.log(Level.WARNING, "", e);
}
}
}
public void sendClientTracert(String account, String[] adress)
{
PlayerTracert ptc = new PlayerTracert(account, adress[0], adress[1], adress[2], adress[3], adress[4]);
try
{
sendPacket(ptc);
}
catch (IOException e)
{
if (Config.DEBUG)
{
_log.log(Level.WARNING, "", e);
}
}
}
private String hexToString(byte[] hex)
{
return new BigInteger(hex).toString(16);
}
public void doKickPlayer(String account)
{
L2GameClient client = _accountsInGameServer.get(account);
if (client != null)
{
LogRecord record = new LogRecord(Level.WARNING, "Kicked by login");
record.setParameters(new Object[]
{
client
});
_logAccounting.log(record);
client.setAditionalClosePacket(SystemMessage.getSystemMessage(SystemMessageId.ANOTHER_LOGIN_WITH_ACCOUNT));
client.closeNow();
}
}
/**
* @param sl
* @throws IOException
*/
private void sendPacket(BaseSendablePacket sl) throws IOException
{
byte[] data = sl.getContent();
NewCrypt.appendChecksum(data);
if (Config.DEBUG)
{
_log.finest("[S]\n" + Util.printData(data));
}
data = _blowfish.crypt(data);
int len = data.length + 2;
synchronized (_out) // avoids tow threads writing in the mean time
{
_out.write(len & 0xff);
_out.write((len >> 8) & 0xff);
_out.write(data);
_out.flush();
}
}
/**
* @param maxPlayer The maxPlayer to set.
*/
public void setMaxPlayer(int maxPlayer)
{
sendServerStatus(ServerStatus.MAX_PLAYERS, maxPlayer);
_maxPlayer = maxPlayer;
}
/**
* @return Returns the maxPlayer.
*/
public int getMaxPlayer()
{
return _maxPlayer;
}
/**
* @param server_gm_only
*/
public void sendServerStatus(int id, int value)
{
ServerStatus ss = new ServerStatus();
ss.addAttribute(id, value);
try
{
sendPacket(ss);
}
catch (IOException e)
{
if (Config.DEBUG)
{
_log.log(Level.WARNING, "", e);
}
}
}
/**
* Send Server Type Config to LS
*/
public void sendServerType()
{
ServerStatus ss = new ServerStatus();
ss.addAttribute(ServerStatus.SERVER_TYPE, Config.SERVER_LIST_TYPE);
try
{
sendPacket(ss);
}
catch (IOException e)
{
if (Config.DEBUG)
{
_log.log(Level.WARNING, "", e);
}
}
}
/**
* @return
*/
public String getStatusString()
{
return ServerStatus.STATUS_STRING[_status];
}
/**
* @return
*/
public boolean isBracketShown()
{
return Config.SERVER_LIST_BRACKET;
}
/**
* @return Returns the serverName.
*/
public String getServerName()
{
return _serverName;
}
public void setServerStatus(int status)
{
switch (status)
{
case ServerStatus.STATUS_AUTO:
sendServerStatus(ServerStatus.SERVER_LIST_STATUS, ServerStatus.STATUS_AUTO);
_status = status;
break;
case ServerStatus.STATUS_DOWN:
sendServerStatus(ServerStatus.SERVER_LIST_STATUS, ServerStatus.STATUS_DOWN);
_status = status;
break;
case ServerStatus.STATUS_FULL:
sendServerStatus(ServerStatus.SERVER_LIST_STATUS, ServerStatus.STATUS_FULL);
_status = status;
break;
case ServerStatus.STATUS_GM_ONLY:
sendServerStatus(ServerStatus.SERVER_LIST_STATUS, ServerStatus.STATUS_GM_ONLY);
_status = status;
break;
case ServerStatus.STATUS_GOOD:
sendServerStatus(ServerStatus.SERVER_LIST_STATUS, ServerStatus.STATUS_GOOD);
_status = status;
break;
case ServerStatus.STATUS_NORMAL:
sendServerStatus(ServerStatus.SERVER_LIST_STATUS, ServerStatus.STATUS_NORMAL);
_status = status;
break;
default:
throw new IllegalArgumentException("Status does not exists:" + status);
}
}
public static class SessionKey
{
public int playOkID1;
public int playOkID2;
public int loginOkID1;
public int loginOkID2;
public SessionKey(int loginOK1, int loginOK2, int playOK1, int playOK2)
{
playOkID1 = playOK1;
playOkID2 = playOK2;
loginOkID1 = loginOK1;
loginOkID2 = loginOK2;
}
@Override
public String toString()
{
return "PlayOk: " + playOkID1 + " " + playOkID2 + " LoginOk:" + loginOkID1 + " " + loginOkID2;
}
}
private static class WaitingClient
{
public int timestamp;
public String account;
public L2GameClient gameClient;
public SessionKey session;
public WaitingClient(String acc, L2GameClient client, SessionKey key)
{
account = acc;
timestamp = GameTimeController.getGameTicks();
gameClient = client;
session = key;
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final LoginServerThread _instance = new LoginServerThread();
}
}
@@ -0,0 +1,152 @@
/*
* 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 com.l2jserver.gameserver;
import java.lang.reflect.Constructor;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.gameserver.datatables.NpcTable;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
import com.l2jserver.util.Rnd;
public class MonsterRace
{
protected static final Logger _log = Logger.getLogger(MonsterRace.class.getName());
private final L2Npc[] _monsters;
private Constructor<?> _constructor;
private int[][] _speeds;
private final int[] _first, _second;
private MonsterRace()
{
_monsters = new L2Npc[8];
_speeds = new int[8][20];
_first = new int[2];
_second = new int[2];
}
public static MonsterRace getInstance()
{
return SingletonHolder._instance;
}
public void newRace()
{
int random = 0;
for (int i = 0; i < 8; i++)
{
int id = 31003;
random = Rnd.get(24);
while (true)
{
for (int j = i - 1; j >= 0; j--)
{
if (_monsters[j].getTemplate().npcId == (id + random))
{
random = Rnd.get(24);
continue;
}
}
break;
}
try
{
L2NpcTemplate template = NpcTable.getInstance().getTemplate(id + random);
_constructor = Class.forName("com.l2jserver.gameserver.model.actor.instance." + template.type + "Instance").getConstructors()[0];
int objectId = IdFactory.getInstance().getNextId();
_monsters[i] = (L2Npc) _constructor.newInstance(objectId, template);
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
}
// _log.info("Monster "+i+" is id: "+(id+random));
}
newSpeeds();
}
public void newSpeeds()
{
_speeds = new int[8][20];
int total = 0;
_first[1] = 0;
_second[1] = 0;
for (int i = 0; i < 8; i++)
{
total = 0;
for (int j = 0; j < 20; j++)
{
if (j == 19)
{
_speeds[i][j] = 100;
}
else
{
_speeds[i][j] = Rnd.get(60) + 65;
}
total += _speeds[i][j];
}
if (total >= _first[1])
{
_second[0] = _first[0];
_second[1] = _first[1];
_first[0] = 8 - i;
_first[1] = total;
}
else if (total >= _second[1])
{
_second[0] = 8 - i;
_second[1] = total;
}
}
}
/**
* @return Returns the monsters.
*/
public L2Npc[] getMonsters()
{
return _monsters;
}
/**
* @return Returns the speeds.
*/
public int[][] getSpeeds()
{
return _speeds;
}
public int getFirstPlace()
{
return _first[0];
}
public int getSecondPlace()
{
return _second[0];
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final MonsterRace _instance = new MonsterRace();
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,594 @@
/*
* 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 com.l2jserver.gameserver;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.datatables.ClanTable;
import com.l2jserver.gameserver.datatables.OfflineTradersTable;
import com.l2jserver.gameserver.instancemanager.CastleManorManager;
import com.l2jserver.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jserver.gameserver.instancemanager.GlobalVariablesManager;
import com.l2jserver.gameserver.instancemanager.GrandBossManager;
import com.l2jserver.gameserver.instancemanager.ItemAuctionManager;
import com.l2jserver.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jserver.gameserver.instancemanager.QuestManager;
import com.l2jserver.gameserver.instancemanager.RaidBossSpawnManager;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.entity.Hero;
import com.l2jserver.gameserver.model.olympiad.Olympiad;
import com.l2jserver.gameserver.network.L2GameClient;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.communityserver.CommunityServerThread;
import com.l2jserver.gameserver.network.gameserverpackets.ServerStatus;
import com.l2jserver.gameserver.network.serverpackets.ServerClose;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.util.Broadcast;
/**
* This class provides the functions for shutting down and restarting the server It closes all open clientconnections and saves all data.
* @version $Revision: 1.2.4.5 $ $Date: 2005/03/27 15:29:09 $
*/
public class Shutdown extends Thread
{
private static Logger _log = Logger.getLogger(Shutdown.class.getName());
private static Shutdown _counterInstance = null;
private int _secondsShut;
private int _shutdownMode;
public static final int SIGTERM = 0;
public static final int GM_SHUTDOWN = 1;
public static final int GM_RESTART = 2;
public static final int ABORT = 3;
private static final String[] MODE_TEXT =
{
"SIGTERM",
"shutting down",
"restarting",
"aborting"
};
/**
* This function starts a shutdown countdown from Telnet (Copied from Function startShutdown())
* @param ip IP Which Issued shutdown command
* @param seconds seconds untill shutdown
* @param restart true if the server will restart after shutdown
*/
private void SendServerQuit(int seconds)
{
SystemMessage sysm = SystemMessage.getSystemMessage(SystemMessageId.THE_SERVER_WILL_BE_COMING_DOWN_IN_S1_SECONDS);
sysm.addNumber(seconds);
Broadcast.toAllOnlinePlayers(sysm);
}
public void startTelnetShutdown(String IP, int seconds, boolean restart)
{
_log.warning("IP: " + IP + " issued shutdown command. " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
// _an.announceToAll("Server is " + _modeText[shutdownMode] + " in "+seconds+ " seconds!");
if (restart)
{
_shutdownMode = GM_RESTART;
}
else
{
_shutdownMode = GM_SHUTDOWN;
}
if (_shutdownMode > 0)
{
switch (seconds)
{
case 540:
case 480:
case 420:
case 360:
case 300:
case 240:
case 180:
case 120:
case 60:
case 30:
case 10:
case 5:
case 4:
case 3:
case 2:
case 1:
break;
default:
SendServerQuit(seconds);
}
}
if (_counterInstance != null)
{
_counterInstance._abort();
}
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
}
/**
* This function aborts a running countdown
* @param IP IP Which Issued shutdown command
*/
public void telnetAbort(String IP)
{
_log.warning("IP: " + IP + " issued shutdown ABORT. " + MODE_TEXT[_shutdownMode] + " has been stopped!");
if (_counterInstance != null)
{
_counterInstance._abort();
Announcements _an = Announcements.getInstance();
_an.announceToAll("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!");
}
}
/**
* Default constucter is only used internal to create the shutdown-hook instance
*/
private Shutdown()
{
_secondsShut = -1;
_shutdownMode = SIGTERM;
}
/**
* This creates a countdown instance of Shutdown.
* @param seconds how many seconds until shutdown
* @param restart true is the server shall restart after shutdown
*/
public Shutdown(int seconds, boolean restart)
{
if (seconds < 0)
{
seconds = 0;
}
_secondsShut = seconds;
if (restart)
{
_shutdownMode = GM_RESTART;
}
else
{
_shutdownMode = GM_SHUTDOWN;
}
}
/**
* get the shutdown-hook instance the shutdown-hook instance is created by the first call of this function, but it has to be registrered externaly.
* @return instance of Shutdown, to be used as shutdown hook
*/
public static Shutdown getInstance()
{
return SingletonHolder._instance;
}
/**
* this function is called, when a new thread starts if this thread is the thread of getInstance, then this is the shutdown hook and we save all data and disconnect all clients. after this thread ends, the server will completely exit if this is not the thread of getInstance, then this is a
* countdown thread. we start the countdown, and when we finished it, and it was not aborted, we tell the shutdown-hook why we call exit, and then call exit when the exit status of the server is 1, startServer.sh / startServer.bat will restart the server.
*/
@Override
public void run()
{
if (this == SingletonHolder._instance)
{
try
{
if ((Config.OFFLINE_TRADE_ENABLE || Config.OFFLINE_CRAFT_ENABLE) && Config.RESTORE_OFFLINERS)
{
OfflineTradersTable.storeOffliners();
}
}
catch (Throwable t)
{
_log.log(Level.WARNING, "Error saving offline shops.", t);
}
try
{
disconnectAllCharacters();
_log.info("All players disconnected.");
}
catch (Throwable t)
{
// ignore
}
// ensure all services are stopped
try
{
GameTimeController.getInstance().stopTimer();
}
catch (Throwable t)
{
// ignore
}
// stop all threadpolls
try
{
ThreadPoolManager.getInstance().shutdown();
}
catch (Throwable t)
{
// ignore
}
try
{
CommunityServerThread.getInstance().interrupt();
}
catch (Throwable t)
{
// ignore
}
try
{
LoginServerThread.getInstance().interrupt();
}
catch (Throwable t)
{
// ignore
}
// last byebye, save all data and quit this server
saveData();
// saveData sends messages to exit players, so shutdown selector after it
try
{
GameServer.gameServer.getSelectorThread().shutdown();
}
catch (Throwable t)
{
// ignore
}
// commit data, last chance
try
{
L2DatabaseFactory.getInstance().shutdown();
}
catch (Throwable t)
{
}
// server will quit, when this function ends.
if (SingletonHolder._instance._shutdownMode == GM_RESTART)
{
Runtime.getRuntime().halt(2);
}
else
{
Runtime.getRuntime().halt(0);
}
}
else
{
// gm shutdown: send warnings and then call exit to start shutdown sequence
countdown();
// last point where logging is operational :(
_log.warning("GM shutdown countdown is over. " + MODE_TEXT[_shutdownMode] + " NOW!");
switch (_shutdownMode)
{
case GM_SHUTDOWN:
SingletonHolder._instance.setMode(GM_SHUTDOWN);
System.exit(0);
break;
case GM_RESTART:
SingletonHolder._instance.setMode(GM_RESTART);
System.exit(2);
break;
}
}
}
/**
* This functions starts a shutdown countdown
* @param activeChar GM who issued the shutdown command
* @param seconds seconds until shutdown
* @param restart true if the server will restart after shutdown
*/
public void startShutdown(L2PcInstance activeChar, int seconds, boolean restart)
{
if (restart)
{
_shutdownMode = GM_RESTART;
}
else
{
_shutdownMode = GM_SHUTDOWN;
}
_log.warning("GM: " + activeChar.getName() + "(" + activeChar.getObjectId() + ") issued shutdown command. " + MODE_TEXT[_shutdownMode] + " in " + seconds + " seconds!");
if (_shutdownMode > 0)
{
switch (seconds)
{
case 540:
case 480:
case 420:
case 360:
case 300:
case 240:
case 180:
case 120:
case 60:
case 30:
case 10:
case 5:
case 4:
case 3:
case 2:
case 1:
break;
default:
SendServerQuit(seconds);
}
}
if (_counterInstance != null)
{
_counterInstance._abort();
}
// the main instance should only run for shutdown hook, so we start a new instance
_counterInstance = new Shutdown(seconds, restart);
_counterInstance.start();
}
/**
* This function aborts a running countdown
* @param activeChar GM who issued the abort command
*/
public void abort(L2PcInstance activeChar)
{
_log.warning("GM: " + activeChar.getName() + "(" + activeChar.getObjectId() + ") issued shutdown ABORT. " + MODE_TEXT[_shutdownMode] + " has been stopped!");
if (_counterInstance != null)
{
_counterInstance._abort();
Announcements _an = Announcements.getInstance();
_an.announceToAll("Server aborts " + MODE_TEXT[_shutdownMode] + " and continues normal operation!");
}
}
/**
* set the shutdown mode
* @param mode what mode shall be set
*/
private void setMode(int mode)
{
_shutdownMode = mode;
}
/**
* set shutdown mode to ABORT
*/
private void _abort()
{
_shutdownMode = ABORT;
}
/**
* this counts the countdown and reports it to all players countdown is aborted if mode changes to ABORT
*/
private void countdown()
{
try
{
while (_secondsShut > 0)
{
switch (_secondsShut)
{
case 540:
SendServerQuit(540);
break;
case 480:
SendServerQuit(480);
break;
case 420:
SendServerQuit(420);
break;
case 360:
SendServerQuit(360);
break;
case 300:
SendServerQuit(300);
break;
case 240:
SendServerQuit(240);
break;
case 180:
SendServerQuit(180);
break;
case 120:
SendServerQuit(120);
break;
case 60:
LoginServerThread.getInstance().setServerStatus(ServerStatus.STATUS_DOWN); // avoids new players from logging in
SendServerQuit(60);
break;
case 30:
SendServerQuit(30);
break;
case 10:
SendServerQuit(10);
break;
case 5:
SendServerQuit(5);
break;
case 4:
SendServerQuit(4);
break;
case 3:
SendServerQuit(3);
break;
case 2:
SendServerQuit(2);
break;
case 1:
SendServerQuit(1);
break;
}
_secondsShut--;
int delay = 1000; // milliseconds
Thread.sleep(delay);
if (_shutdownMode == ABORT)
{
break;
}
}
}
catch (InterruptedException e)
{
// this will never happen
}
}
/**
* this sends a last byebye, disconnects all players and saves data
*/
private void saveData()
{
switch (_shutdownMode)
{
case SIGTERM:
_log.info("SIGTERM received. Shutting down NOW!");
break;
case GM_SHUTDOWN:
_log.info("GM shutdown received. Shutting down NOW!");
break;
case GM_RESTART:
_log.info("GM restart received. Restarting NOW!");
break;
}
/*
* if (Config.ACTIVATE_POSITION_RECORDER) Universe.getInstance().implode(true);
*/
// Seven Signs data is now saved along with Festival data.
if (!SevenSigns.getInstance().isSealValidationPeriod())
{
SevenSignsFestival.getInstance().saveFestivalData(false);
}
// Save Seven Signs data before closing. :)
SevenSigns.getInstance().saveSevenSignsData();
SevenSigns.getInstance().saveSevenSignsStatus();
// Save all raidboss and GrandBoss status ^_^
RaidBossSpawnManager.getInstance().cleanUp();
_log.info("RaidBossSpawnManager: All raidboss info saved!!");
GrandBossManager.getInstance().cleanUp();
_log.info("GrandBossManager: All Grand Boss info saved!!");
_log.info("TradeController saving data.. This action may take some minutes! Please wait until completed!");
TradeController.getInstance().dataCountStore();
_log.info("TradeController: All count Item Saved");
ItemAuctionManager.getInstance().shutdown();
Olympiad.getInstance().saveOlympiadStatus();
_log.info("Olympiad System: Data saved!!");
Hero.getInstance().shutdown();
_log.info("Hero System: Data saved!!");
ClanTable.getInstance().storeClanScore();
_log.info("Clan System: Data saved!!");
// Save Cursed Weapons data before closing.
CursedWeaponsManager.getInstance().saveData();
// Save all manor data
CastleManorManager.getInstance().save();
// Save all global (non-player specific) Quest data that needs to persist after reboot
QuestManager.getInstance().save();
// Save all global variables data
GlobalVariablesManager.getInstance().saveVars();
// Save items on ground before closing
if (Config.SAVE_DROPPED_ITEM)
{
ItemsOnGroundManager.getInstance().saveInDb();
ItemsOnGroundManager.getInstance().cleanUp();
_log.info("ItemsOnGroundManager: All items on ground saved!!");
}
try
{
int delay = 5000;
Thread.sleep(delay);
}
catch (InterruptedException e)
{
// never happens :p
}
}
/**
* this disconnects all clients from the server
*/
private void disconnectAllCharacters()
{
Collection<L2PcInstance> pls = L2World.getInstance().getAllPlayers().values();
// synchronized (L2World.getInstance().getAllPlayers())
{
for (L2PcInstance player : pls)
{
if (player == null)
{
continue;
}
// Logout Character
try
{
L2GameClient client = player.getClient();
if ((client != null) && !client.isDetached())
{
client.close(ServerClose.STATIC_PACKET);
client.setActiveChar(null);
player.setClient(null);
}
player.deleteMe();
}
catch (Throwable t)
{
_log.log(Level.WARNING, "Failed logour char " + player, t);
}
}
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final Shutdown _instance = new Shutdown();
}
}
@@ -0,0 +1,25 @@
/*
* 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 com.l2jserver.gameserver;
/**
* @author mkizub
*/
public enum TaskPriority
{
PR_NORMAL,
PR_HIGH,
PR_URGENT;
}
@@ -0,0 +1,98 @@
/*
* 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/>.
*/
/*
coded by Balancer
ported to L2JRU by Mr
balancer@balancer.ru
http://balancer.ru
version 0.1.1, 2005-06-07
version 0.1, 2005-03-16
*/
package com.l2jserver.gameserver;
import java.util.Map;
import java.util.logging.Logger;
import javolution.util.FastMap;
import com.l2jserver.gameserver.model.L2Territory;
import com.l2jserver.util.lib.SqlUtils;
public class Territory
{
private static Logger _log = Logger.getLogger(TradeController.class.getName());
private static Map<Integer, L2Territory> _territory;
public static Territory getInstance()
{
return SingletonHolder._instance;
}
private Territory()
{
// load all data at server start
reload_data();
}
public int[] getRandomPoint(int terr)
{
return _territory.get(terr).getRandomPoint();
}
public int getProcMax(int terr)
{
return _territory.get(terr).getProcMax();
}
public void reload_data()
{
_territory = new FastMap<>();
Integer[][] point = SqlUtils.get2DIntArray(new String[]
{
"loc_id",
"loc_x",
"loc_y",
"loc_zmin",
"loc_zmax",
"proc"
}, "locations", "loc_id > 0");
for (Integer[] row : point)
{
// _log.info("row = "+row[0]);
Integer terr = row[0];
if (terr == null)
{
_log.warning("Null territory!");
continue;
}
if (_territory.get(terr) == null)
{
L2Territory t = new L2Territory(terr);
_territory.put(terr, t);
}
_territory.get(terr).add(row[1], row[2], row[3], row[4], row[5]);
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final Territory _instance = new Territory();
}
}
@@ -0,0 +1,510 @@
/*
* 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 com.l2jserver.gameserver;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import javolution.util.FastSet;
import com.l2jserver.Config;
import com.l2jserver.util.StringUtil;
/**
* <p>
* This class is made to handle all the ThreadPools used in L2j.
* </p>
* <p>
* Scheduled Tasks can either be sent to a {@link #_generalScheduledThreadPool "general"} or {@link #_effectsScheduledThreadPool "effects"} {@link ScheduledThreadPoolExecutor ScheduledThreadPool}: The "effects" one is used for every effects (skills, hp/mp regen ...) while the "general" one is used
* for everything else that needs to be scheduled.<br>
* There also is an {@link #_aiScheduledThreadPool "ai"} {@link ScheduledThreadPoolExecutor ScheduledThreadPool} used for AI Tasks.
* </p>
* <p>
* Tasks can be sent to {@link ScheduledThreadPoolExecutor ScheduledThreadPool} either with:
* <ul>
* <li>{@link #scheduleEffect(Runnable, long)} : for effects Tasks that needs to be executed only once.</li>
* <li>{@link #scheduleGeneral(Runnable, long)} : for scheduled Tasks that needs to be executed once.</li>
* <li>{@link #scheduleAi(Runnable, long)} : for AI Tasks that needs to be executed once</li>
* </ul>
* or
* <ul>
* <li>{@link #scheduleEffectAtFixedRate(Runnable, long, long)(Runnable, long)} : for effects Tasks that needs to be executed periodicaly.</li>
* <li>{@link #scheduleGeneralAtFixedRate(Runnable, long, long)(Runnable, long)} : for scheduled Tasks that needs to be executed periodicaly.</li>
* <li>{@link #scheduleAiAtFixedRate(Runnable, long, long)(Runnable, long)} : for AI Tasks that needs to be executed periodicaly</li>
* </ul>
* </p>
* <p>
* For all Tasks that should be executed with no delay asynchronously in a ThreadPool there also are usual {@link ThreadPoolExecutor ThreadPools} that can grow/shrink according to their load.:
* <ul>
* <li>{@link #_generalPacketsThreadPool GeneralPackets} where most packets handler are executed.</li>
* <li>{@link #_ioPacketsThreadPool I/O Packets} where all the i/o packets are executed.</li>
* <li>There will be an AI ThreadPool where AI events should be executed</li>
* <li>A general ThreadPool where everything else that needs to run asynchronously with no delay should be executed ({@link com.l2jserver.gameserver.model.actor.knownlist KnownList} updates, SQL updates/inserts...)?</li>
* </ul>
* </p>
* @author -Wooden-
*/
public class ThreadPoolManager
{
protected static final Logger _log = Logger.getLogger(ThreadPoolManager.class.getName());
private static final class RunnableWrapper implements Runnable
{
private final Runnable _r;
public RunnableWrapper(final Runnable r)
{
_r = r;
}
@Override
public final void run()
{
try
{
_r.run();
}
catch (final Throwable e)
{
final Thread t = Thread.currentThread();
final UncaughtExceptionHandler h = t.getUncaughtExceptionHandler();
if (h != null)
{
h.uncaughtException(t, e);
}
}
}
}
protected final ScheduledThreadPoolExecutor _effectsScheduledThreadPool;
protected final ScheduledThreadPoolExecutor _generalScheduledThreadPool;
protected final ScheduledThreadPoolExecutor _aiScheduledThreadPool;
private final ThreadPoolExecutor _generalPacketsThreadPool;
private final ThreadPoolExecutor _ioPacketsThreadPool;
private final ThreadPoolExecutor _generalThreadPool;
/** temp workaround for VM issue */
private static final long MAX_DELAY = Long.MAX_VALUE / 1000000 / 2;
private boolean _shutdown;
public static ThreadPoolManager getInstance()
{
return SingletonHolder._instance;
}
private ThreadPoolManager()
{
_effectsScheduledThreadPool = new ScheduledThreadPoolExecutor(Config.THREAD_P_EFFECTS, new PriorityThreadFactory("EffectsSTPool", Thread.NORM_PRIORITY));
_generalScheduledThreadPool = new ScheduledThreadPoolExecutor(Config.THREAD_P_GENERAL, new PriorityThreadFactory("GeneralSTPool", Thread.NORM_PRIORITY));
_ioPacketsThreadPool = new ThreadPoolExecutor(Config.IO_PACKET_THREAD_CORE_SIZE, Integer.MAX_VALUE, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new PriorityThreadFactory("I/O Packet Pool", Thread.NORM_PRIORITY + 1));
_generalPacketsThreadPool = new ThreadPoolExecutor(Config.GENERAL_PACKET_THREAD_CORE_SIZE, Config.GENERAL_PACKET_THREAD_CORE_SIZE + 2, 15L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new PriorityThreadFactory("Normal Packet Pool", Thread.NORM_PRIORITY + 1));
_generalThreadPool = new ThreadPoolExecutor(Config.GENERAL_THREAD_CORE_SIZE, Config.GENERAL_THREAD_CORE_SIZE + 2, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new PriorityThreadFactory("General Pool", Thread.NORM_PRIORITY));
_aiScheduledThreadPool = new ScheduledThreadPoolExecutor(Config.AI_MAX_THREAD, new PriorityThreadFactory("AISTPool", Thread.NORM_PRIORITY));
scheduleGeneralAtFixedRate(new PurgeTask(), 10 * 60 * 1000l, 5 * 60 * 1000l);
}
public static long validateDelay(long delay)
{
if (delay < 0)
{
delay = 0;
}
else if (delay > MAX_DELAY)
{
delay = MAX_DELAY;
}
return delay;
}
public ScheduledFuture<?> scheduleEffect(Runnable r, long delay)
{
try
{
delay = ThreadPoolManager.validateDelay(delay);
return _effectsScheduledThreadPool.schedule(new RunnableWrapper(r), delay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException e)
{
return null;
}
}
public ScheduledFuture<?> scheduleEffectAtFixedRate(Runnable r, long initial, long delay)
{
try
{
delay = ThreadPoolManager.validateDelay(delay);
initial = ThreadPoolManager.validateDelay(initial);
return _effectsScheduledThreadPool.scheduleAtFixedRate(new RunnableWrapper(r), initial, delay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException e)
{
return null; /* shutdown, ignore */
}
}
@Deprecated
public boolean removeEffect(RunnableScheduledFuture<?> r)
{
return _effectsScheduledThreadPool.remove(r);
}
public ScheduledFuture<?> scheduleGeneral(Runnable r, long delay)
{
try
{
delay = ThreadPoolManager.validateDelay(delay);
return _generalScheduledThreadPool.schedule(new RunnableWrapper(r), delay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException e)
{
return null; /* shutdown, ignore */
}
}
public ScheduledFuture<?> scheduleGeneralAtFixedRate(Runnable r, long initial, long delay)
{
try
{
delay = ThreadPoolManager.validateDelay(delay);
initial = ThreadPoolManager.validateDelay(initial);
return _generalScheduledThreadPool.scheduleAtFixedRate(new RunnableWrapper(r), initial, delay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException e)
{
return null; /* shutdown, ignore */
}
}
@Deprecated
public boolean removeGeneral(RunnableScheduledFuture<?> r)
{
return _generalScheduledThreadPool.remove(r);
}
public ScheduledFuture<?> scheduleAi(Runnable r, long delay)
{
try
{
delay = ThreadPoolManager.validateDelay(delay);
return _aiScheduledThreadPool.schedule(new RunnableWrapper(r), delay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException e)
{
return null; /* shutdown, ignore */
}
}
public ScheduledFuture<?> scheduleAiAtFixedRate(Runnable r, long initial, long delay)
{
try
{
delay = ThreadPoolManager.validateDelay(delay);
initial = ThreadPoolManager.validateDelay(initial);
return _aiScheduledThreadPool.scheduleAtFixedRate(new RunnableWrapper(r), initial, delay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException e)
{
return null; /* shutdown, ignore */
}
}
public void executePacket(Runnable pkt)
{
_generalPacketsThreadPool.execute(pkt);
}
public void executeCommunityPacket(Runnable r)
{
_generalPacketsThreadPool.execute(r);
}
public void executeIOPacket(Runnable pkt)
{
_ioPacketsThreadPool.execute(pkt);
}
public void executeTask(Runnable r)
{
_generalThreadPool.execute(r);
}
public void executeAi(Runnable r)
{
_aiScheduledThreadPool.execute(new RunnableWrapper(r));
}
public String[] getStats()
{
return new String[]
{
"STP:",
" + Effects:",
" |- ActiveThreads: " + _effectsScheduledThreadPool.getActiveCount(),
" |- getCorePoolSize: " + _effectsScheduledThreadPool.getCorePoolSize(),
" |- PoolSize: " + _effectsScheduledThreadPool.getPoolSize(),
" |- MaximumPoolSize: " + _effectsScheduledThreadPool.getMaximumPoolSize(),
" |- CompletedTasks: " + _effectsScheduledThreadPool.getCompletedTaskCount(),
" |- ScheduledTasks: " + (_effectsScheduledThreadPool.getTaskCount() - _effectsScheduledThreadPool.getCompletedTaskCount()),
" | -------",
" + General:",
" |- ActiveThreads: " + _generalScheduledThreadPool.getActiveCount(),
" |- getCorePoolSize: " + _generalScheduledThreadPool.getCorePoolSize(),
" |- PoolSize: " + _generalScheduledThreadPool.getPoolSize(),
" |- MaximumPoolSize: " + _generalScheduledThreadPool.getMaximumPoolSize(),
" |- CompletedTasks: " + _generalScheduledThreadPool.getCompletedTaskCount(),
" |- ScheduledTasks: " + (_generalScheduledThreadPool.getTaskCount() - _generalScheduledThreadPool.getCompletedTaskCount()),
" | -------",
" + AI:",
" |- ActiveThreads: " + _aiScheduledThreadPool.getActiveCount(),
" |- getCorePoolSize: " + _aiScheduledThreadPool.getCorePoolSize(),
" |- PoolSize: " + _aiScheduledThreadPool.getPoolSize(),
" |- MaximumPoolSize: " + _aiScheduledThreadPool.getMaximumPoolSize(),
" |- CompletedTasks: " + _aiScheduledThreadPool.getCompletedTaskCount(),
" |- ScheduledTasks: " + (_aiScheduledThreadPool.getTaskCount() - _aiScheduledThreadPool.getCompletedTaskCount()),
"TP:",
" + Packets:",
" |- ActiveThreads: " + _generalPacketsThreadPool.getActiveCount(),
" |- getCorePoolSize: " + _generalPacketsThreadPool.getCorePoolSize(),
" |- MaximumPoolSize: " + _generalPacketsThreadPool.getMaximumPoolSize(),
" |- LargestPoolSize: " + _generalPacketsThreadPool.getLargestPoolSize(),
" |- PoolSize: " + _generalPacketsThreadPool.getPoolSize(),
" |- CompletedTasks: " + _generalPacketsThreadPool.getCompletedTaskCount(),
" |- QueuedTasks: " + _generalPacketsThreadPool.getQueue().size(),
" | -------",
" + I/O Packets:",
" |- ActiveThreads: " + _ioPacketsThreadPool.getActiveCount(),
" |- getCorePoolSize: " + _ioPacketsThreadPool.getCorePoolSize(),
" |- MaximumPoolSize: " + _ioPacketsThreadPool.getMaximumPoolSize(),
" |- LargestPoolSize: " + _ioPacketsThreadPool.getLargestPoolSize(),
" |- PoolSize: " + _ioPacketsThreadPool.getPoolSize(),
" |- CompletedTasks: " + _ioPacketsThreadPool.getCompletedTaskCount(),
" |- QueuedTasks: " + _ioPacketsThreadPool.getQueue().size(),
" | -------",
" + General Tasks:",
" |- ActiveThreads: " + _generalThreadPool.getActiveCount(),
" |- getCorePoolSize: " + _generalThreadPool.getCorePoolSize(),
" |- MaximumPoolSize: " + _generalThreadPool.getMaximumPoolSize(),
" |- LargestPoolSize: " + _generalThreadPool.getLargestPoolSize(),
" |- PoolSize: " + _generalThreadPool.getPoolSize(),
" |- CompletedTasks: " + _generalThreadPool.getCompletedTaskCount(),
" |- QueuedTasks: " + _generalThreadPool.getQueue().size(),
" | -------",
" + Javolution stats:",
" |- FastList: " + FastList.report(),
" |- FastMap: " + FastMap.report(),
" |- FastSet: " + FastSet.report(),
" | -------"
};
}
private static class PriorityThreadFactory implements ThreadFactory
{
private final int _prio;
private final String _name;
private final AtomicInteger _threadNumber = new AtomicInteger(1);
private final ThreadGroup _group;
public PriorityThreadFactory(String name, int prio)
{
_prio = prio;
_name = name;
_group = new ThreadGroup(_name);
}
@Override
public Thread newThread(Runnable r)
{
Thread t = new Thread(_group, r);
t.setName(_name + "-" + _threadNumber.getAndIncrement());
t.setPriority(_prio);
return t;
}
public ThreadGroup getGroup()
{
return _group;
}
}
public void shutdown()
{
_shutdown = true;
try
{
_effectsScheduledThreadPool.awaitTermination(1, TimeUnit.SECONDS);
_generalScheduledThreadPool.awaitTermination(1, TimeUnit.SECONDS);
_generalPacketsThreadPool.awaitTermination(1, TimeUnit.SECONDS);
_ioPacketsThreadPool.awaitTermination(1, TimeUnit.SECONDS);
_generalThreadPool.awaitTermination(1, TimeUnit.SECONDS);
_effectsScheduledThreadPool.shutdown();
_generalScheduledThreadPool.shutdown();
_generalPacketsThreadPool.shutdown();
_ioPacketsThreadPool.shutdown();
_generalThreadPool.shutdown();
_log.info("All ThreadPools are now stopped");
}
catch (InterruptedException e)
{
_log.log(Level.WARNING, "", e);
}
}
public boolean isShutdown()
{
return _shutdown;
}
public void purge()
{
_effectsScheduledThreadPool.purge();
_generalScheduledThreadPool.purge();
_aiScheduledThreadPool.purge();
_ioPacketsThreadPool.purge();
_generalPacketsThreadPool.purge();
_generalThreadPool.purge();
}
public String getPacketStats()
{
final StringBuilder sb = new StringBuilder(1000);
ThreadFactory tf = _generalPacketsThreadPool.getThreadFactory();
if (tf instanceof PriorityThreadFactory)
{
PriorityThreadFactory ptf = (PriorityThreadFactory) tf;
int count = ptf.getGroup().activeCount();
Thread[] threads = new Thread[count + 2];
ptf.getGroup().enumerate(threads);
StringUtil.append(sb, "General Packet Thread Pool:\r\n" + "Tasks in the queue: ", String.valueOf(_generalPacketsThreadPool.getQueue().size()), "\r\n" + "Showing threads stack trace:\r\n" + "There should be ", String.valueOf(count), " Threads\r\n");
for (Thread t : threads)
{
if (t == null)
{
continue;
}
StringUtil.append(sb, t.getName(), "\r\n");
for (StackTraceElement ste : t.getStackTrace())
{
StringUtil.append(sb, ste.toString(), "\r\n");
}
}
}
sb.append("Packet Tp stack traces printed.\r\n");
return sb.toString();
}
public String getIOPacketStats()
{
final StringBuilder sb = new StringBuilder(1000);
ThreadFactory tf = _ioPacketsThreadPool.getThreadFactory();
if (tf instanceof PriorityThreadFactory)
{
PriorityThreadFactory ptf = (PriorityThreadFactory) tf;
int count = ptf.getGroup().activeCount();
Thread[] threads = new Thread[count + 2];
ptf.getGroup().enumerate(threads);
StringUtil.append(sb, "I/O Packet Thread Pool:\r\n" + "Tasks in the queue: ", String.valueOf(_ioPacketsThreadPool.getQueue().size()), "\r\n" + "Showing threads stack trace:\r\n" + "There should be ", String.valueOf(count), " Threads\r\n");
for (Thread t : threads)
{
if (t == null)
{
continue;
}
StringUtil.append(sb, t.getName(), "\r\n");
for (StackTraceElement ste : t.getStackTrace())
{
StringUtil.append(sb, ste.toString(), "\r\n");
}
}
}
sb.append("Packet Tp stack traces printed.\r\n");
return sb.toString();
}
public String getGeneralStats()
{
final StringBuilder sb = new StringBuilder(1000);
ThreadFactory tf = _generalThreadPool.getThreadFactory();
if (tf instanceof PriorityThreadFactory)
{
PriorityThreadFactory ptf = (PriorityThreadFactory) tf;
int count = ptf.getGroup().activeCount();
Thread[] threads = new Thread[count + 2];
ptf.getGroup().enumerate(threads);
StringUtil.append(sb, "General Thread Pool:\r\n" + "Tasks in the queue: ", String.valueOf(_generalThreadPool.getQueue().size()), "\r\n" + "Showing threads stack trace:\r\n" + "There should be ", String.valueOf(count), " Threads\r\n");
for (Thread t : threads)
{
if (t == null)
{
continue;
}
StringUtil.append(sb, t.getName(), "\r\n");
for (StackTraceElement ste : t.getStackTrace())
{
StringUtil.append(sb, ste.toString(), "\r\n");
}
}
}
sb.append("Packet Tp stack traces printed.\r\n");
return sb.toString();
}
protected class PurgeTask implements Runnable
{
@Override
public void run()
{
_effectsScheduledThreadPool.purge();
_generalScheduledThreadPool.purge();
_aiScheduledThreadPool.purge();
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ThreadPoolManager _instance = new ThreadPoolManager();
}
}
@@ -0,0 +1,330 @@
/*
* 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 com.l2jserver.gameserver;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.datatables.ItemTable;
import com.l2jserver.gameserver.model.L2TradeList;
import com.l2jserver.gameserver.model.L2TradeList.L2TradeItem;
/**
* This class ...
* @version $Revision: 1.5.4.13 $ $Date: 2005/04/06 16:13:38 $
*/
public class TradeController
{
private static Logger _log = Logger.getLogger(TradeController.class.getName());
private int _nextListId;
private final Map<Integer, L2TradeList> _lists = new FastMap<>();
/** Task launching the function for restore count of Item (Clan Hall) */
/*
* public class RestoreCount implements Runnable { private int _timer; public RestoreCount(int time) { _timer = time; } public void run() { restoreCount(_timer); dataTimerSave(_timer); ThreadPoolManager.getInstance().scheduleGeneral(new RestoreCount(_timer), (long)_timer*60*60*1000); } }
*/
public static TradeController getInstance()
{
return SingletonHolder._instance;
}
private TradeController()
{
_lists.clear();
Connection con = null;
/*
* Initialize Shop buylist
*/
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement1 = con.prepareStatement("SELECT shop_id, npc_id FROM merchant_shopids");
ResultSet rset1 = statement1.executeQuery();
int itemId, price, maxCount, currentCount, time;
long saveTimer;
PreparedStatement statement = con.prepareStatement("SELECT item_id, price, shop_id, " + L2DatabaseFactory.getInstance().safetyString("order") + ", count, currentCount, time, savetimer FROM merchant_buylists WHERE shop_id=? ORDER BY " + L2DatabaseFactory.getInstance().safetyString("order") + " ASC");
while (rset1.next())
{
statement.setString(1, String.valueOf(rset1.getInt("shop_id")));
ResultSet rset = statement.executeQuery();
statement.clearParameters();
int shopId = rset1.getInt("shop_id");
L2TradeList buy1 = new L2TradeList(shopId);
while (rset.next())
{
itemId = rset.getInt("item_id");
price = rset.getInt("price");
maxCount = rset.getInt("count");
currentCount = rset.getInt("currentCount");
time = rset.getInt("time");
saveTimer = rset.getLong("saveTimer");
L2TradeItem item = new L2TradeItem(shopId, itemId);
if (ItemTable.getInstance().getTemplate(itemId) == null)
{
_log.warning("Skipping itemId: " + itemId + " on buylistId: " + buy1.getListId() + ", missing data for that item.");
continue;
}
if (price <= -1)
{
price = ItemTable.getInstance().getTemplate(itemId).getReferencePrice();
}
if (Config.DEBUG)
{
// debug
double diff = ((double) (price)) / ItemTable.getInstance().getTemplate(itemId).getReferencePrice();
if ((diff < 0.8) || (diff > 1.2))
{
_log.severe("PRICING DEBUG: TradeListId: " + buy1.getListId() + " - ItemId: " + itemId + " (" + ItemTable.getInstance().getTemplate(itemId).getName() + ") diff: " + diff + " - Price: " + price + " - Reference: " + ItemTable.getInstance().getTemplate(itemId).getReferencePrice());
}
}
item.setPrice(price);
item.setRestoreDelay(time);
item.setNextRestoreTime(saveTimer);
item.setMaxCount(maxCount);
if (currentCount > -1)
{
item.setCurrentCount(currentCount);
}
else
{
item.setCurrentCount(maxCount);
}
buy1.addItem(item);
}
buy1.setNpcId(rset1.getString("npc_id"));
_lists.put(buy1.getListId(), buy1);
_nextListId = Math.max(_nextListId, buy1.getListId() + 1);
rset.close();
}
statement.close();
rset1.close();
statement1.close();
_log.info("TradeController: Loaded " + _lists.size() + " Buylists.");
}
catch (Exception e)
{
// problem with initializing spawn, go to next one
_log.log(Level.WARNING, "TradeController: Buylists could not be initialized: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
/*
* If enabled, initialize the custom buylist
*/
if (Config.CUSTOM_MERCHANT_TABLES)
{
try
{
int initialSize = _lists.size();
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement1 = con.prepareStatement("SELECT shop_id, npc_id FROM custom_merchant_shopids");
ResultSet rset1 = statement1.executeQuery();
int itemId, price, maxCount, currentCount, time;
long saveTimer;
PreparedStatement statement = con.prepareStatement("SELECT item_id, price, shop_id, " + L2DatabaseFactory.getInstance().safetyString("order") + ", count, currentCount, time, savetimer FROM custom_merchant_buylists WHERE shop_id=? ORDER BY " + L2DatabaseFactory.getInstance().safetyString("order") + " ASC");
while (rset1.next())
{
statement.setString(1, String.valueOf(rset1.getInt("shop_id")));
ResultSet rset = statement.executeQuery();
statement.clearParameters();
int shopId = rset1.getInt("shop_id");
L2TradeList buy1 = new L2TradeList(shopId);
while (rset.next())
{
itemId = rset.getInt("item_id");
price = rset.getInt("price");
maxCount = rset.getInt("count");
currentCount = rset.getInt("currentCount");
time = rset.getInt("time");
saveTimer = rset.getLong("saveTimer");
L2TradeItem item = new L2TradeItem(shopId, itemId);
if (ItemTable.getInstance().getTemplate(itemId) == null)
{
_log.warning("Skipping itemId: " + itemId + " on buylistId: " + buy1.getListId() + ", missing data for that item.");
continue;
}
if (price <= -1)
{
price = ItemTable.getInstance().getTemplate(itemId).getReferencePrice();
}
if (Config.DEBUG)
{
// debug
double diff = ((double) (price)) / ItemTable.getInstance().getTemplate(itemId).getReferencePrice();
if ((diff < 0.8) || (diff > 1.2))
{
_log.severe("PRICING DEBUG: TradeListId: " + buy1.getListId() + " - ItemId: " + itemId + " (" + ItemTable.getInstance().getTemplate(itemId).getName() + ") diff: " + diff + " - Price: " + price + " - Reference: " + ItemTable.getInstance().getTemplate(itemId).getReferencePrice());
}
}
item.setPrice(price);
item.setRestoreDelay(time);
item.setNextRestoreTime(saveTimer);
item.setMaxCount(maxCount);
if (currentCount > -1)
{
item.setCurrentCount(currentCount);
}
else
{
item.setCurrentCount(maxCount);
}
buy1.addItem(item);
}
buy1.setNpcId(rset1.getString("npc_id"));
_lists.put(buy1.getListId(), buy1);
_nextListId = Math.max(_nextListId, buy1.getListId() + 1);
rset.close();
}
statement.close();
rset1.close();
statement1.close();
_log.info("TradeController: Loaded " + (_lists.size() - initialSize) + " Custom Buylists.");
}
catch (Exception e)
{
// problem with initializing spawn, go to next one
_log.log(Level.WARNING, "TradeController: Buylists could not be initialized: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
}
public L2TradeList getBuyList(int listId)
{
return _lists.get(listId);
}
public List<L2TradeList> getBuyListByNpcId(int npcId)
{
List<L2TradeList> lists = new FastList<>();
Collection<L2TradeList> values = _lists.values();
for (L2TradeList list : values)
{
String tradeNpcId = list.getNpcId();
if (tradeNpcId.startsWith("gm"))
{
continue;
}
if (npcId == Integer.parseInt(tradeNpcId))
{
lists.add(list);
}
}
return lists;
}
public void dataCountStore()
{
Connection con = null;
int listId;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("UPDATE merchant_buylists SET currentCount=? WHERE item_id=? AND shop_id=?");
for (L2TradeList list : _lists.values())
{
if (list.hasLimitedStockItem())
{
listId = list.getListId();
for (L2TradeItem item : list.getItems())
{
long currentCount;
if (item.hasLimitedStock() && ((currentCount = item.getCurrentCount()) < item.getMaxCount()))
{
statement.setLong(1, currentCount);
statement.setInt(2, item.getItemId());
statement.setInt(3, listId);
statement.executeUpdate();
statement.clearParameters();
}
}
}
}
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "TradeController: Could not store Count Item: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* @return
*/
public synchronized int getNextId()
{
return _nextListId++;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final TradeController _instance = new TradeController();
}
}
@@ -0,0 +1,896 @@
/*
* 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 com.l2jserver.gameserver.ai;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.gameserver.GameTimeController;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.ActionFailed;
import com.l2jserver.gameserver.network.serverpackets.AutoAttackStart;
import com.l2jserver.gameserver.network.serverpackets.AutoAttackStop;
import com.l2jserver.gameserver.network.serverpackets.Die;
import com.l2jserver.gameserver.network.serverpackets.MoveToLocation;
import com.l2jserver.gameserver.network.serverpackets.MoveToPawn;
import com.l2jserver.gameserver.network.serverpackets.StopMove;
import com.l2jserver.gameserver.network.serverpackets.StopRotation;
import com.l2jserver.gameserver.taskmanager.AttackStanceTaskManager;
/**
* Mother class of all objects AI in the world.<BR>
* <BR>
* AbastractAI :<BR>
* <BR>
* <li>L2CharacterAI</li><BR>
* <BR>
*/
abstract class AbstractAI implements Ctrl
{
protected static final Logger _log = Logger.getLogger(AbstractAI.class.getName());
class FollowTask implements Runnable
{
protected int _range = 70;
public FollowTask()
{
}
public FollowTask(int range)
{
_range = range;
}
@Override
public void run()
{
try
{
if (_followTask == null)
{
return;
}
L2Character followTarget = _followTarget; // copy to prevent NPE
if (followTarget == null)
{
if (_actor instanceof L2Summon)
{
((L2Summon) _actor).setFollowStatus(false);
}
setIntention(AI_INTENTION_IDLE);
return;
}
if (!_actor.isInsideRadius(followTarget, _range, true, false))
{
if (!_actor.isInsideRadius(followTarget, 3000, true, false))
{
// if the target is too far (maybe also teleported)
if (_actor instanceof L2Summon)
{
((L2Summon) _actor).setFollowStatus(false);
}
setIntention(AI_INTENTION_IDLE);
return;
}
moveToPawn(followTarget, _range);
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "", e);
}
}
}
/** The character that this AI manages */
protected final L2Character _actor;
/** An accessor for private methods of the actor */
protected final L2Character.AIAccessor _accessor;
/** Current long-term intention */
protected CtrlIntention _intention = AI_INTENTION_IDLE;
/** Current long-term intention parameter */
protected Object _intentionArg0 = null;
/** Current long-term intention parameter */
protected Object _intentionArg1 = null;
/** Flags about client's state, in order to know which messages to send */
protected volatile boolean _clientMoving;
/** Flags about client's state, in order to know which messages to send */
protected volatile boolean _clientAutoAttacking;
/** Flags about client's state, in order to know which messages to send */
protected int _clientMovingToPawnOffset;
/** Different targets this AI maintains */
private L2Object _target;
private L2Character _castTarget;
protected L2Character _attackTarget;
protected L2Character _followTarget;
/** The skill we are currently casting by INTENTION_CAST */
L2Skill _skill;
/** Different internal state flags */
private int _moveToPawnTimeout;
protected Future<?> _followTask = null;
private static final int FOLLOW_INTERVAL = 1000;
private static final int ATTACK_FOLLOW_INTERVAL = 500;
/**
* Constructor of AbstractAI.<BR>
* <BR>
* @param accessor The AI accessor of the L2Character
*/
protected AbstractAI(L2Character.AIAccessor accessor)
{
_accessor = accessor;
// Get the L2Character managed by this Accessor AI
_actor = accessor.getActor();
}
/**
* Return the L2Character managed by this Accessor AI.<BR>
* <BR>
*/
@Override
public L2Character getActor()
{
return _actor;
}
/**
* Return the current Intention.<BR>
* <BR>
*/
@Override
public CtrlIntention getIntention()
{
return _intention;
}
protected void setCastTarget(L2Character target)
{
_castTarget = target;
}
/**
* Return the current cast target.<BR>
* <BR>
*/
public L2Character getCastTarget()
{
return _castTarget;
}
protected void setAttackTarget(L2Character target)
{
_attackTarget = target;
}
/**
* Return current attack target.<BR>
* <BR>
*/
@Override
public L2Character getAttackTarget()
{
return _attackTarget;
}
/**
* Set the Intention of this AbstractAI.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : This method is USED by AI classes</B></FONT><BR>
* <BR>
* <B><U> Overridden in </U> : </B><BR>
* <B>L2AttackableAI</B> : Create an AI Task executed every 1s (if necessary)<BR>
* <B>L2PlayerAI</B> : Stores the current AI intention parameters to later restore it if necessary<BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention
* @param arg1 The second parameter of the Intention
*/
synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
{
/*
* if (Config.DEBUG) _log.warning("AbstractAI: changeIntention -> " + intention + " " + arg0 + " " + arg1);
*/
_intention = intention;
_intentionArg0 = arg0;
_intentionArg1 = arg1;
}
/**
* Launch the L2CharacterAI onIntention method corresponding to the new Intention.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
*/
@Override
public final void setIntention(CtrlIntention intention)
{
setIntention(intention, null, null);
}
/**
* Launch the L2CharacterAI onIntention method corresponding to the new Intention.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention (optional target)
*/
@Override
public final void setIntention(CtrlIntention intention, Object arg0)
{
setIntention(intention, arg0, null);
}
/**
* Launch the L2CharacterAI onIntention method corresponding to the new Intention.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention (optional target)
* @param arg1 The second parameter of the Intention (optional target)
*/
/*
* public final void informAIIntention(CtrlIntention intent, Object arg0) { ThreadPoolManager.getInstance().executeAi(new InformAIMsg(this, intent, arg0)); } public final void informAIIntention(CtrlIntention intent) { ThreadPoolManager.getInstance().executeAi(new InformAIMsg(this, intent,
* null)); } public class InformAIMsg implements Runnable { private AbstractAI _ai; private CtrlIntention _intent; private Object _arg0; public InformAIMsg(AbstractAI ai, CtrlIntention intention, Object arg0) { _ai=ai; _intent = intention; _arg0 = arg0; } public final void run() {
* _ai.setIntention(_intent, _arg0, null); } }
*/
@Override
public final void setIntention(CtrlIntention intention, Object arg0, Object arg1)
{
/*
* if (Config.DEBUG) _log.warning("AbstractAI: setIntention -> " + intention + " " + arg0 + " " + arg1);
*/
// Stop the follow mode if necessary
if ((intention != AI_INTENTION_FOLLOW) && (intention != AI_INTENTION_ATTACK))
{
stopFollow();
}
// Launch the onIntention method of the L2CharacterAI corresponding to the new Intention
switch (intention)
{
case AI_INTENTION_IDLE:
onIntentionIdle();
break;
case AI_INTENTION_ACTIVE:
onIntentionActive();
break;
case AI_INTENTION_REST:
onIntentionRest();
break;
case AI_INTENTION_ATTACK:
onIntentionAttack((L2Character) arg0);
break;
case AI_INTENTION_CAST:
onIntentionCast((L2Skill) arg0, (L2Object) arg1);
break;
case AI_INTENTION_MOVE_TO:
onIntentionMoveTo((L2CharPosition) arg0);
break;
case AI_INTENTION_FOLLOW:
onIntentionFollow((L2Character) arg0);
break;
case AI_INTENTION_PICK_UP:
onIntentionPickUp((L2Object) arg0);
break;
case AI_INTENTION_INTERACT:
onIntentionInteract((L2Object) arg0);
break;
}
}
/**
* Launch the L2CharacterAI onEvt method corresponding to the Event.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT><BR>
* <BR>
* @param evt The event whose the AI must be notified
*/
@Override
public final void notifyEvent(CtrlEvent evt)
{
notifyEvent(evt, null, null);
}
/**
* Launch the L2CharacterAI onEvt method corresponding to the Event.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT><BR>
* <BR>
* @param evt The event whose the AI must be notified
* @param arg0 The first parameter of the Event (optional target)
*/
@Override
public final void notifyEvent(CtrlEvent evt, Object arg0)
{
notifyEvent(evt, arg0, null);
}
/*
* public final void informAIEvent(CtrlEvent evt) { ThreadPoolManager.getInstance().executeAi(new InformAIEvent(this, evt, null, null)); } public final void informAIEvent(CtrlEvent evt, Object arg0) { ThreadPoolManager.getInstance().executeAi(new InformAIEvent(this, evt, arg0, null)); } public
* final void informAIEvent(CtrlEvent evt, Object arg0, Object arg1) { ThreadPoolManager.getInstance().executeAi(new InformAIEvent(this, evt, arg0, arg1)); } public class InformAIEvent implements Runnable { private AbstractAI _ai; private CtrlEvent _evt; private Object _arg0, _arg1; public
* InformAIEvent(AbstractAI ai, CtrlEvent evt, Object arg0, Object arg1) { _ai=ai; _evt = evt; _arg0 = arg0; _arg1 = arg1; } public final void run() { _ai.notifyEvent(_evt, _arg0, _arg1); } }
*/
/**
* Launch the L2CharacterAI onEvt method corresponding to the Event.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT><BR>
* <BR>
* @param evt The event whose the AI must be notified
* @param arg0 The first parameter of the Event (optional target)
* @param arg1 The second parameter of the Event (optional target)
*/
@Override
public final void notifyEvent(CtrlEvent evt, Object arg0, Object arg1)
{
if ((!_actor.isVisible() && !_actor.isTeleporting()) || !_actor.hasAI())
{
return;
}
/*
* if (Config.DEBUG) _log.warning("AbstractAI: notifyEvent -> " + evt + " " + arg0 + " " + arg1);
*/
switch (evt)
{
case EVT_THINK:
onEvtThink();
break;
case EVT_ATTACKED:
onEvtAttacked((L2Character) arg0);
break;
case EVT_AGGRESSION:
onEvtAggression((L2Character) arg0, ((Number) arg1).intValue());
break;
case EVT_STUNNED:
onEvtStunned((L2Character) arg0);
break;
case EVT_PARALYZED:
onEvtParalyzed((L2Character) arg0);
break;
case EVT_SLEEPING:
onEvtSleeping((L2Character) arg0);
break;
case EVT_ROOTED:
onEvtRooted((L2Character) arg0);
break;
case EVT_CONFUSED:
onEvtConfused((L2Character) arg0);
break;
case EVT_MUTED:
onEvtMuted((L2Character) arg0);
break;
case EVT_EVADED:
onEvtEvaded((L2Character) arg0);
break;
case EVT_READY_TO_ACT:
if (!_actor.isCastingNow() && !_actor.isCastingSimultaneouslyNow())
{
onEvtReadyToAct();
}
break;
case EVT_USER_CMD:
onEvtUserCmd(arg0, arg1);
break;
case EVT_ARRIVED:
// happens e.g. from stopmove but we don't process it if we're casting
if (!_actor.isCastingNow() && !_actor.isCastingSimultaneouslyNow())
{
onEvtArrived();
}
break;
case EVT_ARRIVED_REVALIDATE:
// this is disregarded if the char is not moving any more
if (_actor.isMoving())
{
onEvtArrivedRevalidate();
}
break;
case EVT_ARRIVED_BLOCKED:
onEvtArrivedBlocked((L2CharPosition) arg0);
break;
case EVT_FORGET_OBJECT:
onEvtForgetObject((L2Object) arg0);
break;
case EVT_CANCEL:
onEvtCancel();
break;
case EVT_DEAD:
onEvtDead();
break;
case EVT_FAKE_DEATH:
onEvtFakeDeath();
break;
case EVT_FINISH_CASTING:
onEvtFinishCasting();
break;
}
}
protected abstract void onIntentionIdle();
protected abstract void onIntentionActive();
protected abstract void onIntentionRest();
protected abstract void onIntentionAttack(L2Character target);
protected abstract void onIntentionCast(L2Skill skill, L2Object target);
protected abstract void onIntentionMoveTo(L2CharPosition destination);
protected abstract void onIntentionFollow(L2Character target);
protected abstract void onIntentionPickUp(L2Object item);
protected abstract void onIntentionInteract(L2Object object);
protected abstract void onEvtThink();
protected abstract void onEvtAttacked(L2Character attacker);
protected abstract void onEvtAggression(L2Character target, int aggro);
protected abstract void onEvtStunned(L2Character attacker);
protected abstract void onEvtParalyzed(L2Character attacker);
protected abstract void onEvtSleeping(L2Character attacker);
protected abstract void onEvtRooted(L2Character attacker);
protected abstract void onEvtConfused(L2Character attacker);
protected abstract void onEvtMuted(L2Character attacker);
protected abstract void onEvtEvaded(L2Character attacker);
protected abstract void onEvtReadyToAct();
protected abstract void onEvtUserCmd(Object arg0, Object arg1);
protected abstract void onEvtArrived();
protected abstract void onEvtArrivedRevalidate();
protected abstract void onEvtArrivedBlocked(L2CharPosition blocked_at_pos);
protected abstract void onEvtForgetObject(L2Object object);
protected abstract void onEvtCancel();
protected abstract void onEvtDead();
protected abstract void onEvtFakeDeath();
protected abstract void onEvtFinishCasting();
/**
* Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
protected void clientActionFailed()
{
if (_actor instanceof L2PcInstance)
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
}
}
/**
* Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
protected void moveToPawn(L2Object pawn, int offset)
{
// Check if actor can move
if (!_actor.isMovementDisabled())
{
if (offset < 10)
{
offset = 10;
}
// prevent possible extra calls to this function (there is none?),
// also don't send movetopawn packets too often
boolean sendPacket = true;
if (_clientMoving && (_target == pawn))
{
if (_clientMovingToPawnOffset == offset)
{
if (GameTimeController.getGameTicks() < _moveToPawnTimeout)
{
return;
}
sendPacket = false;
}
else if (_actor.isOnGeodataPath())
{
// minimum time to calculate new route is 2 seconds
if (GameTimeController.getGameTicks() < (_moveToPawnTimeout + 10))
{
return;
}
}
}
// Set AI movement data
_clientMoving = true;
_clientMovingToPawnOffset = offset;
_target = pawn;
_moveToPawnTimeout = GameTimeController.getGameTicks();
_moveToPawnTimeout += 1000 / GameTimeController.MILLIS_IN_TICK;
if ((pawn == null) || (_accessor == null))
{
return;
}
// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
_accessor.moveTo(pawn.getX(), pawn.getY(), pawn.getZ(), offset);
if (!_actor.isMoving())
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
return;
}
// Send a Server->Client packet MoveToPawn/CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
if (pawn instanceof L2Character)
{
if (_actor.isOnGeodataPath())
{
_actor.broadcastPacket(new MoveToLocation(_actor));
_clientMovingToPawnOffset = 0;
}
else if (sendPacket)
{
_actor.broadcastPacket(new MoveToPawn(_actor, (L2Character) pawn, offset));
}
}
else
{
_actor.broadcastPacket(new MoveToLocation(_actor));
}
}
else
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
}
}
/**
* Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
protected void moveTo(int x, int y, int z)
{
// Chek if actor can move
if (!_actor.isMovementDisabled())
{
// Set AI movement data
_clientMoving = true;
_clientMovingToPawnOffset = 0;
// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
_accessor.moveTo(x, y, z);
// Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
MoveToLocation msg = new MoveToLocation(_actor);
_actor.broadcastPacket(msg);
}
else
{
_actor.sendPacket(ActionFailed.STATIC_PACKET);
}
}
/**
* Stop the actor movement server side AND client side by sending Server->Client packet StopMove/StopRotation <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
protected void clientStopMoving(L2CharPosition pos)
{
/*
* if (Config.DEBUG) _log.warning("clientStopMoving();");
*/
// Stop movement of the L2Character
if (_actor.isMoving())
{
_accessor.stopMove(pos);
}
_clientMovingToPawnOffset = 0;
if (_clientMoving || (pos != null))
{
_clientMoving = false;
// Send a Server->Client packet StopMove to the actor and all L2PcInstance in its _knownPlayers
StopMove msg = new StopMove(_actor);
_actor.broadcastPacket(msg);
if (pos != null)
{
// Send a Server->Client packet StopRotation to the actor and all L2PcInstance in its _knownPlayers
StopRotation sr = new StopRotation(_actor.getObjectId(), pos.heading, 0);
_actor.sendPacket(sr);
_actor.broadcastPacket(sr);
}
}
}
// Client has already arrived to target, no need to force StopMove packet
protected void clientStoppedMoving()
{
if (_clientMovingToPawnOffset > 0) // movetoPawn needs to be stopped
{
_clientMovingToPawnOffset = 0;
StopMove msg = new StopMove(_actor);
_actor.broadcastPacket(msg);
}
_clientMoving = false;
}
public boolean isAutoAttacking()
{
return _clientAutoAttacking;
}
public void setAutoAttacking(boolean isAutoAttacking)
{
if (_actor instanceof L2Summon)
{
L2Summon summon = (L2Summon) _actor;
if (summon.getOwner() != null)
{
summon.getOwner().getAI().setAutoAttacking(isAutoAttacking);
}
return;
}
_clientAutoAttacking = isAutoAttacking;
}
/**
* Start the actor Auto Attack client side by sending Server->Client packet AutoAttackStart <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
public void clientStartAutoAttack()
{
if (_actor instanceof L2Summon)
{
L2Summon summon = (L2Summon) _actor;
if (summon.getOwner() != null)
{
summon.getOwner().getAI().clientStartAutoAttack();
}
return;
}
if (!isAutoAttacking())
{
if ((_actor instanceof L2PcInstance) && (((L2PcInstance) _actor).getPet() != null))
{
((L2PcInstance) _actor).getPet().broadcastPacket(new AutoAttackStart(((L2PcInstance) _actor).getPet().getObjectId()));
}
// Send a Server->Client packet AutoAttackStart to the actor and all L2PcInstance in its _knownPlayers
_actor.broadcastPacket(new AutoAttackStart(_actor.getObjectId()));
setAutoAttacking(true);
}
AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor);
}
/**
* Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
public void clientStopAutoAttack()
{
if (_actor instanceof L2Summon)
{
L2Summon summon = (L2Summon) _actor;
if (summon.getOwner() != null)
{
summon.getOwner().getAI().clientStopAutoAttack();
}
return;
}
if (_actor instanceof L2PcInstance)
{
if (!AttackStanceTaskManager.getInstance().getAttackStanceTask(_actor) && isAutoAttacking())
{
AttackStanceTaskManager.getInstance().addAttackStanceTask(_actor);
}
}
else if (isAutoAttacking())
{
_actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
setAutoAttacking(false);
}
}
/**
* Kill the actor client side by sending Server->Client packet AutoAttackStop, StopMove/StopRotation, Die <I>(broadcast)</I>.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
*/
protected void clientNotifyDead()
{
// Send a Server->Client packet Die to the actor and all L2PcInstance in its _knownPlayers
Die msg = new Die(_actor);
_actor.broadcastPacket(msg);
// Init AI
_intention = AI_INTENTION_IDLE;
_target = null;
_castTarget = null;
_attackTarget = null;
// Cancel the follow task if necessary
stopFollow();
}
/**
* Update the state of this actor client side by sending Server->Client packet MoveToPawn/CharMoveToLocation and AutoAttackStart to the L2PcInstance player.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
* <BR>
* @param player The L2PcIstance to notify with state of this L2Character
*/
public void describeStateToPlayer(L2PcInstance player)
{
if (_clientMoving)
{
if ((_clientMovingToPawnOffset != 0) && (_followTarget != null))
{
// Send a Server->Client packet MoveToPawn to the actor and all L2PcInstance in its _knownPlayers
MoveToPawn msg = new MoveToPawn(_actor, _followTarget, _clientMovingToPawnOffset);
player.sendPacket(msg);
}
else
{
// Send a Server->Client packet CharMoveToLocation to the actor and all L2PcInstance in its _knownPlayers
MoveToLocation msg = new MoveToLocation(_actor);
player.sendPacket(msg);
}
}
}
/**
* Create and Launch an AI Follow Task to execute every 1s.<BR>
* <BR>
* @param target The L2Character to follow
*/
public synchronized void startFollow(L2Character target)
{
if (_followTask != null)
{
_followTask.cancel(false);
_followTask = null;
}
// Create and Launch an AI Follow Task to execute every 1s
_followTarget = target;
_followTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new FollowTask(), 5, FOLLOW_INTERVAL);
}
/**
* Create and Launch an AI Follow Task to execute every 0.5s, following at specified range.<BR>
* <BR>
* @param target The L2Character to follow
*/
public synchronized void startFollow(L2Character target, int range)
{
if (_followTask != null)
{
_followTask.cancel(false);
_followTask = null;
}
_followTarget = target;
_followTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new FollowTask(range), 5, ATTACK_FOLLOW_INTERVAL);
}
/**
* Stop an AI Follow Task.<BR>
* <BR>
*/
public synchronized void stopFollow()
{
if (_followTask != null)
{
// Stop the Follow Task
_followTask.cancel(false);
_followTask = null;
}
_followTarget = null;
}
protected L2Character getFollowTarget()
{
return _followTarget;
}
protected L2Object getTarget()
{
return _target;
}
protected void setTarget(L2Object target)
{
_target = target;
}
/**
* Stop all Ai tasks and futures.
*/
public void stopAITask()
{
stopFollow();
}
@Override
public String toString()
{
if (_actor == null)
{
return "Actor: null";
}
return "Actor: " + _actor;
}
}
@@ -0,0 +1,55 @@
/*
* 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 com.l2jserver.gameserver.ai;
import com.l2jserver.gameserver.model.actor.L2Character;
/**
* Interface of AI and client state. To correctly send messages to client we need it's state. For example, if we've sent 'StartAutoAttack' message, we need to send 'StopAutoAttack' message before any other action. Or if we've sent 'MoveToPawn', we need to send 'StopMove' when the movement of a
* character is canceled (by Root spell or any other reason). Thus, we need to know the state of client, i.e. which messages we've sent and how the client will show the scene. Close to this task is the task of AI. If a player's character is attacking a mob, his ATTACK may be iterrupted by an event,
* that temporary disable attacking. But when the possibility to ATTACK will be enabled, the character must continue the ATTACK. For mobs it may be more complex, since we want them to decide when to use magic, or when to follow the player for physical combat, or when to escape, to help another mob,
* etc. This interface is hiding complexity of server<->client interaction and multiple states of a character. It allows to set a desired, simple "wish" of a character, and the implementation of this interface will take care about the rest. The goal of a character may be like "ATTACK", "random walk"
* and so on. To reach the goal inplementation will split it into several small actions, several steps (possibly repeatable). Like "run to target" then "hit it", then if target is not dead - repeat. This flow of simplier steps may be interrupted by incoming events. Like a character's movement was
* disabled (by Root spell, for instance). Depending on character's ability AI may choose to wait, or to use magic ATTACK and so on. Additionally incoming events are compared with client's state of the character, and required network messages are sent to client's, i.e. if we have incoming event that
* character's movement was disabled, it causes changing if its behavour, and if client's state for the character is "moving" we send messages to clients to stop the avatar/mob.
*/
public interface Ctrl
{
/** the character this AI serves */
L2Character getActor();
/** get current intention */
CtrlIntention getIntention();
/** get current ATTACK target */
L2Character getAttackTarget();
/** Set general state/intention for AI, with optional data */
void setIntention(CtrlIntention intention);
void setIntention(CtrlIntention intention, Object arg0);
void setIntention(CtrlIntention intention, Object arg0, Object arg1);
/**
* Event, that notifies about previous step result, or user command, that does not change current general intention
*/
void notifyEvent(CtrlEvent evt);
void notifyEvent(CtrlEvent evt, Object arg0);
void notifyEvent(CtrlEvent evt, Object arg0, Object arg1);
}
@@ -0,0 +1,82 @@
/*
* 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 com.l2jserver.gameserver.ai;
/**
* This class contains an enum of each possibles evenements that can happen on an AI character.
*/
public enum CtrlEvent
{
/**
* Something has changed, usually a previous step has being completed or maybe was completed, the AI must thing on next action
*/
EVT_THINK,
/**
* The actor was attacked. This event comes each time a physical or magical attack was done on the actor. NPC may start attack in responce, or ignore this event if they already attack someone, or change target and so on.
*/
EVT_ATTACKED,
/** Increase/decrease aggression towards a target, or reduce global aggression if target is null */
EVT_AGGRESSION,
/** Actor is in stun state */
EVT_STUNNED,
/** Actor is paralyzed or petrified */
EVT_PARALYZED,
/** Actor starts/stops sleeping */
EVT_SLEEPING,
/** Actor is in rooted state (cannot move) */
EVT_ROOTED,
/** Actor evaded hit **/
EVT_EVADED,
/**
* An event that previous action was completed. The action may be an attempt to physically/magically hit an enemy, or an action that discarded attack attempt has finished.
*/
EVT_READY_TO_ACT,
/**
* User's command, like using a combat magic or changing weapon, etc. The command is not intended to change final goal
*/
EVT_USER_CMD,
/**
* The actor arrived to assigned location, or it's a time to modify movement destination (follow, interact, random move and others intentions).
*/
EVT_ARRIVED,
/**
* The actor arrived to an intermidiate point, and needs revalidate destination. This is sent when follow/move to pawn if destination is far away.
*/
EVT_ARRIVED_REVALIDATE,
/** The actor cannot move anymore. */
EVT_ARRIVED_BLOCKED,
/** Forgets an object (if it's used as attack target, follow target and so on */
EVT_FORGET_OBJECT,
/**
* Attempt to cancel current step execution, but not change the intention. For example, the actor was putted into a stun, so it's current attack or movement has to be canceled. But after the stun state expired, the actor may try to attack again. Another usage for CANCEL is a user's attempt to
* cancel a cast/bow attack and so on.
*/
EVT_CANCEL,
/** The character is dead */
EVT_DEAD,
/** The character looks like dead */
EVT_FAKE_DEATH,
/** The character attack anyone randomly **/
EVT_CONFUSED,
/** The character cannot cast spells anymore **/
EVT_MUTED,
/** The character flee in randoms directions **/
EVT_AFRAID,
/** The character finish casting **/
EVT_FINISH_CASTING,
/** The character betrayed its master */
EVT_BETRAYED
}
@@ -0,0 +1,43 @@
/*
* 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 com.l2jserver.gameserver.ai;
/**
* Enumaration of generic intentions of an NPC/PC, an intention may require several steps to be completed
*/
public enum CtrlIntention
{
/** Do nothing, disconnect AI of NPC if no players around */
AI_INTENTION_IDLE,
/** Alerted state without goal : scan attackable targets, random walk, etc */
AI_INTENTION_ACTIVE,
/** Rest (sit until attacked) */
AI_INTENTION_REST,
/**
* Attack target (cast combat magic, go to target, combat), may be ignored, if target is locked on another character or a peacefull zone and so on
*/
AI_INTENTION_ATTACK,
/** Cast a spell, depending on the spell - may start or stop attacking */
AI_INTENTION_CAST,
/** Just move to another location */
AI_INTENTION_MOVE_TO,
/** Like move, but check target's movement and follow it */
AI_INTENTION_FOLLOW,
/** PickUp and item, (got to item, pickup it, become idle */
AI_INTENTION_PICK_UP,
/** Move to target, then interact */
AI_INTENTION_INTERACT;
}
@@ -0,0 +1,73 @@
/*
* 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 com.l2jserver.gameserver.ai;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.actor.instance.L2AirShipInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.ExMoveToLocationAirShip;
import com.l2jserver.gameserver.network.serverpackets.ExStopMoveAirShip;
/**
* @author DS
*/
public class L2AirShipAI extends L2VehicleAI
{
public L2AirShipAI(L2AirShipInstance.AIAccessor accessor)
{
super(accessor);
}
@Override
protected void moveTo(int x, int y, int z)
{
if (!_actor.isMovementDisabled())
{
_clientMoving = true;
_accessor.moveTo(x, y, z);
_actor.broadcastPacket(new ExMoveToLocationAirShip(getActor()));
}
}
@Override
protected void clientStopMoving(L2CharPosition pos)
{
if (_actor.isMoving())
{
_accessor.stopMove(pos);
}
if (_clientMoving || (pos != null))
{
_clientMoving = false;
_actor.broadcastPacket(new ExStopMoveAirShip(getActor()));
}
}
@Override
public void describeStateToPlayer(L2PcInstance player)
{
if (_clientMoving)
{
player.sendPacket(new ExMoveToLocationAirShip(getActor()));
}
}
@Override
public L2AirShipInstance getActor()
{
return (L2AirShipInstance) _actor;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,80 @@
/*
* 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 com.l2jserver.gameserver.ai;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.actor.instance.L2BoatInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.VehicleDeparture;
import com.l2jserver.gameserver.network.serverpackets.VehicleInfo;
import com.l2jserver.gameserver.network.serverpackets.VehicleStarted;
/**
* @author DS
*/
public class L2BoatAI extends L2VehicleAI
{
public L2BoatAI(L2BoatInstance.AIAccessor accessor)
{
super(accessor);
}
@Override
protected void moveTo(int x, int y, int z)
{
if (!_actor.isMovementDisabled())
{
if (!_clientMoving)
{
_actor.broadcastPacket(new VehicleStarted(getActor(), 1));
}
_clientMoving = true;
_accessor.moveTo(x, y, z);
_actor.broadcastPacket(new VehicleDeparture(getActor()));
}
}
@Override
protected void clientStopMoving(L2CharPosition pos)
{
if (_actor.isMoving())
{
_accessor.stopMove(pos);
}
if (_clientMoving || (pos != null))
{
_clientMoving = false;
_actor.broadcastPacket(new VehicleStarted(getActor(), 0));
_actor.broadcastPacket(new VehicleInfo(getActor()));
}
}
@Override
public void describeStateToPlayer(L2PcInstance player)
{
if (_clientMoving)
{
player.sendPacket(new VehicleDeparture(getActor()));
}
}
@Override
public L2BoatInstance getActor()
{
return (L2BoatInstance) _actor;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,589 @@
/*
* 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 com.l2jserver.gameserver.ai;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import java.util.Collection;
import java.util.List;
import javolution.util.FastList;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.MobGroup;
import com.l2jserver.gameserver.model.MobGroupTable;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Character.AIAccessor;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Playable;
import com.l2jserver.gameserver.model.actor.instance.L2ControllableMobInstance;
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.util.Util;
import com.l2jserver.util.Rnd;
/**
* @author littlecrow AI for controllable mobs
*/
public class L2ControllableMobAI extends L2AttackableAI
{
public static final int AI_IDLE = 1;
public static final int AI_NORMAL = 2;
public static final int AI_FORCEATTACK = 3;
public static final int AI_FOLLOW = 4;
public static final int AI_CAST = 5;
public static final int AI_ATTACK_GROUP = 6;
private int _alternateAI;
private boolean _isThinking; // to prevent thinking recursively
private boolean _isNotMoving;
private L2Character _forcedTarget;
private MobGroup _targetGroup;
protected void thinkFollow()
{
L2Attackable me = (L2Attackable) _actor;
if (!Util.checkIfInRange(MobGroupTable.FOLLOW_RANGE, me, getForcedTarget(), true))
{
int signX = (Rnd.nextInt(2) == 0) ? -1 : 1;
int signY = (Rnd.nextInt(2) == 0) ? -1 : 1;
int randX = Rnd.nextInt(MobGroupTable.FOLLOW_RANGE);
int randY = Rnd.nextInt(MobGroupTable.FOLLOW_RANGE);
moveTo(getForcedTarget().getX() + (signX * randX), getForcedTarget().getY() + (signY * randY), getForcedTarget().getZ());
}
}
@Override
protected void onEvtThink()
{
if (isThinking())
{
return;
}
setThinking(true);
try
{
switch (getAlternateAI())
{
case AI_IDLE:
if (getIntention() != CtrlIntention.AI_INTENTION_ACTIVE)
{
setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
}
break;
case AI_FOLLOW:
thinkFollow();
break;
case AI_CAST:
thinkCast();
break;
case AI_FORCEATTACK:
thinkForceAttack();
break;
case AI_ATTACK_GROUP:
thinkAttackGroup();
break;
default:
if (getIntention() == AI_INTENTION_ACTIVE)
{
thinkActive();
}
else if (getIntention() == AI_INTENTION_ATTACK)
{
thinkAttack();
}
break;
}
}
finally
{
setThinking(false);
}
}
protected void thinkCast()
{
L2Attackable npc = (L2Attackable) _actor;
if ((getAttackTarget() == null) || getAttackTarget().isAlikeDead())
{
setAttackTarget(findNextRndTarget());
clientStopMoving(null);
}
if (getAttackTarget() == null)
{
return;
}
npc.setTarget(getAttackTarget());
L2Skill[] skills = _actor.getAllSkills();
if (!_actor.isMuted())
{
int max_range = 0;
// check distant skills
for (L2Skill sk : skills)
{
if (Util.checkIfInRange(sk.getCastRange(), _actor, getAttackTarget(), true) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
max_range = Math.max(max_range, sk.getCastRange());
}
if (!isNotMoving())
{
moveToPawn(getAttackTarget(), max_range);
}
return;
}
}
protected void thinkAttackGroup()
{
L2Character target = getForcedTarget();
if ((target == null) || target.isAlikeDead())
{
// try to get next group target
setForcedTarget(findNextGroupTarget());
clientStopMoving(null);
}
if (target == null)
{
return;
}
_actor.setTarget(target);
L2Skill[] skills = _actor.getAllSkills();
double dist2 = _actor.getPlanDistanceSq(target.getX(), target.getY());
int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + target.getTemplate().collisionRadius;
int max_range = range;
// as a response, we put the target in a forcedattack mode
L2ControllableMobInstance theTarget = (L2ControllableMobInstance) target;
L2ControllableMobAI ctrlAi = (L2ControllableMobAI) theTarget.getAI();
ctrlAi.forceAttack(_actor);
if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
{
// check distant skills
for (L2Skill sk : skills)
{
int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
max_range = Math.max(max_range, castRange);
}
if (!isNotMoving())
{
moveToPawn(target, range);
}
return;
}
_accessor.doAttack(target);
}
protected void thinkForceAttack()
{
if ((getForcedTarget() == null) || getForcedTarget().isAlikeDead())
{
clientStopMoving(null);
setIntention(AI_INTENTION_ACTIVE);
setAlternateAI(AI_IDLE);
}
_actor.setTarget(getForcedTarget());
L2Skill[] skills = _actor.getAllSkills();
double dist2 = _actor.getPlanDistanceSq(getForcedTarget().getX(), getForcedTarget().getY());
int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + getForcedTarget().getTemplate().collisionRadius;
int max_range = range;
if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
{
// check distant skills
for (L2Skill sk : skills)
{
int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
max_range = Math.max(max_range, castRange);
}
if (!isNotMoving())
{
moveToPawn(getForcedTarget(), _actor.getPhysicalAttackRange()/* range */);
}
return;
}
_accessor.doAttack(getForcedTarget());
}
protected void thinkAttack()
{
if ((getAttackTarget() == null) || getAttackTarget().isAlikeDead())
{
if (getAttackTarget() != null)
{
// stop hating
L2Attackable npc = (L2Attackable) _actor;
npc.stopHating(getAttackTarget());
}
setIntention(AI_INTENTION_ACTIVE);
}
else
{
// notify aggression
if (((L2Npc) _actor).getFactionId() != null)
{
String faction_id = ((L2Npc) _actor).getFactionId();
Collection<L2Object> objs = _actor.getKnownList().getKnownObjects().values();
// synchronized (_actor.getKnownList().getKnownObjects())
{
for (L2Object obj : objs)
{
if (!(obj instanceof L2Npc))
{
continue;
}
L2Npc npc = (L2Npc) obj;
if (!faction_id.equals(npc.getFactionId()))
{
continue;
}
if (_actor.isInsideRadius(npc, npc.getFactionRange(), false, true) && (Math.abs(getAttackTarget().getZ() - npc.getZ()) < 200))
{
npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
}
}
}
}
_actor.setTarget(getAttackTarget());
L2Skill[] skills = _actor.getAllSkills();
double dist2 = _actor.getPlanDistanceSq(getAttackTarget().getX(), getAttackTarget().getY());
int range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + getAttackTarget().getTemplate().collisionRadius;
int max_range = range;
if (!_actor.isMuted() && (dist2 > ((range + 20) * (range + 20))))
{
// check distant skills
for (L2Skill sk : skills)
{
int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() > _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
max_range = Math.max(max_range, castRange);
}
moveToPawn(getAttackTarget(), range);
return;
}
// Force mobs to attack anybody if confused.
L2Character hated;
if (_actor.isConfused())
{
hated = findNextRndTarget();
}
else
{
hated = getAttackTarget();
}
if (hated == null)
{
setIntention(AI_INTENTION_ACTIVE);
return;
}
if (hated != getAttackTarget())
{
setAttackTarget(hated);
}
if (!_actor.isMuted() && (skills.length > 0) && (Rnd.nextInt(5) == 3))
{
for (L2Skill sk : skills)
{
int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist2) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() < _actor.getStat().getMpConsume(sk)))
{
_accessor.doCast(sk);
return;
}
}
}
_accessor.doAttack(getAttackTarget());
}
}
private void thinkActive()
{
setAttackTarget(findNextRndTarget());
L2Character hated;
if (_actor.isConfused())
{
hated = findNextRndTarget();
}
else
{
hated = getAttackTarget();
}
if (hated != null)
{
_actor.setRunning();
setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated);
}
}
private boolean autoAttackCondition(L2Character target)
{
if ((target == null) || !(_actor instanceof L2Attackable))
{
return false;
}
L2Attackable me = (L2Attackable) _actor;
if ((target instanceof L2NpcInstance) || (target instanceof L2DoorInstance))
{
return false;
}
if (target.isAlikeDead() || !me.isInsideRadius(target, me.getAggroRange(), false, false) || (Math.abs(_actor.getZ() - target.getZ()) > 100))
{
return false;
}
// Check if the target isn't invulnerable
if (target.isInvul())
{
return false;
}
// Spawn protection (only against mobs)
if ((target instanceof L2PcInstance) && ((L2PcInstance) target).isSpawnProtected())
{
return false;
}
// Check if the target is a L2PlayableInstance
if (target instanceof L2Playable)
{
// Check if the target isn't in silent move mode
if (((L2Playable) target).isSilentMoving())
{
return false;
}
}
if (target instanceof L2Npc)
{
return false;
}
return me.isAggressive();
}
private L2Character findNextRndTarget()
{
int aggroRange = ((L2Attackable) _actor).getAggroRange();
L2Attackable npc = (L2Attackable) _actor;
int npcX, npcY, targetX, targetY;
double dy, dx;
double dblAggroRange = aggroRange * aggroRange;
List<L2Character> potentialTarget = new FastList<>();
Collection<L2Object> objs = npc.getKnownList().getKnownObjects().values();
// synchronized (npc.getKnownList().getKnownObjects())
{
for (L2Object obj : objs)
{
if (!(obj instanceof L2Character))
{
continue;
}
npcX = npc.getX();
npcY = npc.getY();
targetX = obj.getX();
targetY = obj.getY();
dx = npcX - targetX;
dy = npcY - targetY;
if (((dx * dx) + (dy * dy)) > dblAggroRange)
{
continue;
}
L2Character target = (L2Character) obj;
if (autoAttackCondition(target))
{
potentialTarget.add(target);
}
}
}
if (potentialTarget.isEmpty())
{
return null;
}
// we choose a random target
int choice = Rnd.nextInt(potentialTarget.size());
L2Character target = potentialTarget.get(choice);
return target;
}
private L2ControllableMobInstance findNextGroupTarget()
{
return getGroupTarget().getRandomMob();
}
public L2ControllableMobAI(AIAccessor accessor)
{
super(accessor);
setAlternateAI(AI_IDLE);
}
public int getAlternateAI()
{
return _alternateAI;
}
public void setAlternateAI(int _alternateai)
{
_alternateAI = _alternateai;
}
public void forceAttack(L2Character target)
{
setAlternateAI(AI_FORCEATTACK);
setForcedTarget(target);
}
public void forceAttackGroup(MobGroup group)
{
setForcedTarget(null);
setGroupTarget(group);
setAlternateAI(AI_ATTACK_GROUP);
}
public void stop()
{
setAlternateAI(AI_IDLE);
clientStopMoving(null);
}
public void move(int x, int y, int z)
{
moveTo(x, y, z);
}
public void follow(L2Character target)
{
setAlternateAI(AI_FOLLOW);
setForcedTarget(target);
}
public boolean isThinking()
{
return _isThinking;
}
public boolean isNotMoving()
{
return _isNotMoving;
}
public void setNotMoving(boolean isNotMoving)
{
_isNotMoving = isNotMoving;
}
public void setThinking(boolean isThinking)
{
_isThinking = isThinking;
}
private L2Character getForcedTarget()
{
return _forcedTarget;
}
private MobGroup getGroupTarget()
{
return _targetGroup;
}
private void setForcedTarget(L2Character forcedTarget)
{
_forcedTarget = forcedTarget;
}
private void setGroupTarget(MobGroup targetGroup)
{
_targetGroup = targetGroup;
}
}
@@ -0,0 +1,182 @@
/*
* 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 com.l2jserver.gameserver.ai;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.instance.L2DefenderInstance;
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
/**
* @author mkizub
*/
public class L2DoorAI extends L2CharacterAI
{
public L2DoorAI(L2DoorInstance.AIAccessor accessor)
{
super(accessor);
}
// rather stupid AI... well, it's for doors :D
@Override
protected void onIntentionIdle()
{
}
@Override
protected void onIntentionActive()
{
}
@Override
protected void onIntentionRest()
{
}
@Override
protected void onIntentionAttack(L2Character target)
{
}
@Override
protected void onIntentionCast(L2Skill skill, L2Object target)
{
}
@Override
protected void onIntentionMoveTo(L2CharPosition destination)
{
}
@Override
protected void onIntentionFollow(L2Character target)
{
}
@Override
protected void onIntentionPickUp(L2Object item)
{
}
@Override
protected void onIntentionInteract(L2Object object)
{
}
@Override
protected void onEvtThink()
{
}
@Override
protected void onEvtAttacked(L2Character attacker)
{
L2DoorInstance me = (L2DoorInstance) _actor;
ThreadPoolManager.getInstance().executeTask(new onEventAttackedDoorTask(me, attacker));
}
@Override
protected void onEvtAggression(L2Character target, int aggro)
{
}
@Override
protected void onEvtStunned(L2Character attacker)
{
}
@Override
protected void onEvtSleeping(L2Character attacker)
{
}
@Override
protected void onEvtRooted(L2Character attacker)
{
}
@Override
protected void onEvtReadyToAct()
{
}
@Override
protected void onEvtUserCmd(Object arg0, Object arg1)
{
}
@Override
protected void onEvtArrived()
{
}
@Override
protected void onEvtArrivedRevalidate()
{
}
@Override
protected void onEvtArrivedBlocked(L2CharPosition blocked_at_pos)
{
}
@Override
protected void onEvtForgetObject(L2Object object)
{
}
@Override
protected void onEvtCancel()
{
}
@Override
protected void onEvtDead()
{
}
private class onEventAttackedDoorTask implements Runnable
{
private final L2DoorInstance _door;
private final L2Character _attacker;
public onEventAttackedDoorTask(L2DoorInstance door, L2Character attacker)
{
_door = door;
_attacker = attacker;
}
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
for (L2DefenderInstance guard : _door.getKnownDefenders())
{
if (_actor.isInsideRadius(guard, guard.getFactionRange(), false, true) && (Math.abs(_attacker.getZ() - guard.getZ()) < 200))
{
guard.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, _attacker, 15);
}
}
}
}
}
@@ -0,0 +1,980 @@
/*
* 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 com.l2jserver.gameserver.ai;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.concurrent.Future;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.gameserver.GameTimeController;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.L2Effect;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Playable;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.gameserver.model.actor.instance.L2DefenderInstance;
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jserver.gameserver.model.actor.instance.L2FortBallistaInstance;
import com.l2jserver.gameserver.model.actor.instance.L2FortCommanderInstance;
import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.templates.skills.L2SkillType;
import com.l2jserver.gameserver.util.Util;
import com.l2jserver.util.Rnd;
/**
* This class manages AI of L2Attackable.<BR>
* <BR>
*/
public class L2FortSiegeGuardAI extends L2CharacterAI implements Runnable
{
protected static final Logger _log1 = Logger.getLogger(L2FortSiegeGuardAI.class.getName());
private static final int MAX_ATTACK_TIMEOUT = 300; // int ticks, i.e. 30 seconds
/** The L2Attackable AI task executed every 1s (call onEvtThink method) */
private Future<?> _aiTask;
/** For attack AI, analysis of mob and its targets */
private final SelfAnalysis _selfAnalysis = new SelfAnalysis();
/** The delay after which the attacked is stopped */
private int _attackTimeout;
/** The L2Attackable aggro counter */
private int _globalAggro;
/** The flag used to indicate that a thinking action is in progress */
private boolean _thinking; // to prevent recursive thinking
private final int _attackRange;
/**
* Constructor of L2AttackableAI.<BR>
* <BR>
* @param accessor The AI accessor of the L2Character
*/
public L2FortSiegeGuardAI(L2Character.AIAccessor accessor)
{
super(accessor);
_selfAnalysis.init();
_attackTimeout = Integer.MAX_VALUE;
_globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
_attackRange = ((L2Attackable) _actor).getPhysicalAttackRange();
}
@Override
public void run()
{
// Launch actions corresponding to the Event Think
onEvtThink();
}
/**
* Return True if the target is autoattackable (depends on the actor type).<BR>
* <BR>
* <B><U> Actor is a L2GuardInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk or a Door</li> <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li> <li>The target is in the actor Aggro range and is at the same height</li> <li>The L2PcInstance target has karma (=PK)</li> <li>The L2MonsterInstance
* target is aggressive</li><BR>
* <BR>
* <B><U> Actor is a L2SiegeGuardInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk or a Door</li> <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li> <li>The target is in the actor Aggro range and is at the same height</li> <li>A siege is in progress</li> <li>The L2PcInstance target isn't a Defender</li>
* <BR>
* <BR>
* <B><U> Actor is a L2FriendlyMobInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk, a Door or another L2NpcInstance</li> <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li> <li>The target is in the actor Aggro range and is at the same height</li> <li>The L2PcInstance target has karma (=PK)</li><BR>
* <BR>
* <B><U> Actor is a L2MonsterInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk, a Door or another L2NpcInstance</li> <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li> <li>The target is in the actor Aggro range and is at the same height</li> <li>The actor is Aggressive</li><BR>
* <BR>
* @param target The targeted L2Object
*/
private boolean autoAttackCondition(L2Character target)
{
// Check if the target isn't another guard, folk or a door
if ((target == null) || (target instanceof L2DefenderInstance) || (target instanceof L2NpcInstance) || (target instanceof L2DoorInstance) || target.isAlikeDead() || (target instanceof L2FortBallistaInstance) || (target instanceof L2FortCommanderInstance) || (target instanceof L2Playable))
{
L2PcInstance player = null;
if (target instanceof L2PcInstance)
{
player = ((L2PcInstance) target);
}
else if (target instanceof L2Summon)
{
player = ((L2Summon) target).getOwner();
}
if ((player == null) || ((player.getClan() != null) && (player.getClan().getHasFort() == ((L2Npc) _actor).getFort().getFortId())))
{
return false;
}
}
// Check if the target isn't invulnerable
if (target.isInvul())
{
// However EffectInvincible requires to check GMs specially
if ((target instanceof L2PcInstance) && ((L2PcInstance) target).isGM())
{
return false;
}
if ((target instanceof L2Summon) && ((L2Summon) target).getOwner().isGM())
{
return false;
}
}
// Get the owner if the target is a summon
if (target instanceof L2Summon)
{
L2PcInstance owner = ((L2Summon) target).getOwner();
if (_actor.isInsideRadius(owner, 1000, true, false))
{
target = owner;
}
}
// Check if the target is a L2PcInstance
if (target instanceof L2Playable)
{
// Check if the target isn't in silent move mode AND too far (>100)
if (((L2Playable) target).isSilentMoving() && !_actor.isInsideRadius(target, 250, false, false))
{
return false;
}
}
// Los Check Here
return (_actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target));
}
/**
* Set the Intention of this L2CharacterAI and create an AI Task executed every 1s (call onEvtThink method) for this L2Attackable.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : If actor _knowPlayer isn't EMPTY, AI_INTENTION_IDLE will be change in AI_INTENTION_ACTIVE</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention
* @param arg1 The second parameter of the Intention
*/
@Override
synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
{
if (Config.DEBUG)
{
_log1.info("L2SiegeAI.changeIntention(" + intention + ", " + arg0 + ", " + arg1 + ")");
}
if (intention == AI_INTENTION_IDLE /* || intention == AI_INTENTION_ACTIVE */) // active becomes idle if only a summon is present
{
// Check if actor is not dead
if (!_actor.isAlikeDead())
{
L2Attackable npc = (L2Attackable) _actor;
// If its _knownPlayer isn't empty set the Intention to AI_INTENTION_ACTIVE
if (!npc.getKnownList().getKnownPlayers().isEmpty())
{
intention = AI_INTENTION_ACTIVE;
}
else
{
intention = AI_INTENTION_IDLE;
}
}
if (intention == AI_INTENTION_IDLE)
{
// Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE
super.changeIntention(AI_INTENTION_IDLE, null, null);
// Stop AI task and detach AI from NPC
if (_aiTask != null)
{
_aiTask.cancel(true);
_aiTask = null;
}
// Cancel the AI
_accessor.detachAI();
return;
}
}
// Set the Intention of this L2AttackableAI to intention
super.changeIntention(intention, arg0, arg1);
// If not idle - create an AI task (schedule onEvtThink repeatedly)
if (_aiTask == null)
{
_aiTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 1000, 1000);
}
}
/**
* Manage the Attack Intention : Stop current Attack (if necessary), Calculate attack timeout, Start a new Attack and Launch Think Event.<BR>
* <BR>
* @param target The L2Character to attack
*/
@Override
protected void onIntentionAttack(L2Character target)
{
// Calculate the attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
// if (_actor.getTarget() != null)
super.onIntentionAttack(target);
}
/**
* Manage AI standard thinks of a L2Attackable (called by onEvtThink).<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Update every 1s the _globalAggro counter to come close to 0</li> <li>If the actor is Aggressive and can attack, add all autoAttackable L2Character in its Aggro Range to its _aggroList, chose a target and order to attack it</li> <li>If the actor can't attack, order to it to return to its
* home location</li>
*/
private void thinkActive()
{
L2Attackable npc = (L2Attackable) _actor;
// Update every 1s the _globalAggro counter to come close to 0
if (_globalAggro != 0)
{
if (_globalAggro < 0)
{
_globalAggro++;
}
else
{
_globalAggro--;
}
}
// Add all autoAttackable L2Character in L2Attackable Aggro Range to its _aggroList with 0 damage and 1 hate
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(_attackRange))
{
if (target == null)
{
continue;
}
if (autoAttackCondition(target)) // check aggression
{
// Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
int hating = npc.getHating(target);
// Add the attacker to the L2Attackable _aggroList with 0 damage and 1 hate
if (hating == 0)
{
npc.addDamageHate(target, 0, 1);
}
}
}
// Chose a target from its aggroList
L2Character hated;
if (_actor.isConfused())
{
hated = getAttackTarget(); // Force mobs to attack anybody if confused
}
else
{
hated = npc.getMostHated();
// _mostHatedAnalysis.Update(hated);
}
// Order to the L2Attackable to attack the target
if (hated != null)
{
// Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
int aggro = npc.getHating(hated);
if ((aggro + _globalAggro) > 0)
{
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
// Set the AI Intention to AI_INTENTION_ATTACK
setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated, null);
}
return;
}
}
// Order to the L2SiegeGuardInstance to return to its home location because there's no target to attack
if (_actor.getWalkSpeed() >= 0)
{
if (_actor instanceof L2DefenderInstance)
{
((L2DefenderInstance) _actor).returnHome();
}
else
{
((L2FortCommanderInstance) _actor).returnHome();
}
}
}
/**
* Manage AI attack thinks of a L2Attackable (called by onEvtThink).<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Update the attack timeout if actor is running</li> <li>If target is dead or timeout is expired, stop this attack and set the Intention to AI_INTENTION_ACTIVE</li> <li>Call all L2Object of its Faction inside the Faction Range</li> <li>Chose a target and order to attack it with magic skill
* or physical attack</li><BR>
* <BR>
* TODO: Manage casting rules to healer mobs (like Ant Nurses)
*/
private void thinkAttack()
{
if (Config.DEBUG)
{
_log1.info("L2FortSiegeGuardAI.thinkAttack(); timeout=" + (_attackTimeout - GameTimeController.getGameTicks()));
}
if (_attackTimeout < GameTimeController.getGameTicks())
{
// Check if the actor is running
if (_actor.isRunning())
{
// Set the actor movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance
_actor.setWalking();
// Calculate a new attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
}
}
L2Character attackTarget = getAttackTarget();
// Check if target is dead or if timeout is expired to stop this attack
if ((attackTarget == null) || attackTarget.isAlikeDead() || (_attackTimeout < GameTimeController.getGameTicks()))
{
// Stop hating this target after the attack timeout or if target is dead
if (attackTarget != null)
{
L2Attackable npc = (L2Attackable) _actor;
npc.stopHating(attackTarget);
}
// Cancel target and timeout
_attackTimeout = Integer.MAX_VALUE;
setAttackTarget(null);
// Set the AI Intention to AI_INTENTION_ACTIVE
setIntention(AI_INTENTION_ACTIVE, null, null);
_actor.setWalking();
return;
}
factionNotifyAndSupport();
attackPrepare();
}
private final void factionNotifyAndSupport()
{
L2Character target = getAttackTarget();
// Call all L2Object of its Faction inside the Faction Range
if ((((L2Npc) _actor).getFactionId() == null) || (target == null))
{
return;
}
if (target.isInvul())
{
return; // speeding it up for siege guards
}
String faction_id = ((L2Npc) _actor).getFactionId();
// Go through all L2Character that belong to its faction
// for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(((L2NpcInstance) _actor).getFactionRange()+_actor.getTemplate().collisionRadius))
for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(1000))
{
if (cha == null)
{
continue;
}
if (!(cha instanceof L2Npc))
{
if (_selfAnalysis.hasHealOrResurrect && (cha instanceof L2PcInstance) && ((L2Npc) _actor).getFort().getSiege().checkIsDefender(((L2PcInstance) cha).getClan()))
{
// heal friends
if (!_actor.isAttackingDisabled() && (cha.getCurrentHp() < (cha.getMaxHp() * 0.6)) && (_actor.getCurrentHp() > (_actor.getMaxHp() / 2)) && (_actor.getCurrentMp() > (_actor.getMaxMp() / 2)) && cha.isInCombat())
{
for (L2Skill sk : _selfAnalysis.healSkills)
{
if (_actor.getCurrentMp() < sk.getMpConsume())
{
continue;
}
if (_actor.isSkillDisabled(sk))
{
continue;
}
if (!Util.checkIfInRange(sk.getCastRange(), _actor, cha, true))
{
continue;
}
int chance = 5;
if (chance >= Rnd.get(100))
{
continue;
}
if (!GeoData.getInstance().canSeeTarget(_actor, cha))
{
break;
}
L2Object OldTarget = _actor.getTarget();
_actor.setTarget(cha);
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
}
continue;
}
L2Npc npc = (L2Npc) cha;
if (!faction_id.equals(npc.getFactionId()))
{
continue;
}
if (npc.getAI() != null) // TODO: possibly check not needed
{
if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600)
// && _actor.getAttackByList().contains(getAttackTarget())
&& ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE))
// limiting aggro for siege guards
&& target.isInsideRadius(npc, 1500, true, false) && GeoData.getInstance().canSeeTarget(npc, target))
{
// Notify the L2Object AI with EVT_AGGRESSION
npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
return;
}
// heal friends
if (_selfAnalysis.hasHealOrResurrect && !_actor.isAttackingDisabled() && (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) && (_actor.getCurrentHp() > (_actor.getMaxHp() / 2)) && (_actor.getCurrentMp() > (_actor.getMaxMp() / 2)) && npc.isInCombat())
{
for (L2Skill sk : _selfAnalysis.healSkills)
{
if (_actor.getCurrentMp() < sk.getMpConsume())
{
continue;
}
if (_actor.isSkillDisabled(sk))
{
continue;
}
if (!Util.checkIfInRange(sk.getCastRange(), _actor, npc, true))
{
continue;
}
int chance = 4;
if (chance >= Rnd.get(100))
{
continue;
}
if (!GeoData.getInstance().canSeeTarget(_actor, npc))
{
break;
}
L2Object OldTarget = _actor.getTarget();
_actor.setTarget(npc);
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
}
}
}
private void attackPrepare()
{
// Get all information needed to choose between physical or magical attack
L2Skill[] skills = null;
double dist_2 = 0;
int range = 0;
L2DefenderInstance sGuard;
if (_actor instanceof L2FortCommanderInstance)
{
sGuard = (L2FortCommanderInstance) _actor;
}
else
{
sGuard = (L2DefenderInstance) _actor;
}
L2Character attackTarget = getAttackTarget();
try
{
_actor.setTarget(attackTarget);
skills = _actor.getAllSkills();
dist_2 = _actor.getPlanDistanceSq(attackTarget.getX(), attackTarget.getY());
range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + attackTarget.getTemplate().collisionRadius;
if (attackTarget.isMoving())
{
range += 50;
}
}
catch (NullPointerException e)
{
// _log.warning("AttackableAI: Attack target is NULL.");
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
// never attack defenders
if ((attackTarget instanceof L2PcInstance) && sGuard.getFort().getSiege().checkIsDefender(((L2PcInstance) attackTarget).getClan()))
{
// Cancel the target
sGuard.stopHating(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
if (!GeoData.getInstance().canSeeTarget(_actor, attackTarget))
{
// Siege guards differ from normal mobs currently:
// If target cannot seen, don't attack any more
sGuard.stopHating(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
// Check if the actor isn't muted and if it is far from target
if (!_actor.isMuted() && (dist_2 > (range * range)))
{
// check for long ranged skills and heal/buff skills
for (L2Skill sk : skills)
{
int castRange = sk.getCastRange();
if ((dist_2 <= (castRange * castRange)) && (castRange > 70) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !sk.isPassive())
{
L2Object OldTarget = _actor.getTarget();
if ((sk.getSkillType() == L2SkillType.BUFF) || (sk.getSkillType() == L2SkillType.HEAL))
{
boolean useSkillSelf = true;
if ((sk.getSkillType() == L2SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
{
useSkillSelf = false;
break;
}
if (sk.getSkillType() == L2SkillType.BUFF)
{
L2Effect[] effects = _actor.getAllEffects();
for (int i = 0; (effects != null) && (i < effects.length); i++)
{
L2Effect effect = effects[i];
if (effect.getSkill() == sk)
{
useSkillSelf = false;
break;
}
}
}
if (useSkillSelf)
{
_actor.setTarget(_actor);
}
}
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
// Check if the L2SiegeGuardInstance is attacking, knows the target and can't run
if (!(_actor.isAttackingNow()) && (_actor.getRunSpeed() == 0) && (_actor.getKnownList().knowsObject(attackTarget)))
{
// Cancel the target
_actor.getKnownList().removeKnownObject(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
}
else
{
double dx = _actor.getX() - attackTarget.getX();
double dy = _actor.getY() - attackTarget.getY();
double dz = _actor.getZ() - attackTarget.getZ();
double homeX = attackTarget.getX() - sGuard.getSpawn().getLocx();
double homeY = attackTarget.getY() - sGuard.getSpawn().getLocy();
// Check if the L2SiegeGuardInstance isn't too far from it's home location
if ((((dx * dx) + (dy * dy)) > 10000) && (((homeX * homeX) + (homeY * homeY)) > 3240000) // 1800 * 1800
&& (_actor.getKnownList().knowsObject(attackTarget)))
{
// Cancel the target
_actor.getKnownList().removeKnownObject(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
}
else
// Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
{
// Temporary hack for preventing guards jumping off towers,
// before replacing this with effective geodata checks and AI modification
if ((dz * dz) < (170 * 170)) // normally 130 if guard z coordinates correct
{
if (_selfAnalysis.isMage)
{
range = _selfAnalysis.maxCastRange - 50;
}
if (_actor.getWalkSpeed() <= 0)
{
return;
}
if (attackTarget.isMoving())
{
moveToPawn(attackTarget, range - 70);
}
else
{
moveToPawn(attackTarget, range);
}
}
}
}
return;
}
// Else, if the actor is muted and far from target, just "move to pawn"
else if (_actor.isMuted() && (dist_2 > (range * range)))
{
// Temporary hack for preventing guards jumping off towers,
// before replacing this with effective geodata checks and AI modification
double dz = _actor.getZ() - attackTarget.getZ();
if ((dz * dz) < (170 * 170)) // normally 130 if guard z coordinates correct
{
if (_selfAnalysis.isMage)
{
range = _selfAnalysis.maxCastRange - 50;
}
if (_actor.getWalkSpeed() <= 0)
{
return;
}
if (attackTarget.isMoving())
{
moveToPawn(attackTarget, range - 70);
}
else
{
moveToPawn(attackTarget, range);
}
}
return;
}
// Else, if this is close enough to attack
else if (dist_2 <= (range * range))
{
// Force mobs to attack anybody if confused
L2Character hated = null;
if (_actor.isConfused())
{
hated = attackTarget;
}
else
{
hated = ((L2Attackable) _actor).getMostHated();
}
if (hated == null)
{
setIntention(AI_INTENTION_ACTIVE, null, null);
return;
}
if (hated != attackTarget)
{
attackTarget = hated;
}
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// check for close combat skills && heal/buff skills
if (!_actor.isMuted() && (Rnd.nextInt(100) <= 5))
{
for (L2Skill sk : skills)
{
int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist_2) && !sk.isPassive() && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !_actor.isSkillDisabled(sk))
{
L2Object OldTarget = _actor.getTarget();
if ((sk.getSkillType() == L2SkillType.BUFF) || (sk.getSkillType() == L2SkillType.HEAL))
{
boolean useSkillSelf = true;
if ((sk.getSkillType() == L2SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
{
useSkillSelf = false;
break;
}
if (sk.getSkillType() == L2SkillType.BUFF)
{
L2Effect[] effects = _actor.getAllEffects();
for (int i = 0; (effects != null) && (i < effects.length); i++)
{
L2Effect effect = effects[i];
if (effect.getSkill() == sk)
{
useSkillSelf = false;
break;
}
}
}
if (useSkillSelf)
{
_actor.setTarget(_actor);
}
}
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
}
// Finally, do the physical attack itself
_accessor.doAttack(attackTarget);
}
}
/**
* Manage AI thinking actions of a L2Attackable.<BR>
* <BR>
*/
@Override
protected void onEvtThink()
{
// if(getIntention() != AI_INTENTION_IDLE && (!_actor.isVisible() || !_actor.hasAI() || !_actor.isKnownPlayers()))
// setIntention(AI_INTENTION_IDLE);
// Check if the actor can't use skills and if a thinking action isn't already in progress
if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
{
return;
}
// Start thinking action
_thinking = true;
try
{
// Manage AI thinks of a L2Attackable
if (getIntention() == AI_INTENTION_ACTIVE)
{
thinkActive();
}
else if (getIntention() == AI_INTENTION_ATTACK)
{
thinkAttack();
}
}
finally
{
// Stop thinking action
_thinking = false;
}
}
/**
* Launch actions corresponding to the Event Attacked.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Init the attack : Calculate the attack timeout, Set the _globalAggro to 0, Add the attacker to the actor _aggroList</li> <li>Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance</li> <li>Set the Intention to AI_INTENTION_ATTACK</li>
* <BR>
* <BR>
* @param attacker The L2Character that attacks the actor
*/
@Override
protected void onEvtAttacked(L2Character attacker)
{
// Calculate the attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// Set the _globalAggro to 0 to permit attack even just after spawn
if (_globalAggro < 0)
{
_globalAggro = 0;
}
// Add the attacker to the _aggroList of the actor
((L2Attackable) _actor).addDamageHate(attacker, 0, 1);
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
// Set the Intention to AI_INTENTION_ATTACK
if (getIntention() != AI_INTENTION_ATTACK)
{
setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker, null);
}
super.onEvtAttacked(attacker);
}
/**
* Launch actions corresponding to the Event Aggression.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Add the target to the actor _aggroList or update hate if already present</li> <li>Set the actor Intention to AI_INTENTION_ATTACK (if actor is L2GuardInstance check if it isn't too far from its home location)</li><BR>
* <BR>
* @param attacker The L2Character that attacks
* @param aggro The value of hate to add to the actor against the target
*/
@Override
protected void onEvtAggression(L2Character target, int aggro)
{
if (_actor == null)
{
return;
}
L2Attackable me = (L2Attackable) _actor;
if (target != null)
{
// Add the target to the actor _aggroList or update hate if already present
me.addDamageHate(target, 0, aggro);
// Get the hate of the actor against the target
aggro = me.getHating(target);
if (aggro <= 0)
{
if (me.getMostHated() == null)
{
_globalAggro = -25;
me.clearAggroList();
setIntention(AI_INTENTION_IDLE, null, null);
}
return;
}
// Set the actor AI Intention to AI_INTENTION_ATTACK
if (getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
{
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
L2DefenderInstance sGuard;
if (_actor instanceof L2FortCommanderInstance)
{
sGuard = (L2FortCommanderInstance) _actor;
}
else
{
sGuard = (L2DefenderInstance) _actor;
}
double homeX = target.getX() - sGuard.getSpawn().getLocx();
double homeY = target.getY() - sGuard.getSpawn().getLocy();
// Check if the L2SiegeGuardInstance is not too far from its home location
if (((homeX * homeX) + (homeY * homeY)) < 3240000)
{
setIntention(CtrlIntention.AI_INTENTION_ATTACK, target, null);
}
}
}
else
{
// currently only for setting lower general aggro
if (aggro >= 0)
{
return;
}
L2Character mostHated = me.getMostHated();
if (mostHated == null)
{
_globalAggro = -25;
return;
}
for (L2Character aggroed : me.getAggroList().keySet())
{
me.addDamageHate(aggroed, 0, aggro);
}
aggro = me.getHating(mostHated);
if (aggro <= 0)
{
_globalAggro = -25;
me.clearAggroList();
setIntention(AI_INTENTION_IDLE, null, null);
}
}
}
@Override
public void stopAITask()
{
if (_aiTask != null)
{
_aiTask.cancel(false);
_aiTask = null;
}
_accessor.detachAI();
super.stopAITask();
}
}
@@ -0,0 +1,240 @@
/*
* 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 com.l2jserver.gameserver.ai;
import java.util.List;
import com.l2jserver.Config;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.datatables.NpcWalkerRoutesTable;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2NpcWalkerNode;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.instance.L2NpcWalkerInstance;
public class L2NpcWalkerAI extends L2CharacterAI implements Runnable
{
private static final int DEFAULT_MOVE_DELAY = 0;
private long _nextMoveTime;
private boolean _walkingToNextPoint = false;
/**
* home points for xyz
*/
int _homeX, _homeY, _homeZ;
/**
* route of the current npc
*/
private List<L2NpcWalkerNode> _route;
/**
* current node
*/
private int _currentPos;
/**
* Constructor of L2CharacterAI.<BR>
* <BR>
* @param accessor The AI accessor of the L2Character
*/
public L2NpcWalkerAI(L2Character.AIAccessor accessor)
{
super(accessor);
if (!Config.ALLOW_NPC_WALKERS)
{
return;
}
_route = NpcWalkerRoutesTable.getInstance().getRouteForNpc(getActor().getNpcId());
// Here we need 1 second initial delay cause getActor().hasAI() will return null...
// Constructor of L2NpcWalkerAI is called faster then ai object is attached in L2NpcWalkerInstance
if (_route != null)
{
ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 1000, 1000);
}
else
{
_log.warning(getClass().getSimpleName() + ": Missing route data! Npc: " + _actor);
}
}
@Override
public void run()
{
onEvtThink();
}
@Override
protected void onEvtThink()
{
if (!Config.ALLOW_NPC_WALKERS)
{
return;
}
if (isWalkingToNextPoint())
{
checkArrived();
return;
}
if (_nextMoveTime < System.currentTimeMillis())
{
walkToLocation();
}
}
/**
* If npc can't walk to it's target then just teleport to next point
* @param blocked_at_pos ignoring it
*/
@Override
protected void onEvtArrivedBlocked(L2CharPosition blocked_at_pos)
{
_log.warning("NpcWalker ID: " + getActor().getNpcId() + ": Blocked at rote position [" + _currentPos + "], coords: " + blocked_at_pos.x + ", " + blocked_at_pos.y + ", " + blocked_at_pos.z + ". Teleporting to next point");
int destinationX = _route.get(_currentPos).getMoveX();
int destinationY = _route.get(_currentPos).getMoveY();
int destinationZ = _route.get(_currentPos).getMoveZ();
getActor().teleToLocation(destinationX, destinationY, destinationZ, false);
super.onEvtArrivedBlocked(blocked_at_pos);
}
private void checkArrived()
{
int destinationX = _route.get(_currentPos).getMoveX();
int destinationY = _route.get(_currentPos).getMoveY();
int destinationZ = _route.get(_currentPos).getMoveZ();
if (getActor().isInsideRadius(destinationX, destinationY, destinationZ, 5, false, false))
{
int id = _route.get(_currentPos).getChatId();
String chat = null;
if (id == 0)
{
chat = _route.get(_currentPos).getChatText();
}
if ((id > 0) || ((chat != null) && !chat.isEmpty()))
{
getActor().broadcastChat(chat, id);
}
// time in millis
long delay = _route.get(_currentPos).getDelay() * 1000;
// sleeps between each move
if (delay <= 0)
{
delay = DEFAULT_MOVE_DELAY;
if (Config.DEVELOPER)
{
_log.warning("Wrong Delay Set in Npc Walker Functions = " + delay + " secs, using default delay: " + DEFAULT_MOVE_DELAY + " secs instead.");
}
}
_nextMoveTime = System.currentTimeMillis() + delay;
setWalkingToNextPoint(false);
}
}
private void walkToLocation()
{
if (_currentPos < (_route.size() - 1))
{
_currentPos++;
}
else
{
_currentPos = 0;
}
boolean moveType = _route.get(_currentPos).getRunning();
/**
* false - walking true - Running
*/
if (moveType)
{
getActor().setRunning();
}
else
{
getActor().setWalking();
}
// now we define destination
int destinationX = _route.get(_currentPos).getMoveX();
int destinationY = _route.get(_currentPos).getMoveY();
int destinationZ = _route.get(_currentPos).getMoveZ();
// notify AI of MOVE_TO
setWalkingToNextPoint(true);
setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new L2CharPosition(destinationX, destinationY, destinationZ, 0));
}
@Override
public L2NpcWalkerInstance getActor()
{
return (L2NpcWalkerInstance) super.getActor();
}
public int getHomeX()
{
return _homeX;
}
public int getHomeY()
{
return _homeY;
}
public int getHomeZ()
{
return _homeZ;
}
public void setHomeX(int homeX)
{
_homeX = homeX;
}
public void setHomeY(int homeY)
{
_homeY = homeY;
}
public void setHomeZ(int homeZ)
{
_homeZ = homeZ;
}
public boolean isWalkingToNextPoint()
{
return _walkingToNextPoint;
}
public void setWalkingToNextPoint(boolean value)
{
_walkingToNextPoint = value;
}
}
@@ -0,0 +1,136 @@
/*
* 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 com.l2jserver.gameserver.ai;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Character.AIAccessor;
import com.l2jserver.gameserver.model.actor.L2Playable;
import com.l2jserver.gameserver.network.SystemMessageId;
/**
* This class manages AI of L2Playable.<BR>
* <BR>
* L2PlayableAI :<BR>
* <BR>
* <li>L2SummonAI</li> <li>L2PlayerAI</li> <BR>
* <BR>
* @author JIV
*/
public abstract class L2PlayableAI extends L2CharacterAI
{
/**
* @param accessor
*/
public L2PlayableAI(AIAccessor accessor)
{
super(accessor);
}
/**
* @see com.l2jserver.gameserver.ai.L2CharacterAI#onIntentionAttack(com.l2jserver.gameserver.model.actor.L2Character)
*/
@Override
protected void onIntentionAttack(L2Character target)
{
if (target instanceof L2Playable)
{
if (target.getActingPlayer().getProtectionBlessing() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getKarma() > 0) && !(target.isInsideZone(L2Character.ZONE_PVP)))
{
// If attacker have karma and have level >= 10 than his target and target have
// Newbie Protection Buff,
_actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
clientActionFailed();
return;
}
if (_actor.getActingPlayer().getProtectionBlessing() && ((target.getActingPlayer().getLevel() - _actor.getActingPlayer().getLevel()) >= 10) && (target.getActingPlayer().getKarma() > 0) && !(target.isInsideZone(L2Character.ZONE_PVP)))
{
// If target have karma and have level >= 10 than his target and actor have
// Newbie Protection Buff,
_actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
clientActionFailed();
return;
}
if (target.getActingPlayer().isCursedWeaponEquipped() && (_actor.getActingPlayer().getLevel() <= 20))
{
_actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
clientActionFailed();
return;
}
if (_actor.getActingPlayer().isCursedWeaponEquipped() && (target.getActingPlayer().getLevel() <= 20))
{
_actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
clientActionFailed();
return;
}
}
super.onIntentionAttack(target);
}
/**
* @see com.l2jserver.gameserver.ai.L2CharacterAI#onIntentionCast(com.l2jserver.gameserver.model.L2Skill, com.l2jserver.gameserver.model.L2Object)
*/
@Override
protected void onIntentionCast(L2Skill skill, L2Object target)
{
if ((target instanceof L2Playable) && skill.isOffensive())
{
if (target.getActingPlayer().getProtectionBlessing() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getKarma() > 0) && !(((L2Playable) target).isInsideZone(L2Character.ZONE_PVP)))
{
// If attacker have karma and have level >= 10 than his target and target have
// Newbie Protection Buff,
_actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
clientActionFailed();
_actor.setIsCastingNow(false);
return;
}
if (_actor.getActingPlayer().getProtectionBlessing() && ((target.getActingPlayer().getLevel() - _actor.getActingPlayer().getLevel()) >= 10) && (target.getActingPlayer().getKarma() > 0) && !(((L2Playable) target).isInsideZone(L2Character.ZONE_PVP)))
{
// If target have karma and have level >= 10 than his target and actor have
// Newbie Protection Buff,
_actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
clientActionFailed();
_actor.setIsCastingNow(false);
return;
}
if (target.getActingPlayer().isCursedWeaponEquipped() && (_actor.getActingPlayer().getLevel() <= 20))
{
_actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
clientActionFailed();
_actor.setIsCastingNow(false);
return;
}
if (_actor.getActingPlayer().isCursedWeaponEquipped() && (target.getActingPlayer().getLevel() <= 20))
{
_actor.getActingPlayer().sendPacket(SystemMessageId.TARGET_IS_INCORRECT);
clientActionFailed();
_actor.setIsCastingNow(false);
return;
}
}
super.onIntentionCast(skill, target);
}
}
@@ -0,0 +1,387 @@
/*
* 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 com.l2jserver.gameserver.ai;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_CAST;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_INTERACT;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_MOVE_TO;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_PICK_UP;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_REST;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.L2CharPosition;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.L2Skill.SkillTargetType;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Character.AIAccessor;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2StaticObjectInstance;
public class L2PlayerAI extends L2PlayableAI
{
private boolean _thinking; // to prevent recursive thinking
IntentionCommand _nextIntention = null;
public L2PlayerAI(AIAccessor accessor)
{
super(accessor);
}
void saveNextIntention(CtrlIntention intention, Object arg0, Object arg1)
{
_nextIntention = new IntentionCommand(intention, arg0, arg1);
}
@Override
public IntentionCommand getNextIntention()
{
return _nextIntention;
}
/**
* Saves the current Intention for this L2PlayerAI if necessary and calls changeIntention in AbstractAI.<BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention
* @param arg1 The second parameter of the Intention
*/
@Override
synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
{
/*
* if (Config.DEBUG) _log.warning("L2PlayerAI: changeIntention -> " + intention + " " + arg0 + " " + arg1);
*/
// do nothing unless CAST intention
// however, forget interrupted actions when starting to use an offensive skill
if ((intention != AI_INTENTION_CAST) || ((arg0 != null) && ((L2Skill) arg0).isOffensive()))
{
_nextIntention = null;
super.changeIntention(intention, arg0, arg1);
return;
}
// do nothing if next intention is same as current one.
if ((intention == _intention) && (arg0 == _intentionArg0) && (arg1 == _intentionArg1))
{
super.changeIntention(intention, arg0, arg1);
return;
}
// save current intention so it can be used after cast
saveNextIntention(_intention, _intentionArg0, _intentionArg1);
super.changeIntention(intention, arg0, arg1);
}
/**
* Launch actions corresponding to the Event ReadyToAct.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Launch actions corresponding to the Event Think</li><BR>
* <BR>
*/
@Override
protected void onEvtReadyToAct()
{
// Launch actions corresponding to the Event Think
if (_nextIntention != null)
{
setIntention(_nextIntention._crtlIntention, _nextIntention._arg0, _nextIntention._arg1);
_nextIntention = null;
}
super.onEvtReadyToAct();
}
/**
* Launch actions corresponding to the Event Cancel.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Stop an AI Follow Task</li> <li>Launch actions corresponding to the Event Think</li><BR>
* <BR>
*/
@Override
protected void onEvtCancel()
{
_nextIntention = null;
super.onEvtCancel();
}
/**
* Finalize the casting of a skill. This method overrides L2CharacterAI method.<BR>
* <BR>
* <B>What it does:</B> Check if actual intention is set to CAST and, if so, retrieves latest intention before the actual CAST and set it as the current intention for the player
*/
@Override
protected void onEvtFinishCasting()
{
if (getIntention() == AI_INTENTION_CAST)
{
// run interrupted or next intention
IntentionCommand nextIntention = _nextIntention;
if (nextIntention != null)
{
if (nextIntention._crtlIntention != AI_INTENTION_CAST) // previous state shouldn't be casting
{
setIntention(nextIntention._crtlIntention, nextIntention._arg0, nextIntention._arg1);
}
else
{
setIntention(AI_INTENTION_IDLE);
}
}
else
{
/*
* if (Config.DEBUG) _log.warning("L2PlayerAI: no previous intention set... Setting it to IDLE");
*/
// set intention to idle if skill doesn't change intention.
setIntention(AI_INTENTION_IDLE);
}
}
}
@Override
protected void onIntentionRest()
{
if (getIntention() != AI_INTENTION_REST)
{
changeIntention(AI_INTENTION_REST, null, null);
setTarget(null);
if (getAttackTarget() != null)
{
setAttackTarget(null);
}
clientStopMoving(null);
}
}
@Override
protected void onIntentionActive()
{
setIntention(AI_INTENTION_IDLE);
}
/**
* Manage the Move To Intention : Stop current Attack and Launch a Move to Location Task.<BR>
* <BR>
* <B><U> Actions</U> : </B><BR>
* <BR>
* <li>Stop the actor auto-attack server side AND client side by sending Server->Client packet AutoAttackStop (broadcast)</li> <li>Set the Intention of this AI to AI_INTENTION_MOVE_TO</li> <li>Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet
* CharMoveToLocation (broadcast)</li><BR>
* <BR>
*/
@Override
protected void onIntentionMoveTo(L2CharPosition pos)
{
if (getIntention() == AI_INTENTION_REST)
{
// Cancel action client side by sending Server->Client packet ActionFailed to the L2PcInstance actor
clientActionFailed();
return;
}
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow() || _actor.isAttackingNow())
{
clientActionFailed();
saveNextIntention(AI_INTENTION_MOVE_TO, pos, null);
return;
}
// Set the Intention of this AbstractAI to AI_INTENTION_MOVE_TO
changeIntention(AI_INTENTION_MOVE_TO, pos, null);
// Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop (broadcast)
clientStopAutoAttack();
// Abort the attack of the L2Character and send Server->Client ActionFailed packet
_actor.abortAttack();
// Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast)
moveTo(pos.x, pos.y, pos.z);
}
@Override
protected void clientNotifyDead()
{
_clientMovingToPawnOffset = 0;
_clientMoving = false;
super.clientNotifyDead();
}
private void thinkAttack()
{
L2Character target = getAttackTarget();
if (target == null)
{
return;
}
if (checkTargetLostOrDead(target))
{
// Notify the target
setAttackTarget(null);
return;
}
if (maybeMoveToPawn(target, _actor.getPhysicalAttackRange()))
{
return;
}
_accessor.doAttack(target);
}
private void thinkCast()
{
L2Character target = getCastTarget();
if (Config.DEBUG)
{
_log.warning("L2PlayerAI: thinkCast -> Start");
}
if ((_skill.getTargetType() == SkillTargetType.TARGET_GROUND) && (_actor instanceof L2PcInstance))
{
if (maybeMoveToPosition(((L2PcInstance) _actor).getCurrentSkillWorldPosition(), _actor.getMagicalAttackRange(_skill)))
{
_actor.setIsCastingNow(false);
return;
}
}
else
{
if (checkTargetLost(target))
{
if (_skill.isOffensive() && (getAttackTarget() != null))
{
// Notify the target
setCastTarget(null);
}
_actor.setIsCastingNow(false);
return;
}
if ((target != null) && maybeMoveToPawn(target, _actor.getMagicalAttackRange(_skill)))
{
_actor.setIsCastingNow(false);
return;
}
}
if ((_skill.getHitTime() > 50) && !_skill.isSimultaneousCast())
{
clientStopMoving(null);
}
L2Object oldTarget = _actor.getTarget();
if ((oldTarget != null) && (target != null) && (oldTarget != target))
{
// Replace the current target by the cast target
_actor.setTarget(getCastTarget());
// Launch the Cast of the skill
_accessor.doCast(_skill);
// Restore the initial target
_actor.setTarget(oldTarget);
}
else
{
_accessor.doCast(_skill);
}
}
private void thinkPickUp()
{
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
{
return;
}
L2Object target = getTarget();
if (checkTargetLost(target))
{
return;
}
if (maybeMoveToPawn(target, 36))
{
return;
}
setIntention(AI_INTENTION_IDLE);
((L2PcInstance.AIAccessor) _accessor).doPickupItem(target);
}
private void thinkInteract()
{
if (_actor.isAllSkillsDisabled() || _actor.isCastingNow())
{
return;
}
L2Object target = getTarget();
if (checkTargetLost(target))
{
return;
}
if (maybeMoveToPawn(target, 36))
{
return;
}
if (!(target instanceof L2StaticObjectInstance))
{
((L2PcInstance.AIAccessor) _accessor).doInteract((L2Character) target);
}
setIntention(AI_INTENTION_IDLE);
}
@Override
protected void onEvtThink()
{
if (_thinking && (getIntention() != AI_INTENTION_CAST))
{
return;
}
/*
* if (Config.DEBUG) _log.warning("L2PlayerAI: onEvtThink -> Check intention");
*/
_thinking = true;
try
{
if (getIntention() == AI_INTENTION_ATTACK)
{
thinkAttack();
}
else if (getIntention() == AI_INTENTION_CAST)
{
thinkCast();
}
else if (getIntention() == AI_INTENTION_PICK_UP)
{
thinkPickUp();
}
else if (getIntention() == AI_INTENTION_INTERACT)
{
thinkInteract();
}
}
finally
{
_thinking = false;
}
}
}
@@ -0,0 +1,940 @@
/*
* 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 com.l2jserver.gameserver.ai;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ACTIVE;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.concurrent.Future;
import com.l2jserver.Config;
import com.l2jserver.gameserver.GameTimeController;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.L2Effect;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.L2Playable;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.gameserver.model.actor.instance.L2DefenderInstance;
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jserver.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.templates.skills.L2SkillType;
import com.l2jserver.gameserver.util.Util;
import com.l2jserver.util.Rnd;
/**
* This class manages AI of L2Attackable.<BR>
* <BR>
*/
public class L2SiegeGuardAI extends L2CharacterAI implements Runnable
{
// protected static final Logger _log = Logger.getLogger(L2SiegeGuardAI.class.getName());
private static final int MAX_ATTACK_TIMEOUT = 300; // int ticks, i.e. 30 seconds
/** The L2Attackable AI task executed every 1s (call onEvtThink method) */
private Future<?> _aiTask;
/** For attack AI, analysis of mob and its targets */
private final SelfAnalysis _selfAnalysis = new SelfAnalysis();
// private TargetAnalysis _mostHatedAnalysis = new TargetAnalysis();
/** The delay after which the attacked is stopped */
private int _attackTimeout;
/** The L2Attackable aggro counter */
private int _globalAggro;
/** The flag used to indicate that a thinking action is in progress */
private boolean _thinking; // to prevent recursive thinking
private final int _attackRange;
/**
* Constructor of L2AttackableAI.<BR>
* <BR>
* @param accessor The AI accessor of the L2Character
*/
public L2SiegeGuardAI(L2Character.AIAccessor accessor)
{
super(accessor);
_selfAnalysis.init();
_attackTimeout = Integer.MAX_VALUE;
_globalAggro = -10; // 10 seconds timeout of ATTACK after respawn
_attackRange = ((L2Attackable) _actor).getPhysicalAttackRange();
}
@Override
public void run()
{
// Launch actions corresponding to the Event Think
onEvtThink();
}
/**
* Return True if the target is autoattackable (depends on the actor type).<BR>
* <BR>
* <B><U> Actor is a L2GuardInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk or a Door</li> <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li> <li>The target is in the actor Aggro range and is at the same height</li> <li>The L2PcInstance target has karma (=PK)</li> <li>The L2MonsterInstance
* target is aggressive</li><BR>
* <BR>
* <B><U> Actor is a L2SiegeGuardInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk or a Door</li> <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li> <li>The target is in the actor Aggro range and is at the same height</li> <li>A siege is in progress</li> <li>The L2PcInstance target isn't a Defender</li>
* <BR>
* <BR>
* <B><U> Actor is a L2FriendlyMobInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk, a Door or another L2NpcInstance</li> <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li> <li>The target is in the actor Aggro range and is at the same height</li> <li>The L2PcInstance target has karma (=PK)</li><BR>
* <BR>
* <B><U> Actor is a L2MonsterInstance</U> :</B><BR>
* <BR>
* <li>The target isn't a Folk, a Door or another L2NpcInstance</li> <li>The target isn't dead, isn't invulnerable, isn't in silent moving mode AND too far (>100)</li> <li>The target is in the actor Aggro range and is at the same height</li> <li>The actor is Aggressive</li><BR>
* <BR>
* @param target The targeted L2Object
*/
private boolean autoAttackCondition(L2Character target)
{
// Check if the target isn't another guard, folk or a door
if ((target == null) || (target instanceof L2DefenderInstance) || (target instanceof L2NpcInstance) || (target instanceof L2DoorInstance) || target.isAlikeDead())
{
return false;
}
// Check if the target isn't invulnerable
if (target.isInvul())
{
// However EffectInvincible requires to check GMs specially
if ((target instanceof L2PcInstance) && ((L2PcInstance) target).isGM())
{
return false;
}
if ((target instanceof L2Summon) && ((L2Summon) target).getOwner().isGM())
{
return false;
}
}
// Get the owner if the target is a summon
if (target instanceof L2Summon)
{
L2PcInstance owner = ((L2Summon) target).getOwner();
if (_actor.isInsideRadius(owner, 1000, true, false))
{
target = owner;
}
}
// Check if the target is a L2PcInstance
if (target instanceof L2Playable)
{
// Check if the target isn't in silent move mode AND too far (>100)
if (((L2Playable) target).isSilentMoving() && !_actor.isInsideRadius(target, 250, false, false))
{
return false;
}
}
// Los Check Here
return (_actor.isAutoAttackable(target) && GeoData.getInstance().canSeeTarget(_actor, target));
}
/**
* Set the Intention of this L2CharacterAI and create an AI Task executed every 1s (call onEvtThink method) for this L2Attackable.<BR>
* <BR>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : If actor _knowPlayer isn't EMPTY, AI_INTENTION_IDLE will be change in AI_INTENTION_ACTIVE</B></FONT><BR>
* <BR>
* @param intention The new Intention to set to the AI
* @param arg0 The first parameter of the Intention
* @param arg1 The second parameter of the Intention
*/
@Override
synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
{
if (Config.DEBUG)
{
_log.info("L2SiegeAI.changeIntention(" + intention + ", " + arg0 + ", " + arg1 + ")");
}
if (intention == AI_INTENTION_IDLE /* || intention == AI_INTENTION_ACTIVE */) // active becomes idle if only a summon is present
{
// Check if actor is not dead
if (!_actor.isAlikeDead())
{
L2Attackable npc = (L2Attackable) _actor;
// If its _knownPlayer isn't empty set the Intention to AI_INTENTION_ACTIVE
if (!npc.getKnownList().getKnownPlayers().isEmpty())
{
intention = AI_INTENTION_ACTIVE;
}
else
{
intention = AI_INTENTION_IDLE;
}
}
if (intention == AI_INTENTION_IDLE)
{
// Set the Intention of this L2AttackableAI to AI_INTENTION_IDLE
super.changeIntention(AI_INTENTION_IDLE, null, null);
// Stop AI task and detach AI from NPC
if (_aiTask != null)
{
_aiTask.cancel(true);
_aiTask = null;
}
// Cancel the AI
_accessor.detachAI();
return;
}
}
// Set the Intention of this L2AttackableAI to intention
super.changeIntention(intention, arg0, arg1);
// If not idle - create an AI task (schedule onEvtThink repeatedly)
if (_aiTask == null)
{
_aiTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 1000, 1000);
}
}
/**
* Manage the Attack Intention : Stop current Attack (if necessary), Calculate attack timeout, Start a new Attack and Launch Think Event.<BR>
* <BR>
* @param target The L2Character to attack
*/
@Override
protected void onIntentionAttack(L2Character target)
{
// Calculate the attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// Manage the Attack Intention : Stop current Attack (if necessary), Start a new Attack and Launch Think Event
// if (_actor.getTarget() != null)
super.onIntentionAttack(target);
}
/**
* Manage AI standard thinks of a L2Attackable (called by onEvtThink).<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Update every 1s the _globalAggro counter to come close to 0</li> <li>If the actor is Aggressive and can attack, add all autoAttackable L2Character in its Aggro Range to its _aggroList, chose a target and order to attack it</li> <li>If the actor can't attack, order to it to return to its
* home location</li>
*/
private void thinkActive()
{
L2Attackable npc = (L2Attackable) _actor;
// Update every 1s the _globalAggro counter to come close to 0
if (_globalAggro != 0)
{
if (_globalAggro < 0)
{
_globalAggro++;
}
else
{
_globalAggro--;
}
}
// Add all autoAttackable L2Character in L2Attackable Aggro Range to its _aggroList with 0 damage and 1 hate
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
for (L2Character target : npc.getKnownList().getKnownCharactersInRadius(_attackRange))
{
if (target == null)
{
continue;
}
if (autoAttackCondition(target)) // check aggression
{
// Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
int hating = npc.getHating(target);
// Add the attacker to the L2Attackable _aggroList with 0 damage and 1 hate
if (hating == 0)
{
npc.addDamageHate(target, 0, 1);
}
}
}
// Chose a target from its aggroList
L2Character hated;
if (_actor.isConfused())
{
hated = getAttackTarget(); // Force mobs to attack anybody if confused
}
else
{
hated = npc.getMostHated();
// _mostHatedAnalysis.Update(hated);
}
// Order to the L2Attackable to attack the target
if (hated != null)
{
// Get the hate level of the L2Attackable against this L2Character target contained in _aggroList
int aggro = npc.getHating(hated);
if ((aggro + _globalAggro) > 0)
{
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
// Set the AI Intention to AI_INTENTION_ATTACK
setIntention(CtrlIntention.AI_INTENTION_ATTACK, hated, null);
}
return;
}
}
// Order to the L2DefenderInstance to return to its home location because there's no target to attack
((L2DefenderInstance) _actor).returnHome();
}
/**
* Manage AI attack thinks of a L2Attackable (called by onEvtThink).<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Update the attack timeout if actor is running</li> <li>If target is dead or timeout is expired, stop this attack and set the Intention to AI_INTENTION_ACTIVE</li> <li>Call all L2Object of its Faction inside the Faction Range</li> <li>Chose a target and order to attack it with magic skill
* or physical attack</li><BR>
* <BR>
* TODO: Manage casting rules to healer mobs (like Ant Nurses)
*/
private void thinkAttack()
{
if (Config.DEBUG)
{
_log.info("L2SiegeGuardAI.thinkAttack(); timeout=" + (_attackTimeout - GameTimeController.getGameTicks()));
}
if (_attackTimeout < GameTimeController.getGameTicks())
{
// Check if the actor is running
if (_actor.isRunning())
{
// Set the actor movement type to walk and send Server->Client packet ChangeMoveType to all others L2PcInstance
_actor.setWalking();
// Calculate a new attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
}
}
L2Character attackTarget = getAttackTarget();
// Check if target is dead or if timeout is expired to stop this attack
if ((attackTarget == null) || attackTarget.isAlikeDead() || (_attackTimeout < GameTimeController.getGameTicks()))
{
// Stop hating this target after the attack timeout or if target is dead
if (attackTarget != null)
{
L2Attackable npc = (L2Attackable) _actor;
npc.stopHating(attackTarget);
}
// Cancel target and timeout
_attackTimeout = Integer.MAX_VALUE;
setAttackTarget(null);
// Set the AI Intention to AI_INTENTION_ACTIVE
setIntention(AI_INTENTION_ACTIVE, null, null);
_actor.setWalking();
return;
}
factionNotifyAndSupport();
attackPrepare();
}
private final void factionNotifyAndSupport()
{
L2Character target = getAttackTarget();
// Call all L2Object of its Faction inside the Faction Range
if ((((L2Npc) _actor).getFactionId() == null) || (target == null))
{
return;
}
if (target.isInvul())
{
return; // speeding it up for siege guards
}
String faction_id = ((L2Npc) _actor).getFactionId();
// Go through all L2Character that belong to its faction
// for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(((L2NpcInstance) _actor).getFactionRange()+_actor.getTemplate().collisionRadius))
for (L2Character cha : _actor.getKnownList().getKnownCharactersInRadius(1000))
{
if (cha == null)
{
continue;
}
if (!(cha instanceof L2Npc))
{
if (_selfAnalysis.hasHealOrResurrect && (cha instanceof L2PcInstance) && ((L2Npc) _actor).getCastle().getSiege().checkIsDefender(((L2PcInstance) cha).getClan()))
{
// heal friends
if (!_actor.isAttackingDisabled() && (cha.getCurrentHp() < (cha.getMaxHp() * 0.6)) && (_actor.getCurrentHp() > (_actor.getMaxHp() / 2)) && (_actor.getCurrentMp() > (_actor.getMaxMp() / 2)) && cha.isInCombat())
{
for (L2Skill sk : _selfAnalysis.healSkills)
{
if (_actor.getCurrentMp() < sk.getMpConsume())
{
continue;
}
if (_actor.isSkillDisabled(sk))
{
continue;
}
if (!Util.checkIfInRange(sk.getCastRange(), _actor, cha, true))
{
continue;
}
int chance = 5;
if (chance >= Rnd.get(100))
{
continue;
}
if (!GeoData.getInstance().canSeeTarget(_actor, cha))
{
break;
}
L2Object OldTarget = _actor.getTarget();
_actor.setTarget(cha);
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
}
continue;
}
L2Npc npc = (L2Npc) cha;
if (!faction_id.equals(npc.getFactionId()))
{
continue;
}
if (npc.getAI() != null) // TODO: possibly check not needed
{
if (!npc.isDead() && (Math.abs(target.getZ() - npc.getZ()) < 600)
// && _actor.getAttackByList().contains(getAttackTarget())
&& ((npc.getAI()._intention == CtrlIntention.AI_INTENTION_IDLE) || (npc.getAI()._intention == CtrlIntention.AI_INTENTION_ACTIVE))
// limiting aggro for siege guards
&& target.isInsideRadius(npc, 1500, true, false) && GeoData.getInstance().canSeeTarget(npc, target))
{
// Notify the L2Object AI with EVT_AGGRESSION
npc.getAI().notifyEvent(CtrlEvent.EVT_AGGRESSION, getAttackTarget(), 1);
return;
}
// heal friends
if (_selfAnalysis.hasHealOrResurrect && !_actor.isAttackingDisabled() && (npc.getCurrentHp() < (npc.getMaxHp() * 0.6)) && (_actor.getCurrentHp() > (_actor.getMaxHp() / 2)) && (_actor.getCurrentMp() > (_actor.getMaxMp() / 2)) && npc.isInCombat())
{
for (L2Skill sk : _selfAnalysis.healSkills)
{
if (_actor.getCurrentMp() < sk.getMpConsume())
{
continue;
}
if (_actor.isSkillDisabled(sk))
{
continue;
}
if (!Util.checkIfInRange(sk.getCastRange(), _actor, npc, true))
{
continue;
}
int chance = 4;
if (chance >= Rnd.get(100))
{
continue;
}
if (!GeoData.getInstance().canSeeTarget(_actor, npc))
{
break;
}
L2Object OldTarget = _actor.getTarget();
_actor.setTarget(npc);
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
}
}
}
private void attackPrepare()
{
// Get all information needed to choose between physical or magical attack
L2Skill[] skills = null;
double dist_2 = 0;
int range = 0;
L2DefenderInstance sGuard = (L2DefenderInstance) _actor;
L2Character attackTarget = getAttackTarget();
try
{
_actor.setTarget(attackTarget);
skills = _actor.getAllSkills();
dist_2 = _actor.getPlanDistanceSq(attackTarget.getX(), attackTarget.getY());
range = _actor.getPhysicalAttackRange() + _actor.getTemplate().collisionRadius + attackTarget.getTemplate().collisionRadius;
if (attackTarget.isMoving())
{
range += 50;
}
}
catch (NullPointerException e)
{
// _log.warning("AttackableAI: Attack target is NULL.");
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
// never attack defenders
if ((attackTarget instanceof L2PcInstance) && sGuard.getCastle().getSiege().checkIsDefender(((L2PcInstance) attackTarget).getClan()))
{
// Cancel the target
sGuard.stopHating(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
if (!GeoData.getInstance().canSeeTarget(_actor, attackTarget))
{
// Siege guards differ from normal mobs currently:
// If target cannot seen, don't attack any more
sGuard.stopHating(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
return;
}
// Check if the actor isn't muted and if it is far from target
if (!_actor.isMuted() && (dist_2 > (range * range)))
{
// check for long ranged skills and heal/buff skills
for (L2Skill sk : skills)
{
int castRange = sk.getCastRange();
if ((dist_2 <= (castRange * castRange)) && (castRange > 70) && !_actor.isSkillDisabled(sk) && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !sk.isPassive())
{
L2Object OldTarget = _actor.getTarget();
if ((sk.getSkillType() == L2SkillType.BUFF) || (sk.getSkillType() == L2SkillType.HEAL))
{
boolean useSkillSelf = true;
if ((sk.getSkillType() == L2SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
{
useSkillSelf = false;
break;
}
if (sk.getSkillType() == L2SkillType.BUFF)
{
L2Effect[] effects = _actor.getAllEffects();
for (int i = 0; (effects != null) && (i < effects.length); i++)
{
L2Effect effect = effects[i];
if (effect.getSkill() == sk)
{
useSkillSelf = false;
break;
}
}
}
if (useSkillSelf)
{
_actor.setTarget(_actor);
}
}
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
// Check if the L2SiegeGuardInstance is attacking, knows the target and can't run
if (!(_actor.isAttackingNow()) && (_actor.getRunSpeed() == 0) && (_actor.getKnownList().knowsObject(attackTarget)))
{
// Cancel the target
_actor.getKnownList().removeKnownObject(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
}
else
{
double dx = _actor.getX() - attackTarget.getX();
double dy = _actor.getY() - attackTarget.getY();
double dz = _actor.getZ() - attackTarget.getZ();
double homeX = attackTarget.getX() - sGuard.getSpawn().getLocx();
double homeY = attackTarget.getY() - sGuard.getSpawn().getLocy();
// Check if the L2SiegeGuardInstance isn't too far from it's home location
if ((((dx * dx) + (dy * dy)) > 10000) && (((homeX * homeX) + (homeY * homeY)) > 3240000) // 1800 * 1800
&& (_actor.getKnownList().knowsObject(attackTarget)))
{
// Cancel the target
_actor.getKnownList().removeKnownObject(attackTarget);
_actor.setTarget(null);
setIntention(AI_INTENTION_IDLE, null, null);
}
else
// Move the actor to Pawn server side AND client side by sending Server->Client packet MoveToPawn (broadcast)
{
// Temporary hack for preventing guards jumping off towers,
// before replacing this with effective geodata checks and AI modification
if ((dz * dz) < (170 * 170)) // normally 130 if guard z coordinates correct
{
if (_selfAnalysis.isHealer)
{
return;
}
if (_selfAnalysis.isMage)
{
range = _selfAnalysis.maxCastRange - 50;
}
if (attackTarget.isMoving())
{
moveToPawn(attackTarget, range - 70);
}
else
{
moveToPawn(attackTarget, range);
}
}
}
}
return;
}
// Else, if the actor is muted and far from target, just "move to pawn"
else if (_actor.isMuted() && (dist_2 > (range * range)) && !_selfAnalysis.isHealer)
{
// Temporary hack for preventing guards jumping off towers,
// before replacing this with effective geodata checks and AI modification
double dz = _actor.getZ() - attackTarget.getZ();
if ((dz * dz) < (170 * 170)) // normally 130 if guard z coordinates correct
{
if (_selfAnalysis.isMage)
{
range = _selfAnalysis.maxCastRange - 50;
}
if (attackTarget.isMoving())
{
moveToPawn(attackTarget, range - 70);
}
else
{
moveToPawn(attackTarget, range);
}
}
return;
}
// Else, if this is close enough to attack
else if (dist_2 <= (range * range))
{
// Force mobs to attack anybody if confused
L2Character hated = null;
if (_actor.isConfused())
{
hated = attackTarget;
}
else
{
hated = ((L2Attackable) _actor).getMostHated();
}
if (hated == null)
{
setIntention(AI_INTENTION_ACTIVE, null, null);
return;
}
if (hated != attackTarget)
{
attackTarget = hated;
}
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// check for close combat skills && heal/buff skills
if (!_actor.isMuted() && (Rnd.nextInt(100) <= 5))
{
for (L2Skill sk : skills)
{
int castRange = sk.getCastRange();
if (((castRange * castRange) >= dist_2) && !sk.isPassive() && (_actor.getCurrentMp() >= _actor.getStat().getMpConsume(sk)) && !_actor.isSkillDisabled(sk))
{
L2Object OldTarget = _actor.getTarget();
if ((sk.getSkillType() == L2SkillType.BUFF) || (sk.getSkillType() == L2SkillType.HEAL))
{
boolean useSkillSelf = true;
if ((sk.getSkillType() == L2SkillType.HEAL) && (_actor.getCurrentHp() > (int) (_actor.getMaxHp() / 1.5)))
{
useSkillSelf = false;
break;
}
if (sk.getSkillType() == L2SkillType.BUFF)
{
L2Effect[] effects = _actor.getAllEffects();
for (int i = 0; (effects != null) && (i < effects.length); i++)
{
L2Effect effect = effects[i];
if (effect.getSkill() == sk)
{
useSkillSelf = false;
break;
}
}
}
if (useSkillSelf)
{
_actor.setTarget(_actor);
}
}
clientStopMoving(null);
_accessor.doCast(sk);
_actor.setTarget(OldTarget);
return;
}
}
}
// Finally, do the physical attack itself
if (!_selfAnalysis.isHealer)
{
_accessor.doAttack(attackTarget);
}
}
}
/**
* Manage AI thinking actions of a L2Attackable.<BR>
* <BR>
*/
@Override
protected void onEvtThink()
{
// if(getIntention() != AI_INTENTION_IDLE && (!_actor.isVisible() || !_actor.hasAI() || !_actor.isKnownPlayers()))
// setIntention(AI_INTENTION_IDLE);
// Check if the thinking action is already in progress
if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
{
return;
}
// Start thinking action
_thinking = true;
try
{
// Manage AI thinks of a L2Attackable
if (getIntention() == AI_INTENTION_ACTIVE)
{
thinkActive();
}
else if (getIntention() == AI_INTENTION_ATTACK)
{
thinkAttack();
}
}
finally
{
// Stop thinking action
_thinking = false;
}
}
/**
* Launch actions corresponding to the Event Attacked.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Init the attack : Calculate the attack timeout, Set the _globalAggro to 0, Add the attacker to the actor _aggroList</li> <li>Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance</li> <li>Set the Intention to AI_INTENTION_ATTACK</li>
* <BR>
* <BR>
* @param attacker The L2Character that attacks the actor
*/
@Override
protected void onEvtAttacked(L2Character attacker)
{
// Calculate the attack timeout
_attackTimeout = MAX_ATTACK_TIMEOUT + GameTimeController.getGameTicks();
// Set the _globalAggro to 0 to permit attack even just after spawn
if (_globalAggro < 0)
{
_globalAggro = 0;
}
// Add the attacker to the _aggroList of the actor
((L2Attackable) _actor).addDamageHate(attacker, 0, 1);
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
// Set the Intention to AI_INTENTION_ATTACK
if (getIntention() != AI_INTENTION_ATTACK)
{
setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker, null);
}
super.onEvtAttacked(attacker);
}
/**
* Launch actions corresponding to the Event Aggression.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Add the target to the actor _aggroList or update hate if already present</li> <li>Set the actor Intention to AI_INTENTION_ATTACK (if actor is L2GuardInstance check if it isn't too far from its home location)</li><BR>
* <BR>
* @param attacker The L2Character that attacks
* @param aggro The value of hate to add to the actor against the target
*/
@Override
protected void onEvtAggression(L2Character target, int aggro)
{
if (_actor == null)
{
return;
}
L2Attackable me = (L2Attackable) _actor;
if (target != null)
{
// Add the target to the actor _aggroList or update hate if already present
me.addDamageHate(target, 0, aggro);
// Get the hate of the actor against the target
aggro = me.getHating(target);
if (aggro <= 0)
{
if (me.getMostHated() == null)
{
_globalAggro = -25;
me.clearAggroList();
setIntention(AI_INTENTION_IDLE, null, null);
}
return;
}
// Set the actor AI Intention to AI_INTENTION_ATTACK
if (getIntention() != CtrlIntention.AI_INTENTION_ATTACK)
{
// Set the L2Character movement type to run and send Server->Client packet ChangeMoveType to all others L2PcInstance
if (!_actor.isRunning())
{
_actor.setRunning();
}
L2DefenderInstance sGuard = (L2DefenderInstance) _actor;
double homeX = target.getX() - sGuard.getSpawn().getLocx();
double homeY = target.getY() - sGuard.getSpawn().getLocy();
// Check if the L2SiegeGuardInstance is not too far from its home location
if (((homeX * homeX) + (homeY * homeY)) < 3240000)
{
setIntention(CtrlIntention.AI_INTENTION_ATTACK, target, null);
}
}
}
else
{
// currently only for setting lower general aggro
if (aggro >= 0)
{
return;
}
L2Character mostHated = me.getMostHated();
if (mostHated == null)
{
_globalAggro = -25;
return;
}
for (L2Character aggroed : me.getAggroList().keySet())
{
me.addDamageHate(aggroed, 0, aggro);
}
aggro = me.getHating(mostHated);
if (aggro <= 0)
{
_globalAggro = -25;
me.clearAggroList();
setIntention(AI_INTENTION_IDLE, null, null);
}
}
}
@Override
public void stopAITask()
{
if (_aiTask != null)
{
_aiTask.cancel(false);
_aiTask = null;
}
_accessor.detachAI();
super.stopAITask();
}
}
@@ -0,0 +1,299 @@
/*
* 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 com.l2jserver.gameserver.ai;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_ATTACK;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_FOLLOW;
import static com.l2jserver.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import java.util.concurrent.Future;
import com.l2jserver.Config;
import com.l2jserver.gameserver.GeoData;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Character.AIAccessor;
import com.l2jserver.gameserver.model.actor.L2Summon;
import com.l2jserver.util.Rnd;
public class L2SummonAI extends L2PlayableAI implements Runnable
{
private static final int AVOID_RADIUS = 70;
private volatile boolean _thinking; // to prevent recursive thinking
private volatile boolean _startFollow = ((L2Summon) _actor).getFollowStatus();
private L2Character _lastAttack = null;
private volatile boolean _startAvoid = false;
private Future<?> _avoidTask = null;
public L2SummonAI(AIAccessor accessor)
{
super(accessor);
}
@Override
protected void onIntentionIdle()
{
stopFollow();
_startFollow = false;
onIntentionActive();
}
@Override
protected void onIntentionActive()
{
L2Summon summon = (L2Summon) _actor;
if (_startFollow)
{
setIntention(AI_INTENTION_FOLLOW, summon.getOwner());
}
else
{
super.onIntentionActive();
}
}
@Override
synchronized void changeIntention(CtrlIntention intention, Object arg0, Object arg1)
{
switch (intention)
{
case AI_INTENTION_ACTIVE:
case AI_INTENTION_FOLLOW:
startAvoidTask();
break;
default:
stopAvoidTask();
}
super.changeIntention(intention, arg0, arg1);
}
private void thinkAttack()
{
if (checkTargetLostOrDead(getAttackTarget()))
{
setAttackTarget(null);
return;
}
if (maybeMoveToPawn(getAttackTarget(), _actor.getPhysicalAttackRange()))
{
return;
}
clientStopMoving(null);
_accessor.doAttack(getAttackTarget());
}
private void thinkCast()
{
L2Summon summon = (L2Summon) _actor;
if (checkTargetLost(getCastTarget()))
{
setCastTarget(null);
return;
}
boolean val = _startFollow;
if (maybeMoveToPawn(getCastTarget(), _actor.getMagicalAttackRange(_skill)))
{
return;
}
clientStopMoving(null);
summon.setFollowStatus(false);
setIntention(AI_INTENTION_IDLE);
_startFollow = val;
_accessor.doCast(_skill);
}
private void thinkPickUp()
{
if (checkTargetLost(getTarget()))
{
return;
}
if (maybeMoveToPawn(getTarget(), 36))
{
return;
}
setIntention(AI_INTENTION_IDLE);
((L2Summon.AIAccessor) _accessor).doPickupItem(getTarget());
}
private void thinkInteract()
{
if (checkTargetLost(getTarget()))
{
return;
}
if (maybeMoveToPawn(getTarget(), 36))
{
return;
}
setIntention(AI_INTENTION_IDLE);
}
@Override
protected void onEvtThink()
{
if (_thinking || _actor.isCastingNow() || _actor.isAllSkillsDisabled())
{
return;
}
_thinking = true;
try
{
switch (getIntention())
{
case AI_INTENTION_ATTACK:
thinkAttack();
break;
case AI_INTENTION_CAST:
thinkCast();
break;
case AI_INTENTION_PICK_UP:
thinkPickUp();
break;
case AI_INTENTION_INTERACT:
thinkInteract();
break;
}
}
finally
{
_thinking = false;
}
}
@Override
protected void onEvtFinishCasting()
{
if (_lastAttack == null)
{
((L2Summon) _actor).setFollowStatus(_startFollow);
}
else
{
setIntention(CtrlIntention.AI_INTENTION_ATTACK, _lastAttack);
_lastAttack = null;
}
}
@Override
protected void onEvtAttacked(L2Character attacker)
{
super.onEvtAttacked(attacker);
avoidAttack(attacker);
}
@Override
protected void onEvtEvaded(L2Character attacker)
{
super.onEvtEvaded(attacker);
avoidAttack(attacker);
}
private void avoidAttack(L2Character attacker)
{
// trying to avoid if summon near owner
if ((((L2Summon) _actor).getOwner() != null) && (((L2Summon) _actor).getOwner() != attacker) && ((L2Summon) _actor).getOwner().isInsideRadius(_actor, 2 * AVOID_RADIUS, true, false))
{
_startAvoid = true;
}
}
@Override
public void run()
{
if (_startAvoid)
{
_startAvoid = false;
if (!_clientMoving && !_actor.isDead() && !_actor.isMovementDisabled())
{
final int ownerX = ((L2Summon) _actor).getOwner().getX();
final int ownerY = ((L2Summon) _actor).getOwner().getY();
final double angle = Math.toRadians(Rnd.get(-90, 90)) + Math.atan2(ownerY - _actor.getY(), ownerX - _actor.getX());
final int targetX = ownerX + (int) (AVOID_RADIUS * Math.cos(angle));
final int targetY = ownerY + (int) (AVOID_RADIUS * Math.sin(angle));
if ((Config.GEODATA == 0) || GeoData.getInstance().canMoveFromToTarget(_actor.getX(), _actor.getY(), _actor.getZ(), targetX, targetY, _actor.getZ(), _actor.getInstanceId()))
{
moveTo(targetX, targetY, _actor.getZ());
}
}
}
}
public void notifyFollowStatusChange()
{
_startFollow = !_startFollow;
switch (getIntention())
{
case AI_INTENTION_ACTIVE:
case AI_INTENTION_FOLLOW:
case AI_INTENTION_IDLE:
case AI_INTENTION_MOVE_TO:
case AI_INTENTION_PICK_UP:
((L2Summon) _actor).setFollowStatus(_startFollow);
}
}
public void setStartFollowController(boolean val)
{
_startFollow = val;
}
@Override
protected void onIntentionCast(L2Skill skill, L2Object target)
{
if (getIntention() == AI_INTENTION_ATTACK)
{
_lastAttack = getAttackTarget();
}
else
{
_lastAttack = null;
}
super.onIntentionCast(skill, target);
}
private void startAvoidTask()
{
if (_avoidTask == null)
{
_avoidTask = ThreadPoolManager.getInstance().scheduleAiAtFixedRate(this, 100, 100);
}
}
private void stopAvoidTask()
{
if (_avoidTask != null)
{
_avoidTask.cancel(false);
_avoidTask = null;
}
}
@Override
public void stopAITask()
{
stopAvoidTask();
super.stopAITask();
}
}
@@ -0,0 +1,121 @@
/*
* 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 com.l2jserver.gameserver.ai;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Vehicle;
public abstract class L2VehicleAI extends L2CharacterAI
{
/**
* @author DS Simple AI for vehicles
*/
public L2VehicleAI(L2Vehicle.AIAccessor accessor)
{
super(accessor);
}
@Override
protected void onIntentionAttack(L2Character target)
{
}
@Override
protected void onIntentionCast(L2Skill skill, L2Object target)
{
}
@Override
protected void onIntentionFollow(L2Character target)
{
}
@Override
protected void onIntentionPickUp(L2Object item)
{
}
@Override
protected void onIntentionInteract(L2Object object)
{
}
@Override
protected void onEvtAttacked(L2Character attacker)
{
}
@Override
protected void onEvtAggression(L2Character target, int aggro)
{
}
@Override
protected void onEvtStunned(L2Character attacker)
{
}
@Override
protected void onEvtSleeping(L2Character attacker)
{
}
@Override
protected void onEvtRooted(L2Character attacker)
{
}
@Override
protected void onEvtForgetObject(L2Object object)
{
}
@Override
protected void onEvtCancel()
{
}
@Override
protected void onEvtDead()
{
}
@Override
protected void onEvtFakeDeath()
{
}
@Override
protected void onEvtFinishCasting()
{
}
@Override
protected void clientActionFailed()
{
}
@Override
protected void moveToPawn(L2Object pawn, int offset)
{
}
@Override
protected void clientStoppedMoving()
{
}
}
@@ -0,0 +1,321 @@
/*
* 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 com.l2jserver.gameserver.cache;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.datatables.ClanTable;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.model.L2Clan;
/**
* @author Layane
*/
public class CrestCache
{
private static Logger _log = Logger.getLogger(CrestCache.class.getName());
private final FastMRUCache<Integer, byte[]> _cachePledge = new FastMRUCache<>();
private final FastMRUCache<Integer, byte[]> _cachePledgeLarge = new FastMRUCache<>();
private final FastMRUCache<Integer, byte[]> _cacheAlly = new FastMRUCache<>();
private int _loadedFiles;
private long _bytesBuffLen;
public static CrestCache getInstance()
{
return SingletonHolder._instance;
}
private CrestCache()
{
convertOldPedgeFiles();
reload();
}
public void reload()
{
FileFilter filter = new BmpFilter();
File dir = new File(Config.DATAPACK_ROOT, "data/crests/");
File[] files = dir.listFiles(filter);
byte[] content;
synchronized (this)
{
_loadedFiles = 0;
_bytesBuffLen = 0;
_cachePledge.clear();
_cachePledgeLarge.clear();
_cacheAlly.clear();
}
FastMap<Integer, byte[]> _mapPledge = _cachePledge.getContentMap();
FastMap<Integer, byte[]> _mapPledgeLarge = _cachePledgeLarge.getContentMap();
FastMap<Integer, byte[]> _mapAlly = _cacheAlly.getContentMap();
for (File file : files)
{
synchronized (this)
{
try (RandomAccessFile f = new RandomAccessFile(file, "r"))
{
content = new byte[(int) f.length()];
f.readFully(content);
if (file.getName().startsWith("Crest_Large_"))
{
_mapPledgeLarge.put(Integer.valueOf(file.getName().substring(12, file.getName().length() - 4)), content);
}
else if (file.getName().startsWith("Crest_"))
{
_mapPledge.put(Integer.valueOf(file.getName().substring(6, file.getName().length() - 4)), content);
}
else if (file.getName().startsWith("AllyCrest_"))
{
_mapAlly.put(Integer.valueOf(file.getName().substring(10, file.getName().length() - 4)), content);
}
_loadedFiles++;
_bytesBuffLen += content.length;
}
catch (Exception e)
{
_log.log(Level.WARNING, "Problem with crest bmp file " + e.getMessage(), e);
}
}
}
_log.info("Cache[Crest]: " + String.format("%.3f", getMemoryUsage()) + "MB on " + getLoadedFiles() + " files loaded. (Forget Time: " + (_cachePledge.getForgetTime() / 1000) + "s , Capacity: " + _cachePledge.capacity() + ")");
}
public void convertOldPedgeFiles()
{
File dir = new File(Config.DATAPACK_ROOT, "data/crests/");
File[] files = dir.listFiles(new OldPledgeFilter());
for (File file : files)
{
int clanId = Integer.parseInt(file.getName().substring(7, file.getName().length() - 4));
_log.info("Found old crest file \"" + file.getName() + "\" for clanId " + clanId);
int newId = IdFactory.getInstance().getNextId();
L2Clan clan = ClanTable.getInstance().getClan(clanId);
if (clan != null)
{
removeOldPledgeCrest(clan.getCrestId());
file.renameTo(new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + newId + ".bmp"));
_log.info("Renamed Clan crest to new format: Crest_" + newId + ".bmp");
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("UPDATE clan_data SET crest_id = ? WHERE clan_id = ?");
statement.setInt(1, newId);
statement.setInt(2, clan.getClanId());
statement.executeUpdate();
statement.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Could not update the crest id:" + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
clan.setCrestId(newId);
}
else
{
_log.info("Clan Id: " + clanId + " does not exist in table.. deleting.");
file.delete();
}
}
}
public float getMemoryUsage()
{
return ((float) _bytesBuffLen / 1048576);
}
public int getLoadedFiles()
{
return _loadedFiles;
}
public byte[] getPledgeCrest(int id)
{
return _cachePledge.get(id);
}
public byte[] getPledgeCrestLarge(int id)
{
return _cachePledgeLarge.get(id);
}
public byte[] getAllyCrest(int id)
{
return _cacheAlly.get(id);
}
public void removePledgeCrest(int id)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + id + ".bmp");
_cachePledge.remove(id);
try
{
crestFile.delete();
}
catch (Exception e)
{
}
}
public void removePledgeCrestLarge(int id)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_Large_" + id + ".bmp");
_cachePledgeLarge.remove(id);
try
{
crestFile.delete();
}
catch (Exception e)
{
}
}
public void removeOldPledgeCrest(int id)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Pledge_" + id + ".bmp");
try
{
crestFile.delete();
}
catch (Exception e)
{
}
}
public void removeAllyCrest(int id)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/AllyCrest_" + id + ".bmp");
_cacheAlly.remove(id);
try
{
crestFile.delete();
}
catch (Exception e)
{
}
}
public boolean savePledgeCrest(int newId, byte[] data)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_" + newId + ".bmp");
try (FileOutputStream out = new FileOutputStream(crestFile))
{
out.write(data);
_cachePledge.getContentMap().put(newId, data);
return true;
}
catch (IOException e)
{
_log.log(Level.INFO, "Error saving pledge crest" + crestFile + ":", e);
return false;
}
}
public boolean savePledgeCrestLarge(int newId, byte[] data)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/Crest_Large_" + newId + ".bmp");
try (FileOutputStream out = new FileOutputStream(crestFile))
{
out.write(data);
_cachePledgeLarge.getContentMap().put(newId, data);
return true;
}
catch (IOException e)
{
_log.log(Level.INFO, "Error saving Large pledge crest" + crestFile + ":", e);
return false;
}
}
public boolean saveAllyCrest(int newId, byte[] data)
{
File crestFile = new File(Config.DATAPACK_ROOT, "data/crests/AllyCrest_" + newId + ".bmp");
try (FileOutputStream out = new FileOutputStream(crestFile))
{
out.write(data);
_cacheAlly.getContentMap().put(newId, data);
return true;
}
catch (IOException e)
{
_log.log(Level.INFO, "Error saving ally crest" + crestFile + ":", e);
return false;
}
}
protected static class BmpFilter implements FileFilter
{
@Override
public boolean accept(File file)
{
return (file.getName().endsWith(".bmp"));
}
}
protected static class OldPledgeFilter implements FileFilter
{
@Override
public boolean accept(File file)
{
return (file.getName().startsWith("Pledge_"));
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final CrestCache _instance = new CrestCache();
}
}
@@ -0,0 +1,226 @@
/*
* 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 com.l2jserver.gameserver.cache;
import javolution.context.ObjectFactory;
import javolution.lang.Reusable;
import javolution.util.FastCollection;
import javolution.util.FastComparator;
import javolution.util.FastList;
import javolution.util.FastMap;
/**
* @author Layane
*/
@SuppressWarnings(
{
"rawtypes"
})
public class FastMRUCache<K, V> extends FastCollection implements Reusable
{
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
private static final int DEFAULT_CAPACITY = 50;
private static final int DEFAULT_FORGET_TIME = 300000; // 5 Minutes
private final FastMap<K, CacheNode> _cache = new FastMap<K, CacheNode>().setKeyComparator(FastComparator.DIRECT);
private FastMap<K, V> _map;
private final FastList<K> _mruList = new FastList<>();
private int _cacheSize;
private int _forgetTime;
class CacheNode
{
long _lastModified;
V _node;
public CacheNode(V object)
{
_lastModified = System.currentTimeMillis();
_node = object;
}
@Override
public boolean equals(Object object)
{
return _node == object;
}
}
/**
* Holds the set factory.
*/
private static final ObjectFactory FACTORY = new ObjectFactory()
{
@Override
public Object create()
{
return new FastMRUCache();
}
@Override
public void cleanup(Object obj)
{
((FastMRUCache) obj).reset();
}
};
/**
* Returns a set allocated from the stack when executing in a {@link javolution.realtime.PoolContext PoolContext}).
* @return a new, pre-allocated or recycled set instance.
*/
public static FastMRUCache newInstance()
{
return (FastMRUCache) FACTORY.object();
}
public FastMRUCache()
{
this(new FastMap<K, V>(), DEFAULT_CAPACITY, DEFAULT_FORGET_TIME);
}
public FastMRUCache(FastMap<K, V> map)
{
this(map, DEFAULT_CAPACITY, DEFAULT_FORGET_TIME);
}
public FastMRUCache(FastMap<K, V> map, int max)
{
this(map, max, DEFAULT_FORGET_TIME);
}
public FastMRUCache(FastMap<K, V> map, int max, int forgetTime)
{
_map = map;
_cacheSize = max;
_forgetTime = forgetTime;
_map.setKeyComparator(FastComparator.DIRECT);
}
// Implements Reusable.
@Override
public synchronized void reset()
{
_map.reset();
_cache.reset();
_mruList.reset();
_map.setKeyComparator(FastComparator.DIRECT);
_cache.setKeyComparator(FastComparator.DIRECT);
}
public synchronized V get(K key)
{
V result;
if (!_cache.containsKey(key))
{
if (_mruList.size() >= _cacheSize)
{
_cache.remove(_mruList.getLast());
_mruList.removeLast();
}
result = _map.get(key);
_cache.put(key, new CacheNode(result));
_mruList.addFirst(key);
}
else
{
CacheNode current = _cache.get(key);
if ((current._lastModified + _forgetTime) <= System.currentTimeMillis())
{
current._lastModified = System.currentTimeMillis();
current._node = _map.get(key);
_cache.put(key, current);
}
_mruList.remove(key);
_mruList.addFirst(key);
result = current._node;
}
return result;
}
@Override
public synchronized boolean remove(Object key)
{
_cache.remove(key);
_mruList.remove(key);
return _map.remove(key) == key;
}
public FastMap<K, V> getContentMap()
{
return _map;
}
@Override
public int size()
{
return _mruList.size();
}
public int capacity()
{
return _cacheSize;
}
public int getForgetTime()
{
return _forgetTime;
}
@Override
public synchronized void clear()
{
_cache.clear();
_mruList.clear();
_map.clear();
}
// Implements FastCollection abstract method.
@Override
public final Record head()
{
return _mruList.head();
}
@Override
public final Record tail()
{
return _mruList.tail();
}
@Override
public final Object valueOf(Record record)
{
return ((FastMap.Entry) record).getKey();
}
@Override
public final void delete(Record record)
{
remove(((FastMap.Entry) record).getKey());
}
}
@@ -0,0 +1,255 @@
/*
* 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 com.l2jserver.gameserver.cache;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.gameserver.util.Util;
/**
* @author Layane
*/
public class HtmCache
{
private static Logger _log = Logger.getLogger(HtmCache.class.getName());
private final Map<Integer, String> _cache;
private int _loadedFiles;
private long _bytesBuffLen;
public static HtmCache getInstance()
{
return SingletonHolder._instance;
}
private HtmCache()
{
if (Config.LAZY_CACHE)
{
_cache = new FastMap<Integer, String>().shared();
}
else
{
_cache = new FastMap<>();
}
reload();
}
public void reload()
{
reload(Config.DATAPACK_ROOT);
}
public void reload(File f)
{
if (!Config.LAZY_CACHE)
{
_log.info("Html cache start...");
parseDir(f);
_log.info("Cache[HTML]: " + String.format("%.3f", getMemoryUsage()) + " megabytes on " + getLoadedFiles() + " files loaded");
}
else
{
_cache.clear();
_loadedFiles = 0;
_bytesBuffLen = 0;
_log.info("Cache[HTML]: Running lazy cache");
}
}
public void reloadPath(File f)
{
parseDir(f);
_log.info("Cache[HTML]: Reloaded specified path.");
}
public double getMemoryUsage()
{
return ((float) _bytesBuffLen / 1048576);
}
public int getLoadedFiles()
{
return _loadedFiles;
}
protected static class HtmFilter implements FileFilter
{
@Override
public boolean accept(File file)
{
if (!file.isDirectory())
{
return (file.getName().endsWith(".htm") || file.getName().endsWith(".html"));
}
return true;
}
}
private void parseDir(File dir)
{
FileFilter filter = new HtmFilter();
File[] files = dir.listFiles(filter);
for (File file : files)
{
if (!file.isDirectory())
{
loadFile(file);
}
else
{
parseDir(file);
}
}
}
public String loadFile(File file)
{
final String relpath = Util.getRelativePath(Config.DATAPACK_ROOT, file);
final int hashcode = relpath.hashCode();
final HtmFilter filter = new HtmFilter();
if (file.exists() && filter.accept(file) && !file.isDirectory())
{
String content;
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis))
{
int bytes = bis.available();
byte[] raw = new byte[bytes];
bis.read(raw);
content = new String(raw, "UTF-8");
content = content.replaceAll("\r\n", "\n");
String oldContent = _cache.get(hashcode);
if (oldContent == null)
{
_bytesBuffLen += bytes;
_loadedFiles++;
}
else
{
_bytesBuffLen = (_bytesBuffLen - oldContent.length()) + bytes;
}
_cache.put(hashcode, content);
return content;
}
catch (Exception e)
{
_log.log(Level.WARNING, "Problem with htm file " + e.getMessage(), e);
}
}
return null;
}
public String getHtmForce(String prefix, String path)
{
String content = getHtm(prefix, path);
if (content == null)
{
content = "<html><body>My text is missing:<br>" + path + "</body></html>";
_log.warning("Cache[HTML]: Missing HTML page: " + path);
}
return content;
}
public String getHtm(String prefix, String path)
{
String newPath = null;
String content;
if ((prefix != null) && !prefix.isEmpty())
{
newPath = prefix + path;
content = getHtm(newPath);
if (content != null)
{
return content;
}
}
content = getHtm(path);
if ((content != null) && (newPath != null))
{
_cache.put(newPath.hashCode(), content);
}
return content;
}
private String getHtm(String path)
{
if ((path == null) || path.isEmpty())
{
return ""; // avoid possible NPE
}
final int hashCode = path.hashCode();
String content = _cache.get(hashCode);
if (Config.LAZY_CACHE && (content == null))
{
content = loadFile(new File(Config.DATAPACK_ROOT, path));
}
return content;
}
public boolean contains(String path)
{
return _cache.containsKey(path.hashCode());
}
/**
* Check if an HTM exists and can be loaded
* @param path The path to the HTM
*/
public boolean isLoadable(String path)
{
File file = new File(path);
HtmFilter filter = new HtmFilter();
if (file.exists() && filter.accept(file) && !file.isDirectory())
{
return true;
}
return false;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final HtmCache _instance = new HtmCache();
}
}
@@ -0,0 +1,75 @@
/*
* 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 com.l2jserver.gameserver.cache;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* @author -Nemesiss-
*/
public class WarehouseCacheManager
{
protected final FastMap<L2PcInstance, Long> _cachedWh;
protected final long _cacheTime;
public static WarehouseCacheManager getInstance()
{
return SingletonHolder._instance;
}
private WarehouseCacheManager()
{
_cacheTime = Config.WAREHOUSE_CACHE_TIME * 60000L; // 60*1000 = 60000
_cachedWh = new FastMap<L2PcInstance, Long>().shared();
ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new CacheScheduler(), 120000, 60000);
}
public void addCacheTask(L2PcInstance pc)
{
_cachedWh.put(pc, System.currentTimeMillis());
}
public void remCacheTask(L2PcInstance pc)
{
_cachedWh.remove(pc);
}
public class CacheScheduler implements Runnable
{
@Override
public void run()
{
long cTime = System.currentTimeMillis();
for (L2PcInstance pc : _cachedWh.keySet())
{
if ((cTime - _cachedWh.get(pc)) > _cacheTime)
{
pc.clearWarehouse();
_cachedWh.remove(pc);
}
}
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final WarehouseCacheManager _instance = new WarehouseCacheManager();
}
}
@@ -0,0 +1,299 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.BB;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.communitybbs.Manager.ForumsBBSManager;
import com.l2jserver.gameserver.communitybbs.Manager.TopicBBSManager;
public class Forum
{
// type
public static final int ROOT = 0;
public static final int NORMAL = 1;
public static final int CLAN = 2;
public static final int MEMO = 3;
public static final int MAIL = 4;
// perm
public static final int INVISIBLE = 0;
public static final int ALL = 1;
public static final int CLANMEMBERONLY = 2;
public static final int OWNERONLY = 3;
private static Logger _log = Logger.getLogger(Forum.class.getName());
private final List<Forum> _children;
private final Map<Integer, Topic> _topic;
private final int _forumId;
private String _forumName;
// private int _ForumParent;
private int _forumType;
private int _forumPost;
private int _forumPerm;
private final Forum _fParent;
private int _ownerID;
private boolean _loaded = false;
/**
* Creates new instance of Forum. When you create new forum, use {@link com.l2jserver.gameserver.communitybbs.Manager.ForumsBBSManager# addForum(com.l2jserver.gameserver.communitybbs.BB.Forum)} to add forum to the forums manager.
* @param i
*/
public Forum(int Forumid, Forum FParent)
{
_forumId = Forumid;
_fParent = FParent;
_children = new FastList<>();
_topic = new FastMap<>();
/*
* load(); getChildren();
*/
}
/**
* @param name
* @param parent
* @param type
* @param perm
*/
public Forum(String name, Forum parent, int type, int perm, int OwnerID)
{
_forumName = name;
_forumId = ForumsBBSManager.getInstance().getANewID();
// _ForumParent = parent.getID();
_forumType = type;
_forumPost = 0;
_forumPerm = perm;
_fParent = parent;
_ownerID = OwnerID;
_children = new FastList<>();
_topic = new FastMap<>();
parent._children.add(this);
ForumsBBSManager.getInstance().addForum(this);
_loaded = true;
}
/**
*
*/
private void load()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT * FROM forums WHERE forum_id=?");
statement.setInt(1, _forumId);
ResultSet result = statement.executeQuery();
if (result.next())
{
_forumName = result.getString("forum_name");
// _ForumParent = result.getInt("forum_parent");
_forumPost = result.getInt("forum_post");
_forumType = result.getInt("forum_type");
_forumPerm = result.getInt("forum_perm");
_ownerID = result.getInt("forum_owner_id");
}
result.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Data error on Forum " + _forumId + " : " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT * FROM topic WHERE topic_forum_id=? ORDER BY topic_id DESC");
statement.setInt(1, _forumId);
ResultSet result = statement.executeQuery();
while (result.next())
{
Topic t = new Topic(Topic.ConstructorType.RESTORE, result.getInt("topic_id"), result.getInt("topic_forum_id"), result.getString("topic_name"), result.getLong("topic_date"), result.getString("topic_ownername"), result.getInt("topic_ownerid"), result.getInt("topic_type"), result.getInt("topic_reply"));
_topic.put(t.getID(), t);
if (t.getID() > TopicBBSManager.getInstance().getMaxID(this))
{
TopicBBSManager.getInstance().setMaxID(t.getID(), this);
}
}
result.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Data error on Forum " + _forumId + " : " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
*
*/
private void getChildren()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT forum_id FROM forums WHERE forum_parent=?");
statement.setInt(1, _forumId);
ResultSet result = statement.executeQuery();
while (result.next())
{
Forum f = new Forum(result.getInt("forum_id"), this);
_children.add(f);
ForumsBBSManager.getInstance().addForum(f);
}
result.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Data error on Forum (children): " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public int getTopicSize()
{
vload();
return _topic.size();
}
public Topic getTopic(int j)
{
vload();
return _topic.get(j);
}
public void addTopic(Topic t)
{
vload();
_topic.put(t.getID(), t);
}
/**
* @return
*/
public int getID()
{
return _forumId;
}
public String getName()
{
vload();
return _forumName;
}
public int getType()
{
vload();
return _forumType;
}
/**
* @param name
* @return
*/
public Forum getChildByName(String name)
{
vload();
for (Forum f : _children)
{
if (f.getName().equals(name))
{
return f;
}
}
return null;
}
/**
* @param id
*/
public void rmTopicByID(int id)
{
_topic.remove(id);
}
/**
*
*/
public void insertIntoDb()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO forums (forum_id,forum_name,forum_parent,forum_post,forum_type,forum_perm,forum_owner_id) VALUES (?,?,?,?,?,?,?)");
statement.setInt(1, _forumId);
statement.setString(2, _forumName);
statement.setInt(3, _fParent.getID());
statement.setInt(4, _forumPost);
statement.setInt(5, _forumType);
statement.setInt(6, _forumPerm);
statement.setInt(7, _ownerID);
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while saving new Forum to db " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
*
*/
public void vload()
{
if (_loaded == false)
{
load();
getChildren();
_loaded = true;
}
}
}
@@ -0,0 +1,205 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.BB;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.communitybbs.Manager.PostBBSManager;
/**
* @author Maktakien
*/
public class Post
{
private static Logger _log = Logger.getLogger(Post.class.getName());
public static class CPost
{
public int postId;
public String postOwner;
public int postOwnerId;
public long postDate;
public int postTopicId;
public int postForumId;
public String postTxt;
}
private final List<CPost> _post;
/**
* @param restore
* @param t
*/
// public enum ConstructorType {REPLY, CREATE };
public Post(String _PostOwner, int _PostOwnerID, long date, int tid, int _PostForumID, String txt)
{
_post = new FastList<>();
CPost cp = new CPost();
cp.postId = 0;
cp.postOwner = _PostOwner;
cp.postOwnerId = _PostOwnerID;
cp.postDate = date;
cp.postTopicId = tid;
cp.postForumId = _PostForumID;
cp.postTxt = txt;
_post.add(cp);
insertindb(cp);
}
public void insertindb(CPost cp)
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO posts (post_id,post_owner_name,post_ownerid,post_date,post_topic_id,post_forum_id,post_txt) values (?,?,?,?,?,?,?)");
statement.setInt(1, cp.postId);
statement.setString(2, cp.postOwner);
statement.setInt(3, cp.postOwnerId);
statement.setLong(4, cp.postDate);
statement.setInt(5, cp.postTopicId);
statement.setInt(6, cp.postForumId);
statement.setString(7, cp.postTxt);
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while saving new Post to db " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public Post(Topic t)
{
_post = new FastList<>();
load(t);
}
public CPost getCPost(int id)
{
int i = 0;
for (CPost cp : _post)
{
if (i++ == id)
{
return cp;
}
}
return null;
}
public void deleteme(Topic t)
{
PostBBSManager.getInstance().delPostByTopic(t);
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM posts WHERE post_forum_id=? AND post_topic_id=?");
statement.setInt(1, t.getForumID());
statement.setInt(2, t.getID());
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while deleting post: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* @param t
*/
private void load(Topic t)
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT * FROM posts WHERE post_forum_id=? AND post_topic_id=? ORDER BY post_id ASC");
statement.setInt(1, t.getForumID());
statement.setInt(2, t.getID());
ResultSet result = statement.executeQuery();
while (result.next())
{
CPost cp = new CPost();
cp.postId = result.getInt("post_id");
cp.postOwner = result.getString("post_owner_name");
cp.postOwnerId = result.getInt("post_ownerid");
cp.postDate = result.getLong("post_date");
cp.postTopicId = result.getInt("post_topic_id");
cp.postForumId = result.getInt("post_forum_id");
cp.postTxt = result.getString("post_txt");
_post.add(cp);
}
result.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Data error on Post " + t.getForumID() + "/" + t.getID() + " : " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* @param i
*/
public void updatetxt(int i)
{
Connection con = null;
try
{
CPost cp = getCPost(i);
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("UPDATE posts SET post_txt=? WHERE post_id=? AND post_topic_id=? AND post_forum_id=?");
statement.setString(1, cp.postTxt);
statement.setInt(2, cp.postId);
statement.setInt(3, cp.postTopicId);
statement.setInt(4, cp.postForumId);
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while saving new Post to db " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
}
@@ -0,0 +1,170 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.BB;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.communitybbs.Manager.TopicBBSManager;
public class Topic
{
private static Logger _log = Logger.getLogger(Topic.class.getName());
public static final int MORMAL = 0;
public static final int MEMO = 1;
private final int _id;
private final int _forumId;
private final String _topicName;
private final long _date;
private final String _ownerName;
private final int _ownerId;
private final int _type;
private final int _cReply;
/**
* @param restaure
* @param i
* @param j
* @param string
* @param k
* @param string2
* @param l
* @param m
* @param n
*/
public Topic(ConstructorType ct, int id, int fid, String name, long date, String oname, int oid, int type, int Creply)
{
_id = id;
_forumId = fid;
_topicName = name;
_date = date;
_ownerName = oname;
_ownerId = oid;
_type = type;
_cReply = Creply;
TopicBBSManager.getInstance().addTopic(this);
if (ct == ConstructorType.CREATE)
{
insertindb();
}
}
/**
*
*/
public void insertindb()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO topic (topic_id,topic_forum_id,topic_name,topic_date,topic_ownername,topic_ownerid,topic_type,topic_reply) values (?,?,?,?,?,?,?,?)");
statement.setInt(1, _id);
statement.setInt(2, _forumId);
statement.setString(3, _topicName);
statement.setLong(4, _date);
statement.setString(5, _ownerName);
statement.setInt(6, _ownerId);
statement.setInt(7, _type);
statement.setInt(8, _cReply);
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while saving new Topic to db " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public enum ConstructorType
{
RESTORE,
CREATE
}
/**
* @return
*/
public int getID()
{
return _id;
}
public int getForumID()
{
return _forumId;
}
/**
* @return
*/
public String getName()
{
return _topicName;
}
public String getOwnerName()
{
return _ownerName;
}
/**
*
*/
public void deleteme(Forum f)
{
TopicBBSManager.getInstance().delTopic(this);
f.rmTopicByID(getID());
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM topic WHERE topic_id=? AND topic_forum_id=?");
statement.setInt(1, getID());
statement.setInt(2, f.getID());
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while deleting topic: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* @return
*/
public long getDate()
{
return _date;
}
}
@@ -0,0 +1,159 @@
/*
* 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 com.l2jserver.gameserver.communitybbs;
import com.l2jserver.Config;
import com.l2jserver.gameserver.communitybbs.Manager.ClanBBSManager;
import com.l2jserver.gameserver.communitybbs.Manager.PostBBSManager;
import com.l2jserver.gameserver.communitybbs.Manager.RegionBBSManager;
import com.l2jserver.gameserver.communitybbs.Manager.TopBBSManager;
import com.l2jserver.gameserver.communitybbs.Manager.TopicBBSManager;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.L2GameClient;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
public class CommunityBoard
{
private CommunityBoard()
{
}
public static CommunityBoard getInstance()
{
return SingletonHolder._instance;
}
public void handleCommands(L2GameClient client, String command)
{
L2PcInstance activeChar = client.getActiveChar();
if (activeChar == null)
{
return;
}
switch (Config.COMMUNITY_TYPE)
{
default:
case 0: // disabled
activeChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CB_OFFLINE));
break;
case 1: // old
RegionBBSManager.getInstance().parsecmd(command, activeChar);
break;
case 2: // new
if (command.startsWith("_bbsclan"))
{
ClanBBSManager.getInstance().parsecmd(command, activeChar);
}
else if (command.startsWith("_bbsmemo"))
{
TopicBBSManager.getInstance().parsecmd(command, activeChar);
}
else if (command.startsWith("_bbstopics"))
{
TopicBBSManager.getInstance().parsecmd(command, activeChar);
}
else if (command.startsWith("_bbsposts"))
{
PostBBSManager.getInstance().parsecmd(command, activeChar);
}
else if (command.startsWith("_bbstop"))
{
TopBBSManager.getInstance().parsecmd(command, activeChar);
}
else if (command.startsWith("_bbshome"))
{
TopBBSManager.getInstance().parsecmd(command, activeChar);
}
else if (command.startsWith("_bbsloc"))
{
RegionBBSManager.getInstance().parsecmd(command, activeChar);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the command: " + command + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
break;
}
}
/**
* @param client
* @param url
* @param arg1
* @param arg2
* @param arg3
* @param arg4
* @param arg5
*/
public void handleWriteCommands(L2GameClient client, String url, String arg1, String arg2, String arg3, String arg4, String arg5)
{
L2PcInstance activeChar = client.getActiveChar();
if (activeChar == null)
{
return;
}
switch (Config.COMMUNITY_TYPE)
{
case 2:
if (url.equals("Topic"))
{
TopicBBSManager.getInstance().parsewrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else if (url.equals("Post"))
{
PostBBSManager.getInstance().parsewrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else if (url.equals("Region"))
{
RegionBBSManager.getInstance().parsewrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else if (url.equals("Notice"))
{
ClanBBSManager.getInstance().parsewrite(arg1, arg2, arg3, arg4, arg5, activeChar);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the command: " + url + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
break;
case 1:
RegionBBSManager.getInstance().parsewrite(arg1, arg2, arg3, arg4, arg5, activeChar);
break;
default:
case 0:
ShowBoard sb = new ShowBoard("<html><body><br><br><center>The Community board is currently disabled</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
break;
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final CommunityBoard _instance = new CommunityBoard();
}
}
@@ -0,0 +1,77 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.Manager;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
public class AdminBBSManager extends BaseBBSManager
{
/**
* @return
*/
public static AdminBBSManager getInstance()
{
return SingletonHolder._instance;
}
private AdminBBSManager()
{
}
/**
* @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsecmd(java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
*/
@Override
public void parsecmd(String command, L2PcInstance activeChar)
{
if (!activeChar.isGM())
{
return;
}
if (command.startsWith("admin_bbs"))
{
separateAndSend("<html><body><br><br><center>This Page is only an exemple :)<br><br>command=" + command + "</center></body></html>", activeChar);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the command: " + command + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
/**
* @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsewrite(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
*/
@Override
public void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
if (!activeChar.isGM())
{
return;
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final AdminBBSManager _instance = new AdminBBSManager();
}
}
@@ -0,0 +1,105 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.Manager;
import java.util.List;
import javolution.util.FastList;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
public abstract class BaseBBSManager
{
public abstract void parsecmd(String command, L2PcInstance activeChar);
public abstract void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar);
protected void separateAndSend(String html, L2PcInstance acha)
{
if (html == null)
{
return;
}
if (html.length() < 4090)
{
acha.sendPacket(new ShowBoard(html, "101"));
acha.sendPacket(new ShowBoard(null, "102"));
acha.sendPacket(new ShowBoard(null, "103"));
}
else if (html.length() < 8180)
{
acha.sendPacket(new ShowBoard(html.substring(0, 4090), "101"));
acha.sendPacket(new ShowBoard(html.substring(4090, html.length()), "102"));
acha.sendPacket(new ShowBoard(null, "103"));
}
else if (html.length() < 12270)
{
acha.sendPacket(new ShowBoard(html.substring(0, 4090), "101"));
acha.sendPacket(new ShowBoard(html.substring(4090, 8180), "102"));
acha.sendPacket(new ShowBoard(html.substring(8180, html.length()), "103"));
}
}
/**
* @param html
*/
protected void send1001(String html, L2PcInstance acha)
{
if (html.length() < 8180)
{
acha.sendPacket(new ShowBoard(html, "1001"));
}
}
/**
* @param i
*/
protected void send1002(L2PcInstance acha)
{
send1002(acha, " ", " ", "0");
}
/**
* @param activeChar
* @param string
* @param string2
*/
protected void send1002(L2PcInstance activeChar, String string, String string2, String string3)
{
List<String> _arg = new FastList<>();
_arg.add("0");
_arg.add("0");
_arg.add("0");
_arg.add("0");
_arg.add("0");
_arg.add("0");
_arg.add(activeChar.getName());
_arg.add(Integer.toString(activeChar.getObjectId()));
_arg.add(activeChar.getAccountName());
_arg.add("9");
_arg.add(string2);
_arg.add(string2);
_arg.add(string);
_arg.add(string3);
_arg.add(string3);
_arg.add("0");
_arg.add("0");
activeChar.sendPacket(new ShowBoard(_arg));
}
}
@@ -0,0 +1,276 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.Manager;
import java.util.StringTokenizer;
import com.l2jserver.gameserver.datatables.ClanTable;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.util.StringUtil;
public class ClanBBSManager extends BaseBBSManager
{
private ClanBBSManager()
{
}
/**
* @return
*/
public static ClanBBSManager getInstance()
{
return SingletonHolder._instance;
}
/**
* @param command
* @param activeChar
*/
@Override
public void parsecmd(String command, L2PcInstance activeChar)
{
if (command.equals("_bbsclan"))
{
if ((activeChar.getClan() == null) || (activeChar.getClan().getLevel() < 2))
{
clanlist(activeChar, 1);
}
else
{
clanhome(activeChar);
}
}
else if (command.startsWith("_bbsclan_clanlist"))
{
if (command.equals("_bbsclan_clanlist"))
{
clanlist(activeChar, 1);
}
else if (command.startsWith("_bbsclan_clanlist;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
int index = Integer.parseInt(st.nextToken());
clanlist(activeChar, index);
}
}
else if (command.startsWith("_bbsclan_clanhome"))
{
if (command.equals("_bbsclan_clanhome"))
{
clanhome(activeChar);
}
else if (command.startsWith("_bbsclan_clanhome;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
int index = Integer.parseInt(st.nextToken());
clanhome(activeChar, index);
}
}
else if (command.startsWith("_bbsclan_clannotice_edit;"))
{
clanNotice(activeChar, activeChar.getClan().getClanId());
}
else if (command.startsWith("_bbsclan_clannotice_enable"))
{
activeChar.getClan().setNoticeEnabled(true);
clanNotice(activeChar, activeChar.getClan().getClanId());
}
else if (command.startsWith("_bbsclan_clannotice_disable"))
{
activeChar.getClan().setNoticeEnabled(false);
clanNotice(activeChar, activeChar.getClan().getClanId());
}
else
{
separateAndSend("<html><body><br><br><center>Command : " + command + " needs core development</center><br><br></body></html>", activeChar);
}
}
private void clanNotice(L2PcInstance activeChar, int clanId)
{
L2Clan cl = ClanTable.getInstance().getClan(clanId);
if (cl != null)
{
if (cl.getLevel() < 2)
{
activeChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.NO_CB_IN_MY_CLAN));
parsecmd("_bbsclan_clanlist", activeChar);
}
else
{
final StringBuilder html = StringUtil.startAppend(2000, "<html><body><br><br>" + "<table border=0 width=610><tr><td width=10></td><td width=600 align=left>" + "<a action=\"bypass _bbshome\">HOME</a> &gt; " + "<a action=\"bypass _bbsclan_clanlist\"> CLAN COMMUNITY </a> &gt; " + "<a action=\"bypass _bbsclan_clanhome;", String.valueOf(clanId), "\"> &amp;$802; </a>" + "</td></tr>" + "</table>");
if (activeChar.isClanLeader())
{
StringUtil.append(html, "<br><br><center>" + "<table width=610 border=0 cellspacing=0 cellpadding=0>" + "<tr><td fixwidth=610><font color=\"AAAAAA\">The Clan Notice function allows the clan leader to send messages through a pop-up window to clan members at login.</font> </td></tr>" + "<tr><td height=20></td></tr>");
if (activeChar.getClan().isNoticeEnabled())
{
StringUtil.append(html, "<tr><td fixwidth=610> Clan Notice Function:&nbsp;&nbsp;&nbsp;on&nbsp;&nbsp;&nbsp;/&nbsp;&nbsp;&nbsp;<a action=\"bypass _bbsclan_clannotice_disable\">off</a>");
}
else
{
StringUtil.append(html, "<tr><td fixwidth=610> Clan Notice Function:&nbsp;&nbsp;&nbsp;<a action=\"bypass _bbsclan_clannotice_enable\">on</a>&nbsp;&nbsp;&nbsp;/&nbsp;&nbsp;&nbsp;off");
}
StringUtil.append(html, "</td></tr>" + "</table>" + "<img src=\"L2UI.Squaregray\" width=\"610\" height=\"1\">" + "<br> <br>" + "<table width=610 border=0 cellspacing=2 cellpadding=0>" + "<tr><td>Edit Notice: </td></tr>" + "<tr><td height=5></td></tr>" + "<tr><td>" + "<MultiEdit var =\"Content\" width=610 height=100>" + "</td></tr>" + "</table>" + "<br>" + "<table width=610 border=0 cellspacing=0 cellpadding=0>" + "<tr><td height=5></td></tr>" + "<tr>" + "<td align=center FIXWIDTH=65><button value=\"&$140;\" action=\"Write Notice Set _ Content Content Content\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>" + "<td align=center FIXWIDTH=45></td>" + "<td align=center FIXWIDTH=500></td>" + "</tr>" + "</table>" + "</center>" + "</body>" + "</html>");
send1001(html.toString(), activeChar);
send1002(activeChar, activeChar.getClan().getNotice(), " ", "0");
}
else
{
StringUtil.append(html, "<img src=\"L2UI.squareblank\" width=\"1\" height=\"10\">" + "<center>" + "<table border=0 cellspacing=0 cellpadding=0><tr>" + "<td>You are not your clan's leader, and therefore cannot change the clan notice</td>" + "</tr></table>");
if (activeChar.getClan().isNoticeEnabled())
{
StringUtil.append(html, "<table border=0 cellspacing=0 cellpadding=0>" + "<tr>" + "<td>The current clan notice:</td>" + "</tr>" + "<tr><td fixwidth=5></td>" + "<td FIXWIDTH=600 align=left>" + activeChar.getClan().getNotice() + "</td>" + "<td fixqqwidth=5></td>" + "</tr>" + "</table>");
}
StringUtil.append(html, "</center>" + "</body>" + "</html>");
separateAndSend(html.toString(), activeChar);
}
}
}
}
/**
* @param activeChar
*/
private void clanlist(L2PcInstance activeChar, int index)
{
if (index < 1)
{
index = 1;
}
// header
final StringBuilder html = StringUtil.startAppend(2000, "<html><body><br><br><center>" + "<br1><br1><table border=0 cellspacing=0 cellpadding=0>" + "<tr><td FIXWIDTH=15>&nbsp;</td>" + "<td width=610 height=30 align=left>" + "<a action=\"bypass _bbsclan_clanlist\"> CLAN COMMUNITY </a>" + "</td></tr></table>" + "<table border=0 cellspacing=0 cellpadding=0 width=610 bgcolor=434343>" + "<tr><td height=10></td></tr>" + "<tr>" + "<td fixWIDTH=5></td>" + "<td fixWIDTH=600>" + "<a action=\"bypass _bbsclan_clanhome;", String.valueOf((activeChar.getClan() != null) ? activeChar.getClan().getClanId() : 0), "\">[GO TO MY CLAN]</a>&nbsp;&nbsp;" + "</td>" + "<td fixWIDTH=5></td>" + "</tr>" + "<tr><td height=10></td></tr>" + "</table>" + "<br>" + "<table border=0 cellspacing=0 cellpadding=2 bgcolor=5A5A5A width=610>" + "<tr>" + "<td FIXWIDTH=5></td>" + "<td FIXWIDTH=200 align=center>CLAN NAME</td>" + "<td FIXWIDTH=200 align=center>CLAN LEADER</td>" + "<td FIXWIDTH=100 align=center>CLAN LEVEL</td>" + "<td FIXWIDTH=100 align=center>CLAN MEMBERS</td>" + "<td FIXWIDTH=5></td>" + "</tr>" + "</table>" + "<img src=\"L2UI.Squareblank\" width=\"1\" height=\"5\">");
int i = 0;
for (L2Clan cl : ClanTable.getInstance().getClans())
{
if (i > ((index + 1) * 7))
{
break;
}
if (i++ >= ((index - 1) * 7))
{
StringUtil.append(html, "<img src=\"L2UI.SquareBlank\" width=\"610\" height=\"3\">" + "<table border=0 cellspacing=0 cellpadding=0 width=610>" + "<tr> " + "<td FIXWIDTH=5></td>" + "<td FIXWIDTH=200 align=center><a action=\"bypass _bbsclan_clanhome;", String.valueOf(cl.getClanId()), "\">", cl.getName(), "</a></td>" + "<td FIXWIDTH=200 align=center>", cl.getLeaderName(), "</td>" + "<td FIXWIDTH=100 align=center>", String.valueOf(cl.getLevel()), "</td>" + "<td FIXWIDTH=100 align=center>", String.valueOf(cl.getMembersCount()), "</td>" + "<td FIXWIDTH=5></td>" + "</tr>" + "<tr><td height=5></td></tr>" + "</table>" + "<img src=\"L2UI.SquareBlank\" width=\"610\" height=\"3\">" + "<img src=\"L2UI.SquareGray\" width=\"610\" height=\"1\">");
}
}
html.append("<img src=\"L2UI.SquareBlank\" width=\"610\" height=\"2\">" + "<table cellpadding=0 cellspacing=2 border=0><tr>");
if (index == 1)
{
html.append("<td><button action=\"\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16 ></td>");
}
else
{
StringUtil.append(html, "<td><button action=\"_bbsclan_clanlist;", String.valueOf(index - 1), "\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16 ></td>");
}
i = 0;
int nbp;
nbp = ClanTable.getInstance().getClans().length / 8;
if ((nbp * 8) != ClanTable.getInstance().getClans().length)
{
nbp++;
}
for (i = 1; i <= nbp; i++)
{
if (i == index)
{
StringUtil.append(html, "<td> ", String.valueOf(i), " </td>");
}
else
{
StringUtil.append(html, "<td><a action=\"bypass _bbsclan_clanlist;", String.valueOf(i), "\"> ", String.valueOf(i), " </a></td>");
}
}
if (index == nbp)
{
html.append("<td><button action=\"\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16 ></td>");
}
else
{
StringUtil.append(html, "<td><button action=\"bypass _bbsclan_clanlist;", String.valueOf(index + 1), "\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16 ></td>");
}
html.append("</tr></table>" + "<table border=0 cellspacing=0 cellpadding=0>" + "<tr><td width=610><img src=\"sek.cbui141\" width=\"610\" height=\"1\"></td></tr>" + "</table>" + "<table border=0><tr><td><combobox width=65 var=keyword list=\"Name;Ruler\"></td><td><edit var = \"Search\" width=130 height=11 length=\"16\"></td>" +
// TODO: search (Write in BBS)
"<td><button value=\"&$420;\" action=\"Write 5 -1 0 Search keyword keyword\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"> </td> </tr></table>" + "<br>" + "<br>" + "</center>" + "</body>" + "</html>");
separateAndSend(html.toString(), activeChar);
}
/**
* @param activeChar
*/
private void clanhome(L2PcInstance activeChar)
{
clanhome(activeChar, activeChar.getClan().getClanId());
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ClanBBSManager _instance = new ClanBBSManager();
}
/**
* @param activeChar
* @param clanId
*/
private void clanhome(L2PcInstance activeChar, int clanId)
{
L2Clan cl = ClanTable.getInstance().getClan(clanId);
if (cl != null)
{
if (cl.getLevel() < 2)
{
activeChar.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.NO_CB_IN_MY_CLAN));
parsecmd("_bbsclan_clanlist", activeChar);
}
else
{
final String html = StringUtil.concat("<html><body><center><br><br>" + "<br1><br1><table border=0 cellspacing=0 cellpadding=0>" + "<tr><td FIXWIDTH=15>&nbsp;</td>" + "<td width=610 height=30 align=left>" + "<a action=\"bypass _bbshome\">HOME</a> &gt; <a action=\"bypass _bbsclan_clanlist\"> CLAN COMMUNITY </a> &gt; <a action=\"bypass _bbsclan_clanhome;", String.valueOf(clanId), "\"> &amp;$802; </a>" + "</td></tr></table>" + "<table border=0 cellspacing=0 cellpadding=0 width=610 bgcolor=434343>" + "<tr><td height=10></td></tr>" + "<tr>" + "<td fixWIDTH=5></td>" + "<td fixwidth=600>" + "<a action=\"bypass _bbsclan_clanhome;", String.valueOf(clanId), ";announce\">[CLAN ANNOUNCEMENT]</a> <a action=\"bypass _bbsclan_clanhome;", String.valueOf(clanId), ";cbb\">[CLAN BULLETIN BOARD]</a>" + "<a action=\"bypass _bbsclan_clanhome;", String.valueOf(clanId), ";cmail\">[CLAN MAIL]</a>&nbsp;&nbsp;" + "<a action=\"bypass _bbsclan_clannotice_edit;", String.valueOf(clanId), ";cnotice\">[CLAN NOTICE]</a>&nbsp;&nbsp;" + "</td>" + "<td fixWIDTH=5></td>" + "</tr>" + "<tr><td height=10></td></tr>" + "</table>" + "<table border=0 cellspacing=0 cellpadding=0 width=610>" + "<tr><td height=10></td></tr>" + "<tr><td fixWIDTH=5></td>" + "<td fixwidth=290 valign=top>" + "</td>" + "<td fixWIDTH=5></td>" + "<td fixWIDTH=5 align=center valign=top><img src=\"l2ui.squaregray\" width=2 height=128></td>" + "<td fixWIDTH=5></td>" + "<td fixwidth=295>" + "<table border=0 cellspacing=0 cellpadding=0 width=295>" + "<tr>" + "<td fixWIDTH=100 align=left>CLAN NAME</td>" + "<td fixWIDTH=195 align=left>", cl.getName(), "</td>" + "</tr>" + "<tr><td height=7></td></tr>" + "<tr>" + "<td fixWIDTH=100 align=left>CLAN LEVEL</td>" + "<td fixWIDTH=195 align=left height=16>", String.valueOf(cl.getLevel()), "</td>" + "</tr>" + "<tr><td height=7></td></tr>" + "<tr>" + "<td fixWIDTH=100 align=left>CLAN MEMBERS</td>" + "<td fixWIDTH=195 align=left height=16>", String.valueOf(cl.getMembersCount()), "</td>" + "</tr>" + "<tr><td height=7></td></tr>" + "<tr>" + "<td fixWIDTH=100 align=left>CLAN LEADER</td>" + "<td fixWIDTH=195 align=left height=16>", cl.getLeaderName(), "</td>" + "</tr>" + "<tr><td height=7></td></tr>" +
// ADMINISTRATOR ??
/*
* html.append("<tr>"); html.append("<td fixWIDTH=100 align=left>ADMINISTRATOR</td>"); html.append("<td fixWIDTH=195 align=left height=16>"+cl.getLeaderName()+"</td>"); html.append("</tr>");
*/
"<tr><td height=7></td></tr>" + "<tr>" + "<td fixWIDTH=100 align=left>ALLIANCE</td>" + "<td fixWIDTH=195 align=left height=16>", (cl.getAllyName() != null) ? cl.getAllyName() : "", "</td>" + "</tr>" + "</table>" + "</td>" + "<td fixWIDTH=5></td>" + "</tr>" + "<tr><td height=10></td></tr>" + "</table>" +
// TODO: the BB for clan :)
// html.append("<table border=0 cellspacing=0 cellpadding=0 width=610 bgcolor=333333>");
"<img src=\"L2UI.squareblank\" width=\"1\" height=\"5\">" + "<img src=\"L2UI.squaregray\" width=\"610\" height=\"1\">" + "<br>" + "</center>" + "<br> <br>" + "</body>" + "</html>");
separateAndSend(html, activeChar);
}
}
}
@Override
public void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
if (ar1.equals("Set"))
{
activeChar.getClan().setNotice(ar4);
parsecmd("_bbsclan_clanhome;" + activeChar.getClan().getClanId(), activeChar);
}
}
}
@@ -0,0 +1,165 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.Manager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.communitybbs.BB.Forum;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
public class ForumsBBSManager extends BaseBBSManager
{
private static Logger _log = Logger.getLogger(ForumsBBSManager.class.getName());
private final List<Forum> _table;
private int _lastid = 1;
/**
* @return
*/
public static ForumsBBSManager getInstance()
{
return SingletonHolder._instance;
}
private ForumsBBSManager()
{
_table = new FastList<>();
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT forum_id FROM forums WHERE forum_type=0");
ResultSet result = statement.executeQuery();
while (result.next())
{
int forumId = result.getInt("forum_id");
Forum f = new Forum(forumId, null);
addForum(f);
}
result.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "Data error on Forum (root): " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public void initRoot()
{
for (Forum f : _table)
{
f.vload();
}
_log.info("Loaded " + _table.size() + " forums. Last forum id used: " + _lastid);
}
public void addForum(Forum ff)
{
if (ff == null)
{
return;
}
_table.add(ff);
if (ff.getID() > _lastid)
{
_lastid = ff.getID();
}
}
@Override
public void parsecmd(String command, L2PcInstance activeChar)
{
}
/**
* @param string
* @return
*/
public Forum getForumByName(String Name)
{
for (Forum f : _table)
{
if (f.getName().equals(Name))
{
return f;
}
}
return null;
}
/**
* @param name
* @param forumByName
* @return
*/
public Forum createNewForum(String name, Forum parent, int type, int perm, int oid)
{
Forum forum = new Forum(name, parent, type, perm, oid);
forum.insertIntoDb();
return forum;
}
/**
* @return
*/
public int getANewID()
{
return ++_lastid;
}
/**
* @param idf
* @return
*/
public Forum getForumByID(int idf)
{
for (Forum f : _table)
{
if (f.getID() == idf)
{
return f;
}
}
return null;
}
@Override
public void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ForumsBBSManager _instance = new ForumsBBSManager();
}
}
@@ -0,0 +1,282 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.Manager;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import javolution.util.FastMap;
import com.l2jserver.gameserver.communitybbs.BB.Forum;
import com.l2jserver.gameserver.communitybbs.BB.Post;
import com.l2jserver.gameserver.communitybbs.BB.Post.CPost;
import com.l2jserver.gameserver.communitybbs.BB.Topic;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
import com.l2jserver.util.StringUtil;
public class PostBBSManager extends BaseBBSManager
{
private final Map<Topic, Post> _postByTopic;
public static PostBBSManager getInstance()
{
return SingletonHolder._instance;
}
private PostBBSManager()
{
_postByTopic = new FastMap<>();
}
public Post getGPosttByTopic(Topic t)
{
Post post = null;
post = _postByTopic.get(t);
if (post == null)
{
post = load(t);
_postByTopic.put(t, post);
}
return post;
}
/**
* @param t
*/
public void delPostByTopic(Topic t)
{
_postByTopic.remove(t);
}
public void addPostByTopic(Post p, Topic t)
{
if (_postByTopic.get(t) == null)
{
_postByTopic.put(t, p);
}
}
/**
* @param t
* @return
*/
private Post load(Topic t)
{
Post p;
p = new Post(t);
return p;
}
/*
* (non-Javadoc)
* @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsecmd(java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
*/
@Override
public void parsecmd(String command, L2PcInstance activeChar)
{
if (command.startsWith("_bbsposts;read;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
int idp = Integer.parseInt(st.nextToken());
String index = null;
if (st.hasMoreTokens())
{
index = st.nextToken();
}
int ind = 0;
if (index == null)
{
ind = 1;
}
else
{
ind = Integer.parseInt(index);
}
showPost((TopicBBSManager.getInstance().getTopicByID(idp)), ForumsBBSManager.getInstance().getForumByID(idf), activeChar, ind);
}
else if (command.startsWith("_bbsposts;edit;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
int idt = Integer.parseInt(st.nextToken());
int idp = Integer.parseInt(st.nextToken());
showEditPost((TopicBBSManager.getInstance().getTopicByID(idt)), ForumsBBSManager.getInstance().getForumByID(idf), activeChar, idp);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the command: " + command + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
/**
* @param topic
* @param forumByID
* @param activeChar
* @param idp
*/
private void showEditPost(Topic topic, Forum forum, L2PcInstance activeChar, int idp)
{
Post p = getGPosttByTopic(topic);
if ((forum == null) || (topic == null) || (p == null))
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>Error, this forum, topic or post does not exit !</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
showHtmlEditPost(topic, activeChar, forum, p);
}
}
/**
* @param posttByTopic
* @param forumByID
* @param activeChar
* @param ind
* @param idf
*/
private void showPost(Topic topic, Forum forum, L2PcInstance activeChar, int ind)
{
if ((forum == null) || (topic == null))
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>Error, this forum is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else if (forum.getType() == Forum.MEMO)
{
showMemoPost(topic, activeChar, forum);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + forum.getName() + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
/**
* @param topic
* @param activeChar
* @param forum
* @param p
*/
private void showHtmlEditPost(Topic topic, L2PcInstance activeChar, Forum forum, Post p)
{
final String html = StringUtil.concat("<html>" + "<body><br><br>" + "<table border=0 width=610><tr><td width=10></td><td width=600 align=left>" + "<a action=\"bypass _bbshome\">HOME</a>&nbsp;>&nbsp;<a action=\"bypass _bbsmemo\">", forum.getName(), " Form</a>" + "</td></tr>" + "</table>" + "<img src=\"L2UI.squareblank\" width=\"1\" height=\"10\">" + "<center>" + "<table border=0 cellspacing=0 cellpadding=0>" + "<tr><td width=610><img src=\"sek.cbui355\" width=\"610\" height=\"1\"><br1><img src=\"sek.cbui355\" width=\"610\" height=\"1\"></td></tr>" + "</table>" + "<table fixwidth=610 border=0 cellspacing=0 cellpadding=0>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=20></td></tr>" + "<tr>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "<td align=center FIXWIDTH=60 height=29>&$413;</td>" + "<td FIXWIDTH=540>", topic.getName(), "</td>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "</tr></table>" + "<table fixwidth=610 border=0 cellspacing=0 cellpadding=0>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr>" + "<tr>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "<td align=center FIXWIDTH=60 height=29 valign=top>&$427;</td>" + "<td align=center FIXWIDTH=540><MultiEdit var =\"Content\" width=535 height=313></td>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "</tr>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr>" + "</table>" + "<table fixwidth=610 border=0 cellspacing=0 cellpadding=0>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr>" + "<tr>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "<td align=center FIXWIDTH=60 height=29>&nbsp;</td>" + "<td align=center FIXWIDTH=70><button value=\"&$140;\" action=\"Write Post ", String.valueOf(forum.getID()), ";", String.valueOf(topic.getID()), ";0 _ Content Content Content\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>" + "<td align=center FIXWIDTH=70><button value = \"&$141;\" action=\"bypass _bbsmemo\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"> </td>" + "<td align=center FIXWIDTH=400>&nbsp;</td>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "</tr></table>" + "</center>" + "</body>" + "</html>");
send1001(html, activeChar);
send1002(activeChar, p.getCPost(0).postTxt, topic.getName(), DateFormat.getInstance().format(new Date(topic.getDate())));
}
/**
* @param topic
* @param activeChar
* @param forum
*/
private void showMemoPost(Topic topic, L2PcInstance activeChar, Forum forum)
{
//
Post p = getGPosttByTopic(topic);
Locale locale = Locale.getDefault();
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.FULL, locale);
String mes = p.getCPost(0).postTxt.replace(">", "&gt;");
mes = mes.replace("<", "&lt;");
mes = mes.replace("\n", "<br1>");
final String html = StringUtil.concat("<html><body><br><br>" + "<table border=0 width=610><tr><td width=10></td><td width=600 align=left>" + "<a action=\"bypass _bbshome\">HOME</a>&nbsp;>&nbsp;<a action=\"bypass _bbsmemo\">Memo Form</a>" + "</td></tr>" + "</table>" + "<img src=\"L2UI.squareblank\" width=\"1\" height=\"10\">" + "<center>" + "<table border=0 cellspacing=0 cellpadding=0 bgcolor=333333>" + "<tr><td height=10></td></tr>" + "<tr>" + "<td fixWIDTH=55 align=right valign=top>&$413; : &nbsp;</td>" + "<td fixWIDTH=380 valign=top>", topic.getName(), "</td>" + "<td fixwidth=5></td>" + "<td fixwidth=50></td>" + "<td fixWIDTH=120></td>" + "</tr>" + "<tr><td height=10></td></tr>" + "<tr>" + "<td align=right><font color=\"AAAAAA\" >&$417; : &nbsp;</font></td>" + "<td><font color=\"AAAAAA\">", topic.getOwnerName() + "</font></td>" + "<td></td>" + "<td><font color=\"AAAAAA\">&$418; :</font></td>" + "<td><font color=\"AAAAAA\">", dateFormat.format(p.getCPost(0).postDate), "</font></td>" + "</tr>" + "<tr><td height=10></td></tr>" + "</table>" + "<br>" + "<table border=0 cellspacing=0 cellpadding=0>" + "<tr>" + "<td fixwidth=5></td>" + "<td FIXWIDTH=600 align=left>", mes, "</td>" + "<td fixqqwidth=5></td>" + "</tr>" + "</table>" + "<br>" + "<img src=\"L2UI.squareblank\" width=\"1\" height=\"5\">" + "<img src=\"L2UI.squaregray\" width=\"610\" height=\"1\">" + "<img src=\"L2UI.squareblank\" width=\"1\" height=\"5\">" + "<table border=0 cellspacing=0 cellpadding=0 FIXWIDTH=610>" + "<tr>" + "<td width=50>" + "<button value=\"&$422;\" action=\"bypass _bbsmemo\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\">" + "</td>" + "<td width=560 align=right><table border=0 cellspacing=0><tr>" + "<td FIXWIDTH=300></td><td><button value = \"&$424;\" action=\"bypass _bbsposts;edit;", String.valueOf(forum.getID()), ";", String.valueOf(topic.getID()), ";0\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>&nbsp;" + "<td><button value = \"&$425;\" action=\"bypass _bbstopics;del;", String.valueOf(forum.getID()), ";", String.valueOf(topic.getID()), "\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>&nbsp;" + "<td><button value = \"&$421;\" action=\"bypass _bbstopics;crea;", String.valueOf(forum.getID()), "\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>&nbsp;" + "</tr></table>" + "</td>" + "</tr>" + "</table>" + "<br>" + "<br>" + "<br></center>" + "</body>" + "</html>");
separateAndSend(html, activeChar);
}
/*
* (non-Javadoc)
* @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsewrite(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
*/
@Override
public void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
StringTokenizer st = new StringTokenizer(ar1, ";");
int idf = Integer.parseInt(st.nextToken());
int idt = Integer.parseInt(st.nextToken());
int idp = Integer.parseInt(st.nextToken());
Forum f = ForumsBBSManager.getInstance().getForumByID(idf);
if (f == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + idf + " does not exist !</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
Topic t = f.getTopic(idt);
if (t == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the topic: " + idt + " does not exist !</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
CPost cp = null;
Post p = getGPosttByTopic(t);
if (p != null)
{
cp = p.getCPost(idp);
}
if (cp == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the post: " + idp + " does not exist !</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
p.getCPost(idp).postTxt = ar4;
p.updatetxt(idp);
parsecmd("_bbsposts;read;" + f.getID() + ";" + t.getID(), activeChar);
}
}
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final PostBBSManager _instance = new PostBBSManager();
}
}
@@ -0,0 +1,545 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.Manager;
import java.util.Collections;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.gameserver.GameServer;
import com.l2jserver.gameserver.model.BlockList;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.base.Experience;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.clientpackets.Say2;
import com.l2jserver.gameserver.network.serverpackets.CreatureSay;
import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.util.StringUtil;
public class RegionBBSManager extends BaseBBSManager
{
private static Logger _logChat = Logger.getLogger("chat");
private RegionBBSManager()
{
}
/**
* @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsecmd(java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
*/
@Override
public void parsecmd(String command, L2PcInstance activeChar)
{
if (command.equals("_bbsloc"))
{
showOldCommunity(activeChar, 1);
}
else if (command.startsWith("_bbsloc;page;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int page = 0;
try
{
page = Integer.parseInt(st.nextToken());
}
catch (NumberFormatException nfe)
{
}
showOldCommunity(activeChar, page);
}
else if (command.startsWith("_bbsloc;playerinfo;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
String name = st.nextToken();
showOldCommunityPI(activeChar, name);
}
else
{
if (Config.COMMUNITY_TYPE == 1)
{
showOldCommunity(activeChar, 1);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the command: " + command + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
}
/**
* @param activeChar
* @param name
*/
private void showOldCommunityPI(L2PcInstance activeChar, String name)
{
final StringBuilder htmlCode = StringUtil.startAppend(1000, "<html><body><br>" + "<table border=0><tr><td FIXWIDTH=15></td><td align=center>L2J Community Board<img src=\"sek.cbui355\" width=610 height=1></td></tr><tr><td FIXWIDTH=15></td><td>");
L2PcInstance player = L2World.getInstance().getPlayer(name);
if (player != null)
{
String sex = "Male";
if (player.getAppearance().getSex())
{
sex = "Female";
}
String levelApprox = "low";
if (player.getLevel() >= 60)
{
levelApprox = "very high";
}
else if (player.getLevel() >= 40)
{
levelApprox = "high";
}
else if (player.getLevel() >= 20)
{
levelApprox = "medium";
}
StringUtil.append(htmlCode, "<table border=0><tr><td>", player.getName(), " (", sex, " ", player.getTemplate().className, "):</td></tr>" + "<tr><td>Level: ", levelApprox, "</td></tr>" + "<tr><td><br></td></tr>");
if ((activeChar != null) && (activeChar.isGM() || (player.getObjectId() == activeChar.getObjectId()) || Config.SHOW_LEVEL_COMMUNITYBOARD))
{
long nextLevelExp = 0;
long nextLevelExpNeeded = 0;
if (player.getLevel() < (Experience.MAX_LEVEL - 1))
{
nextLevelExp = Experience.LEVEL[player.getLevel() + 1];
nextLevelExpNeeded = nextLevelExp - player.getExp();
}
StringUtil.append(htmlCode, "<tr><td>Level: ", String.valueOf(player.getLevel()), "</td></tr>" + "<tr><td>Experience: ", String.valueOf(player.getExp()), "/", String.valueOf(nextLevelExp), "</td></tr>" + "<tr><td>Experience needed for level up: ", String.valueOf(nextLevelExpNeeded), "</td></tr>" + "<tr><td><br></td></tr>");
}
int uptime = (int) player.getUptime() / 1000;
int h = uptime / 3600;
int m = (uptime - (h * 3600)) / 60;
int s = ((uptime - (h * 3600)) - (m * 60));
StringUtil.append(htmlCode, "<tr><td>Uptime: ", String.valueOf(h), "h ", String.valueOf(m), "m ", String.valueOf(s), "s</td></tr>" + "<tr><td><br></td></tr>");
if (player.getClan() != null)
{
StringUtil.append(htmlCode, "<tr><td>Clan: ", player.getClan().getName(), "</td></tr>" + "<tr><td><br></td></tr>");
}
StringUtil.append(htmlCode, "<tr><td><multiedit var=\"pm\" width=240 height=40><button value=\"Send PM\" action=\"Write Region PM ", player.getName(), " pm pm pm\" width=110 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td></tr><tr><td><br><button value=\"Back\" action=\"bypass _bbsloc\" width=40 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td></tr></table>" + "</td></tr></table>" + "</body></html>");
separateAndSend(htmlCode.toString(), activeChar);
}
else
{
ShowBoard sb = new ShowBoard(StringUtil.concat("<html><body><br><br><center>No player with name ", name, "</center><br><br></body></html>"), "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
/**
* @param activeChar
*/
private void showOldCommunity(L2PcInstance activeChar, int page)
{
separateAndSend(getCommunityPage(page, activeChar.isGM() ? "gm" : "pl"), activeChar);
}
/*
* (non-Javadoc)
* @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsewrite(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
*/
@Override
public void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
if (activeChar == null)
{
return;
}
if (ar1.equals("PM"))
{
final StringBuilder htmlCode = StringUtil.startAppend(500, "<html><body><br>" + "<table border=0><tr><td FIXWIDTH=15></td><td align=center>L2J Community Board<img src=\"sek.cbui355\" width=610 height=1></td></tr><tr><td FIXWIDTH=15></td><td>");
try
{
L2PcInstance receiver = L2World.getInstance().getPlayer(ar2);
if (receiver == null)
{
StringUtil.append(htmlCode, "Player not found!<br><button value=\"Back\" action=\"bypass _bbsloc;playerinfo;", ar2, "\" width=40 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\">" + "</td></tr></table></body></html>");
separateAndSend(htmlCode.toString(), activeChar);
return;
}
if (Config.JAIL_DISABLE_CHAT && receiver.isInJail())
{
activeChar.sendMessage("Player is in jail.");
return;
}
if (receiver.isChatBanned())
{
activeChar.sendMessage("Player is chat banned.");
return;
}
if (activeChar.isInJail() && Config.JAIL_DISABLE_CHAT)
{
activeChar.sendMessage("You can not chat while in jail.");
return;
}
if (activeChar.isChatBanned())
{
activeChar.sendMessage("You are banned from using chat");
return;
}
if (Config.LOG_CHAT)
{
LogRecord record = new LogRecord(Level.INFO, ar3);
record.setLoggerName("chat");
record.setParameters(new Object[]
{
"TELL",
"[" + activeChar.getName() + " to " + receiver.getName() + "]"
});
_logChat.log(record);
}
CreatureSay cs = new CreatureSay(activeChar.getObjectId(), Say2.TELL, activeChar.getName(), ar3);
if (!receiver.isSilenceMode() && !BlockList.isBlocked(receiver, activeChar))
{
receiver.sendPacket(cs);
activeChar.sendPacket(new CreatureSay(activeChar.getObjectId(), Say2.TELL, "->" + receiver.getName(), ar3));
StringUtil.append(htmlCode, "Message Sent<br><button value=\"Back\" action=\"bypass _bbsloc;playerinfo;", receiver.getName(), "\" width=40 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\">" + "</td></tr></table></body></html>");
separateAndSend(htmlCode.toString(), activeChar);
}
else
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
activeChar.sendPacket(sm);
parsecmd("_bbsloc;playerinfo;" + receiver.getName(), activeChar);
}
}
catch (StringIndexOutOfBoundsException e)
{
// ignore
}
}
else
{
ShowBoard sb = new ShowBoard(StringUtil.concat("<html><body><br><br><center>the command: ", ar1, " is not implemented yet</center><br><br></body></html>"), "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
private int _onlineCount = 0;
private int _onlineCountGm = 0;
private static FastMap<Integer, FastList<L2PcInstance>> _onlinePlayers = new FastMap<Integer, FastList<L2PcInstance>>().shared();
private static FastMap<Integer, FastMap<String, String>> _communityPages = new FastMap<Integer, FastMap<String, String>>().shared();
/**
* @return
*/
public static RegionBBSManager getInstance()
{
return SingletonHolder._instance;
}
public/* synchronized */void changeCommunityBoard()
{
FastList<L2PcInstance> sortedPlayers = new FastList<>();
sortedPlayers.addAll(L2World.getInstance().getAllPlayers().values());
Collections.sort(sortedPlayers, (p1, p2) -> p1.getName().compareToIgnoreCase(p2.getName()));
_onlinePlayers.clear();
_onlineCount = 0;
_onlineCountGm = 0;
for (L2PcInstance player : sortedPlayers)
{
addOnlinePlayer(player);
}
_communityPages.clear();
writeCommunityPages();
}
private void addOnlinePlayer(L2PcInstance player)
{
boolean added = false;
for (FastList<L2PcInstance> page : _onlinePlayers.values())
{
if (page.size() < Config.NAME_PAGE_SIZE_COMMUNITYBOARD)
{
if (!page.contains(player))
{
page.add(player);
if (!player.getAppearance().getInvisible())
{
_onlineCount++;
}
_onlineCountGm++;
}
added = true;
break;
}
else if (page.contains(player))
{
added = true;
break;
}
}
if (!added)
{
FastList<L2PcInstance> temp = new FastList<>();
int page = _onlinePlayers.size() + 1;
if (temp.add(player))
{
_onlinePlayers.put(page, temp);
if (!player.getAppearance().getInvisible())
{
_onlineCount++;
}
_onlineCountGm++;
}
}
}
private void writeCommunityPages()
{
final StringBuilder htmlCode = new StringBuilder(2000);
final String tdClose = "</td>";
final String tdOpen = "<td align=left valign=top>";
final String trClose = "</tr>";
final String trOpen = "<tr>";
final String colSpacer = "<td FIXWIDTH=15></td>";
for (int page : _onlinePlayers.keySet())
{
FastMap<String, String> communityPage = new FastMap<>();
htmlCode.setLength(0);
StringUtil.append(htmlCode, "<html><body><br>" + "<table>" + trOpen + "<td align=left valign=top>Server Restarted: ", String.valueOf(GameServer.dateTimeServerStarted.getTime()), tdClose + trClose + "</table>" + "<table>" + trOpen + tdOpen + "XP Rate: x", String.valueOf(Config.RATE_XP), tdClose + colSpacer + tdOpen + "Party XP Rate: x", String.valueOf(Config.RATE_XP * Config.RATE_PARTY_XP), tdClose + colSpacer + tdOpen + "XP Exponent: ", String.valueOf(Config.ALT_GAME_EXPONENT_XP), tdClose + trClose + trOpen + tdOpen + "SP Rate: x", String.valueOf(Config.RATE_SP), tdClose + colSpacer + tdOpen + "Party SP Rate: x", String.valueOf(Config.RATE_SP * Config.RATE_PARTY_SP), tdClose + colSpacer + tdOpen + "SP Exponent: ", String.valueOf(Config.ALT_GAME_EXPONENT_SP), tdClose + trClose + trOpen + tdOpen + "Drop Rate: ", String.valueOf(Config.RATE_DROP_ITEMS), tdClose + colSpacer + tdOpen + "Spoil Rate: ", String.valueOf(Config.RATE_DROP_SPOIL), tdClose + colSpacer + tdOpen + "Adena Rate: ", String.valueOf(Config.RATE_DROP_ITEMS_ID.get(57)), tdClose + trClose + "</table>" + "<table>" + trOpen + "<td><img src=\"sek.cbui355\" width=600 height=1><br></td>" + trClose + trOpen + tdOpen, String.valueOf(L2World.getInstance().getAllVisibleObjectsCount()), " Object count</td>" + trClose + trOpen + tdOpen, String.valueOf(getOnlineCount("gm")), " Player(s) Online</td>" + trClose + "</table>");
int cell = 0;
if (Config.BBS_SHOW_PLAYERLIST)
{
htmlCode.append("<table border=0><tr><td><table border=0>");
for (L2PcInstance player : getOnlinePlayers(page))
{
cell++;
if (cell == 1)
{
htmlCode.append(trOpen);
}
StringUtil.append(htmlCode, "<td align=left valign=top FIXWIDTH=110><a action=\"bypass _bbsloc;playerinfo;", player.getName(), "\">");
if (player.isGM())
{
StringUtil.append(htmlCode, "<font color=\"LEVEL\">", player.getName(), "</font>");
}
else
{
htmlCode.append(player.getName());
}
htmlCode.append("</a></td>");
if (cell < Config.NAME_PER_ROW_COMMUNITYBOARD)
{
htmlCode.append(colSpacer);
}
if (cell == Config.NAME_PER_ROW_COMMUNITYBOARD)
{
cell = 0;
htmlCode.append(trClose);
}
}
if ((cell > 0) && (cell < Config.NAME_PER_ROW_COMMUNITYBOARD))
{
htmlCode.append(trClose);
}
htmlCode.append("</table><br></td></tr>" + trOpen + "<td><img src=\"sek.cbui355\" width=600 height=1><br></td>" + trClose + "</table>");
}
if (getOnlineCount("gm") > Config.NAME_PAGE_SIZE_COMMUNITYBOARD)
{
htmlCode.append("<table border=0 width=600><tr>");
if (page == 1)
{
htmlCode.append("<td align=right width=190><button value=\"Prev\" width=50 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
else
{
StringUtil.append(htmlCode, "<td align=right width=190><button value=\"Prev\" action=\"bypass _bbsloc;page;", String.valueOf(page - 1), "\" width=50 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
StringUtil.append(htmlCode, "<td FIXWIDTH=10></td>" + "<td align=center valign=top width=200>Displaying ", String.valueOf(((page - 1) * Config.NAME_PAGE_SIZE_COMMUNITYBOARD) + 1), " - ", String.valueOf(((page - 1) * Config.NAME_PAGE_SIZE_COMMUNITYBOARD) + getOnlinePlayers(page).size()), " player(s)</td>" + "<td FIXWIDTH=10></td>");
if (getOnlineCount("gm") <= (page * Config.NAME_PAGE_SIZE_COMMUNITYBOARD))
{
htmlCode.append("<td width=190><button value=\"Next\" width=50 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
else
{
StringUtil.append(htmlCode, "<td width=190><button value=\"Next\" action=\"bypass _bbsloc;page;", String.valueOf(page + 1), "\" width=50 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
htmlCode.append("</tr></table>");
}
htmlCode.append("</body></html>");
communityPage.put("gm", htmlCode.toString());
htmlCode.setLength(0);
StringUtil.append(htmlCode, "<html><body><br>" + "<table>" + trOpen + "<td align=left valign=top>Server Restarted: ", String.valueOf(GameServer.dateTimeServerStarted.getTime()), tdClose + trClose + "</table>" + "<table>" + trOpen + tdOpen + "XP Rate: ", String.valueOf(Config.RATE_XP), tdClose + colSpacer + tdOpen + "Party XP Rate: ", String.valueOf(Config.RATE_PARTY_XP), tdClose + colSpacer + tdOpen + "XP Exponent: ", String.valueOf(Config.ALT_GAME_EXPONENT_XP), tdClose + trClose + trOpen + tdOpen + "SP Rate: ", String.valueOf(Config.RATE_SP), tdClose + colSpacer + tdOpen + "Party SP Rate: ", String.valueOf(Config.RATE_PARTY_SP), tdClose + colSpacer + tdOpen + "SP Exponent: ", String.valueOf(Config.ALT_GAME_EXPONENT_SP), tdClose + trClose + trOpen + tdOpen + "Drop Rate: ", String.valueOf(Config.RATE_DROP_ITEMS), tdClose + colSpacer + tdOpen + "Spoil Rate: ", String.valueOf(Config.RATE_DROP_SPOIL), tdClose + colSpacer + tdOpen + "Adena Rate: ", String.valueOf(Config.RATE_DROP_ITEMS_ID.get(57)), tdClose + trClose + "</table>" + "<table>" + trOpen + "<td><img src=\"sek.cbui355\" width=600 height=1><br></td>" + trClose + trOpen + tdOpen, String.valueOf(getOnlineCount("pl")), " Player(s) Online</td>" + trClose + "</table>");
if (Config.BBS_SHOW_PLAYERLIST)
{
htmlCode.append("<table border=0><tr><td><table border=0>");
cell = 0;
for (L2PcInstance player : getOnlinePlayers(page))
{
if ((player == null) || (player.getAppearance().getInvisible()))
{
continue; // Go to next
}
cell++;
if (cell == 1)
{
htmlCode.append(trOpen);
}
StringUtil.append(htmlCode, "<td align=left valign=top FIXWIDTH=110><a action=\"bypass _bbsloc;playerinfo;", player.getName(), "\">");
if (player.isGM())
{
StringUtil.append(htmlCode, "<font color=\"LEVEL\">", player.getName(), "</font>");
}
else
{
htmlCode.append(player.getName());
}
htmlCode.append("</a></td>");
if (cell < Config.NAME_PER_ROW_COMMUNITYBOARD)
{
htmlCode.append(colSpacer);
}
if (cell == Config.NAME_PER_ROW_COMMUNITYBOARD)
{
cell = 0;
htmlCode.append(trClose);
}
}
if ((cell > 0) && (cell < Config.NAME_PER_ROW_COMMUNITYBOARD))
{
htmlCode.append(trClose);
}
htmlCode.append("</table><br></td></tr>" + trOpen + "<td><img src=\"sek.cbui355\" width=600 height=1><br></td>" + trClose + "</table>");
}
if (getOnlineCount("pl") > Config.NAME_PAGE_SIZE_COMMUNITYBOARD)
{
htmlCode.append("<table border=0 width=600><tr>");
if (page == 1)
{
htmlCode.append("<td align=right width=190><button value=\"Prev\" width=50 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
else
{
StringUtil.append(htmlCode, "<td align=right width=190><button value=\"Prev\" action=\"bypass _bbsloc;page;", String.valueOf(page - 1), "\" width=50 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
StringUtil.append(htmlCode, "<td FIXWIDTH=10></td>" + "<td align=center valign=top width=200>Displaying ", String.valueOf(((page - 1) * Config.NAME_PAGE_SIZE_COMMUNITYBOARD) + 1), " - ", String.valueOf(((page - 1) * Config.NAME_PAGE_SIZE_COMMUNITYBOARD) + getOnlinePlayers(page).size()), " player(s)</td>" + "<td FIXWIDTH=10></td>");
if (getOnlineCount("pl") <= (page * Config.NAME_PAGE_SIZE_COMMUNITYBOARD))
{
htmlCode.append("<td width=190><button value=\"Next\" width=50 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
else
{
StringUtil.append(htmlCode, "<td width=190><button value=\"Next\" action=\"bypass _bbsloc;page;", String.valueOf(page + 1), "\" width=50 height=15 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
htmlCode.append("</tr></table>");
}
htmlCode.append("</body></html>");
communityPage.put("pl", htmlCode.toString());
_communityPages.put(page, communityPage);
}
}
private int getOnlineCount(String type)
{
if (type.equalsIgnoreCase("gm"))
{
return _onlineCountGm;
}
return _onlineCount;
}
private FastList<L2PcInstance> getOnlinePlayers(int page)
{
return _onlinePlayers.get(page);
}
public String getCommunityPage(int page, String type)
{
if (_communityPages.get(page) != null)
{
return _communityPages.get(page).get(type);
}
return null;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final RegionBBSManager _instance = new RegionBBSManager();
}
}
@@ -0,0 +1,86 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.Manager;
import java.util.StringTokenizer;
import com.l2jserver.gameserver.cache.HtmCache;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
public class TopBBSManager extends BaseBBSManager
{
private TopBBSManager()
{
}
@Override
public void parsecmd(String command, L2PcInstance activeChar)
{
if (command.equals("_bbstop"))
{
String content = HtmCache.getInstance().getHtm(activeChar.getHtmlPrefix(), "data/html/CommunityBoard/index.htm");
if (content == null)
{
content = "<html><body><br><br><center>404 :File not found: 'data/html/CommunityBoard/index.htm' </center></body></html>";
}
separateAndSend(content, activeChar);
}
else if (command.equals("_bbshome"))
{
String content = HtmCache.getInstance().getHtm(activeChar.getHtmlPrefix(), "data/html/CommunityBoard/index.htm");
if (content == null)
{
content = "<html><body><br><br><center>404 :File not found: 'data/html/CommunityBoard/index.htm' </center></body></html>";
}
separateAndSend(content, activeChar);
}
else if (command.startsWith("_bbstop;"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
int idp = Integer.parseInt(st.nextToken());
String content = HtmCache.getInstance().getHtm(activeChar.getHtmlPrefix(), "data/html/CommunityBoard/" + idp + ".htm");
if (content == null)
{
content = "<html><body><br><br><center>404 :File not found: 'data/html/CommunityBoard/" + idp + ".htm' </center></body></html>";
}
separateAndSend(content, activeChar);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the command: " + command + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
@Override
public void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
}
public static TopBBSManager getInstance()
{
return SingletonHolder._instance;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final TopBBSManager _instance = new TopBBSManager();
}
}
@@ -0,0 +1,383 @@
/*
* 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 com.l2jserver.gameserver.communitybbs.Manager;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.gameserver.communitybbs.BB.Forum;
import com.l2jserver.gameserver.communitybbs.BB.Post;
import com.l2jserver.gameserver.communitybbs.BB.Topic;
import com.l2jserver.gameserver.datatables.ClanTable;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.serverpackets.ShowBoard;
import com.l2jserver.util.StringUtil;
public class TopicBBSManager extends BaseBBSManager
{
private final List<Topic> _table;
private final Map<Forum, Integer> _maxId;
public static TopicBBSManager getInstance()
{
return SingletonHolder._instance;
}
private TopicBBSManager()
{
_table = new FastList<>();
_maxId = new FastMap<Forum, Integer>().shared();
}
public void addTopic(Topic tt)
{
_table.add(tt);
}
/**
* @param topic
*/
public void delTopic(Topic topic)
{
_table.remove(topic);
}
public void setMaxID(int id, Forum f)
{
_maxId.put(f, id);
}
public int getMaxID(Forum f)
{
Integer i = _maxId.get(f);
if (i == null)
{
return 0;
}
return i;
}
public Topic getTopicByID(int idf)
{
for (Topic t : _table)
{
if (t.getID() == idf)
{
return t;
}
}
return null;
}
/**
* @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsewrite(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
*/
@Override
public void parsewrite(String ar1, String ar2, String ar3, String ar4, String ar5, L2PcInstance activeChar)
{
if (ar1.equals("crea"))
{
Forum f = ForumsBBSManager.getInstance().getForumByID(Integer.parseInt(ar2));
if (f == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + ar2 + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
f.vload();
Topic t = new Topic(Topic.ConstructorType.CREATE, TopicBBSManager.getInstance().getMaxID(f) + 1, Integer.parseInt(ar2), ar5, Calendar.getInstance().getTimeInMillis(), activeChar.getName(), activeChar.getObjectId(), Topic.MEMO, 0);
f.addTopic(t);
TopicBBSManager.getInstance().setMaxID(t.getID(), f);
Post p = new Post(activeChar.getName(), activeChar.getObjectId(), Calendar.getInstance().getTimeInMillis(), t.getID(), f.getID(), ar4);
PostBBSManager.getInstance().addPostByTopic(p, t);
parsecmd("_bbsmemo", activeChar);
}
}
else if (ar1.equals("del"))
{
Forum f = ForumsBBSManager.getInstance().getForumByID(Integer.parseInt(ar2));
if (f == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + ar2 + " does not exist !</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
Topic t = f.getTopic(Integer.parseInt(ar3));
if (t == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the topic: " + ar3 + " does not exist !</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
// CPost cp = null;
Post p = PostBBSManager.getInstance().getGPosttByTopic(t);
if (p != null)
{
p.deleteme(t);
}
t.deleteme(f);
parsecmd("_bbsmemo", activeChar);
}
}
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the command: " + ar1 + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
/**
* @see com.l2jserver.gameserver.communitybbs.Manager.BaseBBSManager#parsecmd(java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance)
*/
@Override
public void parsecmd(String command, L2PcInstance activeChar)
{
if (command.equals("_bbsmemo"))
{
showTopics(activeChar.getMemo(), activeChar, 1, activeChar.getMemo().getID());
}
else if (command.startsWith("_bbstopics;read"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
String index = null;
if (st.hasMoreTokens())
{
index = st.nextToken();
}
int ind = 0;
if (index == null)
{
ind = 1;
}
else
{
ind = Integer.parseInt(index);
}
showTopics(ForumsBBSManager.getInstance().getForumByID(idf), activeChar, ind, idf);
}
else if (command.startsWith("_bbstopics;crea"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
showNewTopic(ForumsBBSManager.getInstance().getForumByID(idf), activeChar, idf);
}
else if (command.startsWith("_bbstopics;del"))
{
StringTokenizer st = new StringTokenizer(command, ";");
st.nextToken();
st.nextToken();
int idf = Integer.parseInt(st.nextToken());
int idt = Integer.parseInt(st.nextToken());
Forum f = ForumsBBSManager.getInstance().getForumByID(idf);
if (f == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + idf + " does not exist !</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
Topic t = f.getTopic(idt);
if (t == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the topic: " + idt + " does not exist !</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else
{
// CPost cp = null;
Post p = PostBBSManager.getInstance().getGPosttByTopic(t);
if (p != null)
{
p.deleteme(t);
}
t.deleteme(f);
parsecmd("_bbsmemo", activeChar);
}
}
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the command: " + command + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
/**
* @param forumByID
* @param activeChar
* @param idf
*/
private void showNewTopic(Forum forum, L2PcInstance activeChar, int idf)
{
if (forum == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + idf + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else if (forum.getType() == Forum.MEMO)
{
showMemoNewTopics(forum, activeChar);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + forum.getName() + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
/**
* @param forum
* @param activeChar
*/
private void showMemoNewTopics(Forum forum, L2PcInstance activeChar)
{
final String html = StringUtil.concat("<html>" + "<body><br><br>" + "<table border=0 width=610><tr><td width=10></td><td width=600 align=left>" + "<a action=\"bypass _bbshome\">HOME</a>&nbsp;>&nbsp;<a action=\"bypass _bbsmemo\">Memo Form</a>" + "</td></tr>" + "</table>" + "<img src=\"L2UI.squareblank\" width=\"1\" height=\"10\">" + "<center>" + "<table border=0 cellspacing=0 cellpadding=0>" + "<tr><td width=610><img src=\"sek.cbui355\" width=\"610\" height=\"1\"><br1><img src=\"sek.cbui355\" width=\"610\" height=\"1\"></td></tr>" + "</table>" + "<table fixwidth=610 border=0 cellspacing=0 cellpadding=0>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=20></td></tr>" + "<tr>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "<td align=center FIXWIDTH=60 height=29>&$413;</td>" + "<td FIXWIDTH=540><edit var = \"Title\" width=540 height=13></td>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "</tr></table>" + "<table fixwidth=610 border=0 cellspacing=0 cellpadding=0>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr>" + "<tr>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "<td align=center FIXWIDTH=60 height=29 valign=top>&$427;</td>" + "<td align=center FIXWIDTH=540><MultiEdit var =\"Content\" width=535 height=313></td>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "</tr>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr>" + "</table>" + "<table fixwidth=610 border=0 cellspacing=0 cellpadding=0>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr>" + "<tr>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "<td align=center FIXWIDTH=60 height=29>&nbsp;</td>" + "<td align=center FIXWIDTH=70><button value=\"&$140;\" action=\"Write Topic crea ", String.valueOf(forum.getID()), " Title Content Title\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td>" + "<td align=center FIXWIDTH=70><button value = \"&$141;\" action=\"bypass _bbsmemo\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"> </td>" + "<td align=center FIXWIDTH=400>&nbsp;</td>" + "<td><img src=\"l2ui.mini_logo\" width=5 height=1></td>" + "</tr></table>" + "</center>" + "</body>" + "</html>");
send1001(html, activeChar);
send1002(activeChar);
}
/**
* @param memo
*/
private void showTopics(Forum forum, L2PcInstance activeChar, int index, int idf)
{
if (forum == null)
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + idf + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
else if (forum.getType() == Forum.MEMO)
{
showMemoTopics(forum, activeChar, index);
}
else
{
ShowBoard sb = new ShowBoard("<html><body><br><br><center>the forum: " + forum.getName() + " is not implemented yet</center><br><br></body></html>", "101");
activeChar.sendPacket(sb);
activeChar.sendPacket(new ShowBoard(null, "102"));
activeChar.sendPacket(new ShowBoard(null, "103"));
}
}
/**
* @param forum
* @param activeChar
*/
private void showMemoTopics(Forum forum, L2PcInstance activeChar, int index)
{
forum.vload();
final StringBuilder html = StringUtil.startAppend(2000, "<html><body><br><br>" + "<table border=0 width=610><tr><td width=10></td><td width=600 align=left>" + "<a action=\"bypass _bbshome\">HOME</a>&nbsp;>&nbsp;<a action=\"bypass _bbsmemo\">Memo Form</a>" + "</td></tr>" + "</table>" + "<img src=\"L2UI.squareblank\" width=\"1\" height=\"10\">" + "<center>" + "<table border=0 cellspacing=0 cellpadding=2 bgcolor=888888 width=610>" + "<tr>" + "<td FIXWIDTH=5></td>" + "<td FIXWIDTH=415 align=center>&$413;</td>" + "<td FIXWIDTH=120 align=center></td>" + "<td FIXWIDTH=70 align=center>&$418;</td>" + "</tr>" + "</table>");
final DateFormat dateFormat = DateFormat.getInstance();
for (int i = 0, j = getMaxID(forum) + 1; i < (12 * index); j--)
{
if (j < 0)
{
break;
}
Topic t = forum.getTopic(j);
if (t != null)
{
if (i++ >= (12 * (index - 1)))
{
StringUtil.append(html, "<table border=0 cellspacing=0 cellpadding=5 WIDTH=610>" + "<tr>" + "<td FIXWIDTH=5></td>" + "<td FIXWIDTH=415><a action=\"bypass _bbsposts;read;", String.valueOf(forum.getID()), ";", String.valueOf(t.getID()), "\">", t.getName(), "</a></td>" + "<td FIXWIDTH=120 align=center></td>" + "<td FIXWIDTH=70 align=center>", dateFormat.format(new Date(t.getDate())), "</td>" + "</tr>" + "</table>" + "<img src=\"L2UI.Squaregray\" width=\"610\" height=\"1\">");
}
}
}
html.append("<br>" + "<table width=610 cellspace=0 cellpadding=0>" + "<tr>" + "<td width=50>" + "<button value=\"&$422;\" action=\"bypass _bbsmemo\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\">" + "</td>" + "<td width=510 align=center>" + "<table border=0><tr>");
if (index == 1)
{
html.append("<td><button action=\"\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16 ></td>");
}
else
{
StringUtil.append(html, "<td><button action=\"bypass _bbstopics;read;", String.valueOf(forum.getID()), ";", String.valueOf(index - 1), "\" back=\"l2ui_ch3.prev1_down\" fore=\"l2ui_ch3.prev1\" width=16 height=16 ></td>");
}
int nbp;
nbp = forum.getTopicSize() / 8;
if ((nbp * 8) != ClanTable.getInstance().getClans().length)
{
nbp++;
}
for (int i = 1; i <= nbp; i++)
{
if (i == index)
{
StringUtil.append(html, "<td> ", String.valueOf(i), " </td>");
}
else
{
StringUtil.append(html, "<td><a action=\"bypass _bbstopics;read;", String.valueOf(forum.getID()), ";", String.valueOf(i), "\"> ", String.valueOf(i), " </a></td>");
}
}
if (index == nbp)
{
html.append("<td><button action=\"\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16 ></td>");
}
else
{
StringUtil.append(html, "<td><button action=\"bypass _bbstopics;read;", String.valueOf(forum.getID()), ";", String.valueOf(index + 1), "\" back=\"l2ui_ch3.next1_down\" fore=\"l2ui_ch3.next1\" width=16 height=16 ></td>");
}
StringUtil.append(html, "</tr></table> </td> " + "<td align=right><button value = \"&$421;\" action=\"bypass _bbstopics;crea;", String.valueOf(forum.getID()), "\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\" ></td></tr>" + "<tr><td><img src=\"l2ui.mini_logo\" width=5 height=10></td></tr>" + "<tr> " + "<td></td>" + "<td align=center><table border=0><tr><td></td><td><edit var = \"Search\" width=130 height=11></td>" + "<td><button value=\"&$420;\" action=\"Write 5 -2 0 Search _ _\" back=\"l2ui_ch3.smallbutton2_down\" width=65 height=20 fore=\"l2ui_ch3.smallbutton2\"> </td> </tr></table> </td>" + "</tr>" + "</table>" + "<br>" + "<br>" + "<br>" + "</center>" + "</body>" + "</html>");
separateAndSend(html.toString(), activeChar);
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final TopicBBSManager _instance = new TopicBBSManager();
}
}
@@ -0,0 +1,215 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.L2AccessLevel;
/**
* @author FBIagent<br>
*/
public class AccessLevels
{
/** The logger<br> */
private static Logger _log = Logger.getLogger(AccessLevels.class.getName());
/** Reserved master access level<br> */
public static final int _masterAccessLevelNum = Config.MASTERACCESS_LEVEL;
/** The master access level which can use everything<br> */
public static L2AccessLevel _masterAccessLevel = new L2AccessLevel(_masterAccessLevelNum, "Master Access", Config.MASTERACCESS_NAME_COLOR, Config.MASTERACCESS_TITLE_COLOR, null, true, true, true, true, true, true, true, true);
/** Reserved user access level<br> */
public static final int _userAccessLevelNum = 0;
/** The user access level which can do no administrative tasks<br> */
public static L2AccessLevel _userAccessLevel = new L2AccessLevel(_userAccessLevelNum, "User", -1, -1, null, false, false, false, true, false, true, true, true);
/** FastMap of access levels defined in database<br> */
private TIntObjectHashMap<L2AccessLevel> _accessLevels;
/**
* Returns the one and only instance of this class<br>
* <br>
* @return AccessLevels: the one and only instance of this class<br>
*/
public static AccessLevels getInstance()
{
return SingletonHolder._instance;
}
private AccessLevels()
{
loadAccessLevels();
_accessLevels.put(_userAccessLevelNum, _userAccessLevel);
}
/**
* Loads the access levels from database<br>
*/
private void loadAccessLevels()
{
_accessLevels = new TIntObjectHashMap<>();
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement stmt = con.prepareStatement("SELECT * FROM `access_levels` ORDER BY `accessLevel` DESC");
ResultSet rset = stmt.executeQuery();
int accessLevel = 0;
String name = null;
int nameColor = 0;
int titleColor = 0;
String childs = null;
boolean isGm = false;
boolean allowPeaceAttack = false;
boolean allowFixedRes = false;
boolean allowTransaction = false;
boolean allowAltG = false;
boolean giveDamage = false;
boolean takeAggro = false;
boolean gainExp = false;
while (rset.next())
{
accessLevel = rset.getInt("accessLevel");
name = rset.getString("name");
if (accessLevel == _userAccessLevelNum)
{
_log.warning("AccessLevels: Access level with name " + name + " is using reserved user access level " + _userAccessLevelNum + ". Ignoring it!");
continue;
}
else if (accessLevel == _masterAccessLevelNum)
{
_log.warning("AccessLevels: Access level with name " + name + " is using reserved master access level " + _masterAccessLevelNum + ". Ignoring it!");
continue;
}
else if (accessLevel < 0)
{
_log.warning("AccessLevels: Access level with name " + name + " is using banned access level state(below 0). Ignoring it!");
continue;
}
try
{
nameColor = Integer.decode("0x" + rset.getString("nameColor"));
}
catch (NumberFormatException nfe)
{
try
{
nameColor = Integer.decode("0xFFFFFF");
}
catch (NumberFormatException nfe2)
{
}
}
try
{
titleColor = Integer.decode("0x" + rset.getString("titleColor"));
}
catch (NumberFormatException nfe)
{
try
{
titleColor = Integer.decode("0xFFFF77");
}
catch (NumberFormatException nfe2)
{
}
}
childs = rset.getString("childAccess");
isGm = rset.getBoolean("isGm");
allowPeaceAttack = rset.getBoolean("allowPeaceAttack");
allowFixedRes = rset.getBoolean("allowFixedRes");
allowTransaction = rset.getBoolean("allowTransaction");
allowAltG = rset.getBoolean("allowAltg");
giveDamage = rset.getBoolean("giveDamage");
takeAggro = rset.getBoolean("takeAggro");
gainExp = rset.getBoolean("gainExp");
_accessLevels.put(accessLevel, new L2AccessLevel(accessLevel, name, nameColor, titleColor, childs.isEmpty() ? null : childs, isGm, allowPeaceAttack, allowFixedRes, allowTransaction, allowAltG, giveDamage, takeAggro, gainExp));
}
rset.close();
stmt.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "AccessLevels: Error loading from database:" + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
_log.info("AccessLevels: Loaded " + _accessLevels.size() + " from database.");
}
/**
* Returns the access level by characterAccessLevel<br>
* <br>
* @param accessLevelNum as int<br>
* <br>
* @return AccessLevel: AccessLevel instance by char access level<br>
*/
public L2AccessLevel getAccessLevel(int accessLevelNum)
{
L2AccessLevel accessLevel = null;
synchronized (_accessLevels)
{
accessLevel = _accessLevels.get(accessLevelNum);
}
return accessLevel;
}
public void addBanAccessLevel(int accessLevel)
{
synchronized (_accessLevels)
{
if (accessLevel > -1)
{
return;
}
_accessLevels.put(accessLevel, new L2AccessLevel(accessLevel, "Banned", -1, -1, null, false, false, false, false, false, false, false, false));
}
}
public void reloadAccessLevels()
{
loadAccessLevels();
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final AccessLevels _instance = new AccessLevels();
}
}
@@ -0,0 +1,137 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastMap;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.L2AccessLevel;
import com.l2jserver.gameserver.model.L2AdminCommandAccessRight;
/**
* @author FBIagent<br>
*/
public class AdminCommandAccessRights
{
/** The logger<br> */
private static Logger _log = Logger.getLogger(AdminCommandAccessRights.class.getName());
private Map<String, L2AdminCommandAccessRight> _adminCommandAccessRights;
/**
* Returns the one and only instance of this class<br>
* <br>
* @return AdminCommandAccessRights: the one and only instance of this class<br>
*/
public static AdminCommandAccessRights getInstance()
{
return SingletonHolder._instance;
}
/** The access rights<br> */
private AdminCommandAccessRights()
{
loadAdminCommandAccessRights();
}
/**
* Loads admin command access rights from database<br>
*/
private void loadAdminCommandAccessRights()
{
_adminCommandAccessRights = new FastMap<>();
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement stmt = con.prepareStatement("SELECT * FROM admin_command_access_rights");
ResultSet rset = stmt.executeQuery();
String adminCommand = null;
String accessLevels = null;
boolean confirm = false;
while (rset.next())
{
adminCommand = rset.getString("adminCommand");
accessLevels = rset.getString("accessLevels");
confirm = rset.getBoolean("confirmDlg");
_adminCommandAccessRights.put(adminCommand, new L2AdminCommandAccessRight(adminCommand, accessLevels, confirm));
}
rset.close();
stmt.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "AdminCommandAccessRights: Error loading from database:" + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
_log.info("AdminCommandAccessRights: Loaded " + _adminCommandAccessRights.size() + " from database.");
}
public boolean hasAccess(String adminCommand, L2AccessLevel accessLevel)
{
if (accessLevel.getLevel() == AccessLevels._masterAccessLevelNum)
{
return true;
}
L2AdminCommandAccessRight acar = _adminCommandAccessRights.get(adminCommand);
if (acar == null)
{
_log.info("AdminCommandAccessRights: No rights defined for admin command " + adminCommand + ".");
return false;
}
return acar.hasAccess(accessLevel);
}
public boolean requireConfirm(String command)
{
L2AdminCommandAccessRight acar = _adminCommandAccessRights.get(command);
if (acar == null)
{
_log.info("AdminCommandAccessRights: No rights defined for admin command " + command + ".");
return false;
}
return _adminCommandAccessRights.get(command).getRequireConfirm();
}
public void reloadAdminCommandAccessRights()
{
loadAdminCommandAccessRights();
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final AdminCommandAccessRights _instance = new AdminCommandAccessRights();
}
}
@@ -0,0 +1,152 @@
/*
* 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/>.
*/
/**
* @author godson
*/
package com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.L2ArmorSet;
/**
* @author Luno
*/
public class ArmorSetsTable
{
private static Logger _log = Logger.getLogger(ArmorSetsTable.class.getName());
private final TIntObjectHashMap<L2ArmorSet> _armorSets;
public static ArmorSetsTable getInstance()
{
return SingletonHolder._instance;
}
private ArmorSetsTable()
{
_armorSets = new TIntObjectHashMap<>();
loadData();
}
private void loadData()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT chest, legs, head, gloves, feet, skill, shield, shield_skill_id, enchant6skill, mw_legs, mw_head, mw_gloves, mw_feet, mw_shield FROM armorsets");
ResultSet rset = statement.executeQuery();
while (rset.next())
{
int chest = rset.getInt("chest");
int legs = rset.getInt("legs");
int head = rset.getInt("head");
int gloves = rset.getInt("gloves");
int feet = rset.getInt("feet");
String[] skills = rset.getString("skill").split(";");
int shield = rset.getInt("shield");
int shield_skill_id = rset.getInt("shield_skill_id");
int enchant6skill = rset.getInt("enchant6skill");
int mw_legs = rset.getInt("mw_legs");
int mw_head = rset.getInt("mw_head");
int mw_gloves = rset.getInt("mw_gloves");
int mw_feet = rset.getInt("mw_feet");
int mw_shield = rset.getInt("mw_shield");
_armorSets.put(chest, new L2ArmorSet(chest, legs, head, gloves, feet, skills, shield, shield_skill_id, enchant6skill, mw_legs, mw_head, mw_gloves, mw_feet, mw_shield));
}
rset.close();
statement.close();
_log.info("ArmorSetsTable: Loaded " + _armorSets.size() + " armor sets.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, "ArmorSetsTable: Error reading ArmorSets table: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
if (Config.CUSTOM_ARMORSETS_TABLE)
{
try
{
int cSets = _armorSets.size();
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT chest, legs, head, gloves, feet, skill, shield, shield_skill_id, enchant6skill, mw_legs, mw_head, mw_gloves, mw_feet, mw_shield FROM custom_armorsets");
ResultSet rset = statement.executeQuery();
while (rset.next())
{
int chest = rset.getInt("chest");
int legs = rset.getInt("legs");
int head = rset.getInt("head");
int gloves = rset.getInt("gloves");
int feet = rset.getInt("feet");
String[] skills = rset.getString("skill").split(";");
int shield = rset.getInt("shield");
int shield_skill_id = rset.getInt("shield_skill_id");
int enchant6skill = rset.getInt("enchant6skill");
int mw_legs = rset.getInt("mw_legs");
int mw_head = rset.getInt("mw_head");
int mw_gloves = rset.getInt("mw_gloves");
int mw_feet = rset.getInt("mw_feet");
int mw_shield = rset.getInt("mw_shield");
_armorSets.put(chest, new L2ArmorSet(chest, legs, head, gloves, feet, skills, shield, shield_skill_id, enchant6skill, mw_legs, mw_head, mw_gloves, mw_feet, mw_shield));
}
rset.close();
statement.close();
_log.info("ArmorSetsTable: Loaded " + (_armorSets.size() - cSets) + " Custom armor sets.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, "ArmorSetsTable: Error reading Custom ArmorSets table: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
}
public boolean setExists(int chestId)
{
return _armorSets.containsKey(chestId);
}
public L2ArmorSet getSet(int chestId)
{
return _armorSets.get(chestId);
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ArmorSetsTable _instance = new ArmorSetsTable();
}
}
@@ -0,0 +1,969 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.io.File;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import javolution.util.FastList;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.L2Augmentation;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.network.clientpackets.AbstractRefinePacket;
import com.l2jserver.gameserver.skills.Stats;
import com.l2jserver.gameserver.templates.item.L2Item;
import com.l2jserver.util.Rnd;
/**
* This class manages the augmentation data and can also create new augmentations.
* @author durgus edited by Gigiikun
*/
public class AugmentationData
{
private static final Logger _log = Logger.getLogger(AugmentationData.class.getName());
public static final AugmentationData getInstance()
{
return SingletonHolder._instance;
}
// =========================================================
// Data Field
// stats
private static final int STAT_START = 1;
private static final int STAT_END = 14560;
private static final int STAT_BLOCKSIZE = 3640;
// private static final int STAT_NUMBEROF_BLOCKS = 4;
private static final int STAT_SUBBLOCKSIZE = 91;
// private static final int STAT_NUMBEROF_SUBBLOCKS = 40;
private static final int STAT_NUM = 13;
private static final byte[] STATS1_MAP = new byte[STAT_SUBBLOCKSIZE];
private static final byte[] STATS2_MAP = new byte[STAT_SUBBLOCKSIZE];
// skills
private static final int BLUE_START = 14561;
// private static final int PURPLE_START = 14578;
// private static final int RED_START = 14685;
private static final int SKILLS_BLOCKSIZE = 178;
// basestats
private static final int BASESTAT_STR = 16341;
private static final int BASESTAT_CON = 16342;
private static final int BASESTAT_INT = 16343;
private static final int BASESTAT_MEN = 16344;
// accessory
private static final int ACC_START = 16669;
private static final int ACC_BLOCKS_NUM = 10;
private static final int ACC_STAT_SUBBLOCKSIZE = 21;
private static final int ACC_STAT_NUM = 6;
private static final int ACC_RING_START = ACC_START;
private static final int ACC_RING_SKILLS = 18;
private static final int ACC_RING_BLOCKSIZE = ACC_RING_SKILLS + (4 * ACC_STAT_SUBBLOCKSIZE);
private static final int ACC_RING_END = (ACC_RING_START + (ACC_BLOCKS_NUM * ACC_RING_BLOCKSIZE)) - 1;
private static final int ACC_EAR_START = ACC_RING_END + 1;
private static final int ACC_EAR_SKILLS = 18;
private static final int ACC_EAR_BLOCKSIZE = ACC_EAR_SKILLS + (4 * ACC_STAT_SUBBLOCKSIZE);
private static final int ACC_EAR_END = (ACC_EAR_START + (ACC_BLOCKS_NUM * ACC_EAR_BLOCKSIZE)) - 1;
private static final int ACC_NECK_START = ACC_EAR_END + 1;
private static final int ACC_NECK_SKILLS = 24;
private static final int ACC_NECK_BLOCKSIZE = ACC_NECK_SKILLS + (4 * ACC_STAT_SUBBLOCKSIZE);
private static final int ACC_END = ACC_NECK_START + (ACC_BLOCKS_NUM * ACC_NECK_BLOCKSIZE);
private static final byte[] ACC_STATS1_MAP = new byte[ACC_STAT_SUBBLOCKSIZE];
private static final byte[] ACC_STATS2_MAP = new byte[ACC_STAT_SUBBLOCKSIZE];
private final ArrayList<?>[] _augStats = new ArrayList[4];
private final ArrayList<?>[] _augAccStats = new ArrayList[4];
private final ArrayList<?>[] _blueSkills = new ArrayList[10];
private final ArrayList<?>[] _purpleSkills = new ArrayList[10];
private final ArrayList<?>[] _redSkills = new ArrayList[10];
private final ArrayList<?>[] _yellowSkills = new ArrayList[10];
private final TIntObjectHashMap<AugmentationSkill> _allSkills = new TIntObjectHashMap<>();
// =========================================================
// Constructor
private AugmentationData()
{
_log.info("Initializing AugmentationData.");
_augStats[0] = new ArrayList<AugmentationStat>();
_augStats[1] = new ArrayList<AugmentationStat>();
_augStats[2] = new ArrayList<AugmentationStat>();
_augStats[3] = new ArrayList<AugmentationStat>();
_augAccStats[0] = new ArrayList<AugmentationStat>();
_augAccStats[1] = new ArrayList<AugmentationStat>();
_augAccStats[2] = new ArrayList<AugmentationStat>();
_augAccStats[3] = new ArrayList<AugmentationStat>();
// Lookup tables structure: STAT1 represent first stat, STAT2 - second.
// If both values are the same - use solo stat, if different - combined.
byte idx;
// weapon augmentation block: solo values first
// 00-00, 01-01 ... 11-11,12-12
for (idx = 0; idx < STAT_NUM; idx++)
{
// solo stats
STATS1_MAP[idx] = idx;
STATS2_MAP[idx] = idx;
}
// combined values next.
// 00-01,00-02,00-03 ... 00-11,00-12;
// 01-02,01-03 ... 01-11,01-12;
// ...
// 09-10,09-11,09-12;
// 10-11,10-12;
// 11-12
for (int i = 0; i < STAT_NUM; i++)
{
for (int j = i + 1; j < STAT_NUM; idx++, j++)
{
// combined stats
STATS1_MAP[idx] = (byte) i;
STATS2_MAP[idx] = (byte) j;
}
}
idx = 0;
// accessory augmentation block, structure is different:
// 00-00,00-01,00-02,00-03,00-04,00-05
// 01-01,01-02,01-03,01-04,01-05
// 02-02,02-03,02-04,02-05
// 03-03,03-04,03-05
// 04-04 \
// 05-05 - order is changed here
// 04-05 /
// First values always solo, next are combined, except last 3 values
for (int i = 0; i < (ACC_STAT_NUM - 2); i++)
{
for (int j = i; j < ACC_STAT_NUM; idx++, j++)
{
ACC_STATS1_MAP[idx] = (byte) i;
ACC_STATS2_MAP[idx] = (byte) j;
}
}
ACC_STATS1_MAP[idx] = 4;
ACC_STATS2_MAP[idx++] = 4;
ACC_STATS1_MAP[idx] = 5;
ACC_STATS2_MAP[idx++] = 5;
ACC_STATS1_MAP[idx] = 4;
ACC_STATS2_MAP[idx] = 5;
for (int i = 0; i < 10; i++)
{
_blueSkills[i] = new ArrayList<Integer>();
_purpleSkills[i] = new ArrayList<Integer>();
_redSkills[i] = new ArrayList<Integer>();
_yellowSkills[i] = new ArrayList<Integer>();
}
load();
// Use size*4: since theres 4 blocks of stat-data with equivalent size
_log.info("AugmentationData: Loaded: " + (_augStats[0].size() * 4) + " augmentation stats.");
_log.info("AugmentationData: Loaded: " + (_augAccStats[0].size() * 4) + " accessory augmentation stats.");
for (int i = 0; i < 10; i++)
{
_log.info("AugmentationData: Loaded: " + _blueSkills[i].size() + " blue, " + _purpleSkills[i].size() + " purple and " + _redSkills[i].size() + " red skills for lifeStoneLevel " + i);
}
}
// =========================================================
// Nested Class
public static class AugmentationSkill
{
private final int _skillId;
private final int _skillLevel;
public AugmentationSkill(int skillId, int skillLevel)
{
_skillId = skillId;
_skillLevel = skillLevel;
}
public L2Skill getSkill()
{
return SkillTable.getInstance().getInfo(_skillId, _skillLevel);
}
}
public static class AugmentationStat
{
private final Stats _stat;
private final int _singleSize;
private final int _combinedSize;
private final float _singleValues[];
private final float _combinedValues[];
public AugmentationStat(Stats stat, float sValues[], float cValues[])
{
_stat = stat;
_singleSize = sValues.length;
_singleValues = sValues;
_combinedSize = cValues.length;
_combinedValues = cValues;
}
public int getSingleStatSize()
{
return _singleSize;
}
public int getCombinedStatSize()
{
return _combinedSize;
}
public float getSingleStatValue(int i)
{
if ((i >= _singleSize) || (i < 0))
{
return _singleValues[_singleSize - 1];
}
return _singleValues[i];
}
public float getCombinedStatValue(int i)
{
if ((i >= _combinedSize) || (i < 0))
{
return _combinedValues[_combinedSize - 1];
}
return _combinedValues[i];
}
public Stats getStat()
{
return _stat;
}
}
@SuppressWarnings("unchecked")
private final void load()
{
// Load the skillmap
// Note: the skillmap data is only used when generating new augmentations
// the client expects a different id in order to display the skill in the
// items description...
try
{
int badAugmantData = 0;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT + "/data/stats/augmentation/augmentation_skillmap.xml");
if (!file.exists())
{
if (Config.DEBUG)
{
_log.info("The augmentation skillmap file is missing.");
}
return;
}
Document doc = factory.newDocumentBuilder().parse(file);
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("augmentation".equalsIgnoreCase(d.getNodeName()))
{
NamedNodeMap attrs = d.getAttributes();
int skillId = 0, augmentationId = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
int skillLvL = 0;
String type = "blue";
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("skillId".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
skillId = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
}
else if ("skillLevel".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
skillLvL = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
}
else if ("type".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
type = attrs.getNamedItem("val").getNodeValue();
}
}
if (skillId == 0)
{
if (Config.DEBUG)
{
_log.log(Level.SEVERE, "Bad skillId in augmentation_skillmap.xml in the augmentationId:" + augmentationId);
}
badAugmantData++;
continue;
}
else if (skillLvL == 0)
{
if (Config.DEBUG)
{
_log.log(Level.SEVERE, "Bad skillLevel in augmentation_skillmap.xml in the augmentationId:" + augmentationId);
}
badAugmantData++;
continue;
}
int k = (augmentationId - BLUE_START) / SKILLS_BLOCKSIZE;
if (type.equalsIgnoreCase("blue"))
{
((ArrayList<Integer>) _blueSkills[k]).add(augmentationId);
}
else if (type.equalsIgnoreCase("purple"))
{
((ArrayList<Integer>) _purpleSkills[k]).add(augmentationId);
}
else
{
((ArrayList<Integer>) _redSkills[k]).add(augmentationId);
}
_allSkills.put(augmentationId, new AugmentationSkill(skillId, skillLvL));
}
}
}
}
if (badAugmantData != 0)
{
_log.info("AugmentationData: " + badAugmantData + " bad skill(s) were skipped.");
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error parsing augmentation_skillmap.xml.", e);
return;
}
// Load the stats from xml
for (int i = 1; i < 5; i++)
{
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT + "/data/stats/augmentation/augmentation_stats" + i + ".xml");
if (!file.exists())
{
if (Config.DEBUG)
{
_log.info("The augmentation stat data file " + i + " is missing.");
}
return;
}
Document doc = factory.newDocumentBuilder().parse(file);
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("stat".equalsIgnoreCase(d.getNodeName()))
{
NamedNodeMap attrs = d.getAttributes();
String statName = attrs.getNamedItem("name").getNodeValue();
float soloValues[] = null, combinedValues[] = null;
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("table".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
String tableName = attrs.getNamedItem("name").getNodeValue();
StringTokenizer data = new StringTokenizer(cd.getFirstChild().getNodeValue());
FastList<Float> array = new FastList<>();
while (data.hasMoreTokens())
{
array.add(Float.parseFloat(data.nextToken()));
}
if (tableName.equalsIgnoreCase("#soloValues"))
{
soloValues = new float[array.size()];
int x = 0;
for (float value : array)
{
soloValues[x++] = value;
}
}
else
{
combinedValues = new float[array.size()];
int x = 0;
for (float value : array)
{
combinedValues[x++] = value;
}
}
}
}
// store this stat
((ArrayList<AugmentationStat>) _augStats[(i - 1)]).add(new AugmentationStat(Stats.valueOfXml(statName), soloValues, combinedValues));
}
}
}
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error parsing augmentation_stats" + i + ".xml.", e);
return;
}
try
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT + "/data/stats/augmentation/augmentation_jewel_stats" + i + ".xml");
if (!file.exists())
{
if (Config.DEBUG)
{
_log.info("The jewel augmentation stat data file " + i + " is missing.");
}
return;
}
Document doc = factory.newDocumentBuilder().parse(file);
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("stat".equalsIgnoreCase(d.getNodeName()))
{
NamedNodeMap attrs = d.getAttributes();
String statName = attrs.getNamedItem("name").getNodeValue();
float soloValues[] = null, combinedValues[] = null;
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("table".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
String tableName = attrs.getNamedItem("name").getNodeValue();
StringTokenizer data = new StringTokenizer(cd.getFirstChild().getNodeValue());
FastList<Float> array = new FastList<>();
while (data.hasMoreTokens())
{
array.add(Float.parseFloat(data.nextToken()));
}
if (tableName.equalsIgnoreCase("#soloValues"))
{
soloValues = new float[array.size()];
int x = 0;
for (float value : array)
{
soloValues[x++] = value;
}
}
else
{
combinedValues = new float[array.size()];
int x = 0;
for (float value : array)
{
combinedValues[x++] = value;
}
}
}
}
// store this stat
((ArrayList<AugmentationStat>) _augAccStats[(i - 1)]).add(new AugmentationStat(Stats.valueOfXml(statName), soloValues, combinedValues));
}
}
}
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error parsing jewel augmentation_stats" + i + ".xml.", e);
return;
}
}
}
/**
* Generate a new random augmentation
* @param item
* @param lifeStoneLevel
* @param lifeSoneGrade
* @param bodyPart
* @return L2Augmentation
*/
public L2Augmentation generateRandomAugmentation(int lifeStoneLevel, int lifeStoneGrade, int bodyPart)
{
switch (bodyPart)
{
case L2Item.SLOT_LR_FINGER:
case L2Item.SLOT_LR_EAR:
case L2Item.SLOT_NECK:
return generateRandomAccessoryAugmentation(lifeStoneLevel, bodyPart);
default:
return generateRandomWeaponAugmentation(lifeStoneLevel, lifeStoneGrade);
}
}
private L2Augmentation generateRandomWeaponAugmentation(int lifeStoneLevel, int lifeStoneGrade)
{
// Note that stat12 stands for stat 1 AND 2 (same for stat34 ;p )
// this is because a value can contain up to 2 stat modifications
// (there are two short values packed in one integer value, meaning 4 stat modifications at max)
// for more info take a look at getAugStatsById(...)
// Note: lifeStoneGrade: (0 means low grade, 3 top grade)
// First: determine whether we will add a skill/baseStatModifier or not
// because this determine which color could be the result
int stat12 = 0;
int stat34 = 0;
boolean generateSkill = false;
boolean generateGlow = false;
// lifestonelevel is used for stat Id and skill level, but here the max level is 9
lifeStoneLevel = Math.min(lifeStoneLevel, 9);
switch (lifeStoneGrade)
{
case AbstractRefinePacket.GRADE_NONE:
if (Rnd.get(1, 100) <= Config.AUGMENTATION_NG_SKILL_CHANCE)
{
generateSkill = true;
}
if (Rnd.get(1, 100) <= Config.AUGMENTATION_NG_GLOW_CHANCE)
{
generateGlow = true;
}
break;
case AbstractRefinePacket.GRADE_MID:
if (Rnd.get(1, 100) <= Config.AUGMENTATION_MID_SKILL_CHANCE)
{
generateSkill = true;
}
if (Rnd.get(1, 100) <= Config.AUGMENTATION_MID_GLOW_CHANCE)
{
generateGlow = true;
}
break;
case AbstractRefinePacket.GRADE_HIGH:
if (Rnd.get(1, 100) <= Config.AUGMENTATION_HIGH_SKILL_CHANCE)
{
generateSkill = true;
}
if (Rnd.get(1, 100) <= Config.AUGMENTATION_HIGH_GLOW_CHANCE)
{
generateGlow = true;
}
break;
case AbstractRefinePacket.GRADE_TOP:
if (Rnd.get(1, 100) <= Config.AUGMENTATION_TOP_SKILL_CHANCE)
{
generateSkill = true;
}
if (Rnd.get(1, 100) <= Config.AUGMENTATION_TOP_GLOW_CHANCE)
{
generateGlow = true;
}
break;
case AbstractRefinePacket.GRADE_ACC:
if (Rnd.get(1, 100) <= Config.AUGMENTATION_ACC_SKILL_CHANCE)
{
generateSkill = true;
}
}
if (!generateSkill && (Rnd.get(1, 100) <= Config.AUGMENTATION_BASESTAT_CHANCE))
{
stat34 = Rnd.get(BASESTAT_STR, BASESTAT_MEN);
}
// Second: decide which grade the augmentation result is going to have:
// 0:yellow, 1:blue, 2:purple, 3:red
// The chances used here are most likely custom,
// whats known is: you cant have yellow with skill(or baseStatModifier)
// noGrade stone can not have glow, mid only with skill, high has a chance(custom), top allways glow
int resultColor = Rnd.get(0, 100);
if ((stat34 == 0) && !generateSkill)
{
if (resultColor <= ((15 * lifeStoneGrade) + 40))
{
resultColor = 1;
}
else
{
resultColor = 0;
}
}
else
{
if ((resultColor <= ((10 * lifeStoneGrade) + 5)) || (stat34 != 0))
{
resultColor = 3;
}
else if (resultColor <= ((10 * lifeStoneGrade) + 10))
{
resultColor = 1;
}
else
{
resultColor = 2;
}
}
// generate a skill if neccessary
L2Skill skill = null;
if (generateSkill)
{
switch (resultColor)
{
case 1: // blue skill
stat34 = ((Integer) _blueSkills[lifeStoneLevel].get(Rnd.get(0, _blueSkills[lifeStoneLevel].size() - 1)));
break;
case 2: // purple skill
stat34 = ((Integer) _purpleSkills[lifeStoneLevel].get(Rnd.get(0, _purpleSkills[lifeStoneLevel].size() - 1)));
break;
case 3: // red skill
stat34 = ((Integer) _redSkills[lifeStoneLevel].get(Rnd.get(0, _redSkills[lifeStoneLevel].size() - 1)));
break;
}
skill = _allSkills.get(stat34).getSkill();
}
// Third: Calculate the subblock offset for the choosen color,
// and the level of the lifeStone
// from large number of retail augmentations:
// no skill part
// Id for stat12:
// A:1-910 B:911-1820 C:1821-2730 D:2731-3640 E:3641-4550 F:4551-5460 G:5461-6370 H:6371-7280
// Id for stat34(this defines the color):
// I:7281-8190(yellow) K:8191-9100(blue) L:10921-11830(yellow) M:11831-12740(blue)
// you can combine I-K with A-D and L-M with E-H
// using C-D or G-H Id you will get a glow effect
// there seems no correlation in which grade use which Id except for the glowing restriction
// skill part
// Id for stat12:
// same for no skill part
// A same as E, B same as F, C same as G, D same as H
// A - no glow, no grade LS
// B - weak glow, mid grade LS?
// C - glow, high grade LS?
// D - strong glow, top grade LS?
// is neither a skill nor basestat used for stat34? then generate a normal stat
int offset;
if (stat34 == 0)
{
int temp = Rnd.get(2, 3);
int colorOffset = (resultColor * (10 * STAT_SUBBLOCKSIZE)) + (temp * STAT_BLOCKSIZE) + 1;
offset = (lifeStoneLevel * STAT_SUBBLOCKSIZE) + colorOffset;
stat34 = Rnd.get(offset, (offset + STAT_SUBBLOCKSIZE) - 1);
if (generateGlow && (lifeStoneGrade >= 2))
{
offset = (lifeStoneLevel * STAT_SUBBLOCKSIZE) + ((temp - 2) * STAT_BLOCKSIZE) + (lifeStoneGrade * (10 * STAT_SUBBLOCKSIZE)) + 1;
}
else
{
offset = (lifeStoneLevel * STAT_SUBBLOCKSIZE) + ((temp - 2) * STAT_BLOCKSIZE) + (Rnd.get(0, 1) * (10 * STAT_SUBBLOCKSIZE)) + 1;
}
}
else
{
if (!generateGlow)
{
offset = (lifeStoneLevel * STAT_SUBBLOCKSIZE) + (Rnd.get(0, 1) * STAT_BLOCKSIZE) + 1;
}
else
{
offset = (lifeStoneLevel * STAT_SUBBLOCKSIZE) + (Rnd.get(0, 1) * STAT_BLOCKSIZE) + (((lifeStoneGrade + resultColor) / 2) * (10 * STAT_SUBBLOCKSIZE)) + 1;
}
}
stat12 = Rnd.get(offset, (offset + STAT_SUBBLOCKSIZE) - 1);
if (Config.DEBUG)
{
_log.info("Augmentation success: stat12=" + stat12 + "; stat34=" + stat34 + "; resultColor=" + resultColor + "; level=" + lifeStoneLevel + "; grade=" + lifeStoneGrade);
}
return new L2Augmentation(((stat34 << 16) + stat12), skill);
}
private L2Augmentation generateRandomAccessoryAugmentation(int lifeStoneLevel, int bodyPart)
{
int stat12 = 0;
int stat34 = 0;
int base = 0;
int skillsLength = 0;
lifeStoneLevel = Math.min(lifeStoneLevel, 9);
switch (bodyPart)
{
case L2Item.SLOT_LR_FINGER:
base = ACC_RING_START + (ACC_RING_BLOCKSIZE * lifeStoneLevel);
skillsLength = ACC_RING_SKILLS;
break;
case L2Item.SLOT_LR_EAR:
base = ACC_EAR_START + (ACC_EAR_BLOCKSIZE * lifeStoneLevel);
skillsLength = ACC_EAR_SKILLS;
break;
case L2Item.SLOT_NECK:
base = ACC_NECK_START + (ACC_NECK_BLOCKSIZE * lifeStoneLevel);
skillsLength = ACC_NECK_SKILLS;
break;
default:
return null;
}
int resultColor = Rnd.get(0, 3);
L2Skill skill = null;
// first augmentation (stats only)
stat12 = Rnd.get(ACC_STAT_SUBBLOCKSIZE);
if (Rnd.get(1, 100) <= Config.AUGMENTATION_ACC_SKILL_CHANCE)
{
// second augmentation (skill)
stat34 = base + Rnd.get(skillsLength);
if (_allSkills.contains(stat34))
{
skill = _allSkills.get(stat34).getSkill();
}
}
if (skill == null)
{
// second augmentation (stats)
// calculating any different from stat12 value inside sub-block
// starting from next and wrapping over using remainder
stat34 = (stat12 + 1 + Rnd.get(ACC_STAT_SUBBLOCKSIZE - 1)) % ACC_STAT_SUBBLOCKSIZE;
// this is a stats - skipping skills
stat34 = base + skillsLength + (ACC_STAT_SUBBLOCKSIZE * resultColor) + stat34;
}
// stat12 has stats only
stat12 = base + skillsLength + (ACC_STAT_SUBBLOCKSIZE * resultColor) + stat12;
if (Config.DEBUG)
{
_log.info("Accessory augmentation success: stat12=" + stat12 + "; stat34=" + stat34 + "; level=" + lifeStoneLevel);
}
return new L2Augmentation(((stat34 << 16) + stat12), skill);
}
public static class AugStat
{
private final Stats _stat;
private final float _value;
public AugStat(Stats stat, float value)
{
_stat = stat;
_value = value;
}
public Stats getStat()
{
return _stat;
}
public float getValue()
{
return _value;
}
}
/**
* Returns the stat and basestat boni for a given augmentation id
* @param augmentationId
* @return
*/
public FastList<AugStat> getAugStatsById(int augmentationId)
{
FastList<AugStat> temp = new FastList<>();
// An augmentation id contains 2 short vaues so we gotta seperate them here
// both values contain a number from 1-16380, the first 14560 values are stats
// the 14560 stats are divided into 4 blocks each holding 3640 values
// each block contains 40 subblocks holding 91 stat values
// the first 13 values are so called Solo-stats and they have the highest stat increase possible
// after the 13 Solo-stats come 78 combined stats (thats every possible combination of the 13 solo stats)
// the first 12 combined stats (14-26) is the stat 1 combined with stat 2-13
// the next 11 combined stats then are stat 2 combined with stat 3-13 and so on...
// to get the idea have a look @ optiondata_client-e.dat - thats where the data came from :)
int stats[] = new int[2];
stats[0] = 0x0000FFFF & augmentationId;
stats[1] = (augmentationId >> 16);
for (int i = 0; i < 2; i++)
{
// weapon augmentation - stats
if ((stats[i] >= STAT_START) && (stats[i] <= STAT_END))
{
int base = stats[i] - STAT_START;
int color = base / STAT_BLOCKSIZE; // 4 color blocks
int subblock = base % STAT_BLOCKSIZE; // offset in color block
int level = subblock / STAT_SUBBLOCKSIZE; // stat level (sub-block number)
int stat = subblock % STAT_SUBBLOCKSIZE; // offset in sub-block - stat
byte stat1 = STATS1_MAP[stat];
byte stat2 = STATS2_MAP[stat];
if (stat1 == stat2) // solo stat
{
AugmentationStat as = ((AugmentationStat) _augStats[color].get(stat1));
temp.add(new AugStat(as.getStat(), as.getSingleStatValue(level)));
}
else
// combined stat
{
AugmentationStat as = ((AugmentationStat) _augStats[color].get(stat1));
temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(level)));
as = ((AugmentationStat) _augStats[color].get(stat2));
temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(level)));
}
}
// its a base stat
else if ((stats[i] >= BASESTAT_STR) && (stats[i] <= BASESTAT_MEN))
{
switch (stats[i])
{
case BASESTAT_STR:
temp.add(new AugStat(Stats.STAT_STR, 1.0f));
break;
case BASESTAT_CON:
temp.add(new AugStat(Stats.STAT_CON, 1.0f));
break;
case BASESTAT_INT:
temp.add(new AugStat(Stats.STAT_INT, 1.0f));
break;
case BASESTAT_MEN:
temp.add(new AugStat(Stats.STAT_MEN, 1.0f));
break;
}
}
// accessory augmentation
// 3 areas for rings, earrings and necklaces
// each area consist of 10 blocks (level)
// each block has skills first (18 or 24 for necklaces)
// and sub-block for stats next
else if ((stats[i] >= ACC_START) && (stats[i] <= ACC_END))
{
int base, level, subblock;
if (stats[i] <= ACC_RING_END) // rings area
{
base = stats[i] - ACC_RING_START; // calculate base offset
level = base / ACC_RING_BLOCKSIZE; // stat level (block number)
subblock = (base % ACC_RING_BLOCKSIZE) - ACC_RING_SKILLS; // skills first
}
else if (stats[i] <= ACC_EAR_END) // earrings area
{
base = stats[i] - ACC_EAR_START;
level = base / ACC_EAR_BLOCKSIZE;
subblock = (base % ACC_EAR_BLOCKSIZE) - ACC_EAR_SKILLS;
}
else
// necklaces
{
base = stats[i] - ACC_NECK_START;
level = base / ACC_NECK_BLOCKSIZE;
subblock = (base % ACC_NECK_BLOCKSIZE) - ACC_NECK_SKILLS;
}
if (subblock >= 0) // stat, not skill
{
int color = subblock / ACC_STAT_SUBBLOCKSIZE;
int stat = subblock % ACC_STAT_SUBBLOCKSIZE;
byte stat1 = ACC_STATS1_MAP[stat];
byte stat2 = ACC_STATS2_MAP[stat];
if (stat1 == stat2) // solo
{
AugmentationStat as = ((AugmentationStat) _augAccStats[color].get(stat1));
temp.add(new AugStat(as.getStat(), as.getSingleStatValue(level)));
}
else
// combined
{
AugmentationStat as = ((AugmentationStat) _augAccStats[color].get(stat1));
temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(level)));
as = ((AugmentationStat) _augAccStats[color].get(stat2));
temp.add(new AugStat(as.getStat(), as.getCombinedStatValue(level)));
}
}
}
}
return temp;
}
/*
* Returns skill by augmentation Id or null if not valid or not found
*/
public L2Skill getAugSkillById(int augmentationId)
{
final AugmentationSkill temp = _allSkills.get(augmentationId);
if (temp == null)
{
return null;
}
return temp.getSkill();
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final AugmentationData _instance = new AugmentationData();
}
}
@@ -0,0 +1,303 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* This class ...
* @version $Revision: 1.3.2.2.2.1 $ $Date: 2005/03/27 15:29:18 $
*/
public class CharNameTable
{
private static Logger _log = Logger.getLogger(CharNameTable.class.getName());
private final Map<Integer, String> _chars;
private final Map<Integer, Integer> _accessLevels;
private CharNameTable()
{
_chars = new FastMap<>();
_accessLevels = new FastMap<>();
if (Config.CACHE_CHAR_NAMES)
{
loadAll();
}
}
public static CharNameTable getInstance()
{
return SingletonHolder._instance;
}
public final void addName(L2PcInstance player)
{
if (player != null)
{
addName(player.getObjectId(), player.getName());
_accessLevels.put(player.getObjectId(), player.getAccessLevel().getLevel());
}
}
private final void addName(int objectId, String name)
{
if (name != null)
{
if (!name.equals(_chars.get(objectId)))
{
_chars.put(objectId, name);
}
}
}
public final void removeName(int objId)
{
_chars.remove(objId);
_accessLevels.remove(objId);
}
public final int getIdByName(String name)
{
if ((name == null) || name.isEmpty())
{
return -1;
}
Iterator<Entry<Integer, String>> it = _chars.entrySet().iterator();
Map.Entry<Integer, String> pair;
while (it.hasNext())
{
pair = it.next();
if (pair.getValue().equalsIgnoreCase(name))
{
return pair.getKey();
}
}
if (Config.CACHE_CHAR_NAMES)
{
return -1;
}
int id = -1;
int accessLevel = 0;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT charId,accesslevel FROM characters WHERE char_name=?");
statement.setString(1, name);
ResultSet rset = statement.executeQuery();
while (rset.next())
{
id = rset.getInt(1);
accessLevel = rset.getInt(2);
}
rset.close();
statement.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Could not check existing char name: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
if (id > 0)
{
_chars.put(id, name);
_accessLevels.put(id, accessLevel);
return id;
}
return -1; // not found
}
public final String getNameById(int id)
{
if (id <= 0)
{
return null;
}
String name = _chars.get(id);
if (name != null)
{
return name;
}
if (Config.CACHE_CHAR_NAMES)
{
return null;
}
int accessLevel = 0;
Connection con = null;
PreparedStatement statement = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("SELECT char_name,accesslevel FROM characters WHERE charId=?");
statement.setInt(1, id);
ResultSet rset = statement.executeQuery();
while (rset.next())
{
name = rset.getString(1);
accessLevel = rset.getInt(2);
}
rset.close();
statement.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Could not check existing char id: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
if ((name != null) && !name.isEmpty())
{
_chars.put(id, name);
_accessLevels.put(id, accessLevel);
return name;
}
return null; // not found
}
public final int getAccessLevelById(int objectId)
{
if (getNameById(objectId) != null)
{
return _accessLevels.get(objectId);
}
return 0;
}
public synchronized boolean doesCharNameExist(String name)
{
boolean result = true;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT account_name FROM characters WHERE char_name=?");
statement.setString(1, name);
ResultSet rset = statement.executeQuery();
result = rset.next();
rset.close();
statement.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Could not check existing charname: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
return result;
}
public int accountCharNumber(String account)
{
Connection con = null;
int number = 0;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT COUNT(char_name) FROM characters WHERE account_name=?");
statement.setString(1, account);
ResultSet rset = statement.executeQuery();
while (rset.next())
{
number = rset.getInt(1);
}
rset.close();
statement.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Could not check existing char number: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
return number;
}
private void loadAll()
{
String name;
int id = -1;
int accessLevel = 0;
PreparedStatement statement = null;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
statement = con.prepareStatement("SELECT charId,char_name,accesslevel FROM characters");
ResultSet rset = statement.executeQuery();
while (rset.next())
{
id = rset.getInt(1);
name = rset.getString(2);
accessLevel = rset.getInt(3);
_chars.put(id, name);
_accessLevels.put(id, accessLevel);
}
rset.close();
statement.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Could not load char name: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
_log.info(getClass().getSimpleName() + ": Loaded " + _chars.size() + " char names.");
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final CharNameTable _instance = new CharNameTable();
}
}
@@ -0,0 +1,204 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.base.ClassId;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.templates.chars.L2PcTemplate;
/**
* @author Unknown, Forsaiken
*/
public final class CharTemplateTable
{
private static final Logger _log = Logger.getLogger(CharTemplateTable.class.getName());
public static final CharTemplateTable getInstance()
{
return SingletonHolder._instance;
}
private final L2PcTemplate[] _templates;
private CharTemplateTable()
{
_templates = new L2PcTemplate[ClassId.values().length];
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT * FROM class_list, char_templates, lvlupgain" + " WHERE class_list.id = char_templates.classId" + " AND class_list.id = lvlupgain.classId" + " ORDER BY class_list.id");
ResultSet rset = statement.executeQuery();
int count = 0;
while (rset.next())
{
StatsSet set = new StatsSet();
set.set("classId", rset.getInt("id"));
set.set("className", rset.getString("className"));
set.set("raceId", rset.getInt("raceId"));
set.set("baseSTR", rset.getInt("STR"));
set.set("baseCON", rset.getInt("CON"));
set.set("baseDEX", rset.getInt("DEX"));
set.set("baseINT", rset.getInt("_INT"));
set.set("baseWIT", rset.getInt("WIT"));
set.set("baseMEN", rset.getInt("MEN"));
set.set("baseHpMax", rset.getFloat("defaultHpBase"));
set.set("lvlHpAdd", rset.getFloat("defaultHpAdd"));
set.set("lvlHpMod", rset.getFloat("defaultHpMod"));
set.set("baseMpMax", rset.getFloat("defaultMpBase"));
set.set("baseCpMax", rset.getFloat("defaultCpBase"));
set.set("lvlCpAdd", rset.getFloat("defaultCpAdd"));
set.set("lvlCpMod", rset.getFloat("defaultCpMod"));
set.set("lvlMpAdd", rset.getFloat("defaultMpAdd"));
set.set("lvlMpMod", rset.getFloat("defaultMpMod"));
set.set("baseHpReg", 1.5);
set.set("baseMpReg", 0.9);
set.set("basePAtk", rset.getInt("p_atk"));
set.set("basePDef", /* classId.isMage()? 77 : 129 */rset.getInt("p_def"));
set.set("baseMAtk", rset.getInt("m_atk"));
set.set("baseMDef", rset.getInt("char_templates.m_def"));
set.set("classBaseLevel", rset.getInt("class_lvl"));
set.set("basePAtkSpd", rset.getInt("p_spd"));
set.set("baseMAtkSpd", /* classId.isMage()? 166 : 333 */rset.getInt("char_templates.m_spd"));
set.set("baseCritRate", rset.getInt("char_templates.critical") / 10);
set.set("baseRunSpd", rset.getInt("move_spd"));
set.set("baseWalkSpd", 0);
set.set("baseShldDef", 0);
set.set("baseShldRate", 0);
set.set("baseAtkRange", 40);
set.set("spawnX", rset.getInt("x"));
set.set("spawnY", rset.getInt("y"));
set.set("spawnZ", rset.getInt("z"));
L2PcTemplate ct;
set.set("collision_radius", rset.getDouble("m_col_r"));
set.set("collision_height", rset.getDouble("m_col_h"));
set.set("collision_radius_female", rset.getDouble("f_col_r"));
set.set("collision_height_female", rset.getDouble("f_col_h"));
ct = new L2PcTemplate(set);
_templates[ct.classId.getId()] = ct;
++count;
}
rset.close();
statement.close();
_log.info("CharTemplateTable: Loaded " + count + " Character Templates.");
}
catch (SQLException e)
{
_log.log(Level.SEVERE, "Failed loading char templates", e);
}
finally
{
L2DatabaseFactory.close(con);
}
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT classId, itemId, amount, equipped FROM char_creation_items");
ResultSet rset = statement.executeQuery();
int classId, itemId, amount;
boolean equipped;
while (rset.next())
{
classId = rset.getInt("classId");
itemId = rset.getInt("itemId");
amount = rset.getInt("amount");
equipped = rset.getString("equipped").equals("true");
if (ItemTable.getInstance().getTemplate(itemId) != null)
{
if (classId == -1)
{
for (L2PcTemplate pct : _templates)
{
if (pct != null)
{
pct.addItem(itemId, amount, equipped);
}
}
}
else
{
L2PcTemplate pct = _templates[classId];
if (pct != null)
{
pct.addItem(itemId, amount, equipped);
}
else
{
_log.warning("char_creation_items: Entry for undefined class, classId: " + classId);
}
}
}
else
{
_log.warning("char_creation_items: No data for itemId: " + itemId + " defined for classId " + classId);
}
}
}
catch (SQLException e)
{
_log.log(Level.SEVERE, "Failed loading char creation items.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public L2PcTemplate getTemplate(ClassId classId)
{
return this.getTemplate(classId.getId());
}
public L2PcTemplate getTemplate(int classId)
{
return _templates[classId];
}
public final String getClassNameById(int classId)
{
L2PcTemplate pcTemplate = getTemplate(classId);
if (pcTemplate == null)
{
throw new IllegalArgumentException("No template for classId: " + classId);
}
return pcTemplate.className;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final CharTemplateTable _instance = new CharTemplateTable();
}
}
@@ -0,0 +1,538 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.communitybbs.Manager.ForumsBBSManager;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.instancemanager.FortManager;
import com.l2jserver.gameserver.instancemanager.FortSiegeManager;
import com.l2jserver.gameserver.instancemanager.SiegeManager;
import com.l2jserver.gameserver.model.L2Clan;
import com.l2jserver.gameserver.model.L2ClanMember;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.entity.Fort;
import com.l2jserver.gameserver.model.entity.FortSiege;
import com.l2jserver.gameserver.model.entity.Siege;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.communityserver.CommunityServerThread;
import com.l2jserver.gameserver.network.communityserver.writepackets.WorldInfo;
import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
import com.l2jserver.gameserver.network.serverpackets.PledgeShowInfoUpdate;
import com.l2jserver.gameserver.network.serverpackets.PledgeShowMemberListAll;
import com.l2jserver.gameserver.network.serverpackets.PledgeShowMemberListUpdate;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.network.serverpackets.UserInfo;
import com.l2jserver.gameserver.util.Util;
/**
* This class ...
* @version $Revision: 1.11.2.5.2.5 $ $Date: 2005/03/27 15:29:18 $
*/
public class ClanTable
{
private static Logger _log = Logger.getLogger(ClanTable.class.getName());
private final Map<Integer, L2Clan> _clans;
public static ClanTable getInstance()
{
return SingletonHolder._instance;
}
public L2Clan[] getClans()
{
return _clans.values().toArray(new L2Clan[_clans.size()]);
}
private ClanTable()
{
// forums has to be loaded before clan data, because of last forum id used should have also memo included
if (Config.COMMUNITY_TYPE > 0)
{
ForumsBBSManager.getInstance().initRoot();
}
_clans = new FastMap<>();
L2Clan clan;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT clan_id FROM clan_data");
ResultSet result = statement.executeQuery();
// Count the clans
int clanCount = 0;
while (result.next())
{
int clanId = result.getInt("clan_id");
_clans.put(clanId, new L2Clan(clanId));
clan = getClan(clanId);
if (clan.getDissolvingExpiryTime() != 0)
{
scheduleRemoveClan(clan.getClanId());
}
clanCount++;
}
result.close();
statement.close();
_log.info("Restored " + clanCount + " clans from the database.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error restoring ClanTable.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
allianceCheck();
restorewars();
}
/**
* @param clanId
* @return
*/
public L2Clan getClan(int clanId)
{
L2Clan clan = _clans.get(Integer.valueOf(clanId));
return clan;
}
public L2Clan getClanByName(String clanName)
{
for (L2Clan clan : getClans())
{
if (clan.getName().equalsIgnoreCase(clanName))
{
return clan;
}
}
return null;
}
/**
* Creates a new clan and store clan info to database
* @param player
* @return NULL if clan with same name already exists
*/
public L2Clan createClan(L2PcInstance player, String clanName)
{
if (null == player)
{
return null;
}
if (Config.DEBUG)
{
_log.fine(player.getObjectId() + "(" + player.getName() + ") requested a clan creation.");
}
if (10 > player.getLevel())
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_DO_NOT_MEET_CRITERIA_IN_ORDER_TO_CREATE_A_CLAN));
return null;
}
if (0 != player.getClanId())
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.FAILED_TO_CREATE_CLAN));
return null;
}
if (System.currentTimeMillis() < player.getClanCreateExpiryTime())
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_MUST_WAIT_XX_DAYS_BEFORE_CREATING_A_NEW_CLAN));
return null;
}
if (!Util.isAlphaNumeric(clanName) || (2 > clanName.length()))
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CLAN_NAME_INCORRECT));
return null;
}
if (16 < clanName.length())
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CLAN_NAME_TOO_LONG));
return null;
}
if (null != getClanByName(clanName))
{
// clan name is already taken
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_ALREADY_EXISTS);
sm.addString(clanName);
player.sendPacket(sm);
sm = null;
return null;
}
L2Clan clan = new L2Clan(IdFactory.getInstance().getNextId(), clanName);
L2ClanMember leader = new L2ClanMember(clan, player.getName(), player.getLevel(), player.getClassId().getId(), player.getObjectId(), player.getPledgeType(), player.getPowerGrade(), player.getTitle(), player.getAppearance().getSex(), player.getRace().ordinal());
clan.setLeader(leader);
leader.setPlayerInstance(player);
clan.store();
player.setClan(clan);
player.setPledgeClass(leader.calculatePledgeClass(player));
player.setClanPrivileges(L2Clan.CP_ALL);
if (Config.DEBUG)
{
_log.fine("New clan created: " + clan.getClanId() + " " + clan.getName());
}
_clans.put(Integer.valueOf(clan.getClanId()), clan);
// should be update packet only
player.sendPacket(new PledgeShowInfoUpdate(clan));
player.sendPacket(new PledgeShowMemberListAll(clan, player));
player.sendPacket(new UserInfo(player));
player.sendPacket(new ExBrExtraUserInfo(player));
player.sendPacket(new PledgeShowMemberListUpdate(player));
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.CLAN_CREATED));
// notify CB server that a new Clan is created
CommunityServerThread.getInstance().sendPacket(new WorldInfo(null, clan, WorldInfo.TYPE_UPDATE_CLAN_DATA));
return clan;
}
public synchronized void destroyClan(int clanId)
{
L2Clan clan = getClan(clanId);
if (clan == null)
{
return;
}
clan.broadcastToOnlineMembers(SystemMessage.getSystemMessage(SystemMessageId.CLAN_HAS_DISPERSED));
int castleId = clan.getHasCastle();
if (castleId == 0)
{
for (Siege siege : SiegeManager.getInstance().getSieges())
{
siege.removeSiegeClan(clan);
}
}
int fortId = clan.getHasFort();
if (fortId == 0)
{
for (FortSiege siege : FortSiegeManager.getInstance().getSieges())
{
siege.removeSiegeClan(clan);
}
}
L2ClanMember leaderMember = clan.getLeader();
if (leaderMember == null)
{
clan.getWarehouse().destroyAllItems("ClanRemove", null, null);
}
else
{
clan.getWarehouse().destroyAllItems("ClanRemove", clan.getLeader().getPlayerInstance(), null);
}
for (L2ClanMember member : clan.getMembers())
{
clan.removeClanMember(member.getObjectId(), 0);
}
_clans.remove(clanId);
IdFactory.getInstance().releaseId(clanId);
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM clan_data WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement.close();
statement = con.prepareStatement("DELETE FROM clan_privs WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement.close();
statement = con.prepareStatement("DELETE FROM clan_skills WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement.close();
statement = con.prepareStatement("DELETE FROM clan_subpledges WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement.close();
statement = con.prepareStatement("DELETE FROM clan_wars WHERE clan1=? OR clan2=?");
statement.setInt(1, clanId);
statement.setInt(2, clanId);
statement.execute();
statement.close();
statement = con.prepareStatement("DELETE FROM clan_notices WHERE clan_id=?");
statement.setInt(1, clanId);
statement.execute();
statement.close();
if (castleId != 0)
{
statement = con.prepareStatement("UPDATE castle SET taxPercent = 0 WHERE id = ?");
statement.setInt(1, castleId);
statement.execute();
statement.close();
}
if (fortId != 0)
{
Fort fort = FortManager.getInstance().getFortById(fortId);
if (fort != null)
{
L2Clan owner = fort.getOwnerClan();
if (clan == owner)
{
fort.removeOwner(true);
}
}
}
if (Config.DEBUG)
{
_log.fine("clan removed in db: " + clanId);
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error removing clan from DB.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public void scheduleRemoveClan(final int clanId)
{
ThreadPoolManager.getInstance().scheduleGeneral(() ->
{
if (getClan(clanId) == null)
{
return;
}
if (getClan(clanId).getDissolvingExpiryTime() != 0)
{
destroyClan(clanId);
}
}, Math.max(getClan(clanId).getDissolvingExpiryTime() - System.currentTimeMillis(), 300000));
}
public boolean isAllyExists(String allyName)
{
for (L2Clan clan : getClans())
{
if ((clan.getAllyName() != null) && clan.getAllyName().equalsIgnoreCase(allyName))
{
return true;
}
}
return false;
}
public void storeclanswars(int clanId1, int clanId2)
{
L2Clan clan1 = ClanTable.getInstance().getClan(clanId1);
L2Clan clan2 = ClanTable.getInstance().getClan(clanId2);
clan1.setEnemyClan(clan2);
clan2.setAttackerClan(clan1);
clan1.broadcastClanStatus();
clan2.broadcastClanStatus();
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("REPLACE INTO clan_wars (clan1, clan2, wantspeace1, wantspeace2) VALUES(?,?,?,?)");
statement.setInt(1, clanId1);
statement.setInt(2, clanId2);
statement.setInt(3, 0);
statement.setInt(4, 0);
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error storing clan wars data.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
// SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.WAR_WITH_THE_S1_CLAN_HAS_BEGUN);
//
SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.CLAN_WAR_DECLARED_AGAINST_S1_IF_KILLED_LOSE_LOW_EXP);
msg.addString(clan2.getName());
clan1.broadcastToOnlineMembers(msg);
// msg = SystemMessage.getSystemMessage(SystemMessageId.WAR_WITH_THE_S1_CLAN_HAS_BEGUN);
// msg.addString(clan1.getName());
// clan2.broadcastToOnlineMembers(msg);
// clan1 declared clan war.
msg = SystemMessage.getSystemMessage(SystemMessageId.CLAN_S1_DECLARED_WAR);
msg.addString(clan1.getName());
clan2.broadcastToOnlineMembers(msg);
}
public void deleteclanswars(int clanId1, int clanId2)
{
L2Clan clan1 = ClanTable.getInstance().getClan(clanId1);
L2Clan clan2 = ClanTable.getInstance().getClan(clanId2);
clan1.deleteEnemyClan(clan2);
clan2.deleteAttackerClan(clan1);
clan1.broadcastClanStatus();
clan2.broadcastClanStatus();
// for(L2ClanMember player: clan1.getMembers())
// {
// if(player.getPlayerInstance()!=null)
// player.getPlayerInstance().setWantsPeace(0);
// }
// for(L2ClanMember player: clan2.getMembers())
// {
// if(player.getPlayerInstance()!=null)
// player.getPlayerInstance().setWantsPeace(0);
// }
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM clan_wars WHERE clan1=? AND clan2=?");
statement.setInt(1, clanId1);
statement.setInt(2, clanId2);
statement.execute();
// statement = con.prepareStatement("DELETE FROM clan_wars WHERE clan1=? AND clan2=?");
// statement.setInt(1,clanId2);
// statement.setInt(2,clanId1);
// statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error removing clan wars data.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
// SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.WAR_WITH_THE_S1_CLAN_HAS_ENDED);
SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.WAR_AGAINST_S1_HAS_STOPPED);
msg.addString(clan2.getName());
clan1.broadcastToOnlineMembers(msg);
msg = SystemMessage.getSystemMessage(SystemMessageId.CLAN_S1_HAS_DECIDED_TO_STOP);
msg.addString(clan1.getName());
clan2.broadcastToOnlineMembers(msg);
// msg = SystemMessage.getSystemMessage(SystemMessageId.WAR_WITH_THE_S1_CLAN_HAS_ENDED);
// msg.addString(clan1.getName());
// clan2.broadcastToOnlineMembers(msg);
}
public void checkSurrender(L2Clan clan1, L2Clan clan2)
{
int count = 0;
for (L2ClanMember player : clan1.getMembers())
{
if ((player != null) && (player.getPlayerInstance().getWantsPeace() == 1))
{
count++;
}
}
if (count == (clan1.getMembers().length - 1))
{
clan1.deleteEnemyClan(clan2);
clan2.deleteEnemyClan(clan1);
deleteclanswars(clan1.getClanId(), clan2.getClanId());
}
}
private void restorewars()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT clan1, clan2, wantspeace1, wantspeace2 FROM clan_wars");
ResultSet rset = statement.executeQuery();
while (rset.next())
{
getClan(rset.getInt("clan1")).setEnemyClan(rset.getInt("clan2"));
getClan(rset.getInt("clan2")).setAttackerClan(rset.getInt("clan1"));
}
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error restoring clan wars data.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* Check for nonexistent alliances
*/
private void allianceCheck()
{
for (L2Clan clan : _clans.values())
{
int allyId = clan.getAllyId();
if ((allyId != 0) && (clan.getClanId() != allyId))
{
if (!_clans.containsKey(allyId))
{
clan.setAllyId(0);
clan.setAllyName(null);
clan.changeAllyCrest(0, true);
clan.updateClanInDB();
_log.info(getClass().getSimpleName() + ": Removed alliance from clan: " + clan);
}
}
}
}
public void storeClanScore()
{
for (L2Clan clan : _clans.values())
{
clan.updateClanScoreInDB();
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ClanTable _instance = new ClanTable();
}
}
@@ -0,0 +1,396 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.instancemanager.ClanHallManager;
import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jserver.gameserver.model.entity.ClanHall;
import com.l2jserver.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.templates.chars.L2CharTemplate;
public class DoorTable
{
private static final Logger _log = Logger.getLogger(DoorTable.class.getName());
private final TIntObjectHashMap<L2DoorInstance> _staticItems;
private final TIntObjectHashMap<ArrayList<L2DoorInstance>> _regions;
public static DoorTable getInstance()
{
return SingletonHolder._instance;
}
private DoorTable()
{
_staticItems = new TIntObjectHashMap<>();
_regions = new TIntObjectHashMap<>();
parseData();
onStart();
}
public void reloadAll()
{
respawn();
}
public void respawn()
{
_staticItems.clear();
_regions.clear();
parseData();
}
public void parseData()
{
File doorData = new File(Config.DATAPACK_ROOT, "data/door.csv");
try (LineNumberReader lnr = new LineNumberReader(new BufferedReader(new FileReader(doorData))))
{
String line = null;
_log.info("Searching clan halls doors:");
while ((line = lnr.readLine()) != null)
{
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
L2DoorInstance door = parseList(line, false);
putDoor(door);
door.spawnMe(door.getX(), door.getY(), door.getZ());
ClanHall clanhall = ClanHallManager.getInstance().getNearbyClanHall(door.getX(), door.getY(), 500);
if (clanhall != null)
{
clanhall.getDoors().add(door);
door.setClanHall(clanhall);
if (Config.DEBUG)
{
_log.info("door " + door.getDoorName() + " attached to ch " + clanhall.getName());
}
}
}
_log.info("DoorTable: Loaded " + _staticItems.size() + " Door Templates for " + _regions.size() + " regions.");
}
catch (FileNotFoundException e)
{
_log.warning("door.csv is missing in data folder");
}
catch (IOException e)
{
_log.log(Level.WARNING, "Error while creating door table " + e.getMessage(), e);
}
}
/**
* Parses door list.
* @param line string
* @param commanderDoor whether the door is commander door (fortress)
* @return created door instance
*/
public static L2DoorInstance parseList(final String line, final boolean commanderDoor)
{
StringTokenizer st = new StringTokenizer(line, ";");
L2DoorInstance door = null;
try
{
String name = st.nextToken();
int id = Integer.parseInt(st.nextToken());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
int z = Integer.parseInt(st.nextToken());
int rangeXMin = Integer.parseInt(st.nextToken());
int rangeYMin = Integer.parseInt(st.nextToken());
int rangeZMin = Integer.parseInt(st.nextToken());
int rangeXMax = Integer.parseInt(st.nextToken());
int rangeYMax = Integer.parseInt(st.nextToken());
int rangeZMax = Integer.parseInt(st.nextToken());
int hp = Integer.parseInt(st.nextToken());
int pdef = Integer.parseInt(st.nextToken());
int mdef = Integer.parseInt(st.nextToken());
int emitter = Integer.parseInt(st.nextToken());
boolean unlockable = false;
if (st.hasMoreTokens())
{
unlockable = Boolean.parseBoolean(st.nextToken());
}
boolean startOpen = false;
if (st.hasMoreTokens())
{
startOpen = Boolean.parseBoolean(st.nextToken());
}
boolean targetable = true;
if (st.hasMoreTokens())
{
targetable = Boolean.parseBoolean(st.nextToken());
}
if (rangeXMin > rangeXMax)
{
_log.severe("Error in door data, XMin > XMax, ID:" + id);
}
if (rangeYMin > rangeYMax)
{
_log.severe("Error in door data, YMin > YMax, ID:" + id);
}
if (rangeZMin > rangeZMax)
{
_log.severe("Error in door data, ZMin > ZMax, ID:" + id);
}
int collisionRadius; // (max) radius for movement checks
if ((rangeXMax - rangeXMin) > (rangeYMax - rangeYMin))
{
collisionRadius = rangeYMax - rangeYMin;
}
else
{
collisionRadius = rangeXMax - rangeXMin;
}
StatsSet npcDat = new StatsSet();
npcDat.set("npcId", id);
npcDat.set("level", 0);
npcDat.set("jClass", "door");
npcDat.set("baseSTR", 0);
npcDat.set("baseCON", 0);
npcDat.set("baseDEX", 0);
npcDat.set("baseINT", 0);
npcDat.set("baseWIT", 0);
npcDat.set("baseMEN", 0);
npcDat.set("baseShldDef", 0);
npcDat.set("baseShldRate", 0);
npcDat.set("baseAccCombat", 38);
npcDat.set("baseEvasRate", 38);
npcDat.set("baseCritRate", 38);
// npcDat.set("name", "");
npcDat.set("collision_radius", collisionRadius);
npcDat.set("collision_height", rangeZMax - rangeZMin);
npcDat.set("sex", "male");
npcDat.set("type", "");
npcDat.set("baseAtkRange", 0);
npcDat.set("baseMpMax", 0);
npcDat.set("baseCpMax", 0);
npcDat.set("rewardExp", 0);
npcDat.set("rewardSp", 0);
npcDat.set("basePAtk", 0);
npcDat.set("baseMAtk", 0);
npcDat.set("basePAtkSpd", 0);
npcDat.set("aggroRange", 0);
npcDat.set("baseMAtkSpd", 0);
npcDat.set("rhand", 0);
npcDat.set("lhand", 0);
npcDat.set("armor", 0);
npcDat.set("baseWalkSpd", 0);
npcDat.set("baseRunSpd", 0);
npcDat.set("name", name);
npcDat.set("baseHpMax", hp);
npcDat.set("baseHpReg", 3.e-3f);
npcDat.set("baseMpReg", 3.e-3f);
npcDat.set("basePDef", pdef);
npcDat.set("baseMDef", mdef);
L2CharTemplate template = new L2CharTemplate(npcDat);
door = new L2DoorInstance(IdFactory.getInstance().getNextId(), template, id, name, unlockable);
door.setRange(rangeXMin, rangeYMin, rangeZMin, rangeXMax, rangeYMax, rangeZMax);
door.setCurrentHpMp(door.getMaxHp(), door.getMaxMp());
door.setXYZInvisible(x, y, z);
door.setMapRegion(MapRegionTable.getInstance().getMapRegion(x, y));
door.setEmitter(emitter);
door.setTargetable(targetable);
if (commanderDoor)
{
door.setIsCommanderDoor(startOpen);
}
else
{
door.setOpen(startOpen);
}
}
catch (Exception e)
{
_log.severe("Error in door data at line: " + line);
}
return door;
}
public L2DoorInstance getDoor(Integer id)
{
return _staticItems.get(id);
}
public void putDoor(L2DoorInstance door)
{
_staticItems.put(door.getDoorId(), door);
if (_regions.contains(door.getMapRegion()))
{
_regions.get(door.getMapRegion()).add(door);
}
else
{
final ArrayList<L2DoorInstance> region = new ArrayList<>();
region.add(door);
_regions.put(door.getMapRegion(), region);
}
}
public L2DoorInstance[] getDoors()
{
L2DoorInstance[] _allTemplates = _staticItems.getValues(new L2DoorInstance[_staticItems.size()]);
return _allTemplates;
}
/**
* Performs a check and sets up a scheduled task for those doors that require auto opening/closing.
*/
public void checkAutoOpen()
{
for (L2DoorInstance doorInst : getDoors())
{
// Garden of Eva (every 7 minutes)
if (doorInst.getDoorName().startsWith("goe"))
{
doorInst.setAutoActionDelay(420000);
}
else if (doorInst.getDoorName().startsWith("aden_tower"))
{
doorInst.setAutoActionDelay(300000);
}
}
/*
* TODO: check which are automatic // devils (every 5 minutes) else if (doorInst.getDoorName().startsWith("pirate_isle")) doorInst.setAutoActionDelay(300000); // Cruma Tower (every 20 minutes) else if (doorInst.getDoorName().startsWith("cruma")) doorInst.setAutoActionDelay(1200000);
*/
}
public boolean checkIfDoorsBetween(AbstractNodeLoc start, AbstractNodeLoc end, int instanceId)
{
return checkIfDoorsBetween(start.getX(), start.getY(), start.getZ(), end.getX(), end.getY(), end.getZ(), instanceId);
}
public boolean checkIfDoorsBetween(int x, int y, int z, int tx, int ty, int tz, int instanceId)
{
ArrayList<L2DoorInstance> allDoors;
if ((instanceId > 0) && (InstanceManager.getInstance().getInstance(instanceId) != null))
{
allDoors = InstanceManager.getInstance().getInstance(instanceId).getDoors();
}
else
{
allDoors = _regions.get(MapRegionTable.getInstance().getMapRegion(x, y));
}
if (allDoors == null)
{
return false;
}
for (L2DoorInstance doorInst : allDoors)
{
if (doorInst.getXMax() == 0)
{
continue;
}
// line segment goes through box
// first basic checks to stop most calculations short
// phase 1, x
if (((x <= doorInst.getXMax()) && (tx >= doorInst.getXMin())) || ((tx <= doorInst.getXMax()) && (x >= doorInst.getXMin())))
{
// phase 2, y
if (((y <= doorInst.getYMax()) && (ty >= doorInst.getYMin())) || ((ty <= doorInst.getYMax()) && (y >= doorInst.getYMin())))
{
// phase 3, basically only z remains but now we calculate it with another formula (by rage)
// in some cases the direct line check (only) in the beginning isn't sufficient,
// when char z changes a lot along the path
if ((doorInst.getCurrentHp() > 0) && !doorInst.getOpen())
{
int px1 = doorInst.getXMin();
int py1 = doorInst.getYMin();
int pz1 = doorInst.getZMin();
int px2 = doorInst.getXMax();
int py2 = doorInst.getYMax();
int pz2 = doorInst.getZMax();
int l = tx - x;
int m = ty - y;
int n = tz - z;
int dk;
if ((dk = ((doorInst.getA() * l) + (doorInst.getB() * m) + (doorInst.getC() * n))) == 0)
{
continue; // Parallel
}
float p = (float) ((doorInst.getA() * x) + (doorInst.getB() * y) + (doorInst.getC() * z) + doorInst.getD()) / (float) dk;
int fx = (int) (x - (l * p));
int fy = (int) (y - (m * p));
int fz = (int) (z - (n * p));
if (((Math.min(x, tx) <= fx) && (fx <= Math.max(x, tx))) && ((Math.min(y, ty) <= fy) && (fy <= Math.max(y, ty))) && ((Math.min(z, tz) <= fz) && (fz <= Math.max(z, tz))))
{
if ((((fx >= px1) && (fx <= px2)) || ((fx >= px2) && (fx <= px1))) && (((fy >= py1) && (fy <= py2)) || ((fy >= py2) && (fy <= py1))) && (((fz >= pz1) && (fz <= pz2)) || ((fz >= pz2) && (fz <= pz1))))
{
return true; // Door between
}
}
}
}
}
}
return false;
}
private void onStart()
{
try
{
checkAutoOpen();
}
catch (NullPointerException e)
{
_log.log(Level.WARNING, "There are errors in your Door.csv file. Update door.csv", e);
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final DoorTable _instance = new DoorTable();
}
}
@@ -0,0 +1,232 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.L2EnchantSkillGroup;
import com.l2jserver.gameserver.model.L2EnchantSkillGroup.EnchantSkillDetail;
import com.l2jserver.gameserver.model.L2EnchantSkillLearn;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* This class ...
* @version $Revision: 1.13.2.2.2.8 $ $Date: 2005/04/06 16:13:25 $
*/
public class EnchantGroupsTable
{
public static final int NORMAL_ENCHANT_COST_MULTIPLIER = 1;
public static final int SAFE_ENCHANT_COST_MULTIPLIER = 5;
public static final int NORMAL_ENCHANT_BOOK = 6622;
public static final int SAFE_ENCHANT_BOOK = 9627;
public static final int CHANGE_ENCHANT_BOOK = 9626;
public static final int UNTRAIN_ENCHANT_BOOK = 9625;
private static Logger _log = Logger.getLogger(EnchantGroupsTable.class.getName());
private TIntObjectHashMap<L2EnchantSkillGroup> _enchantSkillGroups; // enchant skill group
private TIntObjectHashMap<L2EnchantSkillLearn> _enchantSkillTrees; // enchant skill list
public static EnchantGroupsTable getInstance()
{
return SingletonHolder._instance;
}
private EnchantGroupsTable()
{
load();
}
private void load()
{
int count = 0;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
try
{
_enchantSkillGroups = new TIntObjectHashMap<>();
_enchantSkillTrees = new TIntObjectHashMap<>();
PreparedStatement statement = con.prepareStatement("SELECT group_id, level, adena, exp, sp, success_rate76, success_rate77, success_rate78, success_rate79, success_rate80, success_rate81, success_rate82, success_rate83, success_rate84, success_rate85 FROM enchant_skill_groups ORDER BY group_id, level");
ResultSet enchantGroups = statement.executeQuery();
int prevGroupId = -1;
while (enchantGroups.next())
{
int id = enchantGroups.getInt("group_id");
int lvl = enchantGroups.getInt("level");
int adena = enchantGroups.getInt("adena");
int exp = enchantGroups.getInt("exp");
int sp = enchantGroups.getInt("sp");
byte rate76 = enchantGroups.getByte("success_rate76");
byte rate77 = enchantGroups.getByte("success_rate77");
byte rate78 = enchantGroups.getByte("success_rate78");
byte rate79 = enchantGroups.getByte("success_rate79");
byte rate80 = enchantGroups.getByte("success_rate80");
byte rate81 = enchantGroups.getByte("success_rate81");
byte rate82 = enchantGroups.getByte("success_rate82");
byte rate83 = enchantGroups.getByte("success_rate83");
byte rate84 = enchantGroups.getByte("success_rate84");
byte rate85 = enchantGroups.getByte("success_rate85");
if (prevGroupId != id)
{
prevGroupId = id;
}
L2EnchantSkillGroup group = _enchantSkillGroups.get(id);
if (group == null)
{
group = new L2EnchantSkillGroup(id);
_enchantSkillGroups.put(id, group);
count++;
}
EnchantSkillDetail esd = new EnchantSkillDetail(lvl, adena, exp, sp, rate76, rate77, rate78, rate79, rate80, rate81, rate82, rate83, rate84, rate85);
group.addEnchantDetail(esd);
}
enchantGroups.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error while loading enchant skill groups ", e);
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error while loading enchant skill groups ", e);
}
finally
{
L2DatabaseFactory.close(con);
}
_log.info("EnchantGroupsTable: Loaded " + count + " groups.");
}
public int addNewRouteForSkill(int skillId, int maxLvL, int route, int group)
{
L2EnchantSkillLearn enchantableSkill = _enchantSkillTrees.get(skillId);
if (enchantableSkill == null)
{
enchantableSkill = new L2EnchantSkillLearn(skillId, maxLvL);
_enchantSkillTrees.put(skillId, enchantableSkill);
}
if (_enchantSkillGroups.containsKey(group))
{
enchantableSkill.addNewEnchantRoute(route, group);
return _enchantSkillGroups.get(group).getEnchantGroupDetails().size();
}
_log.log(Level.SEVERE, "Error while loading generating enchant skill id: " + skillId + "; route: " + route + "; missing group: " + group);
return 0;
}
public L2EnchantSkillLearn getSkillEnchantmentForSkill(L2Skill skill)
{
L2EnchantSkillLearn esl = getSkillEnchantmentBySkillId(skill.getId());
// there is enchantment for this skill and we have the required level of it
if ((esl != null) && (skill.getLevel() >= esl.getBaseLevel()))
{
return esl;
}
return null;
}
public L2EnchantSkillLearn getSkillEnchantmentBySkillId(int skillId)
{
return _enchantSkillTrees.get(skillId);
}
public int getEnchantSkillSpCost(L2Skill skill)
{
L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
if (enchantSkillLearn != null)
{
EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
if (esd != null)
{
return esd.getSpCost();
}
}
return Integer.MAX_VALUE;
}
public int getEnchantSkillAdenaCost(L2Skill skill)
{
L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
if (enchantSkillLearn != null)
{
EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
if (esd != null)
{
return esd.getAdenaCost();
}
}
return Integer.MAX_VALUE;
}
public byte getEnchantSkillRate(L2PcInstance player, L2Skill skill)
{
L2EnchantSkillLearn enchantSkillLearn = _enchantSkillTrees.get(skill.getId());
if (enchantSkillLearn != null)
{
EnchantSkillDetail esd = enchantSkillLearn.getEnchantSkillDetail(skill.getLevel());
if (esd != null)
{
return esd.getRate(player);
}
}
return 0;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final EnchantGroupsTable _instance = new EnchantGroupsTable();
}
/**
* @return L2EnchantSkillGroup
*/
public L2EnchantSkillGroup getEnchantSkillGroupById(int id)
{
return _enchantSkillGroups.get(id);
}
public void reload()
{
load();
}
}
@@ -0,0 +1,202 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.io.File;
import java.util.Collection;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.skills.Stats;
import com.l2jserver.gameserver.skills.funcs.FuncTemplate;
import com.l2jserver.gameserver.skills.funcs.LambdaConst;
import com.l2jserver.gameserver.templates.item.L2Item;
/**
* @author MrPoke
*/
public class EnchantHPBonusData
{
protected static final Logger _log = Logger.getLogger(EnchantHPBonusData.class.getName());
private final TIntObjectHashMap<Integer[]> _armorHPBonus = new TIntObjectHashMap<>();
private static final float fullArmorModifier = 1.5f;
public static final EnchantHPBonusData getInstance()
{
return SingletonHolder._instance;
}
private EnchantHPBonusData()
{
load();
}
public void reload()
{
load();
}
private void load()
{
_armorHPBonus.clear();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT, "data/enchantHPBonus.xml");
Document doc = null;
if (file.exists())
{
try
{
doc = factory.newDocumentBuilder().parse(file);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Could not parse enchantHPBonus.xml file: " + e.getMessage(), e);
return;
}
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("enchantHP".equalsIgnoreCase(d.getNodeName()))
{
NamedNodeMap attrs = d.getAttributes();
Node att;
Integer grade;
att = attrs.getNamedItem("grade");
if (att == null)
{
_log.severe("[EnchantHPBonusData] Missing grade, skipping");
continue;
}
grade = Integer.parseInt(att.getNodeValue());
att = attrs.getNamedItem("values");
if (att == null)
{
_log.severe("[EnchantHPBonusData] Missing bonus id: " + grade + ", skipping");
continue;
}
StringTokenizer st = new StringTokenizer(att.getNodeValue(), ",");
int tokenCount = st.countTokens();
Integer[] bonus = new Integer[tokenCount];
for (int i = 0; i < tokenCount; i++)
{
Integer value = Integer.decode(st.nextToken().trim());
if (value == null)
{
_log.severe("[EnchantHPBonusData] Bad Hp value!! grade: " + grade + " token: " + i);
value = 0;
}
bonus[i] = value;
}
_armorHPBonus.put(grade, bonus);
}
}
}
}
if (_armorHPBonus.isEmpty())
{
return;
}
Collection<Integer> itemIds = ItemTable.getInstance().getAllArmorsId();
int count = 0;
for (Integer itemId : itemIds)
{
L2Item item = ItemTable.getInstance().getTemplate(itemId);
if ((item != null) && (item.getCrystalType() != L2Item.CRYSTAL_NONE))
{
switch (item.getBodyPart())
{
case L2Item.SLOT_CHEST:
case L2Item.SLOT_FEET:
case L2Item.SLOT_GLOVES:
case L2Item.SLOT_HEAD:
case L2Item.SLOT_LEGS:
case L2Item.SLOT_BACK:
case L2Item.SLOT_FULL_ARMOR:
case L2Item.SLOT_UNDERWEAR:
case L2Item.SLOT_L_HAND:
count++;
FuncTemplate ft = new FuncTemplate(null, null, "EnchantHp", Stats.MAX_HP, 0x60, new LambdaConst(0));
item.attach(ft);
break;
}
}
}
// shields in the weapons table
itemIds = ItemTable.getInstance().getAllWeaponsId();
for (Integer itemId : itemIds)
{
L2Item item = ItemTable.getInstance().getTemplate(itemId);
if ((item != null) && (item.getCrystalType() != L2Item.CRYSTAL_NONE))
{
switch (item.getBodyPart())
{
case L2Item.SLOT_L_HAND:
count++;
FuncTemplate ft = new FuncTemplate(null, null, "EnchantHp", Stats.MAX_HP, 0x60, new LambdaConst(0));
item.attach(ft);
break;
}
}
}
_log.info("Enchant HP Bonus registered for " + count + " items!");
}
}
public final int getHPBonus(L2ItemInstance item)
{
final Integer[] values = _armorHPBonus.get(item.getItem().getItemGradeSPlus());
if ((values == null) || (values.length == 0))
{
return 0;
}
if (item.getItem().getBodyPart() == L2Item.SLOT_FULL_ARMOR)
{
return (int) (values[Math.min(item.getEnchantLevel(), values.length) - 1] * fullArmorModifier);
}
return values[Math.min(item.getEnchantLevel(), values.length) - 1];
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final EnchantHPBonusData _instance = new EnchantHPBonusData();
}
}
@@ -0,0 +1,118 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.util.Date;
import java.util.List;
import javolution.util.FastList;
import com.l2jserver.gameserver.script.DateRange;
/**
* This class manage drop of Special Events created by GM for a defined period. During a Special Event all L2Attackable can drop extra Items. Those extra Items are defined in the table <B>allNpcDateDrops</B>. Each Special Event has a start and end date to stop to drop extra Items automaticaly.<BR>
* <BR>
*/
public class EventDroplist
{
// private static Logger _log = Logger.getLogger(EventDroplist.class.getName());
/** The table containing all DataDrop object */
private final List<DateDrop> _allNpcDateDrops;
public static EventDroplist getInstance()
{
return SingletonHolder._instance;
}
public static class DateDrop
{
/** Start and end date of the Event */
public DateRange dateRange;
/** The table containing Item identifier that can be dropped as extra Items during the Event */
public int[] items;
/** The min number of Item dropped in one time during this Event */
public int min;
/** The max number of Item dropped in one time during this Event */
public int max;
/** The rate of drop for this Event */
public int chance;
}
/**
* Constructor of EventDroplist.<BR>
* <BR>
*/
private EventDroplist()
{
_allNpcDateDrops = new FastList<>();
}
/**
* Create and Init a new DateDrop then add it to the allNpcDateDrops of EventDroplist .<BR>
* <BR>
* @param items The table containing all item identifier of this DateDrop
* @param count The table containing min and max value of this DateDrop
* @param chance The chance to obtain this drop
* @param range The DateRange object to add to this DateDrop
*/
public void addGlobalDrop(int[] items, int[] count, int chance, DateRange range)
{
DateDrop date = new DateDrop();
date.dateRange = range;
date.items = items;
date.min = count[0];
date.max = count[1];
date.chance = chance;
_allNpcDateDrops.add(date);
}
/**
* Return all DateDrop of EventDroplist allNpcDateDrops within the date range.<BR>
* <BR>
*/
public List<DateDrop> getAllDrops()
{
List<DateDrop> list = new FastList<>();
for (DateDrop drop : _allNpcDateDrops)
{
Date currentDate = new Date();
// _log.info("From: "+drop.from+" To: "+drop.to+" Now: "+ currentDate);
if (drop.dateRange.isWithinRange(currentDate))
{
list.add(drop);
}
}
return list;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final EventDroplist _instance = new EventDroplist();
}
}
@@ -0,0 +1,153 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.FishData;
/**
* @author -Nemesiss-
*/
public class FishTable
{
private static Logger _log = Logger.getLogger(FishTable.class.getName());
private static List<FishData> _fishsNormal;
private static List<FishData> _fishsEasy;
private static List<FishData> _fishsHard;
public static FishTable getInstance()
{
return SingletonHolder._instance;
}
private FishTable()
{
// Create table that contains all fish datas
int count = 0;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
_fishsEasy = new FastList<>();
_fishsNormal = new FastList<>();
_fishsHard = new FastList<>();
FishData fish;
PreparedStatement statement = con.prepareStatement("SELECT id, level, name, hp, hpregen, fish_type, fish_group, fish_guts, guts_check_time, wait_time, combat_time FROM fish ORDER BY id");
ResultSet fishes = statement.executeQuery();
while (fishes.next())
{
int id = fishes.getInt("id");
int lvl = fishes.getInt("level");
String name = fishes.getString("name");
int hp = fishes.getInt("hp");
int hpreg = fishes.getInt("hpregen");
int type = fishes.getInt("fish_type");
int group = fishes.getInt("fish_group");
int fish_guts = fishes.getInt("fish_guts");
int guts_check_time = fishes.getInt("guts_check_time");
int wait_time = fishes.getInt("wait_time");
int combat_time = fishes.getInt("combat_time");
fish = new FishData(id, lvl, name, hp, hpreg, type, group, fish_guts, guts_check_time, wait_time, combat_time);
switch (fish.getGroup())
{
case 0:
_fishsEasy.add(fish);
break;
case 1:
_fishsNormal.add(fish);
break;
case 2:
_fishsHard.add(fish);
}
}
fishes.close();
statement.close();
count = _fishsEasy.size() + _fishsNormal.size() + _fishsHard.size();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error while creating fish table" + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
_log.info("FishTable: Loaded " + count + " Fishes.");
}
/**
* @param Fish - lvl
* @param Fish - type
* @param Fish - group
* @return List of Fish that can be fished
*/
public List<FishData> getfish(int lvl, int type, int group)
{
List<FishData> result = new FastList<>();
List<FishData> _Fishs = null;
switch (group)
{
case 0:
_Fishs = _fishsEasy;
break;
case 1:
_Fishs = _fishsNormal;
break;
case 2:
_Fishs = _fishsHard;
}
if (_Fishs == null)
{
// the fish list is empty
_log.warning("Fish are not defined !");
return null;
}
for (FishData f : _Fishs)
{
if (f.getLevel() != lvl)
{
continue;
}
if (f.getType() != type)
{
continue;
}
result.add(f);
}
if (result.isEmpty())
{
_log.warning("Cant Find Any Fish!? - Lvl: " + lvl + " Type: " + type);
}
return result;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final FishTable _instance = new FishTable();
}
}
@@ -0,0 +1,108 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* @author Gnacik
*/
public class GMSkillTable
{
private static final L2Skill[] _gmSkills = new L2Skill[34];
private static final int[] _gmSkillsId =
{
7029,
7041,
7042,
7043,
7044,
7045,
7046,
7047,
7048,
7049,
7050,
7051,
7052,
7053,
7054,
7055,
7056,
7057,
7058,
7059,
7060,
7061,
7062,
7063,
7064,
7088,
7089,
7090,
7091,
7092,
7093,
7094,
7095,
7096
};
private GMSkillTable()
{
for (int i = 0; i < _gmSkillsId.length; i++)
{
_gmSkills[i] = SkillTable.getInstance().getInfo(_gmSkillsId[i], 1);
}
}
public static GMSkillTable getInstance()
{
return SingletonHolder._instance;
}
public static L2Skill[] getGMSkills()
{
return _gmSkills;
}
public static boolean isGMSkill(int skillid)
{
for (int id : _gmSkillsId)
{
if (id == skillid)
{
return true;
}
}
return false;
}
public void addSkills(L2PcInstance gmchar)
{
for (L2Skill s : getGMSkills())
{
gmchar.addSkill(s, false); // Don't Save GM skills to database
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final GMSkillTable _instance = new GMSkillTable();
}
}
@@ -0,0 +1,227 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.templates.L2HelperBuff;
import com.l2jserver.gameserver.templates.StatsSet;
/**
* This class represents the Newbie Helper Buff list Author: Ayor
*/
public class HelperBuffTable
{
private static Logger _log = Logger.getLogger(HennaTable.class.getName());
/** The table containing all Buff of the Newbie Helper */
private final List<L2HelperBuff> _helperBuff;
/**
* The player level since Newbie Helper can give the fisrt buff <BR>
* Used to generate message : "Come back here when you have reached level ...")
*/
private int _magicClassLowestLevel = 100;
private int _physicClassLowestLevel = 100;
/**
* The player level above which Newbie Helper won't give any buff <BR>
* Used to generate message : "Only novice character of level ... or less can receive my support magic.")
*/
private int _magicClassHighestLevel = 1;
private int _physicClassHighestLevel = 1;
private int _servitorLowestLevel = 100;
private int _servitorHighestLevel = 1;
public static HelperBuffTable getInstance()
{
return SingletonHolder._instance;
}
/**
* Create and Load the Newbie Helper Buff list from SQL Table helper_buff_list
*/
private HelperBuffTable()
{
_helperBuff = new FastList<>();
restoreHelperBuffData();
}
/**
* Read and Load the Newbie Helper Buff list from SQL Table helper_buff_list
*/
private void restoreHelperBuffData()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT * FROM helper_buff_list");
ResultSet helperbuffdata = statement.executeQuery();
fillHelperBuffTable(helperbuffdata);
helperbuffdata.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Table helper_buff_list not found : Update your DataPack! Error : " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* Load the Newbie Helper Buff list from SQL Table helper_buff_list
*/
private void fillHelperBuffTable(ResultSet HelperBuffData) throws Exception
{
while (HelperBuffData.next())
{
StatsSet helperBuffDat = new StatsSet();
int id = HelperBuffData.getInt("id");
helperBuffDat.set("id", id);
helperBuffDat.set("skillID", HelperBuffData.getInt("skill_id"));
helperBuffDat.set("skillLevel", HelperBuffData.getInt("skill_level"));
helperBuffDat.set("lowerLevel", HelperBuffData.getInt("lower_level"));
helperBuffDat.set("upperLevel", HelperBuffData.getInt("upper_level"));
helperBuffDat.set("isMagicClass", HelperBuffData.getString("is_magic_class"));
helperBuffDat.set("forSummon", HelperBuffData.getString("forSummon"));
// Calulate the range level in wich player must be to obtain buff from Newbie Helper
if ("false".equals(HelperBuffData.getString("is_magic_class")))
{
if (HelperBuffData.getInt("lower_level") < _physicClassLowestLevel)
{
_physicClassLowestLevel = HelperBuffData.getInt("lower_level");
}
if (HelperBuffData.getInt("upper_level") > _physicClassHighestLevel)
{
_physicClassHighestLevel = HelperBuffData.getInt("upper_level");
}
}
else
{
if (HelperBuffData.getInt("lower_level") < _magicClassLowestLevel)
{
_magicClassLowestLevel = HelperBuffData.getInt("lower_level");
}
if (HelperBuffData.getInt("upper_level") > _magicClassHighestLevel)
{
_magicClassHighestLevel = HelperBuffData.getInt("upper_level");
}
}
if ("true".equals(HelperBuffData.getString("forSummon")))
{
if (HelperBuffData.getInt("lower_level") < _servitorLowestLevel)
{
_servitorLowestLevel = HelperBuffData.getInt("lower_level");
}
if (HelperBuffData.getInt("upper_level") > _servitorHighestLevel)
{
_servitorHighestLevel = HelperBuffData.getInt("upper_level");
}
}
// Add this Helper Buff to the Helper Buff List
L2HelperBuff template = new L2HelperBuff(helperBuffDat);
_helperBuff.add(template);
}
_log.info("Helper Buff Table: Loaded " + _helperBuff.size() + " Templates.");
}
/**
* Return the Helper Buff List
*/
public List<L2HelperBuff> getHelperBuffTable()
{
return _helperBuff;
}
/**
* @return Returns the magicClassHighestLevel.
*/
public int getMagicClassHighestLevel()
{
return _magicClassHighestLevel;
}
/**
* @return Returns the magicClassLowestLevel.
*/
public int getMagicClassLowestLevel()
{
return _magicClassLowestLevel;
}
/**
* @return Returns the physicClassHighestLevel.
*/
public int getPhysicClassHighestLevel()
{
return _physicClassHighestLevel;
}
/**
* @return Returns the physicClassLowestLevel.
*/
public int getPhysicClassLowestLevel()
{
return _physicClassLowestLevel;
}
/**
* @return Returns the servitorLowestLevel.
*/
public int getServitorLowestLevel()
{
return _servitorLowestLevel;
}
/**
* @return Returns the servitorHighestLevel.
*/
public int getServitorHighestLevel()
{
return _servitorHighestLevel;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final HelperBuffTable _instance = new HelperBuffTable();
}
}
@@ -0,0 +1,111 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.templates.item.L2Henna;
/**
* This class ...
* @version $Revision$ $Date$
*/
public class HennaTable
{
private static Logger _log = Logger.getLogger(HennaTable.class.getName());
private final TIntObjectHashMap<L2Henna> _henna;
public static HennaTable getInstance()
{
return SingletonHolder._instance;
}
private HennaTable()
{
_henna = new TIntObjectHashMap<>();
restoreHennaData();
}
/**
*
*/
private void restoreHennaData()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT symbol_id, symbol_name, dye_id, dye_amount, price, stat_INT, stat_STR, stat_CON, stat_MEM, stat_DEX, stat_WIT FROM henna");
ResultSet hennadata = statement.executeQuery();
fillHennaTable(hennadata);
hennadata.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error while creating henna table " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
private void fillHennaTable(ResultSet HennaData) throws Exception
{
while (HennaData.next())
{
StatsSet hennaDat = new StatsSet();
int id = HennaData.getInt("symbol_id");
hennaDat.set("symbol_id", id);
hennaDat.set("dye", HennaData.getInt("dye_id"));
hennaDat.set("price", HennaData.getInt("price"));
// amount of dye required
hennaDat.set("amount", HennaData.getInt("dye_amount"));
hennaDat.set("stat_INT", HennaData.getInt("stat_INT"));
hennaDat.set("stat_STR", HennaData.getInt("stat_STR"));
hennaDat.set("stat_CON", HennaData.getInt("stat_CON"));
hennaDat.set("stat_MEM", HennaData.getInt("stat_MEM"));
hennaDat.set("stat_DEX", HennaData.getInt("stat_DEX"));
hennaDat.set("stat_WIT", HennaData.getInt("stat_WIT"));
L2Henna template = new L2Henna(hennaDat);
_henna.put(id, template);
}
_log.info("HennaTable: Loaded " + _henna.size() + " Templates.");
}
public L2Henna getTemplate(int id)
{
return _henna.get(id);
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final HennaTable _instance = new HennaTable();
}
}
@@ -0,0 +1,149 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.L2HennaInstance;
import com.l2jserver.gameserver.model.base.ClassId;
import com.l2jserver.gameserver.templates.item.L2Henna;
/**
* This class ...
* @version $Revision$ $Date$
*/
public class HennaTreeTable
{
private static Logger _log = Logger.getLogger(HennaTreeTable.class.getName());
private Map<ClassId, List<L2HennaInstance>> _hennaTrees;
private final boolean _initialized = true;
public static HennaTreeTable getInstance()
{
return SingletonHolder._instance;
}
private HennaTreeTable()
{
_hennaTrees = new FastMap<>();
int classId = 0;
int count = 0;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT class_name, id, parent_id FROM class_list ORDER BY id");
ResultSet classlist = statement.executeQuery();
List<L2HennaInstance> list;
// int parentClassId;
// L2Henna henna;
PreparedStatement statement2 = con.prepareStatement("SELECT class_id, symbol_id FROM henna_trees where class_id=? ORDER BY symbol_id");
while (classlist.next())
{
list = new FastList<>();
classId = classlist.getInt("id");
statement2.setInt(1, classId);
ResultSet hennatree = statement2.executeQuery();
statement2.clearParameters();
while (hennatree.next())
{
int id = hennatree.getInt("symbol_id");
// String name = hennatree.getString("name");
L2Henna template = HennaTable.getInstance().getTemplate(id);
if (template == null)
{
hennatree.close();
statement2.close();
classlist.close();
statement.close();
return;
}
L2HennaInstance temp = new L2HennaInstance(template);
temp.setSymbolId(id);
temp.setItemIdDye(template.getDyeId());
temp.setAmountDyeRequire(template.getAmountDyeRequire());
temp.setPrice(template.getPrice());
temp.setStatINT(template.getStatINT());
temp.setStatSTR(template.getStatSTR());
temp.setStatCON(template.getStatCON());
temp.setStatMEM(template.getStatMEM());
temp.setStatDEX(template.getStatDEX());
temp.setStatWIT(template.getStatWIT());
list.add(temp);
}
_hennaTrees.put(ClassId.values()[classId], list);
hennatree.close();
count += list.size();
_log.fine("Henna Tree for Class: " + classId + " has " + list.size() + " Henna Templates.");
}
classlist.close();
statement.close();
statement2.close();
_log.info("HennaTreeTable: Loaded " + count + " Henna Tree Templates.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error loading Henna Tree Table.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public L2HennaInstance[] getAvailableHenna(ClassId classId)
{
List<L2HennaInstance> result = new FastList<>();
List<L2HennaInstance> henna = _hennaTrees.get(classId);
if (henna == null)
{
// the hennatree for this class is undefined, so we give an empty list
_log.warning("Hennatree for class " + classId + " is not defined !");
return new L2HennaInstance[0];
}
for (L2HennaInstance temp : henna)
{
result.add(temp);
}
return result.toArray(new L2HennaInstance[result.size()]);
}
public boolean isInitialized()
{
return _initialized;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final HennaTreeTable _instance = new HennaTreeTable();
}
}
@@ -0,0 +1,142 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.L2DropCategory;
import com.l2jserver.gameserver.model.L2DropData;
/**
* This class ...
* @version $Revision$ $Date$
*/
public class HerbDropTable
{
private static Logger _log = Logger.getLogger(HerbDropTable.class.getName());
private final TIntObjectHashMap<FastList<L2DropCategory>> _herbGroups;
public static HerbDropTable getInstance()
{
return SingletonHolder._instance;
}
private HerbDropTable()
{
_herbGroups = new TIntObjectHashMap<>();
restoreData();
}
private void restoreData()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT " + L2DatabaseFactory.getInstance().safetyString(new String[]
{
"groupId",
"itemId",
"min",
"max",
"category",
"chance"
}) + " FROM herb_droplist_groups ORDER BY groupId, chance DESC");
ResultSet dropData = statement.executeQuery();
L2DropData dropDat = null;
while (dropData.next())
{
int groupId = dropData.getInt("groupId");
FastList<L2DropCategory> category;
if (_herbGroups.contains(groupId))
{
category = _herbGroups.get(groupId);
}
else
{
category = new FastList<>();
_herbGroups.put(groupId, category);
}
dropDat = new L2DropData();
dropDat.setItemId(dropData.getInt("itemId"));
dropDat.setMinDrop(dropData.getInt("min"));
dropDat.setMaxDrop(dropData.getInt("max"));
dropDat.setChance(dropData.getInt("chance"));
int categoryType = dropData.getInt("category");
if (ItemTable.getInstance().getTemplate(dropDat.getItemId()) == null)
{
_log.warning("Herb Drop data for undefined item template! GroupId: " + groupId + " itemId: " + dropDat.getItemId());
continue;
}
boolean catExists = false;
for (L2DropCategory cat : category)
{
// if the category exists, add the drop to this category.
if (cat.getCategoryType() == categoryType)
{
cat.addDropData(dropDat, false);
catExists = true;
break;
}
}
// if the category doesn't exit, create it and add the drop
if (!catExists)
{
L2DropCategory cat = new L2DropCategory(categoryType);
cat.addDropData(dropDat, false);
category.add(cat);
}
}
dropData.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "HerbDroplistGroupsTable: Error reading Herb dropdata. ", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public FastList<L2DropCategory> getHerbDroplist(int groupId)
{
return _herbGroups.get(groupId);
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final HerbDropTable _instance = new HerbDropTable();
}
}
@@ -0,0 +1,73 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import com.l2jserver.gameserver.model.L2Skill;
/**
* @author BiTi
*/
public class HeroSkillTable
{
private static final L2Skill[] _heroSkills = new L2Skill[5];
private static final int[] _heroSkillsId =
{
395,
396,
1374,
1375,
1376
};
private HeroSkillTable()
{
for (int i = 0; i < _heroSkillsId.length; i++)
{
_heroSkills[i] = SkillTable.getInstance().getInfo(_heroSkillsId[i], 1);
}
}
public static HeroSkillTable getInstance()
{
return SingletonHolder._instance;
}
public static L2Skill[] getHeroSkills()
{
return _heroSkills;
}
public static boolean isHeroSkill(int skillid)
{
/*
* Do not perform checks directly on L2Skill array, it will cause errors due to SkillTable not initialized
*/
for (int id : _heroSkillsId)
{
if (id == skillid)
{
return true;
}
}
return false;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final HeroSkillTable _instance = new HeroSkillTable();
}
}
@@ -0,0 +1,511 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import static com.l2jserver.gameserver.model.itemcontainer.PcInventory.ADENA_ID;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.Item;
import com.l2jserver.gameserver.ThreadPoolManager;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.model.L2ItemInstance;
import com.l2jserver.gameserver.model.L2ItemInstance.ItemLocation;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.actor.L2Attackable;
import com.l2jserver.gameserver.model.actor.instance.L2EventMonsterInstance;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.skills.SkillsEngine;
import com.l2jserver.gameserver.templates.item.L2Armor;
import com.l2jserver.gameserver.templates.item.L2ArmorType;
import com.l2jserver.gameserver.templates.item.L2EtcItem;
import com.l2jserver.gameserver.templates.item.L2Item;
import com.l2jserver.gameserver.templates.item.L2Weapon;
import com.l2jserver.gameserver.templates.item.L2WeaponType;
import com.l2jserver.gameserver.util.GMAudit;
/**
* This class ...
* @version $Revision: 1.9.2.6.2.9 $ $Date: 2005/04/02 15:57:34 $
*/
public class ItemTable
{
private static Logger _log = Logger.getLogger(ItemTable.class.getName());
private static Logger _logItems = Logger.getLogger("item");
public static final Map<String, Integer> _materials = new FastMap<>();
public static final Map<String, Integer> _crystalTypes = new FastMap<>();
public static final Map<String, Integer> _slots = new FastMap<>();
public static final Map<String, L2WeaponType> _weaponTypes = new FastMap<>();
public static final Map<String, L2ArmorType> _armorTypes = new FastMap<>();
private L2Item[] _allTemplates;
private final Map<Integer, L2EtcItem> _etcItems;
private final Map<Integer, L2Armor> _armors;
private final Map<Integer, L2Weapon> _weapons;
static
{
_materials.put("adamantaite", L2Item.MATERIAL_ADAMANTAITE);
_materials.put("blood_steel", L2Item.MATERIAL_BLOOD_STEEL);
_materials.put("bone", L2Item.MATERIAL_BONE);
_materials.put("bronze", L2Item.MATERIAL_BRONZE);
_materials.put("cloth", L2Item.MATERIAL_CLOTH);
_materials.put("chrysolite", L2Item.MATERIAL_CHRYSOLITE);
_materials.put("cobweb", L2Item.MATERIAL_COBWEB);
_materials.put("cotton", L2Item.MATERIAL_FINE_STEEL);
_materials.put("crystal", L2Item.MATERIAL_CRYSTAL);
_materials.put("damascus", L2Item.MATERIAL_DAMASCUS);
_materials.put("dyestuff", L2Item.MATERIAL_DYESTUFF);
_materials.put("fine_steel", L2Item.MATERIAL_FINE_STEEL);
_materials.put("fish", L2Item.MATERIAL_FISH);
_materials.put("gold", L2Item.MATERIAL_GOLD);
_materials.put("horn", L2Item.MATERIAL_HORN);
_materials.put("leather", L2Item.MATERIAL_LEATHER);
_materials.put("liquid", L2Item.MATERIAL_LIQUID);
_materials.put("mithril", L2Item.MATERIAL_MITHRIL);
_materials.put("oriharukon", L2Item.MATERIAL_ORIHARUKON);
_materials.put("paper", L2Item.MATERIAL_PAPER);
_materials.put("rune_xp", L2Item.MATERIAL_RUNE_XP);
_materials.put("rune_sp", L2Item.MATERIAL_RUNE_SP);
_materials.put("rune_remove_penalty", L2Item.MATERIAL_RUNE_PENALTY);
_materials.put("scale_of_dragon", L2Item.MATERIAL_SCALE_OF_DRAGON);
_materials.put("seed", L2Item.MATERIAL_SEED);
_materials.put("silver", L2Item.MATERIAL_SILVER);
_materials.put("steel", L2Item.MATERIAL_STEEL);
_materials.put("wood", L2Item.MATERIAL_WOOD);
_crystalTypes.put("s84", L2Item.CRYSTAL_S84);
_crystalTypes.put("s80", L2Item.CRYSTAL_S80);
_crystalTypes.put("s", L2Item.CRYSTAL_S);
_crystalTypes.put("a", L2Item.CRYSTAL_A);
_crystalTypes.put("b", L2Item.CRYSTAL_B);
_crystalTypes.put("c", L2Item.CRYSTAL_C);
_crystalTypes.put("d", L2Item.CRYSTAL_D);
_crystalTypes.put("none", L2Item.CRYSTAL_NONE);
// weapon types
for (L2WeaponType type : L2WeaponType.values())
{
_weaponTypes.put(type.toString(), type);
}
// armor types
for (L2ArmorType type : L2ArmorType.values())
{
_armorTypes.put(type.toString(), type);
}
_slots.put("shirt", L2Item.SLOT_UNDERWEAR);
_slots.put("lbracelet", L2Item.SLOT_L_BRACELET);
_slots.put("rbracelet", L2Item.SLOT_R_BRACELET);
_slots.put("talisman", L2Item.SLOT_DECO);
_slots.put("chest", L2Item.SLOT_CHEST);
_slots.put("fullarmor", L2Item.SLOT_FULL_ARMOR);
_slots.put("head", L2Item.SLOT_HEAD);
_slots.put("hair", L2Item.SLOT_HAIR);
_slots.put("hairall", L2Item.SLOT_HAIRALL);
_slots.put("underwear", L2Item.SLOT_UNDERWEAR);
_slots.put("back", L2Item.SLOT_BACK);
_slots.put("neck", L2Item.SLOT_NECK);
_slots.put("legs", L2Item.SLOT_LEGS);
_slots.put("feet", L2Item.SLOT_FEET);
_slots.put("gloves", L2Item.SLOT_GLOVES);
_slots.put("chest,legs", L2Item.SLOT_CHEST | L2Item.SLOT_LEGS);
_slots.put("belt", L2Item.SLOT_BELT);
_slots.put("rhand", L2Item.SLOT_R_HAND);
_slots.put("lhand", L2Item.SLOT_L_HAND);
_slots.put("lrhand", L2Item.SLOT_LR_HAND);
_slots.put("rear;lear", L2Item.SLOT_R_EAR | L2Item.SLOT_L_EAR);
_slots.put("rfinger;lfinger", L2Item.SLOT_R_FINGER | L2Item.SLOT_L_FINGER);
_slots.put("wolf", L2Item.SLOT_WOLF);
_slots.put("greatwolf", L2Item.SLOT_GREATWOLF);
_slots.put("hatchling", L2Item.SLOT_HATCHLING);
_slots.put("strider", L2Item.SLOT_STRIDER);
_slots.put("babypet", L2Item.SLOT_BABYPET);
_slots.put("none", L2Item.SLOT_NONE);
// retail compatibility
_slots.put("onepiece", L2Item.SLOT_FULL_ARMOR);
_slots.put("hair2", L2Item.SLOT_HAIR2);
_slots.put("dhair", L2Item.SLOT_HAIRALL);
_slots.put("alldress", L2Item.SLOT_ALLDRESS);
_slots.put("deco1", L2Item.SLOT_DECO);
_slots.put("waist", L2Item.SLOT_BELT);
}
/**
* Returns instance of ItemTable
* @return ItemTable
*/
public static ItemTable getInstance()
{
return SingletonHolder._instance;
}
/**
* Returns a new object Item
* @return
*/
public Item newItem()
{
return new Item();
}
/**
* Constructor.
*/
private ItemTable()
{
_etcItems = new FastMap<>();
_armors = new FastMap<>();
_weapons = new FastMap<>();
load();
}
private void load()
{
int highest = 0;
_armors.clear();
_etcItems.clear();
_weapons.clear();
for (L2Item item : SkillsEngine.getInstance().loadItems())
{
if (highest < item.getItemId())
{
highest = item.getItemId();
}
if (item instanceof L2EtcItem)
{
_etcItems.put(item.getItemId(), (L2EtcItem) item);
}
else if (item instanceof L2Armor)
{
_armors.put(item.getItemId(), (L2Armor) item);
}
else
{
_weapons.put(item.getItemId(), (L2Weapon) item);
}
}
buildFastLookupTable(highest);
}
/**
* Builds a variable in which all items are putting in in function of their ID.
*/
private void buildFastLookupTable(int size)
{
// Create a FastLookUp Table called _allTemplates of size : value of the highest item ID
_log.info("Highest item id used:" + size);
_allTemplates = new L2Item[size + 1];
// Insert armor item in Fast Look Up Table
for (L2Armor item : _armors.values())
{
_allTemplates[item.getItemId()] = item;
}
// Insert weapon item in Fast Look Up Table
for (L2Weapon item : _weapons.values())
{
_allTemplates[item.getItemId()] = item;
}
// Insert etcItem item in Fast Look Up Table
for (L2EtcItem item : _etcItems.values())
{
_allTemplates[item.getItemId()] = item;
}
}
/**
* Returns the item corresponding to the item ID
* @param id : int designating the item
* @return L2Item
*/
public L2Item getTemplate(int id)
{
if (id >= _allTemplates.length)
{
return null;
}
return _allTemplates[id];
}
/**
* Create the L2ItemInstance corresponding to the Item Identifier and quantitiy add logs the activity.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Create and Init the L2ItemInstance corresponding to the Item Identifier and quantity</li> <li>Add the L2ItemInstance object to _allObjects of L2world</li> <li>Logs Item creation according to log settings</li><BR>
* <BR>
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
* @param actor : L2PcInstance Player requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
if (process.equalsIgnoreCase("loot"))
{
ScheduledFuture<?> itemLootShedule;
if ((reference instanceof L2Attackable) && ((L2Attackable) reference).isRaid()) // loot privilege for raids
{
L2Attackable raid = (L2Attackable) reference;
// if in CommandChannel and was killing a World/RaidBoss
if ((raid.getFirstCommandChannelAttacked() != null) && !Config.AUTO_LOOT_RAIDS)
{
item.setOwnerId(raid.getFirstCommandChannelAttacked().getChannelLeader().getObjectId());
itemLootShedule = ThreadPoolManager.getInstance().scheduleGeneral(new ResetOwner(item), Config.LOOT_RAIDS_PRIVILEGE_INTERVAL);
item.setItemLootShedule(itemLootShedule);
}
}
else if (!Config.AUTO_LOOT || ((reference instanceof L2EventMonsterInstance) && ((L2EventMonsterInstance) reference).eventDropOnGround()))
{
item.setOwnerId(actor.getObjectId());
itemLootShedule = ThreadPoolManager.getInstance().scheduleGeneral(new ResetOwner(item), 15000);
item.setItemLootShedule(itemLootShedule);
}
}
if (Config.DEBUG)
{
_log.fine("ItemTable: Item created oid:" + item.getObjectId() + " itemid:" + itemId);
}
// Add the L2ItemInstance object to _allObjects of L2world
L2World.getInstance().storeObject(item);
// Set Item parameters
if (item.isStackable() && (count > 1))
{
item.setCount(count);
}
if (Config.LOG_ITEMS && !process.equals("Reset"))
{
if (!Config.LOG_ITEMS_SMALL_LOG || (Config.LOG_ITEMS_SMALL_LOG && (item.isEquipable() || (item.getItemId() == ADENA_ID))))
{
LogRecord record = new LogRecord(Level.INFO, "CREATE:" + process);
record.setLoggerName("item");
record.setParameters(new Object[]
{
item,
actor,
reference
});
_logItems.log(record);
}
}
if (actor != null)
{
if (actor.isGM())
{
String referenceName = "no-reference";
if (reference instanceof L2Object)
{
referenceName = (((L2Object) reference).getName() != null ? ((L2Object) reference).getName() : "no-name");
}
else if (reference instanceof String)
{
referenceName = (String) reference;
}
String targetName = (actor.getTarget() != null ? actor.getTarget().getName() : "no-target");
if (Config.GMAUDIT)
{
GMAudit.auditGMAction(actor.getName() + " [" + actor.getObjectId() + "]", process + "(id: " + itemId + " count: " + count + " name: " + item.getItemName() + " objId: " + item.getObjectId() + ")", targetName, "L2Object referencing this action is: " + referenceName);
}
}
}
return item;
}
public L2ItemInstance createItem(String process, int itemId, int count, L2PcInstance actor)
{
return createItem(process, itemId, count, actor, null);
}
/**
* Returns a dummy (fr = factice) item.<BR>
* <BR>
* <U><I>Concept :</I></U><BR>
* Dummy item is created by setting the ID of the object in the world at null value
* @param itemId : int designating the item
* @return L2ItemInstance designating the dummy item created
*/
public L2ItemInstance createDummyItem(int itemId)
{
L2Item item = getTemplate(itemId);
if (item == null)
{
return null;
}
L2ItemInstance temp = new L2ItemInstance(0, item);
return temp;
}
/**
* Destroys the L2ItemInstance.<BR>
* <BR>
* <B><U> Actions</U> :</B><BR>
* <BR>
* <li>Sets L2ItemInstance parameters to be unusable</li> <li>Removes the L2ItemInstance object to _allObjects of L2world</li> <li>Logs Item delettion according to log settings</li><BR>
* <BR>
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param actor : L2PcInstance Player requesting the item destroy
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
*/
public void destroyItem(String process, L2ItemInstance item, L2PcInstance actor, Object reference)
{
synchronized (item)
{
long old = item.getCount();
item.setCount(0);
item.setOwnerId(0);
item.setLocation(ItemLocation.VOID);
item.setLastChange(L2ItemInstance.REMOVED);
L2World.getInstance().removeObject(item);
IdFactory.getInstance().releaseId(item.getObjectId());
if (Config.LOG_ITEMS)
{
if (!Config.LOG_ITEMS_SMALL_LOG || (Config.LOG_ITEMS_SMALL_LOG && (item.isEquipable() || (item.getItemId() == ADENA_ID))))
{
LogRecord record = new LogRecord(Level.INFO, "DELETE:" + process);
record.setLoggerName("item");
record.setParameters(new Object[]
{
item,
"PrevCount(" + old + ")",
actor,
reference
});
_logItems.log(record);
}
}
if (actor != null)
{
if (actor.isGM())
{
String referenceName = "no-reference";
if (reference instanceof L2Object)
{
referenceName = (((L2Object) reference).getName() != null ? ((L2Object) reference).getName() : "no-name");
}
else if (reference instanceof String)
{
referenceName = (String) reference;
}
String targetName = (actor.getTarget() != null ? actor.getTarget().getName() : "no-target");
if (Config.GMAUDIT)
{
GMAudit.auditGMAction(actor.getName() + " [" + actor.getObjectId() + "]", process + "(id: " + item.getItemId() + " count: " + item.getCount() + " itemObjId: " + item.getObjectId() + ")", targetName, "L2Object referencing this action is: " + referenceName);
}
}
}
// if it's a pet control item, delete the pet as well
if (PetDataTable.isPetItem(item.getItemId()))
{
Connection con = null;
try
{
// Delete the pet in db
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM pets WHERE item_obj_id=?");
statement.setInt(1, item.getObjectId());
statement.execute();
statement.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "could not delete pet objectid:", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
}
}
public void reload()
{
load();
EnchantHPBonusData.getInstance().reload();
}
protected static class ResetOwner implements Runnable
{
L2ItemInstance _item;
public ResetOwner(L2ItemInstance item)
{
_item = item;
}
@Override
public void run()
{
_item.setOwnerId(0);
_item.setItemLootShedule(null);
}
}
public Set<Integer> getAllArmorsId()
{
return _armors.keySet();
}
public Set<Integer> getAllWeaponsId()
{
return _weapons.keySet();
}
public int getArraySize()
{
return _allTemplates.length;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final ItemTable _instance = new ItemTable();
}
}
@@ -0,0 +1,121 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.L2LvlupData;
import com.l2jserver.gameserver.model.base.ClassId;
/**
* This class ...
* @author NightMarez
* @version $Revision: 1.3.2.4.2.3 $ $Date: 2005/03/27 15:29:18 $
*/
public class LevelUpData
{
private static final String SELECT_ALL = "SELECT classid, defaulthpbase, defaulthpadd, defaulthpmod, defaultcpbase, defaultcpadd, defaultcpmod, defaultmpbase, defaultmpadd, defaultmpmod, class_lvl FROM lvlupgain";
private static final String CLASS_LVL = "class_lvl";
private static final String MP_MOD = "defaultmpmod";
private static final String MP_ADD = "defaultmpadd";
private static final String MP_BASE = "defaultmpbase";
private static final String HP_MOD = "defaulthpmod";
private static final String HP_ADD = "defaulthpadd";
private static final String HP_BASE = "defaulthpbase";
private static final String CP_MOD = "defaultcpmod";
private static final String CP_ADD = "defaultcpadd";
private static final String CP_BASE = "defaultcpbase";
private static final String CLASS_ID = "classid";
private static Logger _log = Logger.getLogger(LevelUpData.class.getName());
private final TIntObjectHashMap<L2LvlupData> _lvlTable;
public static LevelUpData getInstance()
{
return SingletonHolder._instance;
}
private LevelUpData()
{
_lvlTable = new TIntObjectHashMap<>();
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(SELECT_ALL);
ResultSet rset = statement.executeQuery();
L2LvlupData lvlDat;
while (rset.next())
{
lvlDat = new L2LvlupData();
lvlDat.setClassid(rset.getInt(CLASS_ID));
lvlDat.setClassLvl(rset.getInt(CLASS_LVL));
lvlDat.setClassHpBase(rset.getFloat(HP_BASE));
lvlDat.setClassHpAdd(rset.getFloat(HP_ADD));
lvlDat.setClassHpModifier(rset.getFloat(HP_MOD));
lvlDat.setClassCpBase(rset.getFloat(CP_BASE));
lvlDat.setClassCpAdd(rset.getFloat(CP_ADD));
lvlDat.setClassCpModifier(rset.getFloat(CP_MOD));
lvlDat.setClassMpBase(rset.getFloat(MP_BASE));
lvlDat.setClassMpAdd(rset.getFloat(MP_ADD));
lvlDat.setClassMpModifier(rset.getFloat(MP_MOD));
_lvlTable.put(lvlDat.getClassid(), lvlDat);
}
rset.close();
statement.close();
_log.info("LevelUpData: Loaded " + _lvlTable.size() + " Character Level Up Templates.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error loading Level Up data.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
/**
* @param template id
* @return
*/
public L2LvlupData getTemplate(int classId)
{
return _lvlTable.get(classId);
}
public L2LvlupData getTemplate(ClassId classId)
{
return _lvlTable.get(classId.getId());
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final LevelUpData _instance = new LevelUpData();
}
}
@@ -0,0 +1,543 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.SevenSigns;
import com.l2jserver.gameserver.instancemanager.CastleManager;
import com.l2jserver.gameserver.instancemanager.ClanHallManager;
import com.l2jserver.gameserver.instancemanager.FortManager;
import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.instancemanager.TerritoryWarManager;
import com.l2jserver.gameserver.instancemanager.TownManager;
import com.l2jserver.gameserver.instancemanager.ZoneManager;
import com.l2jserver.gameserver.model.Location;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.actor.instance.L2SiegeFlagInstance;
import com.l2jserver.gameserver.model.entity.Castle;
import com.l2jserver.gameserver.model.entity.ClanHall;
import com.l2jserver.gameserver.model.entity.Fort;
import com.l2jserver.gameserver.model.entity.Instance;
import com.l2jserver.gameserver.model.zone.type.L2ArenaZone;
import com.l2jserver.gameserver.model.zone.type.L2ClanHallZone;
/**
* This class ...
*/
public class MapRegionTable
{
private static Logger _log = Logger.getLogger(MapRegionTable.class.getName());
private final int[][] _regions = new int[16][18];
public static enum TeleportWhereType
{
Castle,
ClanHall,
SiegeFlag,
Town,
Fortress
}
public static MapRegionTable getInstance()
{
return SingletonHolder._instance;
}
private MapRegionTable()
{
int count2 = 0;
// LineNumberReader lnr = null;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT region, sec0, sec1, sec2, sec3, sec4, sec5, sec6, sec7, sec8, sec9, sec10,sec11,sec12,sec13,sec14,sec15 FROM mapregion");
ResultSet rset = statement.executeQuery();
int region;
while (rset.next())
{
region = rset.getInt(1);
for (int j = 0; j < 16; j++)
{
_regions[j][region] = rset.getInt(j + 2);
count2++;
// _log.fine(j+","+region+" -> "+rset.getInt(j+2));
}
}
rset.close();
statement.close();
if (Config.DEBUG)
{
_log.fine(count2 + " mapregion loaded");
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error loading Map Region Table.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public final int getMapRegion(int posX, int posY)
{
try
{
return _regions[getMapRegionX(posX)][getMapRegionY(posY)];
}
catch (ArrayIndexOutOfBoundsException e)
{
// Position sent is outside MapRegionTable area.
if (Config.DEBUG)
{
_log.log(Level.WARNING, "MapRegionTable: Player outside map regions at X,Y=" + posX + "," + posY, e);
}
return 0;
}
}
public final int getMapRegionX(int posX)
{
return (posX >> 15) + 9;// + centerTileX;
}
public final int getMapRegionY(int posY)
{
return (posY >> 15) + 10;// + centerTileX;
}
public int getAreaCastle(L2Character activeChar)
{
int area = getClosestTownNumber(activeChar);
int castle;
switch (area)
{
case 0:
castle = 1;
break;// Talking Island Village
case 1:
castle = 4;
break; // Elven Village
case 2:
castle = 4;
break; // Dark Elven Village
case 3:
castle = 9;
break; // Orc Village
case 4:
castle = 9;
break; // Dwarven Village
case 5:
castle = 1;
break; // Town of Gludio
case 6:
castle = 1;
break; // Gludin Village
case 7:
castle = 2;
break; // Town of Dion
case 8:
castle = 3;
break; // Town of Giran
case 9:
castle = 4;
break; // Town of Oren
case 10:
castle = 5;
break; // Town of Aden
case 11:
castle = 5;
break; // Hunters Village
case 12:
castle = 3;
break; // Giran Harbor
case 13:
castle = 6;
break; // Heine
case 14:
castle = 8;
break; // Rune Township
case 15:
castle = 7;
break; // Town of Goddard
case 16:
castle = 9;
break; // Town of Shuttgart
case 17:
castle = 2;
break; // Floran Village
case 18:
castle = 8;
break; // Primeval Isle Wharf
case 19:
castle = 5;
break; // Kamael Village
case 20:
castle = 6;
break; // South of Wastelands Camp
case 21:
castle = 8;
break; // Fantasy Island
default:
castle = 5;
break; // Town of Aden
}
return castle;
}
public int getClosestTownNumber(L2Character activeChar)
{
return getMapRegion(activeChar.getX(), activeChar.getY());
}
/**
* Get town name by character position
* @param activeChar
* @return String
*/
public String getClosestTownName(L2Character activeChar)
{
return getClosestTownName(getMapRegion(activeChar.getX(), activeChar.getY()));
}
/**
* Get town name by town id
* @param townId
* @return String
*/
public String getClosestTownName(int townId)
{
String nearestTown = null;
switch (townId)
{
case 0:
nearestTown = "Talking Island Village";
break;
case 1:
nearestTown = "Elven Village";
break;
case 2:
nearestTown = "Dark Elven Village";
break;
case 3:
nearestTown = "Orc Village";
break;
case 4:
nearestTown = "Dwarven Village";
break;
case 5:
nearestTown = "Town of Gludio";
break;
case 6:
nearestTown = "Gludin Village";
break;
case 7:
nearestTown = "Town of Dion";
break;
case 8:
nearestTown = "Town of Giran";
break;
case 9:
nearestTown = "Town of Oren";
break;
case 10:
nearestTown = "Town of Aden";
break;
case 11:
nearestTown = "Hunters Village";
break;
case 12:
nearestTown = "Giran Harbor";
break;
case 13:
nearestTown = "Heine";
break;
case 14:
nearestTown = "Rune Township";
break;
case 15:
nearestTown = "Town of Goddard";
break;
case 16:
nearestTown = "Town of Schuttgart";
break;
case 18:
nearestTown = "Primeval Isle";
break;
case 19:
nearestTown = "Kamael Village";
break;
case 20:
nearestTown = "South of Wastelands Camp";
break;
case 21:
nearestTown = "Fantasy Island";
break;
case 22:
nearestTown = "Neutral Zone";
break;
case 23:
nearestTown = "Coliseum";
break;
case 24:
nearestTown = "GM Consultation service";
break;
case 25:
nearestTown = "Dimensional Gap";
break;
case 26:
nearestTown = "Cemetary of the Empire";
break;
case 27:
nearestTown = "Inside the Steel Citadel";
break;
case 28:
nearestTown = "Steel Citadel Resistance";
break;
case 29:
nearestTown = "Inside Kamaloka";
break;
case 30:
nearestTown = "Inside Nia Kamaloka";
break;
case 31:
nearestTown = "Inside Rim Kamaloka";
break;
case 32:
nearestTown = "Keucereus clan association";
break;
case 33:
nearestTown = "Inside the Seed of Infinity";
break;
case 34:
nearestTown = "Outside the Seed of Infinity";
break;
case 35:
nearestTown = "Aerial Cleft";
break;
default:
nearestTown = "Town of Aden";
break;
}
return nearestTown;
}
public Location getTeleToLocation(L2Character activeChar, TeleportWhereType teleportWhere)
{
int[] coord;
if (activeChar instanceof L2PcInstance)
{
L2PcInstance player = ((L2PcInstance) activeChar);
// If in Monster Derby Track
if (player.isInsideZone(L2Character.ZONE_MONSTERTRACK))
{
return new Location(12661, 181687, -3560);
}
Castle castle = null;
Fort fort = null;
ClanHall clanhall = null;
if ((player.getClan() != null) && !player.isFlyingMounted() && !player.isFlying()) // flying players in gracia cant use teleports to aden continent
{
// If teleport to clan hall
if (teleportWhere == TeleportWhereType.ClanHall)
{
clanhall = ClanHallManager.getInstance().getClanHallByOwner(player.getClan());
if (clanhall != null)
{
L2ClanHallZone zone = clanhall.getZone();
if ((zone != null) && !player.isFlyingMounted())
{
return zone.getSpawnLoc();
}
}
}
// If teleport to castle
if (teleportWhere == TeleportWhereType.Castle)
{
castle = CastleManager.getInstance().getCastleByOwner(player.getClan());
// Otherwise check if player is on castle or fortress ground
// and player's clan is defender
if (castle == null)
{
castle = CastleManager.getInstance().getCastle(player);
if (!((castle != null) && castle.getSiege().getIsInProgress() && (castle.getSiege().getDefenderClan(player.getClan()) != null)))
{
castle = null;
}
}
if ((castle != null) && (castle.getCastleId() > 0))
{
return castle.getCastleZone().getSpawnLoc();
}
}
// If teleport to fortress
if (teleportWhere == TeleportWhereType.Fortress)
{
fort = FortManager.getInstance().getFortByOwner(player.getClan());
// Otherwise check if player is on castle or fortress ground
// and player's clan is defender
if (fort == null)
{
fort = FortManager.getInstance().getFort(player);
if (!((fort != null) && fort.getSiege().getIsInProgress() && (fort.getOwnerClan() == player.getClan())))
{
fort = null;
}
}
if ((fort != null) && (fort.getFortId() > 0))
{
return fort.getFortZone().getSpawnLoc();
}
}
// If teleport to SiegeHQ
if (teleportWhere == TeleportWhereType.SiegeFlag)
{
castle = CastleManager.getInstance().getCastle(player);
fort = FortManager.getInstance().getFort(player);
L2SiegeFlagInstance tw_flag = TerritoryWarManager.getInstance().getFlagForClan(player.getClan());
if (tw_flag != null)
{
return new Location(tw_flag.getX(), tw_flag.getY(), tw_flag.getZ());
}
else if (castle != null)
{
if (castle.getSiege().getIsInProgress())
{
// Check if player's clan is attacker
List<L2Npc> flags = castle.getSiege().getFlag(player.getClan());
if ((flags != null) && !flags.isEmpty())
{
// Spawn to flag - Need more work to get player to the nearest flag
L2Npc flag = flags.get(0);
return new Location(flag.getX(), flag.getY(), flag.getZ());
}
}
}
else if (fort != null)
{
if (fort.getSiege().getIsInProgress())
{
// Check if player's clan is attacker
List<L2Npc> flags = fort.getSiege().getFlag(player.getClan());
if ((flags != null) && !flags.isEmpty())
{
// Spawn to flag - Need more work to get player to the nearest flag
L2Npc flag = flags.get(0);
return new Location(flag.getX(), flag.getY(), flag.getZ());
}
}
}
}
}
// Karma player land out of city
if (player.getKarma() > 0)
{
try
{
return TownManager.getClosestTown(activeChar).getChaoticSpawnLoc();
}
catch (Exception e)
{
if (player.isFlyingMounted())
{
return new Location(-186330, 242944, 2544);
}
return new Location(17817, 170079, -3530);
}
}
// Checking if in arena
L2ArenaZone arena = ZoneManager.getInstance().getArena(player);
if (arena != null)
{
return arena.getSpawnLoc();
}
// Checking if needed to be respawned in "far" town from the castle;
castle = CastleManager.getInstance().getCastle(player);
if (castle != null)
{
if (castle.getSiege().getIsInProgress())
{
// Check if player's clan is participating
if ((castle.getSiege().checkIsDefender(player.getClan()) || castle.getSiege().checkIsAttacker(player.getClan())) && (SevenSigns.getInstance().getSealOwner(SevenSigns.SEAL_STRIFE) == SevenSigns.CABAL_DAWN))
{
return TownManager.getSecondClosestTown(activeChar).getSpawnLoc();
}
}
}
// Checking if in an instance
if (player.getInstanceId() > 0)
{
Instance inst = InstanceManager.getInstance().getInstance(player.getInstanceId());
if (inst != null)
{
coord = inst.getSpawnLoc();
if ((coord[0] != 0) && (coord[1] != 0) && (coord[2] != 0))
{
return new Location(coord[0], coord[1], coord[2]);
}
}
}
}
// Get the nearest town
try
{
return TownManager.getClosestTown(activeChar).getSpawnLoc();
}
catch (NullPointerException e)
{
// port to the Talking Island if no closest town found
return new Location(-84176, 243382, -3126);
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final MapRegionTable _instance = new MapRegionTable();
}
}
@@ -0,0 +1,289 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javolution.util.FastMap;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
import com.l2jserver.Config;
import com.l2jserver.gameserver.InstanceListManager;
import com.l2jserver.gameserver.instancemanager.CastleManager;
import com.l2jserver.gameserver.model.actor.instance.L2MerchantInstance;
import com.l2jserver.gameserver.model.entity.Castle;
/**
* @author KenM
*/
public class MerchantPriceConfigTable implements InstanceListManager
{
private static Logger _log = Logger.getLogger(MerchantPriceConfigTable.class.getName());
public static MerchantPriceConfigTable getInstance()
{
return SingletonHolder._instance;
}
private static final String MPCS_FILE = "MerchantPriceConfig.xml";
private final Map<Integer, MerchantPriceConfig> _mpcs = new FastMap<>();
private MerchantPriceConfig _defaultMpc;
private MerchantPriceConfigTable()
{
}
public MerchantPriceConfig getMerchantPriceConfig(L2MerchantInstance npc)
{
for (MerchantPriceConfig mpc : _mpcs.values())
{
if (npc.getWorldRegion().containsZone(mpc.getZoneId()))
{
return mpc;
}
}
return _defaultMpc;
}
public MerchantPriceConfig getMerchantPriceConfig(int id)
{
return _mpcs.get(id);
}
public void loadXML() throws SAXException, IOException, ParserConfigurationException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT + "/data/" + MPCS_FILE);
if (file.exists())
{
int defaultPriceConfigId;
Document doc = factory.newDocumentBuilder().parse(file);
Node n = doc.getDocumentElement();
Node dpcNode = n.getAttributes().getNamedItem("defaultPriceConfig");
if (dpcNode == null)
{
throw new IllegalStateException("merchantPriceConfig must define an 'defaultPriceConfig'");
}
defaultPriceConfigId = Integer.parseInt(dpcNode.getNodeValue());
MerchantPriceConfig mpc;
for (n = n.getFirstChild(); n != null; n = n.getNextSibling())
{
mpc = parseMerchantPriceConfig(n);
if (mpc != null)
{
_mpcs.put(mpc.getId(), mpc);
}
}
MerchantPriceConfig defaultMpc = this.getMerchantPriceConfig(defaultPriceConfigId);
if (defaultMpc == null)
{
throw new IllegalStateException("'defaultPriceConfig' points to an non-loaded priceConfig");
}
_defaultMpc = defaultMpc;
}
}
private MerchantPriceConfig parseMerchantPriceConfig(Node n)
{
if (n.getNodeName().equals("priceConfig"))
{
final int id;
final int baseTax;
int castleId = -1;
int zoneId = -1;
final String name;
Node node = n.getAttributes().getNamedItem("id");
if (node == null)
{
throw new IllegalStateException("Must define the priceConfig 'id'");
}
id = Integer.parseInt(node.getNodeValue());
node = n.getAttributes().getNamedItem("name");
if (node == null)
{
throw new IllegalStateException("Must define the priceConfig 'name'");
}
name = node.getNodeValue();
node = n.getAttributes().getNamedItem("baseTax");
if (node == null)
{
throw new IllegalStateException("Must define the priceConfig 'baseTax'");
}
baseTax = Integer.parseInt(node.getNodeValue());
node = n.getAttributes().getNamedItem("castleId");
if (node != null)
{
castleId = Integer.parseInt(node.getNodeValue());
}
node = n.getAttributes().getNamedItem("zoneId");
if (node != null)
{
zoneId = Integer.parseInt(node.getNodeValue());
}
return new MerchantPriceConfig(id, name, baseTax, castleId, zoneId);
}
return null;
}
@Override
public void loadInstances()
{
try
{
loadXML();
_log.info("MerchantPriceConfigTable: Loaded " + _mpcs.size() + " merchant price configs.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Failed loading MerchantPriceConfigTable. Reason: " + e.getMessage(), e);
}
}
@Override
public void updateReferences()
{
for (final MerchantPriceConfig mpc : _mpcs.values())
{
mpc.updateReferences();
}
}
@Override
public void activateInstances()
{
}
/**
* @author KenM
*/
public static final class MerchantPriceConfig
{
private final int _id;
private final String _name;
private final int _baseTax;
private final int _castleId;
private Castle _castle;
private final int _zoneId;
public MerchantPriceConfig(final int id, final String name, final int baseTax, final int castleId, final int zoneId)
{
_id = id;
_name = name;
_baseTax = baseTax;
_castleId = castleId;
_zoneId = zoneId;
}
/**
* @return Returns the id.
*/
public int getId()
{
return _id;
}
/**
* @return Returns the name.
*/
public String getName()
{
return _name;
}
/**
* @return Returns the baseTax.
*/
public int getBaseTax()
{
return _baseTax;
}
/**
* @return Returns the baseTax / 100.0.
*/
public double getBaseTaxRate()
{
return _baseTax / 100.0;
}
/**
* @return Returns the castle.
*/
public Castle getCastle()
{
return _castle;
}
/**
* @return Returns the zoneId.
*/
public int getZoneId()
{
return _zoneId;
}
public boolean hasCastle()
{
return getCastle() != null;
}
public double getCastleTaxRate()
{
return hasCastle() ? getCastle().getTaxRate() : 0.0;
}
public int getTotalTax()
{
return hasCastle() ? (getCastle().getTaxPercent() + getBaseTax()) : getBaseTax();
}
public double getTotalTaxRate()
{
return getTotalTax() / 100.0;
}
public void updateReferences()
{
_castle = CastleManager.getInstance().getCastleById(_castleId);
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final MerchantPriceConfigTable _instance = new MerchantPriceConfigTable();
}
}
@@ -0,0 +1,374 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import gnu.trove.TIntObjectIterator;
import java.io.File;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import javolution.util.FastList;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.multisell.Entry;
import com.l2jserver.gameserver.model.multisell.Ingredient;
import com.l2jserver.gameserver.model.multisell.ListContainer;
import com.l2jserver.gameserver.model.multisell.PreparedListContainer;
import com.l2jserver.gameserver.network.SystemMessageId;
import com.l2jserver.gameserver.network.serverpackets.ExBrExtraUserInfo;
import com.l2jserver.gameserver.network.serverpackets.MultiSellList;
import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
import com.l2jserver.gameserver.network.serverpackets.UserInfo;
public class MultiSell
{
public static final int PAGE_SIZE = 40;
public static final int PC_BANG_POINTS = -100;
public static final int CLAN_REPUTATION = -200;
public static final int FAME = -300;
private static final Logger _log = Logger.getLogger(MultiSell.class.getName());
private final TIntObjectHashMap<ListContainer> _entries;
public static MultiSell getInstance()
{
return SingletonHolder._instance;
}
private MultiSell()
{
_entries = new TIntObjectHashMap<>();
load();
}
public final void reload()
{
_entries.clear();
load();
}
/**
* This will generate the multisell list for the items. There exist various parameters in multisells that affect the way they will appear: 1) inventory only: * if true, only show items of the multisell for which the "primary" ingredients are already in the player's inventory. By "primary"
* ingredients we mean weapon and armor. * if false, show the entire list. 2) maintain enchantment: presumably, only lists with "inventory only" set to true should sometimes have this as true. This makes no sense otherwise... * If true, then the product will match the enchantment level of the
* ingredient. if the player has multiple items that match the ingredient list but the enchantment levels differ, then the entries need to be duplicated to show the products and ingredients for each enchantment level. For example: If the player has a crystal staff +1 and a crystal staff +3 and
* goes to exchange it at the mammon, the list should have all exchange possibilities for the +1 staff, followed by all possibilities for the +3 staff. * If false, then any level ingredient will be considered equal and product will always be at +0 3) apply taxes: Uses the "taxIngredient" entry
* in order to add a certain amount of adena to the ingredients
*/
public final void separateAndSend(int listId, L2PcInstance player, L2Npc npc, boolean inventoryOnly)
{
ListContainer template = _entries.get(listId);
if (template == null)
{
_log.warning("[MultiSell] can't find list id: " + listId + " requested by player: " + player.getName() + ", npcId:" + (npc != null ? npc.getNpcId() : 0));
return;
}
final PreparedListContainer list = new PreparedListContainer(template, inventoryOnly, player, npc);
int index = 0;
do
{
// send list at least once even if size = 0
player.sendPacket(new MultiSellList(list, index));
index += PAGE_SIZE;
}
while (index < list.getEntries().size());
player.setMultiSell(list);
}
public static final boolean checkSpecialIngredient(int id, long amount, L2PcInstance player)
{
switch (id)
{
case CLAN_REPUTATION:
if (player.getClan() == null)
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_ARE_NOT_A_CLAN_MEMBER));
break;
}
if (!player.isClanLeader())
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.ONLY_THE_CLAN_LEADER_IS_ENABLED));
break;
}
if (player.getClan().getReputationScore() < amount)
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.THE_CLAN_REPUTATION_SCORE_IS_TOO_LOW));
break;
}
return true;
case FAME:
if (player.getFame() < amount)
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.NOT_ENOUGH_FAME_POINTS));
break;
}
return true;
}
return false;
}
public static final boolean getSpecialIngredient(int id, long amount, L2PcInstance player)
{
switch (id)
{
case CLAN_REPUTATION:
player.getClan().takeReputationScore((int) amount, true);
SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.S1_DEDUCTED_FROM_CLAN_REP);
smsg.addItemNumber(amount);
player.sendPacket(smsg);
return true;
case FAME:
player.setFame(player.getFame() - (int) amount);
player.sendPacket(new UserInfo(player));
player.sendPacket(new ExBrExtraUserInfo(player));
return true;
}
return false;
}
public static final void addSpecialProduct(int id, long amount, L2PcInstance player)
{
switch (id)
{
case CLAN_REPUTATION:
player.getClan().addReputationScore((int) amount, true);
break;
case FAME:
player.setFame((int) (player.getFame() + amount));
player.sendPacket(new UserInfo(player));
player.sendPacket(new ExBrExtraUserInfo(player));
break;
}
}
private final void load()
{
Document doc = null;
int id = 0;
List<File> files = new FastList<>();
hashFiles("multisell", files);
for (File f : files)
{
try
{
id = Integer.parseInt(f.getName().replaceAll(".xml", ""));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
doc = factory.newDocumentBuilder().parse(f);
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error loading file " + f, e);
continue;
}
try
{
ListContainer list = parseDocument(doc);
list.setListId(id);
_entries.put(id, list);
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error in file " + f, e);
}
}
verify();
_log.log(Level.INFO, "MultiSell: Loaded " + _entries.size() + " lists.");
}
private final ListContainer parseDocument(Document doc)
{
int entryId = 1;
Node attribute;
ListContainer list = new ListContainer();
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
attribute = n.getAttributes().getNamedItem("applyTaxes");
if (attribute == null)
{
list.setApplyTaxes(false);
}
else
{
list.setApplyTaxes(Boolean.parseBoolean(attribute.getNodeValue()));
}
attribute = n.getAttributes().getNamedItem("maintainEnchantment");
if (attribute == null)
{
list.setMaintainEnchantment(false);
}
else
{
list.setMaintainEnchantment(Boolean.parseBoolean(attribute.getNodeValue()));
}
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("item".equalsIgnoreCase(d.getNodeName()))
{
Entry e = parseEntry(d, entryId++);
list.getEntries().add(e);
}
}
}
else if ("item".equalsIgnoreCase(n.getNodeName()))
{
Entry e = parseEntry(n, entryId++);
list.getEntries().add(e);
}
}
return list;
}
private final Entry parseEntry(Node n, int entryId)
{
Node attribute;
Node first = n.getFirstChild();
final Entry entry = new Entry(entryId);
for (n = first; n != null; n = n.getNextSibling())
{
if ("ingredient".equalsIgnoreCase(n.getNodeName()))
{
int id = Integer.parseInt(n.getAttributes().getNamedItem("id").getNodeValue());
long count = Long.parseLong(n.getAttributes().getNamedItem("count").getNodeValue());
boolean isTaxIngredient, mantainIngredient;
attribute = n.getAttributes().getNamedItem("isTaxIngredient");
if (attribute != null)
{
isTaxIngredient = Boolean.parseBoolean(attribute.getNodeValue());
}
else
{
isTaxIngredient = false;
}
attribute = n.getAttributes().getNamedItem("maintainIngredient");
if (attribute != null)
{
mantainIngredient = Boolean.parseBoolean(attribute.getNodeValue());
}
else
{
mantainIngredient = false;
}
entry.addIngredient(new Ingredient(id, count, isTaxIngredient, mantainIngredient));
}
else if ("production".equalsIgnoreCase(n.getNodeName()))
{
int id = Integer.parseInt(n.getAttributes().getNamedItem("id").getNodeValue());
long count = Long.parseLong(n.getAttributes().getNamedItem("count").getNodeValue());
entry.addProduct(new Ingredient(id, count, false, false));
}
}
return entry;
}
private final void hashFiles(String dirname, List<File> hash)
{
File dir = new File(Config.DATAPACK_ROOT, "data/" + dirname);
if (!dir.exists())
{
_log.log(Level.WARNING, "Dir " + dir.getAbsolutePath() + " not exists");
return;
}
File[] files = dir.listFiles();
for (File f : files)
{
if (f.getName().endsWith(".xml"))
{
hash.add(f);
}
}
}
private final void verify()
{
ListContainer list;
final TIntObjectIterator<ListContainer> iter = _entries.iterator();
while (iter.hasNext())
{
iter.advance();
list = iter.value();
for (Entry ent : list.getEntries())
{
for (Ingredient ing : ent.getIngredients())
{
if (!verifyIngredient(ing))
{
_log.warning("[MultiSell] can't find ingredient with itemId: " + ing.getItemId() + " in list: " + list.getListId());
}
}
for (Ingredient ing : ent.getProducts())
{
if (!verifyIngredient(ing))
{
_log.warning("[MultiSell] can't find product with itemId: " + ing.getItemId() + " in list: " + list.getListId());
}
}
}
}
}
private final boolean verifyIngredient(Ingredient ing)
{
switch (ing.getItemId())
{
case CLAN_REPUTATION:
case FAME:
return true;
default:
if (ing.getTemplate() != null)
{
return true;
}
}
return false;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final MultiSell _instance = new MultiSell();
}
}
@@ -0,0 +1,53 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import com.l2jserver.gameserver.model.L2Skill;
/**
* @author -Nemesiss-
*/
public class NobleSkillTable
{
private static final L2Skill[] _nobleSkills = new L2Skill[8];
private NobleSkillTable()
{
_nobleSkills[0] = SkillTable.getInstance().getInfo(1323, 1);
_nobleSkills[1] = SkillTable.getInstance().getInfo(325, 1);
_nobleSkills[2] = SkillTable.getInstance().getInfo(326, 1);
_nobleSkills[3] = SkillTable.getInstance().getInfo(327, 1);
_nobleSkills[4] = SkillTable.getInstance().getInfo(1324, 1);
_nobleSkills[5] = SkillTable.getInstance().getInfo(1325, 1);
_nobleSkills[6] = SkillTable.getInstance().getInfo(1326, 1);
_nobleSkills[7] = SkillTable.getInstance().getInfo(1327, 1);
}
public static NobleSkillTable getInstance()
{
return SingletonHolder._instance;
}
public L2Skill[] getNobleSkills()
{
return _nobleSkills;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final NobleSkillTable _instance = new NobleSkillTable();
}
}
@@ -0,0 +1,212 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntIntHashMap;
import gnu.trove.TIntObjectHashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
public class NpcBufferTable
{
protected static Logger _log = Logger.getLogger(NpcBufferTable.class.getName());
private final TIntObjectHashMap<NpcBufferSkills> _buffers = new TIntObjectHashMap<>();
private static class NpcBufferSkills
{
private final TIntIntHashMap _skillId = new TIntIntHashMap();
private final TIntIntHashMap _skillLevels = new TIntIntHashMap();
private final TIntIntHashMap _skillFeeIds = new TIntIntHashMap();
private final TIntIntHashMap _skillFeeAmounts = new TIntIntHashMap();
public NpcBufferSkills(int npcId)
{
}
public void addSkill(int skillId, int skillLevel, int skillFeeId, int skillFeeAmount, int buffGroup)
{
_skillId.put(buffGroup, skillId);
_skillLevels.put(buffGroup, skillLevel);
_skillFeeIds.put(buffGroup, skillFeeId);
_skillFeeAmounts.put(buffGroup, skillFeeAmount);
}
public int[] getSkillGroupInfo(int buffGroup)
{
Integer skillId = _skillId.get(buffGroup);
Integer skillLevel = _skillLevels.get(buffGroup);
Integer skillFeeId = _skillFeeIds.get(buffGroup);
Integer skillFeeAmount = _skillFeeAmounts.get(buffGroup);
if ((skillId == null) || (skillLevel == null) || (skillFeeId == null) || (skillFeeAmount == null))
{
return null;
}
return new int[]
{
skillId,
skillLevel,
skillFeeId,
skillFeeAmount
};
}
}
private NpcBufferTable()
{
Connection con = null;
int skillCount = 0;
try
{
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT `npc_id`,`skill_id`,`skill_level`,`skill_fee_id`,`skill_fee_amount`,`buff_group` FROM `npc_buffer` ORDER BY `npc_id` ASC");
ResultSet rset = statement.executeQuery();
int lastNpcId = 0;
NpcBufferSkills skills = null;
while (rset.next())
{
int npcId = rset.getInt("npc_id");
int skillId = rset.getInt("skill_id");
int skillLevel = rset.getInt("skill_level");
int skillFeeId = rset.getInt("skill_fee_id");
int skillFeeAmount = rset.getInt("skill_fee_amount");
int buffGroup = rset.getInt("buff_group");
if (npcId != lastNpcId)
{
if (lastNpcId != 0)
{
_buffers.put(lastNpcId, skills);
}
skills = new NpcBufferSkills(npcId);
skills.addSkill(skillId, skillLevel, skillFeeId, skillFeeAmount, buffGroup);
}
else
{
skills.addSkill(skillId, skillLevel, skillFeeId, skillFeeAmount, buffGroup);
}
lastNpcId = npcId;
skillCount++;
}
if (lastNpcId != 0)
{
_buffers.put(lastNpcId, skills);
}
rset.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "NpcBufferTable: Error reading npc_buffer table: " + e.getMessage(), e);
}
if (Config.CUSTOM_NPCBUFFER_TABLES)
{
try
{
PreparedStatement statement = con.prepareStatement("SELECT `npc_id`,`skill_id`,`skill_level`,`skill_fee_id`,`skill_fee_amount`,`buff_group` FROM `custom_npc_buffer` ORDER BY `npc_id` ASC");
ResultSet rset = statement.executeQuery();
int lastNpcId = 0;
NpcBufferSkills skills = null;
while (rset.next())
{
int npcId = rset.getInt("npc_id");
int skillId = rset.getInt("skill_id");
int skillLevel = rset.getInt("skill_level");
int skillFeeId = rset.getInt("skill_fee_id");
int skillFeeAmount = rset.getInt("skill_fee_amount");
int buffGroup = rset.getInt("buff_group");
if (npcId != lastNpcId)
{
if (lastNpcId != 0)
{
_buffers.put(lastNpcId, skills);
}
skills = new NpcBufferSkills(npcId);
skills.addSkill(skillId, skillLevel, skillFeeId, skillFeeAmount, buffGroup);
}
else
{
skills.addSkill(skillId, skillLevel, skillFeeId, skillFeeAmount, buffGroup);
}
lastNpcId = npcId;
skillCount++;
}
if (lastNpcId != 0)
{
_buffers.put(lastNpcId, skills);
}
rset.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "NpcBufferTable: Error reading custom_npc_buffer table: " + e.getMessage(), e);
}
}
}
finally
{
L2DatabaseFactory.close(con);
}
_log.info("NpcBufferSkillIdsTable: Loaded " + _buffers.size() + " buffers and " + skillCount + " skills.");
}
public static NpcBufferTable getInstance()
{
return SingletonHolder._instance;
}
public int[] getSkillInfo(int npcId, int buffGroup)
{
NpcBufferSkills skills = _buffers.get(npcId);
if (skills == null)
{
return null;
}
return skills.getSkillGroupInfo(buffGroup);
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final NpcBufferTable _instance = new NpcBufferTable();
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,129 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.L2NpcWalkerNode;
/**
* Main Table to Load Npc Walkers Routes and Chat SQL Table.<br>
* @author Rayan RPG for L2Emu Project, JIV
* @since 927
*/
public class NpcWalkerRoutesTable
{
private final static Logger _log = Logger.getLogger(SpawnTable.class.getName());
private final TIntObjectHashMap<List<L2NpcWalkerNode>> _routes = new TIntObjectHashMap<>();
public static NpcWalkerRoutesTable getInstance()
{
return SingletonHolder._instance;
}
private NpcWalkerRoutesTable()
{
if (Config.ALLOW_NPC_WALKERS)
{
_log.info("Initializing Walkers Routes Table.");
load();
}
}
public void load()
{
_routes.clear();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT, "data/WalkerRoutes.xml");
Document doc = null;
if (file.exists())
{
try
{
doc = factory.newDocumentBuilder().parse(file);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Could not parse WalkerRoutes.xml file: " + e.getMessage(), e);
return;
}
Node n = doc.getFirstChild();
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equals("walker"))
{
List<L2NpcWalkerNode> list = new ArrayList<>();
int npcId = Integer.parseInt(d.getAttributes().getNamedItem("npcId").getNodeValue());
for (Node r = d.getFirstChild(); r != null; r = r.getNextSibling())
{
if (r.getNodeName().equals("route"))
{
NamedNodeMap attrs = r.getAttributes();
int id = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
int x = Integer.parseInt(attrs.getNamedItem("X").getNodeValue());
int y = Integer.parseInt(attrs.getNamedItem("Y").getNodeValue());
int z = Integer.parseInt(attrs.getNamedItem("Z").getNodeValue());
int delay = Integer.parseInt(attrs.getNamedItem("delay").getNodeValue());
String chat = attrs.getNamedItem("string").getNodeValue();
boolean running = Boolean.parseBoolean(attrs.getNamedItem("run").getNodeValue());
list.add(new L2NpcWalkerNode(id, chat, x, y, z, delay, running));
}
}
_routes.put(npcId, list);
}
}
}
for (Object list : _routes.getValues())
{
((ArrayList<?>) list).trimToSize();
}
_log.info("WalkerRoutesTable: Loaded " + _routes.size() + " Npc Walker Routes.");
}
public List<L2NpcWalkerNode> getRouteForNpc(int id)
{
return _routes.get(id);
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final NpcWalkerRoutesTable _instance = new NpcWalkerRoutesTable();
}
public static void main(String... arg)
{
getInstance().load();
}
}
@@ -0,0 +1,277 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.LoginServerThread;
import com.l2jserver.gameserver.model.L2ManufactureItem;
import com.l2jserver.gameserver.model.L2ManufactureList;
import com.l2jserver.gameserver.model.L2World;
import com.l2jserver.gameserver.model.TradeList.TradeItem;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.network.L2GameClient;
import com.l2jserver.gameserver.network.L2GameClient.GameClientState;
public class OfflineTradersTable
{
private static Logger _log = Logger.getLogger(OfflineTradersTable.class.getName());
// SQL DEFINITIONS
private static final String SAVE_OFFLINE_STATUS = "INSERT INTO character_offline_trade (`charId`,`time`,`type`,`title`) VALUES (?,?,?,?)";
private static final String SAVE_ITEMS = "INSERT INTO character_offline_trade_items (`charId`,`item`,`count`,`price`) VALUES (?,?,?,?)";
private static final String CLEAR_OFFLINE_TABLE = "DELETE FROM character_offline_trade";
private static final String CLEAR_OFFLINE_TABLE_ITEMS = "DELETE FROM character_offline_trade_items";
private static final String LOAD_OFFLINE_STATUS = "SELECT * FROM character_offline_trade";
private static final String LOAD_OFFLINE_ITEMS = "SELECT * FROM character_offline_trade_items WHERE charId = ?";
public static void storeOffliners()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement stm = con.prepareStatement(CLEAR_OFFLINE_TABLE);
stm.execute();
stm.close();
stm = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS);
stm.execute();
stm.close();
con.setAutoCommit(false); // avoid halfway done
stm = con.prepareStatement(SAVE_OFFLINE_STATUS);
PreparedStatement stm_items = con.prepareStatement(SAVE_ITEMS);
// TextBuilder items = TextBuilder.newInstance();
for (L2PcInstance pc : L2World.getInstance().getAllPlayers().values())
{
try
{
if ((pc.getPrivateStoreType() != L2PcInstance.STORE_PRIVATE_NONE) && ((pc.getClient() == null) || pc.getClient().isDetached()))
{
stm.setInt(1, pc.getObjectId()); // Char Id
stm.setLong(2, pc.getOfflineStartTime());
stm.setInt(3, pc.getPrivateStoreType()); // store type
String title = null;
switch (pc.getPrivateStoreType())
{
case L2PcInstance.STORE_PRIVATE_BUY:
if (!Config.OFFLINE_TRADE_ENABLE)
{
continue;
}
title = pc.getBuyList().getTitle();
for (TradeItem i : pc.getBuyList().getItems())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getItem().getItemId());
stm_items.setLong(3, i.getCount());
stm_items.setLong(4, i.getPrice());
stm_items.executeUpdate();
stm_items.clearParameters();
}
break;
case L2PcInstance.STORE_PRIVATE_SELL:
case L2PcInstance.STORE_PRIVATE_PACKAGE_SELL:
if (!Config.OFFLINE_TRADE_ENABLE)
{
continue;
}
title = pc.getSellList().getTitle();
for (TradeItem i : pc.getSellList().getItems())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getObjectId());
stm_items.setLong(3, i.getCount());
stm_items.setLong(4, i.getPrice());
stm_items.executeUpdate();
stm_items.clearParameters();
}
break;
case L2PcInstance.STORE_PRIVATE_MANUFACTURE:
if (!Config.OFFLINE_CRAFT_ENABLE)
{
continue;
}
title = pc.getCreateList().getStoreName();
for (L2ManufactureItem i : pc.getCreateList().getList())
{
stm_items.setInt(1, pc.getObjectId());
stm_items.setInt(2, i.getRecipeId());
stm_items.setLong(3, 0);
stm_items.setLong(4, i.getCost());
stm_items.executeUpdate();
stm_items.clearParameters();
}
}
stm.setString(4, title);
stm.executeUpdate();
stm.clearParameters();
con.commit(); // flush
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "OfflineTradersTable[storeTradeItems()]: Error while saving offline trader: " + pc.getObjectId() + " " + e, e);
}
}
stm.close();
stm_items.close();
_log.info("Offline traders stored.");
}
catch (Exception e)
{
_log.log(Level.WARNING, "OfflineTradersTable[storeTradeItems()]: Error while saving offline traders: " + e, e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public static void restoreOfflineTraders()
{
_log.info("Loading offline traders...");
Connection con = null;
int nTraders = 0;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement stm = con.prepareStatement(LOAD_OFFLINE_STATUS);
ResultSet rs = stm.executeQuery();
while (rs.next())
{
long time = rs.getLong("time");
if (Config.OFFLINE_MAX_DAYS > 0)
{
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(time);
cal.add(Calendar.DAY_OF_YEAR, Config.OFFLINE_MAX_DAYS);
if (cal.getTimeInMillis() <= System.currentTimeMillis())
{
continue;
}
}
int type = rs.getInt("type");
if (type == L2PcInstance.STORE_PRIVATE_NONE)
{
continue;
}
L2PcInstance player = null;
try
{
L2GameClient client = new L2GameClient(null);
client.setDetached(true);
player = L2PcInstance.load(rs.getInt("charId"));
client.setActiveChar(player);
player.setOnlineStatus(true, false);
client.setAccountName(player.getAccountNamePlayer());
client.setState(GameClientState.IN_GAME);
player.setClient(client);
player.setOfflineStartTime(time);
player.spawnMe(player.getX(), player.getY(), player.getZ());
LoginServerThread.getInstance().addGameServerLogin(player.getAccountName(), client);
PreparedStatement stm_items = con.prepareStatement(LOAD_OFFLINE_ITEMS);
stm_items.setInt(1, player.getObjectId());
ResultSet items = stm_items.executeQuery();
switch (type)
{
case L2PcInstance.STORE_PRIVATE_BUY:
while (items.next())
{
if (player.getBuyList().addItemByItemId(items.getInt(2), items.getLong(3), items.getLong(4)) == null)
{
throw new NullPointerException();
}
}
player.getBuyList().setTitle(rs.getString("title"));
break;
case L2PcInstance.STORE_PRIVATE_SELL:
case L2PcInstance.STORE_PRIVATE_PACKAGE_SELL:
while (items.next())
{
if (player.getSellList().addItem(items.getInt(2), items.getLong(3), items.getLong(4)) == null)
{
throw new NullPointerException();
}
}
player.getSellList().setTitle(rs.getString("title"));
player.getSellList().setPackaged(type == L2PcInstance.STORE_PRIVATE_PACKAGE_SELL);
break;
case L2PcInstance.STORE_PRIVATE_MANUFACTURE:
L2ManufactureList createList = new L2ManufactureList();
while (items.next())
{
createList.add(new L2ManufactureItem(items.getInt(2), items.getLong(4)));
}
player.setCreateList(createList);
player.getCreateList().setStoreName(rs.getString("title"));
break;
}
items.close();
stm_items.close();
player.sitDown();
if (Config.OFFLINE_SET_NAME_COLOR)
{
player.getAppearance().setNameColor(Config.OFFLINE_NAME_COLOR);
}
player.setPrivateStoreType(type);
player.setOnlineStatus(true, true);
player.restoreEffects();
player.broadcastUserInfo();
nTraders++;
}
catch (Exception e)
{
_log.log(Level.WARNING, "OfflineTradersTable[loadOffliners()]: Error loading trader: " + player, e);
if (player != null)
{
player.deleteMe();
}
}
}
rs.close();
stm.close();
_log.info("Loaded: " + nTraders + " offline trader(s)");
stm = con.prepareStatement(CLEAR_OFFLINE_TABLE);
stm.execute();
stm.close();
stm = con.prepareStatement(CLEAR_OFFLINE_TABLE_ITEMS);
stm.execute();
stm.close();
}
catch (Exception e)
{
_log.log(Level.WARNING, "OfflineTradersTable[loadOffliners()]: Error while loading offline traders: ", e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
}
@@ -0,0 +1,516 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.L2PetData;
import com.l2jserver.gameserver.model.L2PetLevelData;
import com.l2jserver.gameserver.model.actor.instance.L2PetInstance;
import com.l2jserver.gameserver.templates.item.L2EtcItemType;
import com.l2jserver.gameserver.templates.item.L2Item;
public class PetDataTable
{
private static Logger _log = Logger.getLogger(L2PetInstance.class.getName());
private static TIntObjectHashMap<L2PetData> _petTable;
public static PetDataTable getInstance()
{
return SingletonHolder._instance;
}
private PetDataTable()
{
_petTable = new TIntObjectHashMap<>();
load();
}
public void load()
{
_petTable.clear();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
File file = new File(Config.DATAPACK_ROOT, "data/stats/npc/PetData.xml");
Document doc = null;
if (file.exists())
{
try
{
doc = factory.newDocumentBuilder().parse(file);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Could not parse PetData.xml file: " + e.getMessage(), e);
return;
}
Node n = doc.getFirstChild();
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equals("pet"))
{
int npcId = Integer.parseInt(d.getAttributes().getNamedItem("id").getNodeValue());
// index ignored for now
L2PetData data = new L2PetData();
for (Node p = d.getFirstChild(); p != null; p = p.getNextSibling())
{
if (p.getNodeName().equals("set"))
{
NamedNodeMap attrs = p.getAttributes();
String type = attrs.getNamedItem("name").getNodeValue();
if ("food".equals(type))
{
String[] values = attrs.getNamedItem("val").getNodeValue().split(";");
int[] food = new int[values.length];
for (int i = 0; i < values.length; i++)
{
food[i] = Integer.parseInt(values[i]);
}
data.set_food(food);
}
else if ("load".equals(type))
{
data.set_load(Integer.parseInt(attrs.getNamedItem("val").getNodeValue()));
}
else if ("hungry_limit".equals(type))
{
data.set_hungry_limit(Integer.parseInt(attrs.getNamedItem("val").getNodeValue()));
}
// sync_level and evolve ignored
}
else if (p.getNodeName().equals("skills"))
{
for (Node s = p.getFirstChild(); s != null; s = s.getNextSibling())
{
if (s.getNodeName().equals("skill"))
{
NamedNodeMap attrs = s.getAttributes();
int skillId = Integer.parseInt(attrs.getNamedItem("skillId").getNodeValue());
int skillLvl = Integer.parseInt(attrs.getNamedItem("skillLvl").getNodeValue());
int minLvl = Integer.parseInt(attrs.getNamedItem("minLvl").getNodeValue());
data.addNewSkill(skillId, skillLvl, minLvl);
}
}
}
else if (p.getNodeName().equals("stats"))
{
for (Node s = p.getFirstChild(); s != null; s = s.getNextSibling())
{
if (s.getNodeName().equals("stat"))
{
int level = Integer.parseInt(s.getAttributes().getNamedItem("level").getNodeValue());
L2PetLevelData stat = new L2PetLevelData();
for (Node bean = s.getFirstChild(); bean != null; bean = bean.getNextSibling())
{
if (bean.getNodeName().equals("set"))
{
NamedNodeMap attrs = bean.getAttributes();
String type = attrs.getNamedItem("name").getNodeValue();
String value = attrs.getNamedItem("val").getNodeValue();
if ("max_meal".equals(type))
{
stat.setPetMaxFeed(Integer.parseInt(value));
}
else if ("exp".equals(type))
{
stat.setPetMaxExp(Long.parseLong(value));
}
else if ("get_exp_type".equals(type))
{
stat.setOwnerExpTaken(Integer.parseInt(value));
}
else if ("consume_meal_in_battle".equals(type))
{
stat.setPetFeedBattle(Integer.parseInt(value));
}
else if ("consume_meal_in_normal".equals(type))
{
stat.setPetFeedNormal(Integer.parseInt(value));
}
else if ("org_pattack".equals(type))
{
stat.setPetPAtk(Float.parseFloat(value));
}
else if ("org_pdefend".equals(type))
{
stat.setPetPDef(Float.parseFloat(value));
}
else if ("org_mattack".equals(type))
{
stat.setPetMAtk(Float.parseFloat(value));
}
else if ("org_mdefend".equals(type))
{
stat.setPetMDef(Float.parseFloat(value));
}
else if ("org_hp".equals(type))
{
stat.setPetMaxHP(Float.parseFloat(value));
}
else if ("org_mp".equals(type))
{
stat.setPetMaxMP(Float.parseFloat(value));
}
else if ("org_hp_regen".equals(type))
{
stat.setPetRegenHP(Float.parseFloat(value));
}
else if ("org_mp_regen".equals(type))
{
stat.setPetRegenMP(Float.parseFloat(value));
}
else if ("soulshot_count".equals(type))
{
stat.setPetSoulShot((short) Integer.parseInt(value));
}
else if ("spiritshot_count".equals(type))
{
stat.setPetSpiritShot((short) Integer.parseInt(value));
}
}
}
data.addNewStat(stat, level);
}
}
}
}
_petTable.put(npcId, data);
}
}
}
else
{
_log.warning("Not found PetData.xml");
}
_log.info(getClass().getSimpleName() + ": Loaded " + _petTable.size() + " Pets.");
}
public L2PetLevelData getPetLevelData(int petID, int petLevel)
{
return _petTable.get(petID).getPetLevelData(petLevel);
}
public L2PetData getPetData(int petID)
{
if (!_petTable.contains(petID))
{
_log.info("Missing pet data for npcid: " + petID);
}
return _petTable.get(petID);
}
public int getPetMinLevel(int petID)
{
return _petTable.get(petID).getMinLevel();
}
/*
* Pets stuffs
*/
public static boolean isWolf(int npcId)
{
return npcId == 12077;
}
public static boolean isEvolvedWolf(int npcId)
{
return (npcId == 16030) || (npcId == 16037) || (npcId == 16025) || (npcId == 16041) || (npcId == 16042);
}
public static boolean isSinEater(int npcId)
{
return npcId == 12564;
}
public static boolean isHatchling(int npcId)
{
return (npcId > 12310) && (npcId < 12314);
}
public static boolean isStrider(int npcId)
{
return ((npcId > 12525) && (npcId < 12529)) || ((npcId > 16037) && (npcId < 16041)) || (npcId == 16068);
}
public static boolean isWyvern(int npcId)
{
return npcId == 12621;
}
public static boolean isBaby(int npcId)
{
return (npcId > 12779) && (npcId < 12783);
}
public static boolean isImprovedBaby(int npcId)
{
return (npcId > 16033) && (npcId < 16037);
}
public static boolean isPetFood(int itemId)
{
switch (itemId)
{
case 2515:
case 4038:
case 5168:
case 5169:
case 6316:
case 7582:
case 9668:
case 10425:
return true;
default:
return false;
}
}
/**
* @see L2PetData#getFood()
*/
@Deprecated
public static int[] getFoodItemId(int npcId)
{
switch (npcId)
{
case 12077:// Wolf
case 12564:// Sin Eater
return new int[]
{
2515
};
case 16030:// Great Wolf
case 16025:// Black Wolf
case 16037:// White Great Wolf
case 16041:// Fenrir
case 16042:// White Fenrir
return new int[]
{
9668
};
case 12311:// hatchling of wind
case 12312:// hatchling of star
case 12313:// hatchling of twilight
return new int[]
{
4038
};
case 12526:// wind strider
case 12527:// Star strider
case 12528:// Twilight strider
case 16038:// red wind strider
case 16039:// red Star strider
case 16040:// red Twilight strider
case 16068:// Guardian Strider
return new int[]
{
5168,
5169
};
case 12621: // wyvern
return new int[]
{
6316
};
case 12780:// Baby Buffalo
case 12782:// Baby Cougar
case 12781:// Baby Kookaburra
return new int[]
{
7582
};
case 16034:// Improved Baby Buffalo
case 16036:// Improved Baby Cougar
case 16035:// Improved Baby Kookaburra
return new int[]
{
10425
};
default:
return new int[]
{
0
};
}
}
public static boolean isPetItem(int itemId)
{
L2Item item = ItemTable.getInstance().getTemplate(itemId);
if ((item != null) && (item.getItemType() == L2EtcItemType.PET_COLLAR))
{
return true;
}
return false;
/*
* switch (itemId) { case 2375: // Wolf case 3500: // hatchling of wind case 3501: // hatchling of star case 3502: // hatchling of twilight case 4422: // strider of wind case 4423: // strider of star case 4424: // strider of dusk case 4425: // Sin Eater case 6648: // baby buffalo case 6649:
* // baby cougar case 6650: // baby kookaburra case 8663: // Wyvern case 9882: // Great Wolf case 10163: // Black Wolf case 10307: // Great Snow Wolf case 10308: // red strider of wind case 10309: // red strider of star case 10310: // red strider of dusk case 10311: // improved buffalo case
* 10312: // improved cougar case 10313: // improved kookaburra case 10426: // Fenrir case 10611: // White Fenrir case 14819: // Guardian Strider return true; default: return false; }
*/
}
public static int[] getPetItemsByNpc(int npcId)
{
switch (npcId)
{
case 12077:// Wolf
return new int[]
{
2375
};
case 16025:// Great Wolf
return new int[]
{
9882
};
case 16030:// Black Wolf
return new int[]
{
10163
};
case 16037:// White Great Wolf
return new int[]
{
10307
};
case 16041:// Fenrir
return new int[]
{
10426
};
case 16042:// White Fenrir
return new int[]
{
10611
};
case 12564:// Sin Eater
return new int[]
{
4425
};
case 12311:// hatchling of wind
case 12312:// hatchling of star
case 12313:// hatchling of twilight
return new int[]
{
3500,
3501,
3502
};
case 12526:// wind strider
case 12527:// Star strider
case 12528:// Twilight strider
case 16038: // red strider of wind
case 16039: // red strider of star
case 16040: // red strider of dusk
case 16068: // Guardian Strider
return new int[]
{
4422,
4423,
4424,
10308,
10309,
10310,
14819
};
case 12621:// Wyvern
return new int[]
{
8663
};
case 12780:// Baby Buffalo
case 12782:// Baby Cougar
case 12781:// Baby Kookaburra
return new int[]
{
6648,
6649,
6650
};
case 16034:// Improved Baby Buffalo
case 16036:// Improved Baby Cougar
case 16035:// Improved Baby Kookaburra
return new int[]
{
10311,
10312,
10313
};
// unknown item id.. should never happen
default:
return new int[]
{
0
};
}
}
public static boolean isMountable(int npcId)
{
return (npcId == 12526 // wind strider
) || (npcId == 12527 // star strider
) || (npcId == 12528 // twilight strider
) || (npcId == 12621 // wyvern
) || (npcId == 16037 // Great Snow Wolf
) || (npcId == 16041 // Fenrir Wolf
) || (npcId == 16042 // White Fenrir Wolf
) || (npcId == 16038 // Red Wind Strider
) || (npcId == 16039 // Red Star Strider
) || (npcId == 16040 // Red Twilight Strider
) || (npcId == 16068); // Guardian Strider
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final PetDataTable _instance = new PetDataTable();
}
public static void main(String... s)
{
getInstance();
}
}
@@ -0,0 +1,127 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
public class PetNameTable
{
private static Logger _log = Logger.getLogger(PetNameTable.class.getName());
private PetNameTable()
{
}
public static PetNameTable getInstance()
{
return SingletonHolder._instance;
}
public boolean doesPetNameExist(String name, int petNpcId)
{
boolean result = true;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT name FROM pets p, items i WHERE p.item_obj_id = i.object_id AND name=? AND i.item_id IN (?)");
statement.setString(1, name);
String cond = "";
for (int it : PetDataTable.getPetItemsByNpc(petNpcId))
{
if (!cond.isEmpty())
{
cond += ", ";
}
cond += it;
}
statement.setString(2, cond);
ResultSet rset = statement.executeQuery();
result = rset.next();
rset.close();
statement.close();
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Could not check existing petname:" + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
return result;
}
public boolean isValidPetName(String name)
{
boolean result = true;
if (!isAlphaNumeric(name))
{
return result;
}
Pattern pattern;
try
{
pattern = Pattern.compile(Config.PET_NAME_TEMPLATE);
}
catch (PatternSyntaxException e) // case of illegal pattern
{
_log.warning("ERROR : Pet name pattern of config is wrong!");
pattern = Pattern.compile(".*");
}
Matcher regexp = pattern.matcher(name);
if (!regexp.matches())
{
result = false;
}
return result;
}
private boolean isAlphaNumeric(String text)
{
boolean result = true;
char[] chars = text.toCharArray();
for (int i = 0; i < chars.length; i++)
{
if (!Character.isLetterOrDigit(chars[i]))
{
result = false;
break;
}
}
return result;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final PetNameTable _instance = new PetNameTable();
}
}
@@ -0,0 +1,209 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntIntHashMap;
import gnu.trove.TIntObjectHashMap;
import java.util.logging.Logger;
import com.l2jserver.gameserver.model.L2Skill;
import com.l2jserver.gameserver.skills.SkillsEngine;
/**
*
*/
public class SkillTable
{
private static Logger _log = Logger.getLogger(SkillTable.class.getName());
private final TIntObjectHashMap<L2Skill> _skills;
private final TIntIntHashMap _skillMaxLevel;
private final TIntArrayList _enchantable;
public static SkillTable getInstance()
{
return SingletonHolder._instance;
}
private SkillTable()
{
_skills = new TIntObjectHashMap<>();
_skillMaxLevel = new TIntIntHashMap();
_enchantable = new TIntArrayList();
load();
}
public void reload()
{
load();
// Reload Skill Tree as well.
SkillTreesData.getInstance().load();
}
private void load()
{
_skills.clear();
SkillsEngine.getInstance().loadAllSkills(_skills);
_skillMaxLevel.clear();
for (final L2Skill skill : _skills.getValues(new L2Skill[_skills.size()]))
{
final int skillId = skill.getId();
final int skillLvl = skill.getLevel();
if (skillLvl > 99)
{
if (!_enchantable.contains(skillId))
{
_enchantable.add(skillId);
}
continue;
}
// only non-enchanted skills
final int maxLvl = _skillMaxLevel.get(skillId);
if (skillLvl > maxLvl)
{
_skillMaxLevel.put(skillId, skillLvl);
}
}
// Sorting for binarySearch
_enchantable.sort();
// Reloading as well FrequentSkill enumeration values
for (FrequentSkill sk : FrequentSkill.values())
{
sk._skill = getInfo(sk._id, sk._level);
}
}
/**
* Provides the skill hash
* @param skill The L2Skill to be hashed
* @return getSkillHashCode(skill.getId(), skill.getLevel())
*/
public static int getSkillHashCode(L2Skill skill)
{
return getSkillHashCode(skill.getId(), skill.getLevel());
}
/**
* Centralized method for easier change of the hashing sys
* @param skillId The Skill Id
* @param skillLevel The Skill Level
* @return The Skill hash number
*/
public static int getSkillHashCode(int skillId, int skillLevel)
{
return (skillId * 1021) + skillLevel;
}
public final L2Skill getInfo(final int skillId, final int level)
{
final L2Skill result = _skills.get(getSkillHashCode(skillId, level));
if (result != null)
{
return result;
}
// skill/level not found, fix for transformation scripts
final int maxLvl = _skillMaxLevel.get(skillId);
// requested level too high
if ((maxLvl > 0) && (level > maxLvl))
{
return _skills.get(getSkillHashCode(skillId, maxLvl));
}
_log.warning("No skill info found for skill id " + skillId + " and skill level " + level + ".");
return null;
}
public final int getMaxLevel(final int skillId)
{
return _skillMaxLevel.get(skillId);
}
public final boolean isEnchantable(final int skillId)
{
return _enchantable.binarySearch(skillId) >= 0;
}
/**
* Returns an array with siege skills. If addNoble == true, will add also Advanced headquarters.
*/
public L2Skill[] getSiegeSkills(boolean addNoble, boolean hasCastle)
{
L2Skill[] temp = new L2Skill[2 + (addNoble ? 1 : 0) + (hasCastle ? 2 : 0)];
int i = 0;
temp[i++] = _skills.get(SkillTable.getSkillHashCode(246, 1));
temp[i++] = _skills.get(SkillTable.getSkillHashCode(247, 1));
if (addNoble)
{
temp[i++] = _skills.get(SkillTable.getSkillHashCode(326, 1));
}
if (hasCastle)
{
temp[i++] = _skills.get(SkillTable.getSkillHashCode(844, 1));
temp[i++] = _skills.get(SkillTable.getSkillHashCode(845, 1));
}
return temp;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final SkillTable _instance = new SkillTable();
}
/**
* Enum to hold some important references to frequently used (hardcoded) skills in core
* @author DrHouse
*/
public static enum FrequentSkill
{
RAID_CURSE(4215, 1),
RAID_CURSE2(4515, 1),
SEAL_OF_RULER(246, 1),
BUILD_HEADQUARTERS(247, 1),
WYVERN_BREATH(4289, 1),
STRIDER_SIEGE_ASSAULT(325, 1),
FAKE_PETRIFICATION(4616, 1),
FIREWORK(5965, 1),
LARGE_FIREWORK(2025, 1),
BLESSING_OF_PROTECTION(5182, 1),
ARENA_CP_RECOVERY(4380, 1),
VOID_BURST(3630, 1),
VOID_FLOW(3631, 1),
THE_VICTOR_OF_WAR(5074, 1),
THE_VANQUISHED_OF_WAR(5075, 1),
SPECIAL_TREE_RECOVERY_BONUS(2139, 1);
protected final int _id;
protected final int _level;
protected L2Skill _skill = null;
private FrequentSkill(int id, int level)
{
_id = id;
_level = level;
}
public L2Skill getSkill()
{
return _skill;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,372 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastSet;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.instancemanager.DayNightSpawnManager;
import com.l2jserver.gameserver.model.L2Spawn;
import com.l2jserver.gameserver.model.actor.L2Npc;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.templates.chars.L2NpcTemplate;
/**
* This class ...
* @author Nightmare
* @version $Revision: 1.5.2.6.2.7 $ $Date: 2005/03/27 15:29:18 $
*/
public class SpawnTable
{
private static Logger _log = Logger.getLogger(SpawnTable.class.getName());
private final FastSet<L2Spawn> _spawntable = new FastSet<L2Spawn>().shared();
private int _npcSpawnCount;
private int _customSpawnCount;
public static SpawnTable getInstance()
{
return SingletonHolder._instance;
}
private SpawnTable()
{
if (!Config.ALT_DEV_NO_SPAWNS)
{
fillSpawnTable();
}
}
public FastSet<L2Spawn> getSpawnTable()
{
return _spawntable;
}
private void fillSpawnTable()
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT count, npc_templateid, locx, locy, locz, heading, respawn_delay, loc_id, periodOfDay FROM spawnlist");
ResultSet rset = statement.executeQuery();
L2Spawn spawnDat;
L2NpcTemplate template1;
while (rset.next())
{
template1 = NpcTable.getInstance().getTemplate(rset.getInt("npc_templateid"));
if (template1 != null)
{
if (template1.type.equalsIgnoreCase("L2SiegeGuard"))
{
// Don't spawn
}
else if (template1.type.equalsIgnoreCase("L2RaidBoss"))
{
// Don't spawn raidboss
}
else if (!Config.ALLOW_CLASS_MASTERS && template1.type.equals("L2ClassMaster"))
{
// Dont' spawn class masters
}
else
{
spawnDat = new L2Spawn(template1);
spawnDat.setAmount(rset.getInt("count"));
spawnDat.setLocx(rset.getInt("locx"));
spawnDat.setLocy(rset.getInt("locy"));
spawnDat.setLocz(rset.getInt("locz"));
spawnDat.setHeading(rset.getInt("heading"));
spawnDat.setRespawnDelay(rset.getInt("respawn_delay"));
int loc_id = rset.getInt("loc_id");
spawnDat.setLocation(loc_id);
switch (rset.getInt("periodOfDay"))
{
case 0: // default
_npcSpawnCount += spawnDat.init();
break;
case 1: // Day
DayNightSpawnManager.getInstance().addDayCreature(spawnDat);
_npcSpawnCount++;
break;
case 2: // Night
DayNightSpawnManager.getInstance().addNightCreature(spawnDat);
_npcSpawnCount++;
break;
}
_spawntable.add(spawnDat);
}
}
else
{
_log.warning("SpawnTable: Data missing in NPC table for ID: " + rset.getInt("npc_templateid") + ".");
}
}
rset.close();
statement.close();
}
catch (Exception e)
{
// problem with initializing spawn, go to next one
_log.log(Level.WARNING, "SpawnTable: Spawn could not be initialized: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
_log.info("SpawnTable: Loaded " + _spawntable.size() + " Npc Spawn Locations.");
if (Config.CUSTOM_SPAWNLIST_TABLE)
{
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT count, npc_templateid, locx, locy, locz, heading, respawn_delay, loc_id, periodOfDay FROM custom_spawnlist");
ResultSet rset = statement.executeQuery();
L2Spawn spawnDat;
L2NpcTemplate template1;
while (rset.next())
{
template1 = NpcTable.getInstance().getTemplate(rset.getInt("npc_templateid"));
if (template1 != null)
{
if (template1.type.equalsIgnoreCase("L2SiegeGuard"))
{
// Don't spawn
}
else if (template1.type.equalsIgnoreCase("L2RaidBoss"))
{
// Don't spawn raidboss
}
else if (!Config.ALLOW_CLASS_MASTERS && template1.type.equals("L2ClassMaster"))
{
// Dont' spawn class masters
}
else
{
spawnDat = new L2Spawn(template1);
spawnDat.setAmount(rset.getInt("count"));
spawnDat.setLocx(rset.getInt("locx"));
spawnDat.setLocy(rset.getInt("locy"));
spawnDat.setLocz(rset.getInt("locz"));
spawnDat.setHeading(rset.getInt("heading"));
spawnDat.setRespawnDelay(rset.getInt("respawn_delay"));
spawnDat.setCustom(true);
int loc_id = rset.getInt("loc_id");
spawnDat.setLocation(loc_id);
switch (rset.getInt("periodOfDay"))
{
case 0: // default
_customSpawnCount += spawnDat.init();
break;
case 1: // Day
DayNightSpawnManager.getInstance().addDayCreature(spawnDat);
_customSpawnCount++;
break;
case 2: // Night
DayNightSpawnManager.getInstance().addNightCreature(spawnDat);
_customSpawnCount++;
break;
}
_spawntable.add(spawnDat);
}
}
else
{
_log.warning("CustomSpawnTable: Data missing in NPC table for ID: " + rset.getInt("npc_templateid") + ".");
}
}
rset.close();
statement.close();
}
catch (Exception e)
{
// problem with initializing spawn, go to next one
_log.log(Level.WARNING, "CustomSpawnTable: Spawn could not be initialized: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
_log.info("CustomSpawnTable: Loaded " + _customSpawnCount + " Npc Spawn Locations.");
}
if (Config.DEBUG)
{
_log.fine("SpawnTable: Spawning completed, total number of NPCs in the world: " + (_npcSpawnCount + _customSpawnCount));
}
}
public void addNewSpawn(L2Spawn spawn, boolean storeInDb)
{
_spawntable.add(spawn);
if (storeInDb)
{
String spawnTable;
if (spawn.isCustom() && Config.CUSTOM_SPAWNLIST_TABLE)
{
spawnTable = "custom_spawnlist";
}
else
{
spawnTable = "spawnlist";
}
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO " + spawnTable + "(count,npc_templateid,locx,locy,locz,heading,respawn_delay,loc_id) values(?,?,?,?,?,?,?,?)");
statement.setInt(1, spawn.getAmount());
statement.setInt(2, spawn.getNpcid());
statement.setInt(3, spawn.getLocx());
statement.setInt(4, spawn.getLocy());
statement.setInt(5, spawn.getLocz());
statement.setInt(6, spawn.getHeading());
statement.setInt(7, spawn.getRespawnDelay() / 1000);
statement.setInt(8, spawn.getLocation());
statement.execute();
statement.close();
}
catch (Exception e)
{
// problem with storing spawn
_log.log(Level.WARNING, "SpawnTable: Could not store spawn in the DB:" + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
}
public void deleteSpawn(L2Spawn spawn, boolean updateDb)
{
if (!_spawntable.remove(spawn))
{
return;
}
if (updateDb)
{
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM " + (spawn.isCustom() ? "custom_spawnlist" : "spawnlist") + " WHERE locx=? AND locy=? AND locz=? AND npc_templateid=? AND heading=?");
statement.setInt(1, spawn.getLocx());
statement.setInt(2, spawn.getLocy());
statement.setInt(3, spawn.getLocz());
statement.setInt(4, spawn.getNpcid());
statement.setInt(5, spawn.getHeading());
statement.execute();
statement.close();
}
catch (Exception e)
{
// problem with deleting spawn
_log.log(Level.WARNING, "SpawnTable: Spawn " + spawn + " could not be removed from DB: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
}
// just wrapper
public void reloadAll()
{
fillSpawnTable();
}
/**
* Get all the spawn of a NPC<BR>
* <BR>
* @param npcId : ID of the NPC to find.
* @return
*/
public void findNPCInstances(L2PcInstance activeChar, int npcId, int teleportIndex, boolean showposition)
{
int index = 0;
for (L2Spawn spawn : _spawntable)
{
if (npcId == spawn.getNpcid())
{
index++;
L2Npc _npc = spawn.getLastSpawn();
if (teleportIndex > -1)
{
if (teleportIndex == index)
{
if (showposition && (_npc != null))
{
activeChar.teleToLocation(_npc.getX(), _npc.getY(), _npc.getZ(), true);
}
else
{
activeChar.teleToLocation(spawn.getLocx(), spawn.getLocy(), spawn.getLocz(), true);
}
}
}
else
{
if (showposition && (_npc != null))
{
activeChar.sendMessage(index + " - " + spawn.getTemplate().name + " (" + spawn + "): " + _npc.getX() + " " + _npc.getY() + " " + _npc.getZ());
}
else
{
activeChar.sendMessage(index + " - " + spawn.getTemplate().name + " (" + spawn + "): " + spawn.getLocx() + " " + spawn.getLocy() + " " + spawn.getLocz());
}
}
}
}
if (index == 0)
{
activeChar.sendMessage("No current spawns found.");
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final SpawnTable _instance = new SpawnTable();
}
}
@@ -0,0 +1,159 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.gameserver.idfactory.IdFactory;
import com.l2jserver.gameserver.model.actor.instance.L2StaticObjectInstance;
import com.l2jserver.gameserver.templates.StatsSet;
import com.l2jserver.gameserver.templates.chars.L2CharTemplate;
public class StaticObjects
{
private static Logger _log = Logger.getLogger(StaticObjects.class.getName());
private final TIntObjectHashMap<L2StaticObjectInstance> _staticObjects;
public static StaticObjects getInstance()
{
return SingletonHolder._instance;
}
private StaticObjects()
{
_staticObjects = new TIntObjectHashMap<>();
parseData();
_log.info("StaticObject: Loaded " + _staticObjects.size() + " StaticObject Templates.");
}
private void parseData()
{
File doorData = new File(Config.DATAPACK_ROOT, "data/staticobjects.csv");
try (LineNumberReader lnr = new LineNumberReader(new BufferedReader(new FileReader(doorData))))
{
String line = null;
while ((line = lnr.readLine()) != null)
{
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
L2StaticObjectInstance obj = parse(line);
_staticObjects.put(obj.getStaticObjectId(), obj);
}
}
catch (FileNotFoundException e)
{
_log.warning("staticobjects.csv is missing in data folder");
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while creating StaticObjects table " + e.getMessage(), e);
}
}
public static L2StaticObjectInstance parse(String line)
{
StringTokenizer st = new StringTokenizer(line, ";");
st.nextToken(); // Pass over static object name (not used in server)
int id = Integer.parseInt(st.nextToken());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
int z = Integer.parseInt(st.nextToken());
int type = Integer.parseInt(st.nextToken());
String texture = st.nextToken();
int map_x = Integer.parseInt(st.nextToken());
int map_y = Integer.parseInt(st.nextToken());
StatsSet npcDat = new StatsSet();
npcDat.set("npcId", id);
npcDat.set("level", 0);
npcDat.set("jClass", "staticobject");
npcDat.set("baseSTR", 0);
npcDat.set("baseCON", 0);
npcDat.set("baseDEX", 0);
npcDat.set("baseINT", 0);
npcDat.set("baseWIT", 0);
npcDat.set("baseMEN", 0);
npcDat.set("baseShldDef", 0);
npcDat.set("baseShldRate", 0);
npcDat.set("baseAccCombat", 38);
npcDat.set("baseEvasRate", 38);
npcDat.set("baseCritRate", 38);
// npcDat.set("name", "");
npcDat.set("collision_radius", 10);
npcDat.set("collision_height", 10);
npcDat.set("sex", "male");
npcDat.set("type", "");
npcDat.set("baseAtkRange", 0);
npcDat.set("baseMpMax", 0);
npcDat.set("baseCpMax", 0);
npcDat.set("rewardExp", 0);
npcDat.set("rewardSp", 0);
npcDat.set("basePAtk", 0);
npcDat.set("baseMAtk", 0);
npcDat.set("basePAtkSpd", 0);
npcDat.set("aggroRange", 0);
npcDat.set("baseMAtkSpd", 0);
npcDat.set("rhand", 0);
npcDat.set("lhand", 0);
npcDat.set("armor", 0);
npcDat.set("baseWalkSpd", 0);
npcDat.set("baseRunSpd", 0);
npcDat.set("name", "");
npcDat.set("baseHpMax", 1);
npcDat.set("baseHpReg", 3.e-3f);
npcDat.set("baseMpReg", 3.e-3f);
npcDat.set("basePDef", 1);
npcDat.set("baseMDef", 1);
L2CharTemplate template = new L2CharTemplate(npcDat);
L2StaticObjectInstance obj = new L2StaticObjectInstance(IdFactory.getInstance().getNextId(), template, id);
obj.setType(type);
obj.setXYZ(x, y, z);
obj.setMap(texture, map_x, map_y);
obj.spawnMe();
return obj;
}
public void putObject(L2StaticObjectInstance obj)
{
_staticObjects.put(obj.getStaticObjectId(), obj);
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final StaticObjects _instance = new StaticObjects();
}
}
@@ -0,0 +1,133 @@
/*
* 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/>.
*/
/**
*
* @author FBIagent
*
*/
package com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.io.File;
import java.util.Scanner;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.L2SummonItem;
public class SummonItemsData
{
protected static final Logger _log = Logger.getLogger(SummonItemsData.class.getName());
private TIntObjectHashMap<L2SummonItem> _summonitems;
public static SummonItemsData getInstance()
{
return SingletonHolder._instance;
}
private SummonItemsData()
{
_summonitems = new TIntObjectHashMap<>();
Scanner s;
try
{
s = new Scanner(new File(Config.DATAPACK_ROOT + "/data/summon_items.csv"));
}
catch (Exception e)
{
_log.warning("Summon items data: Can not find '" + Config.DATAPACK_ROOT + "/data/summon_items.csv'");
return;
}
int lineCount = 0;
while (s.hasNextLine())
{
lineCount++;
String line = s.nextLine();
if (line.startsWith("#"))
{
continue;
}
else if (line.isEmpty())
{
continue;
}
String[] lineSplit = line.split(";");
boolean ok = true;
int itemID = 0, npcID = 0;
byte summonType = 0;
int despawn = -1;
try
{
itemID = Integer.parseInt(lineSplit[0]);
npcID = Integer.parseInt(lineSplit[1]);
summonType = Byte.parseByte(lineSplit[2]);
if (summonType == 0)
{
despawn = Integer.parseInt(lineSplit[3]);
}
}
catch (Exception e)
{
_log.warning("Summon items data: Error in line " + lineCount + " -> incomplete/invalid data or wrong seperator!");
_log.warning(" " + line);
ok = false;
}
if (!ok)
{
continue;
}
L2SummonItem summonitem = new L2SummonItem(itemID, npcID, summonType, despawn);
_summonitems.put(itemID, summonitem);
}
_log.info("Summon items data: Loaded " + _summonitems.size() + " summon items.");
}
public L2SummonItem getSummonItem(int itemId)
{
return _summonitems.get(itemId);
}
public int[] itemIDs()
{
int size = _summonitems.size();
int[] result = new int[size];
int i = 0;
for (Object si : _summonitems.getValues())
{
result[i++] = ((L2SummonItem) si).getItemId();
}
return result;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final SummonItemsData _instance = new SummonItemsData();
}
}
@@ -0,0 +1,216 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.actor.L2Summon;
public class SummonSkillsTable
{
private static Logger _log = Logger.getLogger(SummonSkillsTable.class.getName());
private final FastMap<Integer, Map<Integer, L2PetSkillLearn>> _skillTrees;
public static SummonSkillsTable getInstance()
{
return SingletonHolder._instance;
}
public void reload()
{
_skillTrees.clear();
load();
}
private SummonSkillsTable()
{
_skillTrees = new FastMap<>();
load();
}
private void load()
{
int npcId = 0;
int count = 0;
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
try
{
PreparedStatement statement = con.prepareStatement("SELECT id FROM npc WHERE type IN ('L2Pet','L2BabyPet','L2SiegeSummon') ORDER BY id");
ResultSet petlist = statement.executeQuery();
Map<Integer, L2PetSkillLearn> map;
L2PetSkillLearn skillLearn;
PreparedStatement statement2 = con.prepareStatement("SELECT minLvl, skillId, skillLvl FROM pets_skills where templateId=? ORDER BY skillId, skillLvl");
while (petlist.next())
{
map = new FastMap<>();
npcId = petlist.getInt("id");
statement2.setInt(1, npcId);
ResultSet skilltree = statement2.executeQuery();
statement2.clearParameters();
while (skilltree.next())
{
int id = skilltree.getInt("skillId");
int lvl = skilltree.getInt("skillLvl");
int minLvl = skilltree.getInt("minLvl");
skillLearn = new L2PetSkillLearn(id, lvl, minLvl);
map.put(SkillTable.getSkillHashCode(id, lvl + 1), skillLearn);
}
_skillTrees.put(npcId, map);
skilltree.close();
count += map.size();
_log.fine("PetSkillsTable: skill tree for pet " + npcId + " has " + map.size() + " skills");
}
statement2.close();
petlist.close();
statement.close();
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error while creating pet skill tree (Pet ID " + npcId + "): " + e.getMessage(), e);
}
_log.info("PetSkillsTable: Loaded " + count + " skills.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error while loading pet skills tables: " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
public int getAvailableLevel(L2Summon cha, int skillId)
{
int lvl = 0;
if (!_skillTrees.containsKey(cha.getNpcId()))
{
_log.warning("Pet id " + cha.getNpcId() + " does not have any skills assigned.");
return lvl;
}
Collection<L2PetSkillLearn> skills = _skillTrees.get(cha.getNpcId()).values();
for (L2PetSkillLearn temp : skills)
{
if (temp.getId() != skillId)
{
continue;
}
if (temp.getLevel() == 0)
{
if (cha.getLevel() < 70)
{
lvl = (cha.getLevel() / 10);
if (lvl <= 0)
{
lvl = 1;
}
}
else
{
lvl = (7 + ((cha.getLevel() - 70) / 5));
}
// formula usable for skill that have 10 or more skill levels
int maxLvl = SkillTable.getInstance().getMaxLevel(temp.getId());
if (lvl > maxLvl)
{
lvl = maxLvl;
}
break;
}
else if (temp.getMinLevel() <= cha.getLevel())
{
if (temp.getLevel() > lvl)
{
lvl = temp.getLevel();
}
}
}
return lvl;
}
public FastList<Integer> getAvailableSkills(L2Summon cha)
{
FastList<Integer> skillIds = new FastList<>();
if (!_skillTrees.containsKey(cha.getNpcId()))
{
_log.warning("Pet id " + cha.getNpcId() + " does not have any skills assigned.");
return skillIds;
}
Collection<L2PetSkillLearn> skills = _skillTrees.get(cha.getNpcId()).values();
for (L2PetSkillLearn temp : skills)
{
if (skillIds.contains(temp.getId()))
{
continue;
}
skillIds.add(temp.getId());
}
return skillIds;
}
public static final class L2PetSkillLearn
{
private final int _id;
private final int _level;
private final int _minLevel;
public L2PetSkillLearn(int id, int lvl, int minLvl)
{
_id = id;
_level = lvl;
_minLevel = minLvl;
}
public int getId()
{
return _id;
}
public int getLevel()
{
return _level;
}
public int getMinLevel()
{
return _minLevel;
}
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final SummonSkillsTable _instance = new SummonSkillsTable();
}
}
@@ -0,0 +1,145 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import gnu.trove.TIntObjectHashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jserver.Config;
import com.l2jserver.L2DatabaseFactory;
import com.l2jserver.gameserver.model.L2TeleportLocation;
/**
* This class ...
* @version $Revision: 1.3.2.2.2.3 $ $Date: 2005/03/27 15:29:18 $
*/
public class TeleportLocationTable
{
private static Logger _log = Logger.getLogger(TeleportLocationTable.class.getName());
private TIntObjectHashMap<L2TeleportLocation> _teleports;
public static TeleportLocationTable getInstance()
{
return SingletonHolder._instance;
}
private TeleportLocationTable()
{
reloadAll();
}
public void reloadAll()
{
_teleports = new TIntObjectHashMap<>();
Connection con = null;
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT id, loc_x, loc_y, loc_z, price, fornoble, itemId FROM teleport");
ResultSet rset = statement.executeQuery();
L2TeleportLocation teleport;
while (rset.next())
{
teleport = new L2TeleportLocation();
teleport.setTeleId(rset.getInt("id"));
teleport.setLocX(rset.getInt("loc_x"));
teleport.setLocY(rset.getInt("loc_y"));
teleport.setLocZ(rset.getInt("loc_z"));
teleport.setPrice(rset.getInt("price"));
teleport.setIsForNoble(rset.getInt("fornoble") == 1);
teleport.setItemId(rset.getInt("itemId"));
_teleports.put(teleport.getTeleId(), teleport);
}
rset.close();
statement.close();
_log.info("TeleportLocationTable: Loaded " + _teleports.size() + " Teleport Location Templates.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error loading Teleport Table.", e);
}
finally
{
L2DatabaseFactory.close(con);
}
if (Config.CUSTOM_TELEPORT_TABLE)
{
try
{
con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT id, loc_x, loc_y, loc_z, price, fornoble, itemId FROM custom_teleport");
ResultSet rset = statement.executeQuery();
L2TeleportLocation teleport;
int _cTeleCount = _teleports.size();
while (rset.next())
{
teleport = new L2TeleportLocation();
teleport.setTeleId(rset.getInt("id"));
teleport.setLocX(rset.getInt("loc_x"));
teleport.setLocY(rset.getInt("loc_y"));
teleport.setLocZ(rset.getInt("loc_z"));
teleport.setPrice(rset.getInt("price"));
teleport.setIsForNoble(rset.getInt("fornoble") == 1);
teleport.setItemId(rset.getInt("itemId"));
_teleports.put(teleport.getTeleId(), teleport);
}
rset.close();
statement.close();
_cTeleCount = _teleports.size() - _cTeleCount;
if (_cTeleCount > 0)
{
_log.info("TeleportLocationTable: Loaded " + _cTeleCount + " Custom Teleport Location Templates.");
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while creating custom teleport table " + e.getMessage(), e);
}
finally
{
L2DatabaseFactory.close(con);
}
}
}
/**
* @param template id
* @return
*/
public L2TeleportLocation getTemplate(int id)
{
return _teleports.get(id);
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final TeleportLocationTable _instance = new TeleportLocationTable();
}
}
@@ -0,0 +1,170 @@
/*
* 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 com.l2jserver.gameserver.datatables;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.LineNumberReader;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import javolution.util.FastMap;
import com.l2jserver.Config;
import com.l2jserver.gameserver.model.entity.ActionKey;
/**
* @author mrTJO
*/
public class UITable
{
private static Logger _log = Logger.getLogger(UITable.class.getName());
private final Map<Integer, List<ActionKey>> _storedKeys;
private final Map<Integer, List<Integer>> _storedCategories;
public static UITable getInstance()
{
return SingletonHolder._instance;
}
private UITable()
{
_storedKeys = new FastMap<>();
_storedCategories = new FastMap<>();
parseCatData();
parseKeyData();
_log.info("UITable: Loaded " + _storedCategories.size() + " Categories.");
_log.info("UITable: Loaded " + _storedKeys.size() + " Keys.");
}
private void parseCatData()
{
File uiData = new File(Config.DATAPACK_ROOT, "data/uicats_en.csv");
try (LineNumberReader lnr = new LineNumberReader(new BufferedReader(new FileReader(uiData))))
{
String line = null;
while ((line = lnr.readLine()) != null)
{
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
StringTokenizer st = new StringTokenizer(line, ";");
int cat = Integer.parseInt(st.nextToken());
int cmd = Integer.parseInt(st.nextToken());
insertCategory(cat, cmd);
}
}
catch (FileNotFoundException e)
{
_log.warning("uicats_en.csv is missing in data folder");
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while creating UI Default Categories table " + e.getMessage(), e);
}
}
private void parseKeyData()
{
File uiData = new File(Config.DATAPACK_ROOT, "data/uikeys_en.csv");
try (LineNumberReader lnr = new LineNumberReader(new BufferedReader(new FileReader(uiData))))
{
String line = null;
while ((line = lnr.readLine()) != null)
{
if ((line.trim().length() == 0) || line.startsWith("#"))
{
continue;
}
StringTokenizer st = new StringTokenizer(line, ";");
int cat = Integer.parseInt(st.nextToken());
int cmd = Integer.parseInt(st.nextToken());
int key = Integer.parseInt(st.nextToken());
int tk1 = Integer.parseInt(st.nextToken());
int tk2 = Integer.parseInt(st.nextToken());
int shw = Integer.parseInt(st.nextToken());
insertKey(cat, cmd, key, tk1, tk2, shw);
}
}
catch (FileNotFoundException e)
{
_log.warning("uikeys_en.csv is missing in data folder");
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while creating UI Default Keys table " + e.getMessage(), e);
}
}
private void insertCategory(int cat, int cmd)
{
if (_storedCategories.containsKey(cat))
{
_storedCategories.get(cat).add(cmd);
}
else
{
List<Integer> tmp = new FastList<>();
tmp.add(cmd);
_storedCategories.put(cat, tmp);
}
}
private void insertKey(int cat, int cmdId, int key, int tgKey1, int tgKey2, int show)
{
ActionKey tmk = new ActionKey(cat, cmdId, key, tgKey1, tgKey2, show);
if (_storedKeys.containsKey(cat))
{
_storedKeys.get(cat).add(tmk);
}
else
{
List<ActionKey> tmp = new FastList<>();
tmp.add(tmk);
_storedKeys.put(cat, tmp);
}
}
public Map<Integer, List<Integer>> getCategories()
{
return _storedCategories;
}
public Map<Integer, List<ActionKey>> getKeys()
{
return _storedKeys;
}
@SuppressWarnings("synthetic-access")
private static class SingletonHolder
{
protected static final UITable _instance = new UITable();
}
}
@@ -0,0 +1,119 @@
/*
* 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 com.l2jserver.gameserver.geoeditorcon;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Dezmond
*/
public class GeoEditorListener extends Thread
{
private static GeoEditorListener _instance;
private static final int PORT = 9011;
private static Logger _log = Logger.getLogger(GeoEditorListener.class.getName());
private final ServerSocket _serverSocket;
private static GeoEditorThread _geoEditor;
public static GeoEditorListener getInstance()
{
synchronized (GeoEditorListener.class)
{
if (_instance == null)
{
try
{
_instance = new GeoEditorListener();
_instance.start();
_log.info("GeoEditorListener Initialized.");
}
catch (IOException e)
{
_log.log(Level.SEVERE, "Error creating geoeditor listener! " + e.getMessage(), e);
System.exit(1);
}
}
}
return _instance;
}
private GeoEditorListener() throws IOException
{
_serverSocket = new ServerSocket(PORT);
}
public GeoEditorThread getThread()
{
return _geoEditor;
}
public String getStatus()
{
if ((_geoEditor != null) && _geoEditor.isWorking())
{
return "Geoeditor connected.";
}
return "Geoeditor not connected.";
}
@Override
public void run()
{
Socket connection = null;
try
{
while (true)
{
connection = _serverSocket.accept();
if ((_geoEditor != null) && _geoEditor.isWorking())
{
_log.warning("Geoeditor already connected!");
connection.close();
continue;
}
_log.info("Received geoeditor connection from: " + connection.getInetAddress().getHostAddress());
_geoEditor = new GeoEditorThread(connection);
_geoEditor.start();
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "GeoEditorListener: " + e.getMessage(), e);
try
{
connection.close();
}
catch (Exception e2)
{
}
}
finally
{
try
{
_serverSocket.close();
}
catch (IOException io)
{
_log.log(Level.INFO, "", io);
}
_log.warning("GeoEditorListener Closed!");
}
}
}
@@ -0,0 +1,284 @@
/*
* 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 com.l2jserver.gameserver.geoeditorcon;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.util.FastList;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
/**
* @author Luno, Dezmond
*/
public class GeoEditorThread extends Thread
{
private static Logger _log = Logger.getLogger(GeoEditorThread.class.getName());
private boolean _working = false;
private int _mode = 0; // 0 - don't send coords, 1 - send each
// validateposition from client, 2 - send in
// intervals of _sendDelay ms.
private int _sendDelay = 1000; // default - once in second
private final Socket _geSocket;
private OutputStream _out;
private final FastList<L2PcInstance> _gms;
public GeoEditorThread(Socket ge)
{
_geSocket = ge;
_working = true;
_gms = new FastList<>();
}
@Override
public void interrupt()
{
try
{
_geSocket.close();
}
catch (Exception e)
{
}
super.interrupt();
}
@Override
public void run()
{
try
{
_out = _geSocket.getOutputStream();
int timer = 0;
while (_working)
{
if (!isConnected())
{
_working = false;
}
if ((_mode == 2) && (timer > _sendDelay))
{
for (L2PcInstance gm : _gms)
{
if (!gm.getClient().getConnection().isClosed())
{
sendGmPosition(gm);
}
else
{
_gms.remove(gm);
}
}
timer = 0;
}
try
{
sleep(100);
if (_mode == 2)
{
timer += 100;
}
}
catch (Exception e)
{
}
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "GeoEditor disconnected. " + e.getMessage(), e);
}
finally
{
try
{
_geSocket.close();
}
catch (Exception e)
{
}
_working = false;
}
}
public void sendGmPosition(int gx, int gy, short z)
{
if (!isConnected())
{
return;
}
try
{
synchronized (_out)
{
writeC(0x0b); // length 11 bytes!
writeC(0x01); // Cmd = save cell;
writeD(gx); // Global coord X;
writeD(gy); // Global coord Y;
writeH(z); // Coord Z;
_out.flush();
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "GeoEditor disconnected. " + e.getMessage(), e);
_working = false;
}
finally
{
try
{
_geSocket.close();
}
catch (Exception ex)
{
}
_working = false;
}
}
public void sendGmPosition(L2PcInstance _gm)
{
sendGmPosition(_gm.getX(), _gm.getY(), (short) _gm.getZ());
}
public void sendPing()
{
if (!isConnected())
{
return;
}
try
{
synchronized (_out)
{
writeC(0x01); // length 1 byte!
writeC(0x02); // Cmd = ping (dummy packet for connection
// test);
_out.flush();
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "GeoEditor disconnected. " + e.getMessage(), e);
_working = false;
}
finally
{
try
{
_geSocket.close();
}
catch (Exception ex)
{
}
_working = false;
}
}
private void writeD(int value) throws IOException
{
_out.write(value & 0xff);
_out.write((value >> 8) & 0xff);
_out.write((value >> 16) & 0xff);
_out.write((value >> 24) & 0xff);
}
private void writeH(int value) throws IOException
{
_out.write(value & 0xff);
_out.write((value >> 8) & 0xff);
}
private void writeC(int value) throws IOException
{
_out.write(value & 0xff);
}
public void setMode(int value)
{
_mode = value;
}
public void setTimer(int value)
{
if (value < 500)
{
_sendDelay = 500; // maximum - 2 times per second!
}
else if (value > 60000)
{
_sendDelay = 60000; // Minimum - 1 time per minute.
}
else
{
_sendDelay = value;
}
}
public void addGM(L2PcInstance gm)
{
if (!_gms.contains(gm))
{
_gms.add(gm);
}
}
public void removeGM(L2PcInstance gm)
{
if (_gms.contains(gm))
{
_gms.remove(gm);
}
}
public boolean isSend(L2PcInstance gm)
{
if ((_mode == 1) && _gms.contains(gm))
{
return true;
}
return false;
}
private boolean isConnected()
{
return _geSocket.isConnected() && !_geSocket.isClosed();
}
public boolean isWorking()
{
sendPing();
return _working;
}
public int getMode()
{
return _mode;
}
}

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