diff --git a/.travis.yml b/.travis.yml index f5dd9ec6..c401f889 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,7 @@ language: java jdk: - - oraclejdk9 - -addons: - apt: - packages: - - oracle-java9-installer + - oraclejdk10 script: ./gradlew build --daemon @@ -17,4 +12,7 @@ before_cache: cache: directories: - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ \ No newline at end of file + - $HOME/.gradle/wrapper/ + +notifications: + email: false \ No newline at end of file diff --git a/Commons/build.gradle b/Commons/build.gradle index d849cc2a..f25e1e29 100644 --- a/Commons/build.gradle +++ b/Commons/build.gradle @@ -4,7 +4,7 @@ plugins { id "eclipse" } -version '1.3.0' +version '1.4' ext.moduleName = 'com.l2jbr.commons' @@ -19,9 +19,16 @@ sourceSets { } } + + dependencies { - compile 'com.mchange:c3p0:0.9.5.2' compile 'org.slf4j:slf4j-api:1.8.0-beta2' + compile 'org.springframework.data:spring-data-jdbc:1.0.0.M3' + compile 'com.zaxxer:HikariCP:3.2.0' + + runtime ('mysql:mysql-connector-java:8.0.11') { + transitive = false + } } jar { diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/Config.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/Config.java index bebfa3d0..c1b04313 100644 --- a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/Config.java +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/Config.java @@ -37,6 +37,8 @@ */ public final class Config { protected static final Logger _log = LoggerFactory.getLogger(Config.class.getName()); + + /** * Debug/release mode */ @@ -102,6 +104,8 @@ public final class Config { */ public static int DATABASE_MAX_CONNECTIONS; + public static int DATABASE_MAX_IDLE_TIME; + /** * Maximum number of players allowed to play simultaneously on server */ @@ -1466,19 +1470,6 @@ public static enum L2WalkerAllowed { */ public static int DUMP_INTERVAL_SECONDS = 60; - /** - * Enumeration for type of ID Factory - */ - public static enum IdFactoryType { - Compaction, - BitSet, - Stack - } - - /** - * ID Factory type - */ - public static IdFactoryType IDFACTORY_TYPE; /** * Check for bad ID ? */ @@ -1908,6 +1899,7 @@ public static void load() { DATABASE_LOGIN = serverSettings.getProperty("Login", "root"); DATABASE_PASSWORD = serverSettings.getProperty("Password", ""); DATABASE_MAX_CONNECTIONS = Integer.parseInt(serverSettings.getProperty("MaximumDbConnections", "10")); + DATABASE_MAX_IDLE_TIME = Integer.parseInt(serverSettings.getProperty("MaximumDbIdleTime", "0")); DATAPACK_ROOT = new File(serverSettings.getProperty("DatapackRoot", ".")).getCanonicalFile(); @@ -2100,7 +2092,6 @@ public static void load() { MAP_TYPE = ObjectMapType.valueOf(idSettings.getProperty("L2Map", "WorldObjectMap")); SET_TYPE = ObjectSetType.valueOf(idSettings.getProperty("L2Set", "WorldObjectSet")); - IDFACTORY_TYPE = IdFactoryType.valueOf(idSettings.getProperty("IDFactory", "Compaction")); BAD_ID_CHECKING = Boolean.valueOf(idSettings.getProperty("BadIdChecking", "True")); } catch (Exception e) { e.printStackTrace(); @@ -2735,7 +2726,8 @@ public static void load() { DATABASE_LOGIN = serverSettings.getProperty("Login", "root"); DATABASE_PASSWORD = serverSettings.getProperty("Password", ""); DATABASE_MAX_CONNECTIONS = Integer.parseInt(serverSettings.getProperty("MaximumDbConnections", "10")); - + DATABASE_MAX_IDLE_TIME = Integer.parseInt(serverSettings.getProperty("MaximumDbIdleTime", "0")); + SHOW_LICENCE = Boolean.parseBoolean(serverSettings.getProperty("ShowLicence", "true")); IP_UPDATE_TIME = Integer.parseInt(serverSettings.getProperty("IpUpdateTime", "15")); FORCE_GGAUTH = Boolean.parseBoolean(serverSettings.getProperty("ForceGGAuth", "false")); diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/L2DatabaseFactory.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/L2DatabaseFactory.java deleted file mode 100644 index 90d69585..00000000 --- a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/L2DatabaseFactory.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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 2, 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * http://www.gnu.org/copyleft/gpl.html - */ -package com.l2jbr.commons; - -import com.mchange.v2.c3p0.ComboPooledDataSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.sql.Connection; -import java.sql.SQLException; - - -public class L2DatabaseFactory -{ - static Logger _log = LoggerFactory.getLogger(L2DatabaseFactory.class.getName()); - - public static enum ProviderType - { - MySql, - MsSql - } - - // ========================================================= - // Data Field - private static L2DatabaseFactory _instance; - private ProviderType _providerType; - private ComboPooledDataSource _source; - - // ========================================================= - // Constructor - public L2DatabaseFactory() throws SQLException - { - try - { - if (Config.DATABASE_MAX_CONNECTIONS < 2) - { - Config.DATABASE_MAX_CONNECTIONS = 2; - _log.warn("at least " + Config.DATABASE_MAX_CONNECTIONS + " db connections are required."); - } - - _source = new ComboPooledDataSource(); - _source.setAutoCommitOnClose(true); - - _source.setInitialPoolSize(10); - _source.setMinPoolSize(10); - _source.setMaxPoolSize(Config.DATABASE_MAX_CONNECTIONS); - - _source.setAcquireRetryAttempts(0); // try to obtain connections indefinitely (0 = never quit) - _source.setAcquireRetryDelay(500); // 500 miliseconds 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(0); // 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.debug("Database Connection Working"); - } - - if (Config.DATABASE_DRIVER.toLowerCase().contains("microsoft")) - { - _providerType = ProviderType.MsSql; - } - else - { - _providerType = ProviderType.MySql; - } - } - catch (SQLException x) - { - if (Config.DEBUG) - { - _log.debug("Database Connection FAILED"); - } - // rethrow the exception - throw x; - } - catch (Exception e) - { - if (Config.DEBUG) - { - _log.debug("Database Connection FAILED"); - } - throw new SQLException("could not init DB connection:" + e); - } - } - - // ========================================================= - // 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.info( "", e); - } - try - { - _source = null; - } - catch (Exception e) - { - _log.info( "", e); - } - } - - public final String safetyString(String[] whatToCheck) - { - // NOTE: Use brace as a safty percaution just incase name is a reserved word - String braceLeft = "`"; - String braceRight = "`"; - if (getProviderType() == ProviderType.MsSql) - { - braceLeft = "["; - braceRight = "]"; - } - - String result = ""; - for (String word : whatToCheck) - { - if (result != "") - { - result += ", "; - } - result += braceLeft + word + braceRight; - } - return result; - } - - // ========================================================= - // Property - Public - public static L2DatabaseFactory getInstance() throws SQLException - { - if (_instance == null) - { - _instance = new L2DatabaseFactory(); - } - return _instance; - } - - public Connection getConnection() // throws SQLException - { - Connection con = null; - - while (con == null) - { - try - { - con = _source.getConnection(); - } - catch (SQLException e) - { - _log.warn("L2DatabaseFactory: getConnection() failed, trying again " + e); - } - } - return con; - } - - public int getBusyConnectionCount() throws SQLException - { - return _source.getNumBusyConnectionsDefaultUser(); - } - - public int getIdleConnectionCount() throws SQLException - { - return _source.getNumIdleConnectionsDefaultUser(); - } - - public final ProviderType getProviderType() - { - return _providerType; - } -} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/crypt/NewCrypt.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/crypt/NewCrypt.java index 0a201fb1..87f69f94 100644 --- a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/crypt/NewCrypt.java +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/crypt/NewCrypt.java @@ -77,7 +77,7 @@ public static boolean verifyChecksum(byte[] raw, final int offset, final int siz chksum ^= check; } - + check = raw[i] & 0xff; check |= (raw[i + 1] << 8) & 0xff00; check |= (raw[i + 2] << 0x10) & 0xff0000; @@ -130,7 +130,10 @@ public static void encXORPass(byte[] raw, int key) } /** - * Packet is first XOR encoded with key Then, the last 4 bytes are overwritten with the the XOR "key". Thus this assume that there is enough room for the key to fit without overwriting data. + * Packet is first XOR encoded with key + * Then, the last 4 bytes are overwritten with the the XOR "key". + * Thus this assume that there is enough room for the key to fit without overwriting data. + * * @param raw The raw bytes to be encrypted * @param offset The begining of the data to be encrypted * @param size Length of the data to be encrypted diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/AccountRepository.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/AccountRepository.java new file mode 100644 index 00000000..003d9992 --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/AccountRepository.java @@ -0,0 +1,29 @@ +package com.l2jbr.commons.database; + +import com.l2jbr.commons.database.model.Account; +import org.springframework.data.jdbc.repository.query.Modifying; +import org.springframework.data.jdbc.repository.query.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; + +import java.util.Optional; + +public interface AccountRepository extends CrudRepository { + + @Modifying + @Query("REPLACE accounts (login, password, access_level) values (:login, :password, :accessLevel)") + int createOrUpdateAccount(@Param("login") String login, @Param("password") String password, @Param("accessLevel") short accessLevel); + + @Modifying + @Query("UPDATE accounts SET access_level=:accessLevel WHERE login=:login") + int updateAccessLevel(@Param("login") String login, @Param("accessLevel") int acessLevel); + + @Modifying + @Query("UPDATE accounts SET lastServer=:server WHERE login=:login") + int updateLastServer(@Param("login") String login, @Param("server") int server); + + @Query("SELECT * FROM accounts WHERE login=:login") + Optional findByLogin(@Param("login") String login); + +} + diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/AnnotationNamingStrategy.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/AnnotationNamingStrategy.java new file mode 100644 index 00000000..46dc2f5d --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/AnnotationNamingStrategy.java @@ -0,0 +1,35 @@ +package com.l2jbr.commons.database; + +import com.l2jbr.commons.database.annotation.Column; +import com.l2jbr.commons.database.annotation.Table; +import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty; +import org.springframework.data.jdbc.mapping.model.NamingStrategy; + +import static java.util.Objects.nonNull; + +public class AnnotationNamingStrategy implements NamingStrategy { + + @Override + public String getTableName(Class type) { + Table tableAnnotation = type.getAnnotation(Table.class); + if(nonNull(tableAnnotation)) { + return tableAnnotation.value(); + } + return type.getSimpleName(); + } + + @Override + public String getColumnName(JdbcPersistentProperty property) { + Column columnAnnotation = property.getField().getAnnotation(Column.class); + if(nonNull(columnAnnotation)) { + return columnAnnotation.value(); + } + return property.getName(); + } + + @Override + public String getReverseColumnName(JdbcPersistentProperty property) { + return getColumnName(property); + + } +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/DatabaseAccess.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/DatabaseAccess.java new file mode 100644 index 00000000..cf99048c --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/DatabaseAccess.java @@ -0,0 +1,43 @@ +package com.l2jbr.commons.database; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.repository.Repository; + +import java.sql.SQLException; +import java.util.LinkedHashMap; +import java.util.Map; + +import static java.util.Objects.nonNull; + +public class DatabaseAccess { + + private static Logger logger = LoggerFactory.getLogger(DatabaseAccess.class); + + private static Map, Repository> repositories = new LinkedHashMap<>(); + + public static T getRepository(Class repositoryClass) { + if(repositories.containsKey(repositoryClass)) { + return repositoryClass.cast(repositories.get(repositoryClass)); + } + T repository = null; + try { + repository = L2DatabaseFactory.getInstance().getRepository(repositoryClass); + if(nonNull(repository)) { + repositories.put(repositoryClass, repository); + } + } catch (Exception e) { + logger.error("Error accessing Database", e); + } + return repository; + } + + + public static void shutdown() { + try { + L2DatabaseFactory.getInstance().shutdown(); + } catch (SQLException e) { + logger.warn(e.getLocalizedMessage(), e); + } + } +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/DatabaseContextConfiguration.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/DatabaseContextConfiguration.java new file mode 100644 index 00000000..d233ac3e --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/DatabaseContextConfiguration.java @@ -0,0 +1,83 @@ +package com.l2jbr.commons.database; + +import com.l2jbr.commons.Config; +import com.l2jbr.commons.database.model.Entity; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jdbc.mapping.event.AfterLoadEvent; +import org.springframework.data.jdbc.mapping.event.AfterSaveEvent; +import org.springframework.data.jdbc.mapping.event.WithEntity; +import org.springframework.data.jdbc.mapping.model.NamingStrategy; +import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; + +import javax.sql.DataSource; +import java.util.Optional; + +@Configuration +@EnableJdbcRepositories({"com.l2jbr.commons.database", "com.l2jbr.gameserver.model.entity.database.repository"}) +public class DatabaseContextConfiguration { + + @Bean + public HikariDataSource dataSource() { + HikariConfig dataSourceConfig = new HikariConfig(); + dataSourceConfig.addDataSourceProperty("driverClassName", Config.DATABASE_DRIVER); + dataSourceConfig.setJdbcUrl(Config.DATABASE_URL); + dataSourceConfig.setUsername(Config.DATABASE_LOGIN); + dataSourceConfig.setPassword(Config.DATABASE_PASSWORD); + dataSourceConfig.addDataSourceProperty("maximumPoolSize", Config.DATABASE_MAX_CONNECTIONS); + dataSourceConfig.addDataSourceProperty("idleTimeout", Config.DATABASE_MAX_IDLE_TIME); // 0 = idle connections never expire + dataSourceConfig.addDataSourceProperty("cachePrepStmts", true); + dataSourceConfig.addDataSourceProperty("prepStmtCacheSize", 250); + dataSourceConfig.addDataSourceProperty("prepStmtCacheSqlLimit", 2048); + dataSourceConfig.addDataSourceProperty("useServerPrepStmts", true); + dataSourceConfig.addDataSourceProperty("useLocalSessionState", true); + dataSourceConfig.addDataSourceProperty("useLocalTransactionState", true); + dataSourceConfig.addDataSourceProperty("rewriteBatchedStatements", true); + dataSourceConfig.addDataSourceProperty("cacheServerConfiguration", true); + dataSourceConfig.addDataSourceProperty("cacheResultSetMetadata", true); + dataSourceConfig.addDataSourceProperty("maintainTimeStats", true); + dataSourceConfig.addDataSourceProperty("logger", "com.mysql.cj.log.Slf4JLogger"); + dataSourceConfig.addDataSourceProperty("autoCommit", true); + dataSourceConfig.addDataSourceProperty("minimumIdle", 10); + dataSourceConfig.addDataSourceProperty("validationTimeout", 500); // 500 milliseconds wait before try to acquire connection again + dataSourceConfig.addDataSourceProperty("connectionTimeout", 0); // 0 = wait indefinitely for new connection if pool is exhausted + return new HikariDataSource(dataSourceConfig); + } + + @Bean + public NamedParameterJdbcOperations template(DataSource dataSource) { + return new NamedParameterJdbcTemplate(dataSource); + } + + @Bean + public NamingStrategy namingStrategy() { + return new AnnotationNamingStrategy(); + } + + @Bean + public ApplicationListener afterSaveEventApplicationListener() { + return event -> { + extractModel(event).ifPresent(Entity::onSave); + }; + } + + private Optional extractModel(WithEntity event) { + Object entity = event.getEntity(); + if (entity instanceof Entity) { + return Optional.of((Entity) entity); + } + return Optional.empty(); + } + + @Bean + public ApplicationListener afterLoadEventApplicationListener() { + return event -> { + extractModel(event).ifPresent(Entity::onLoad); + }; + } +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/GameserverRepository.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/GameserverRepository.java new file mode 100644 index 00000000..7414660b --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/GameserverRepository.java @@ -0,0 +1,7 @@ +package com.l2jbr.commons.database; + +import com.l2jbr.commons.database.model.GameServers; +import org.springframework.data.repository.CrudRepository; + +public interface GameserverRepository extends CrudRepository { +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/L2DatabaseFactory.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/L2DatabaseFactory.java new file mode 100644 index 00000000..412536b8 --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/L2DatabaseFactory.java @@ -0,0 +1,116 @@ +/* + * 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 2, 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jbr.commons.database; + +import com.zaxxer.hikari.HikariDataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +import java.sql.Connection; +import java.sql.SQLException; + + +public class L2DatabaseFactory { + private static Logger _log = LoggerFactory.getLogger(L2DatabaseFactory.class); + + private static L2DatabaseFactory _instance; + private final HikariDataSource _dataSource; + private final ApplicationContext context; + + public L2DatabaseFactory() throws SQLException { + context = new AnnotationConfigApplicationContext(DatabaseContextConfiguration.class); + _dataSource = context.getBean(HikariDataSource.class); + + try { + _dataSource.getConnection().close(); + } catch (SQLException e) { + _log.error(e.getMessage(), e); + throw e; + } + } + + public static String prepQuerySelect(String[] fields, String tableName, String whereClause, boolean returnOnlyTopRecord) { + String msSqlTop1 = ""; + String mySqlTop1 = ""; + if (returnOnlyTopRecord) { + mySqlTop1 = " Limit 1 "; + } + String query = "SELECT " + msSqlTop1 + safetyString(fields) + " FROM " + tableName + " WHERE " + whereClause + mySqlTop1; + return query; + } + + public void shutdown() { + try { + _dataSource.close(); + } catch (Exception e) { + _log.info(e.getMessage(), e); + } + + } + + public final static String safetyString(String[] whatToCheck) { + // NOTE: Use brace as a safty percaution just incase name is a reserved word + String braceLeft = "`"; + String braceRight = "`"; + + String result = ""; + for (String word : whatToCheck) { + if (result != "") result += ", "; + result += braceLeft + word + braceRight; + } + return result; + } + + // TODO remove access from external modules + public static L2DatabaseFactory getInstance() throws SQLException { + if (_instance == null) { + _instance = new L2DatabaseFactory(); + } + return _instance; + } + + public Connection getConnection() //throws SQLException + { + Connection con = null; + + while (con == null) { + try { + con = _dataSource.getConnection(); + } catch (SQLException e) { + _log.warn("L2DatabaseFactory: getConnection() failed, trying again", e); + } + } + return con; + } + + public static void close(Connection conn) { + } + + public T getRepository(Class repositoryClass) { + try { + return context.getBean(repositoryClass); + }catch (Exception e) { + _log.error("could.not.retrieve.repository", e); + throw e; + } + } + +} \ No newline at end of file diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/annotation/Column.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/annotation/Column.java new file mode 100644 index 00000000..f7e386c6 --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/annotation/Column.java @@ -0,0 +1,13 @@ +package com.l2jbr.commons.database.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Column { + + String value() default ""; +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/annotation/Table.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/annotation/Table.java new file mode 100644 index 00000000..eaf8d0e2 --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/annotation/Table.java @@ -0,0 +1,14 @@ +package com.l2jbr.commons.database.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Table { + + String value(); +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/Account.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/Account.java new file mode 100644 index 00000000..776133a6 --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/Account.java @@ -0,0 +1,76 @@ +package com.l2jbr.commons.database.model; + +import com.l2jbr.commons.Config; +import com.l2jbr.commons.database.annotation.Column; +import com.l2jbr.commons.database.annotation.Table; +import org.springframework.data.annotation.Id; + +@Table("accounts") +public class Account extends Entity { + + @Id + private String login; + private String password; + private Long lastActive; + @Column("access_level") + private Integer accessLevel; + private Integer lastServer; + private String lastIP; + private Integer newbieCharacterId; + + public Account() { } + + public Account(String login, String password, long lastActive, String lastIP) { + this.login = login; + this.password = password; + this.lastActive = lastActive; + this.lastIP = lastIP; + this.accessLevel = 0; + this.lastServer = 1; + } + + @Override + public String getId() { + return login; + } + + public int getAccessLevel() { + return accessLevel; + } + + public String getPassword() { + return password; + } + + public int getLastServer() { + return lastServer; + } + + public boolean isBanned() { + return accessLevel < 0; + } + + public void setLastActive(long lastActive) { + this.lastActive = lastActive; + } + + public void setLastIP(String lastIP) { + this.lastIP = lastIP; + } + + public void setAccessLevel(int accessLevel) { + this.accessLevel = accessLevel; + } + + public boolean isGM() { + return accessLevel >= Config.GM_MIN; + } + + public int getNewbieCharacterId() { + return newbieCharacterId; + } + + public void setNewbieCharacterId(int newbieCharacterId) { + this.newbieCharacterId = newbieCharacterId; + } +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/Entity.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/Entity.java new file mode 100644 index 00000000..85b63d3e --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/Entity.java @@ -0,0 +1,29 @@ +package com.l2jbr.commons.database.model; + +import org.springframework.data.annotation.Transient; +import org.springframework.data.domain.Persistable; + +public abstract class Entity implements Persistable { + + @Transient + protected boolean isNew = true; + + @Override + public boolean isNew() { + return isNew; + } + + public void onSave() { + isNew = false; + } + + public void onLoad() { + isNew = false; + } + + public boolean isPersisted() { + return !isNew; + } + + public void setPersisted() { isNew = false;} +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/GameServers.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/GameServers.java new file mode 100644 index 00000000..60ff7067 --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/database/model/GameServers.java @@ -0,0 +1,36 @@ +package com.l2jbr.commons.database.model; + +import com.l2jbr.commons.database.annotation.Column; +import com.l2jbr.commons.database.annotation.Table; +import org.springframework.data.annotation.Id; + +@Table("gameservers") +public class GameServers extends Entity { + + @Id + @Column("server_id") + private Integer serverId; + private String hexid; + private String host; + + public GameServers() { } + + public GameServers(int id, String hexId, String host) { + this.serverId = id; + this.hexid = hexId; + this.host = host; + } + + @Override + public Integer getId() { + return serverId; + } + + public String getHexid() { + return hexid; + } + + public String getHost() { + return host; + } +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/lib/SqlUtils.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/lib/SqlUtils.java deleted file mode 100644 index 2a0361b1..00000000 --- a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/lib/SqlUtils.java +++ /dev/null @@ -1,226 +0,0 @@ -/* 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 2, 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * http://www.gnu.org/copyleft/gpl.html - */ -package com.l2jbr.commons.lib; - -import com.l2jbr.commons.L2DatabaseFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; - - -public class SqlUtils -{ - private static Logger _log = LoggerFactory.getLogger(SqlUtils.class.getName()); - - // ========================================================= - // Data Field - private static SqlUtils _instance; - - // ========================================================= - // Property - Public - public static SqlUtils getInstance() - { - if (_instance == null) - { - _instance = new SqlUtils(); - } - return _instance; - } - - // ========================================================= - // Method - Public - public static Integer getIntValue(String resultField, String tableName, String whereClause) - { - String query = ""; - Integer res = null; - - PreparedStatement statement = null; - ResultSet rset = null; - - try - { - query = L2DatabaseFactory.getInstance().prepQuerySelect(new String[] - { - resultField - }, tableName, whereClause, true); - - statement = L2DatabaseFactory.getInstance().getConnection().prepareStatement(query); - rset = statement.executeQuery(); - - if (rset.next()) - { - res = rset.getInt(1); - } - } - catch (Exception e) - { - _log.warn("Error in query '" + query + "':" + e); - e.printStackTrace(); - } - finally - { - try - { - rset.close(); - } - catch (Exception e) - { - } - try - { - statement.close(); - } - catch (Exception e) - { - } - } - - return res; - } - - public static Integer[] getIntArray(String resultField, String tableName, String whereClause) - { - String query = ""; - Integer[] res = null; - - PreparedStatement statement = null; - ResultSet rset = null; - - try - { - query = L2DatabaseFactory.getInstance().prepQuerySelect(new String[] - { - resultField - }, tableName, whereClause, false); - statement = L2DatabaseFactory.getInstance().getConnection().prepareStatement(query); - rset = statement.executeQuery(); - - int rows = 0; - - while (rset.next()) - { - rows++; - } - - if (rows == 0) - { - return new Integer[0]; - } - - res = new Integer[rows - 1]; - - rset.first(); - - int row = 0; - while (rset.next()) - { - res[row] = rset.getInt(1); - } - } - catch (Exception e) - { - _log.warn("mSGI: Error in query '" + query + "':" + e); - e.printStackTrace(); - } - finally - { - try - { - rset.close(); - } - catch (Exception e) - { - } - try - { - statement.close(); - } - catch (Exception e) - { - } - } - - return res; - } - - public static Integer[][] get2DIntArray(String[] resultFields, String usedTables, String whereClause) - { - long start = System.currentTimeMillis(); - - String query = ""; - - PreparedStatement statement = null; - ResultSet rset = null; - - Integer res[][] = null; - - try - { - query = L2DatabaseFactory.getInstance().prepQuerySelect(resultFields, usedTables, whereClause, false); - statement = L2DatabaseFactory.getInstance().getConnection().prepareStatement(query); - rset = statement.executeQuery(); - - int rows = 0; - while (rset.next()) - { - rows++; - } - - res = new Integer[rows - 1][resultFields.length]; - - rset.first(); - - int row = 0; - while (rset.next()) - { - for (int i = 0; i < resultFields.length; i++) - { - res[row][i] = rset.getInt(i + 1); - } - row++; - } - } - catch (Exception e) - { - _log.warn("Error in query '" + query + "':" + e); - e.printStackTrace(); - } - finally - { - try - { - rset.close(); - } - catch (Exception e) - { - } - try - { - statement.close(); - } - catch (Exception e) - { - } - } - - _log.debug("Get all rows in query '" + query + "' in " + (System.currentTimeMillis() - start) + "ms"); - return res; - } -} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/util/FilterUtils.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/util/FilterUtils.java new file mode 100644 index 00000000..8f00715b --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/util/FilterUtils.java @@ -0,0 +1,13 @@ +package com.l2jbr.commons.util; + +import java.io.File; + +public class FilterUtils { + + public static boolean htmlFilter(File file) { + if (!file.isDirectory()) { + return (file.getName().endsWith(".htm") || file.getName().endsWith(".html")); + } + return true; + } +} diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/util/Util.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/util/Util.java index cb880ecd..eabe2376 100644 --- a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/util/Util.java +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/util/Util.java @@ -14,15 +14,25 @@ */ package com.l2jbr.commons.util; - -/** - * This class ... - * - * @version $Revision: 1.2 $ $Date: 2004/06/27 08:12:59 $ - */ +import java.lang.reflect.Field; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.time.temporal.TemporalAccessor; +import java.util.Collection; +import java.util.Locale; +import java.util.Optional; + +import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; public class Util { + private static final DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT ) + .withLocale( Locale.getDefault() ) + .withZone( ZoneId.systemDefault() ); + + public static boolean isInternalIP(String ipAddress) { return (ipAddress.startsWith("192.168.") || ipAddress.startsWith("10.") || // ipAddress.startsWith("172.16.") || @@ -31,6 +41,10 @@ public static boolean isInternalIP(String ipAddress) { ipAddress.startsWith("127.0.0.1")); } + public static String printData(byte[] raw) { + return printData(raw, raw.length); + } + public static String printData(byte[] data, int len) { StringBuilder result = new StringBuilder(); @@ -76,29 +90,59 @@ public static String printData(byte[] data, int len) { result.append('.'); } } - result.append("\n"); } - return result.toString(); } public static String fillHex(int data, int digits) { - String number = Integer.toHexString(data); + StringBuilder builder = new StringBuilder(Integer.toHexString(data)); + + for (int i = builder.length(); i < digits; i++) { + builder.insert(0, "0"); + } + return builder.toString(); + } - for (int i = number.length(); i < digits; i++) { - number = "0" + number; + public static Optional getField(String fieldName, Class clazz) { + Class searchClass = clazz; + Field f = null; + while(nonNull(searchClass)) { + try { + f = searchClass.getDeclaredField(fieldName); + break; + } catch (NoSuchFieldException e) { + searchClass = searchClass.getSuperclass(); + } } + return Optional.of(f); + } - return number; + public static boolean isNullOrEmpty(String value) { + return isNull(value) || value.isEmpty(); } - /** - * @param raw - * @return - */ - public static String printData(byte[] raw) { - return printData(raw, raw.length); + public static boolean isNullOrEmpty(Collection collection) { + return isNull(collection) || collection.isEmpty(); + } + + public static String capitalize(String text) { + if(isNullOrEmpty(text)){ + return ""; + } + String[] words = text.split(" "); + StringBuilder builder = new StringBuilder(); + for(String word : words) { + char[] caracteres = word.toLowerCase().toCharArray(); + caracteres[0] = Character.toUpperCase(caracteres[0]); + builder.append(caracteres); + builder.append(" "); + } + return builder.substring(0, builder.length()-1); + } + + public static String formatDateTime(TemporalAccessor temporal) { + return formatter.format(temporal); } } diff --git a/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/xml/XMLReader.java b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/xml/XMLReader.java new file mode 100644 index 00000000..f9a3b2a3 --- /dev/null +++ b/Commons/src/main/com.l2jbr.commons/com/l2jbr/commons/xml/XMLReader.java @@ -0,0 +1,90 @@ +package com.l2jbr.commons.xml; + +import com.l2jbr.commons.Config; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +import javax.xml.XMLConstants; +import javax.xml.bind.*; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import java.io.File; + +public abstract class XMLReader implements ValidationEventHandler { + + protected static final Logger logger = LoggerFactory.getLogger(XMLReader.class); + private Schema schema; + private String processingFile; + private Unmarshaller unmarshaller; + + public XMLReader() throws JAXBException { + loadSchema(); + createUnmarshaller(); + } + + private void loadSchema() { + try { + SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + schema = factory.newSchema(new File(getSchemaFilePath())); + } catch (SAXException e) { + logger.warn(e.getLocalizedMessage(), e); + } + } + + private void createUnmarshaller() throws JAXBException { + JAXBContext context = getJAXBContext(); + unmarshaller = context.createUnmarshaller(); + unmarshaller.setSchema(schema); + unmarshaller.setEventHandler(this); + } + + public void readAll() { + for (String directory : getXmlFileDirectories()) { + read(getDirectoryFiles(directory)); + } + } + + private File[] getDirectoryFiles(String directory) { + File fileDir = new File(Config.DATAPACK_ROOT, directory); + return fileDir.listFiles((dir, name) -> name.endsWith(".xml")); + } + + private void read(File... files) { + if(files == null || files.length < 1) { + return; + } + + for (File file : files) { + try { + readFile(file); + } catch (JAXBException e) { + logger.error(e.getLocalizedMessage(), e); + } + } + } + + private void readFile(File file) throws JAXBException{ + T entity = processFile(file); + processEntity(entity); + } + + @SuppressWarnings("unchecked") + private T processFile(File file) throws JAXBException { + processingFile = file.getAbsolutePath(); + return (T) unmarshaller.unmarshal(file); + } + + @Override + public boolean handleEvent(ValidationEvent event) { + ValidationEventLocator locator = event.getLocator(); + logger.error("reading {} on line {} column {} : {} ", processingFile, locator.getLineNumber(), locator.getColumnNumber(), event.getMessage()); + return true; + } + + protected abstract void processEntity(T entity); + protected abstract JAXBContext getJAXBContext() throws JAXBException; + protected abstract String getSchemaFilePath(); + protected abstract String[] getXmlFileDirectories(); + +} diff --git a/Commons/src/main/com.l2jbr.commons/module-info.java b/Commons/src/main/com.l2jbr.commons/module-info.java index 0ea3d9c8..fd5c3795 100644 --- a/Commons/src/main/com.l2jbr.commons/module-info.java +++ b/Commons/src/main/com.l2jbr.commons/module-info.java @@ -1,9 +1,14 @@ module com.l2jbr.commons { requires java.sql; - requires c3p0; requires java.naming; requires java.desktop; requires org.slf4j; + requires com.zaxxer.hikari; + requires spring.data.commons; + requires spring.data.jdbc; + requires spring.context; + requires spring.jdbc; + requires java.xml.bind; exports com.l2jbr.commons.util; exports com.l2jbr.commons.xml; @@ -11,5 +16,8 @@ exports com.l2jbr.commons.status; exports com.l2jbr.commons.lib; exports com.l2jbr.commons; + exports com.l2jbr.commons.database; + exports com.l2jbr.commons.database.model; + exports com.l2jbr.commons.database.annotation; } \ No newline at end of file diff --git a/Datapack/build.gradle b/Datapack/build.gradle index 38f13605..8c8a88c4 100644 --- a/Datapack/build.gradle +++ b/Datapack/build.gradle @@ -4,7 +4,7 @@ plugins { id "eclipse" } -version '1.3.0' +version '1.4' task zip(type: Zip) { from('data') { diff --git a/Datapack/data/door.csv b/Datapack/data/door.csv index 97b168fd..067efdd1 100644 --- a/Datapack/data/door.csv +++ b/Datapack/data/door.csv @@ -53,12 +53,12 @@ devastated_castle_inner_003;25170005;178302;-18573;-2287;0;0;0;0;0;0;79125;644;5 devastated_castle_inner_004;25170006;178302;-18648;-2287;0;0;0;0;0;0;79125;644;518;False # Devils Isle -pirate_isle_001;21240001;42001;208378;-3666;0;0;0;0;0;0;187500;100000;10000;True -pirate_isle_002;21240002;43745;212594;-3623;0;0;0;0;0;0;187500;100000;10000;True +pirate_isle_001;21240001;42001;208378;-3666;0;0;0;0;0;0;187500;32767;32767;True +pirate_isle_002;21240002;43745;212594;-3623;0;0;0;0;0;0;187500;32767;32767;True pirate_isle_003;21240003;42167;213285;-3643;0;0;0;0;0;0;187500;476;383;True pirate_isle_004;21240004;51111;206106;-3912;0;0;0;0;0;0;187500;476;383;True pirate_isle_005;21240005;52910;206720;-3692;0;0;0;0;0;0;187500;476;383;True -pirate_isle_006;21240006;52423;219103;-3209;0;0;0;0;0;0;187500;1000000;383;True +pirate_isle_006;21240006;52423;219103;-3209;0;0;0;0;0;0;187500;32767;383;True # Garden of Eva - Water Walls and Secret Walls goe_001;22250001;86226;247063;-8584;0;0;0;0;0;0;187500;476;383;False diff --git a/Datapack/data/html/admin/help/gmcommands2.htm b/Datapack/data/html/admin/help/gmcommands2.htm index ca3d03d7..ab401587 100644 --- a/Datapack/data/html/admin/help/gmcommands2.htm +++ b/Datapack/data/html/admin/help/gmcommands2.htm @@ -40,9 +40,6 @@ //clear_siege_list
//sgspawn <npc_id> <group>
//siege - Castle names: gludio, giran, dion, oren
-//box_access - with box targetted, shows access list
-//box_access char1 char2 - To add players to box
Usage: //box_access kadar LadyPain
-//box_access no char1 - Removes player from box access
Usage: //box_access LadyPain no kadar
//fight_calculator
//fight_calculator_show
//fcs
diff --git a/Datapack/data/html/guard/30348-1.htm b/Datapack/data/html/guard/30348-1.htm index 761d4360..8b307791 100644 --- a/Datapack/data/html/guard/30348-1.htm +++ b/Datapack/data/html/guard/30348-1.htm @@ -1,2 +1,5 @@ -Sentry Nelsya:
In a few days the mass of darkness dedicated to Shilen and Gran Kain will be held. Shilen's Hunt will be held for ten days before the mass. The purpose of his ceremony is to hunt wild animals in the name of the goddess and offer them as a sarcrifice at the sanctuary. Of course, the act of offering a sarcrifice is only symbolic - in thepast, the hunt's purpose was also to acquire supplies for the winter during our long period of hiding in the darkness.
The hunt has already begun! The youth of the village are in the woods and on the hunt, armed with swords and bows. The fervor is impressive - the Humans who witnessed it called it the "wild hunt". I think you should also hurry and participate in the hunt to honor the mother of the abyss!
Say you will participate +Sentry Nelsya:
+In a few days the mass of darkness dedicated to Shilen and Gran Kain will be held. Shilen's Hunt will be held for ten days before the mass. The purpose of his ceremony is to hunt wild animals in the name of the goddess and offer them as a sarcrifice at the sanctuary. Of course, the act of offering a sarcrifice is only symbolic - in thepast, the hunt's purpose was also to acquire supplies for the winter during our long period of hiding in the darkness.
+The hunt has already begun! The youth of the village are in the woods and on the hunt, armed with swords and bows. The fervor is impressive - the Humans who witnessed it called it the "wild hunt". I think you should also hurry and participate in the hunt to honor the mother of the abyss!
+Say you will participate \ No newline at end of file diff --git a/Datapack/data/html/guard/30543-3.htm b/Datapack/data/html/guard/30543-3.htm index 87ba2c8f..38fd49b1 100644 --- a/Datapack/data/html/guard/30543-3.htm +++ b/Datapack/data/html/guard/30543-3.htm @@ -1 +1,6 @@ -Defender Ethan:
So how'd you like it? I'll read it again for you.
Jangle jangle, the sound of rolling adena.
Clink clink, the sound of gathering treasure.
Boom boom, the sound of collecting mithril. \ No newline at end of file +Defender Ethan:
+So how'd you like it? I'll read it again for you.
+Jangle jangle, the sound of rolling adena.
+Clink clink, the sound of gathering treasure.
+Boom boom, the sound of collecting mithril. + \ No newline at end of file diff --git a/Datapack/data/html/trainer/30715-2.htm b/Datapack/data/html/trainer/30715-2.htm index e7b5139c..04bcdc96 100644 --- a/Datapack/data/html/trainer/30715-2.htm +++ b/Datapack/data/html/trainer/30715-2.htm @@ -1 +1,24 @@ - Skill Enchantment is a way of strengthening certain skills that have reached their natural limit. Any player who has completed their third occupation change and reached level 76 or above can enchant a skill with help of a skill trainer.
When enchanting a skill for the first time, pay particular attention to the methods of reinforcement. If there are two or more, the method will be determined during the first enchantment session. When enchanting a skill, carefully note the descriptions of each effect before choosing.
Also pay particular attention to the success rate. All skill enchantments have a specified success rate. If enchantment fails, exp. and SP will be consumed and your skill will return to +0 status, so please check the success rate carefully before enchanting. The success rate improves as the player's level increases.
You may be required to find a specific NPC to enchant the skill. There are currently 20 NPCs in the game that allow Skill Enchantment. Among these, you must find the NPC that fits both your race and your occupation. If your race and occupation do not match the NPCS, the skill Enchantment will not be allowed.
Sedrick's Training Hall in the Town of Aden: Master Aiken, Master Sinden
Einhasad's Temple in the Town of Oren: Priest Valdin, Priest Egnos
Oren's Ivory Tower: Magister Marina, Magister Joan, Magister Ladd
Hardin's Academy: Master Galadril, Magister Anastia, Dark Knight Mordred, Lich King Icarus
fighters Guild in Hunters Village: Master Aren Athebalt, Master Stedmiel
Rune Township Fighters Guild: Prefect Tazki
Rune Township Sage's Library: Seer Mekara
Rune Township Blacksmith's Shop: Blacksmith Vincenz
Rune Township Warehouse: Warehouse Keeper Hugin, Warehouse Keeper Durin, Warehouse Keeper Lunin, Warehouse Freightman Daisy. \ No newline at end of file + +Skill Enchantment is a way of strengthening certain skills that have reached their natural limit. Any player who has completed their third occupation change and reached level 76 or above can enchant a skill with help of a skill trainer.
+When enchanting a skill for the first time, pay particular attention to the methods of reinforcement. If there are two or more, the method will be determined during the first enchantment session. When enchanting a skill, carefully note the descriptions of each effect before choosing.
+Also pay particular attention to the success rate. All skill enchantments have a specified success rate. If enchantment fails, exp. and SP will be consumed and your skill will return to +0 status, so please check the success rate carefully before enchanting. The success rate improves as the player's level increases.
+You may be required to find a specific NPC to enchant the skill. There are currently 20 NPCs in the game that allow Skill Enchantment. Among these, you must find the NPC that fits both your race and your occupation. If your race and occupation do not match the NPCS, the skill Enchantment will not be allowed.
+Sedrick's Training Hall in the Town of Aden: +Master Aiken, Master Sinden
+Einhasad's Temple in the Town of Oren: +Priest Valdin, Priest Egnos
+Oren's Ivory Tower: +Magister Marina, Magister Joan, Magister Ladd
+Hardin's Academy: +Master Galadril, Magister Anastia, Dark Knight Mordred, Lich King Icarus
+fighters Guild in Hunters Village: +Master Aren Athebalt, Master Stedmiel
+Rune Township Fighters Guild: +Prefect Tazki
+Rune Township Sage's Library: +Seer Mekara
+Rune Township Blacksmith's Shop: +Blacksmith Vincenz
+Rune Township Warehouse: +Warehouse Keeper Hugin, Warehouse Keeper Durin, Warehouse Keeper Lunin, Warehouse Freightman Daisy. + \ No newline at end of file diff --git a/Datapack/data/html/trainer/30718-2.htm b/Datapack/data/html/trainer/30718-2.htm index 791805ad..0cb941fb 100644 --- a/Datapack/data/html/trainer/30718-2.htm +++ b/Datapack/data/html/trainer/30718-2.htm @@ -1 +1,24 @@ - Skill Enchantment is a way of strengthening certain skills that have reached their natural limit. Any player who has completed their third occupation change and reached level 76 or above can enchant a skill with help of a skill trainer.
When enchanting a skill for the first time, pay particular attention to the methods of reinforcement. If there are two or more, the method will be determined during the first enchantment session. When enchanting a skill, carefully note the descriptions of each effect before choosing.
Also pay particular attention to the success rate. All skill enchantments have a specified success rate. If enchantment fails, exp. and SP will be consumed and your skill will return to +0 status, so please check the success rate carefully before enchanting. The success rate improves as the player's level increases.
You may be required to find a specific NPC to enchant the skill. There are currently 20 NPCs in the game that allow Skill Enchantment. Among these, you must find the NPC that fits both your race and your occupation. If your race and occupation do not match the NPCS, the skill Enchantment will not be allowed.
Sedrick's Training Hall in the Town of Aden: Master Aiken, Master Sinden
Einhasad's Temple in the Town of Oren: Priest Valdin, Priest Egnos
Oren's Ivory Tower: Magister Marina, Magister Joan, Magister Ladd
Hardin's Academy: Master Galadril, Magister Anastia, Dark Knight Mordred, Lich King Icarus
fighters Guild in Hunters Village: Master Aren Athebalt, Master Stedmiel
Rune Township Fighters Guild: Prefect Tazki
Rune Township Sage's Library: Seer Mekara
Rune Township Blacksmith's Shop: Blacksmith Vincenz
Rune Township Warehouse: Warehouse Keeper Hugin, Warehouse Keeper Durin, Warehouse Keeper Lunin, Warehouse Freightman Daisy. \ No newline at end of file + +Skill Enchantment is a way of strengthening certain skills that have reached their natural limit. Any player who has completed their third occupation change and reached level 76 or above can enchant a skill with help of a skill trainer.
+When enchanting a skill for the first time, pay particular attention to the methods of reinforcement. If there are two or more, the method will be determined during the first enchantment session. When enchanting a skill, carefully note the descriptions of each effect before choosing.
+Also pay particular attention to the success rate. All skill enchantments have a specified success rate. If enchantment fails, exp. and SP will be consumed and your skill will return to +0 status, so please check the success rate carefully before enchanting. The success rate improves as the player's level increases.
+You may be required to find a specific NPC to enchant the skill. There are currently 20 NPCs in the game that allow Skill Enchantment. Among these, you must find the NPC that fits both your race and your occupation. If your race and occupation do not match the NPCS, the skill Enchantment will not be allowed.
+Sedrick's Training Hall in the Town of Aden: +Master Aiken, Master Sinden
+Einhasad's Temple in the Town of Oren: +Priest Valdin, Priest Egnos
+Oren's Ivory Tower: +Magister Marina, Magister Joan, Magister Ladd
+Hardin's Academy: +Master Galadril, Magister Anastia, Dark Knight Mordred, Lich King Icarus
+fighters Guild in Hunters Village: +Master Aren Athebalt, Master Stedmiel
+Rune Township Fighters Guild: +Prefect Tazki
+Rune Township Sage's Library: +Seer Mekara
+Rune Township Blacksmith's Shop: +Blacksmith Vincenz
+Rune Township Warehouse: +Warehouse Keeper Hugin, Warehouse Keeper Durin, Warehouse Keeper Lunin, Warehouse Freightman Daisy. + \ No newline at end of file diff --git a/Datapack/data/html/villagemaster/32095.htm b/Datapack/data/html/villagemaster/32095.htm index 7a7d3228..25500704 100644 --- a/Datapack/data/html/villagemaster/32095.htm +++ b/Datapack/data/html/villagemaster/32095.htm @@ -1,7 +1,7 @@ -High Priest Marie:
-Greetings, my child. I am but a mere vessel for the spirit and will of Einhasad!
-Tell me about the second class transfer.
-Clan
-Alliance
-Quest - \ No newline at end of file +High Priest Marie:
+Greetings, my child. I am but a mere vessel for the spirit and will of Einhasad!
+Tell me about the second class transfer.
+Clan
+Alliance
+Quest + diff --git a/Datapack/data/html/warehouse/30521.htm b/Datapack/data/html/warehouse/30521.htm index e9d1b667..8e928712 100644 --- a/Datapack/data/html/warehouse/30521.htm +++ b/Datapack/data/html/warehouse/30521.htm @@ -1 +1,7 @@ -Warehouse Freightman Murdoc:
Welcome to the Iron Gate Guild. I'm Murdoc, a member of the guild that prides itself on having the longest history and being the largest among the 6 guilds! We have wharehouses in all the cities in this land! Hahaha!
The Iron Gate can deliver and receive cargo from anywhere!
"I want to use your freight service."
"I want to learn a skill."

Quest
\ No newline at end of file +Warehouse Freightman Murdoc:
+Welcome to the Iron Gate Guild. I'm Murdoc, a member of the guild that prides itself on having the longest history and being the largest among the 6 guilds! We have wharehouses in all the cities in this land! Hahaha!
+The Iron Gate can deliver and receive cargo from anywhere!
+
"I want to use your freight service."
+"I want to learn a skill."

+Quest
+ \ No newline at end of file diff --git a/Datapack/data/jscript/ai/group_template/chests.py b/Datapack/data/jscript/ai/group_template/chests.py index c03638e4..9bb6da62 100644 --- a/Datapack/data/jscript/ai/group_template/chests.py +++ b/Datapack/data/jscript/ai/group_template/chests.py @@ -3,7 +3,7 @@ # Written by Fulminus # # # # # # # # # # # import sys -from com.l2jbr.gameserver.ai import CtrlIntention +from com.l2jbr.gameserver.ai import Intention from com.l2jbr.gameserver.model.quest.jython import QuestJython as JQuest from com.l2jbr.commons.util import Rnd; @@ -74,7 +74,7 @@ def onSkillUse (self,npc,player,skill): attacker = player.getPet() npc.setRunning() npc.addDamageHate(attacker,0,999) - npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker) + npc.getAI().setIntention(Intention.AI_INTENTION_ATTACK, attacker) return def onAttack(self,npc,player,damage,isPet) : @@ -94,7 +94,7 @@ def onAttack(self,npc,player,damage,isPet) : attacker = player.getPet() npc.setRunning() npc.addDamageHate(attacker,0,(damage*100)/(npc.getLevel()+7)) - npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, attacker) + npc.getAI().setIntention(Intention.AI_INTENTION_ATTACK, attacker) return # now call the constructor (starts up the ai) diff --git a/Datapack/data/jscript/ai/group_template/feedable_beasts.py b/Datapack/data/jscript/ai/group_template/feedable_beasts.py index 80ef3f99..dc68aa66 100644 --- a/Datapack/data/jscript/ai/group_template/feedable_beasts.py +++ b/Datapack/data/jscript/ai/group_template/feedable_beasts.py @@ -2,7 +2,7 @@ # Written by Fulminus # # # # # # # # # # # import sys -from com.l2jbr.gameserver.ai import CtrlIntention +from com.l2jbr.gameserver.ai import Intention from com.l2jbr.gameserver.idfactory import IdFactory from com.l2jbr.gameserver.datatables import NpcTable from com.l2jbr.gameserver.model.actor.instance import L2TamedBeastInstance @@ -112,7 +112,7 @@ def onAdvEvent(self,event,npc,player) : self.feedInfo[nextNpc.getObjectId()] = player.getObjectId() nextNpc.setRunning() nextNpc.addDamageHate(player,0,99999) - nextNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player) + nextNpc.getAI().setIntention(Intention.AI_INTENTION_ATTACK, player) def spawnNext(self, npc, growthLevel,player,food) : npcId = npc.getNpcId() @@ -197,7 +197,7 @@ def spawnNext(self, npc, growthLevel,player,food) : self.feedInfo[nextNpc.getObjectId()] = player.getObjectId() nextNpc.setRunning() nextNpc.addDamageHate(player,0,99999) - nextNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, player) + nextNpc.getAI().setIntention(Intention.AI_INTENTION_ATTACK, player) def onSkillUse (self,npc,player,skill): # gather some values on local variables diff --git a/Datapack/data/jscript/ai/group_template/polymorphing_angel.py b/Datapack/data/jscript/ai/group_template/polymorphing_angel.py index 2d787509..364d30fe 100644 --- a/Datapack/data/jscript/ai/group_template/polymorphing_angel.py +++ b/Datapack/data/jscript/ai/group_template/polymorphing_angel.py @@ -1,7 +1,7 @@ import sys from com.l2jbr.gameserver.model.quest.jython import QuestJython as JQuest from com.l2jbr.gameserver.serverpackets import MagicSkillUser -from com.l2jbr.gameserver.ai import CtrlIntention +from com.l2jbr.gameserver.ai import Intention # Angel spawns...when one of the angels in the keys dies, the other angel will spawn. @@ -29,7 +29,7 @@ def onKill (self,npc,player,isPet): killer = player.getPet() newNpc.setRunning() newNpc.addDamageHate(killer,0,999) - newNpc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, killer) + newNpc.getAI().setIntention(Intention.AI_INTENTION_ATTACK, killer) return # now call the constructor (starts up the ai) diff --git a/Datapack/data/jscript/ai/individual/baium.py b/Datapack/data/jscript/ai/individual/baium.py index c199ce65..ed314b87 100644 --- a/Datapack/data/jscript/ai/individual/baium.py +++ b/Datapack/data/jscript/ai/individual/baium.py @@ -8,7 +8,7 @@ from com.l2jbr.gameserver.serverpackets import SocialAction from com.l2jbr.gameserver.serverpackets import Earthquake from com.l2jbr.gameserver.serverpackets import PlaySound -from com.l2jbr.gameserver.ai import CtrlIntention +from com.l2jbr.gameserver.ai import Intention from com.l2jbr.commons.util import Rnd from java.lang import System diff --git a/Datapack/data/jscript/quests/104_SpiritOfMirrors/__init__.py b/Datapack/data/jscript/quests/104_SpiritOfMirrors/__init__.py index 6a4a17a7..11472e8c 100644 --- a/Datapack/data/jscript/quests/104_SpiritOfMirrors/__init__.py +++ b/Datapack/data/jscript/quests/104_SpiritOfMirrors/__init__.py @@ -103,7 +103,7 @@ def onKill(self,npc,player,isPet): if not st: return if st.getState() != STARTED : return npcId = npc.getNpcId() - if st.getInt("cond") >= 1 and st.getItemEquipped(7) == GALLINS_OAK_WAND_ID and not st.getQuestItemsCount(DROPLIST[npcId]) : # (7) means weapon slot + if st.getInt("cond") >= 1 and st.getItemEquipped(7) == GALLINS_OAK_WAND_ID and not st.getQuestItemsCount(DROPLIST[npcId]) : # (7) means weapon bodyPart st.takeItems(GALLINS_OAK_WAND_ID,1) st.giveItems(DROPLIST[npcId],1) if HaveAllQuestItems(st) : diff --git a/Datapack/data/jscript/quests/21_HiddenTruth/__init__.py b/Datapack/data/jscript/quests/21_HiddenTruth/__init__.py index c496d965..71a2cd29 100644 --- a/Datapack/data/jscript/quests/21_HiddenTruth/__init__.py +++ b/Datapack/data/jscript/quests/21_HiddenTruth/__init__.py @@ -2,11 +2,11 @@ # this script is part of the Official L2J Datapack Project. # Visit http://forum.l2jdp.com for more details. import sys -from com.l2jbr.gameserver.ai import CtrlIntention +from com.l2jbr.gameserver.ai import Intention from com.l2jbr.gameserver.model.quest import State from com.l2jbr.gameserver.model.quest import QuestState from com.l2jbr.gameserver.model.quest.jython import QuestJython as JQuest -from com.l2jbr.gameserver.model import L2CharPosition +from com.l2jbr.gameserver.model import L2Position qn = "21_HiddenTruth" @@ -77,19 +77,19 @@ def onAdvEvent (self,event,npc,player): loc = int(event) x,y,z,heading=ROUTES[loc] if event == "1" : - npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, L2CharPosition(x,y,z,heading)) + npc.getAI().setIntention(Intention.AI_INTENTION_MOVE_TO, L2Position(x,y,z,heading)) self.startQuestTimer("2",5000,npc,player) elif event == "2" : - npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, L2CharPosition(x,y,z,heading)) + npc.getAI().setIntention(Intention.AI_INTENTION_MOVE_TO, L2Position(x,y,z,heading)) self.startQuestTimer("3",12000,npc,player) elif event == "3" : - npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, L2CharPosition(x,y,z,heading)) + npc.getAI().setIntention(Intention.AI_INTENTION_MOVE_TO, L2Position(x,y,z,heading)) self.startQuestTimer("4",15000,npc,player) elif event == "4" : - npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, L2CharPosition(x,y,z,heading)) + npc.getAI().setIntention(Intention.AI_INTENTION_MOVE_TO, L2Position(x,y,z,heading)) self.startQuestTimer("5",5000,npc,player) elif event == "5" : - npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, L2CharPosition(x,y,z,heading)) + npc.getAI().setIntention(Intention.AI_INTENTION_MOVE_TO, L2Position(x,y,z,heading)) return htmltext def onTalk (self,npc,player): diff --git a/Datapack/data/jscript/quests/22_TragedyInVonHellmannForest/__init__.py b/Datapack/data/jscript/quests/22_TragedyInVonHellmannForest/__init__.py index 7d739670..28ca8744 100644 --- a/Datapack/data/jscript/quests/22_TragedyInVonHellmannForest/__init__.py +++ b/Datapack/data/jscript/quests/22_TragedyInVonHellmannForest/__init__.py @@ -4,7 +4,7 @@ from com.l2jbr.gameserver.model.quest import QuestState from com.l2jbr.gameserver.model.quest.jython import QuestJython as JQuest from com.l2jbr.gameserver.serverpackets import CreatureSay -from com.l2jbr.gameserver.ai import CtrlIntention +from com.l2jbr.gameserver.ai import Intention qn = "22_TragedyInVonHellmannForest" @@ -120,7 +120,7 @@ def onAdvEvent (self,event,npc, player) : st.startQuestTimer("Soul of Well 1",90000,soul) st.startQuestTimer("Soul of Well Despawn",120000,soul) soul.addDamageHate(player,0,99999) - soul.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK,player,None) + soul.getAI().setIntention(Intention.AI_INTENTION_ATTACK,player,None) else : htmltext = "31527-03.htm" elif event == "31328-13.htm" : diff --git a/Datapack/data/jscript/quests/403_PathToRogue/30379-09.htm b/Datapack/data/jscript/quests/403_PathToRogue/30379-09.htm index e6a23e67..454e328f 100644 --- a/Datapack/data/jscript/quests/403_PathToRogue/30379-09.htm +++ b/Datapack/data/jscript/quests/403_PathToRogue/30379-09.htm @@ -1,6 +1,7 @@ - - -Captain Bezique:
-Oh! You've recovered all the stolen items. Thank you for your trouble. Your skills are better than I thought. I think you really have the qualities to become a good Rogue. Red-eyed Bandits... Have you ever heard of them? They are the largest group of bandits on the continent with their home in the snow-covered mountains of Oren. I can’t believe those stupid thieves were related to the Red-eyed Bandits... I need to make a detailed inquiry into this. Hmm... Anyhow, I will write you a letter of recommendation. Go to Grand Master Ramos at the Fighters Guild and show him my recommendation. Then you can change occupations to a Rogue. Well then, I wish you luck. Oh, and I almost forgot! I will give Neti back her bow and dagger for you. I have to go and thank her, anyway. - + + +Captain Bezique: +
+Oh! You've recovered all the stolen items. Thank you for your trouble. Your skills are better than I thought. I think you really have the qualities to become a good Rogue. Red-eyed Bandits... Have you ever heard of them? They are the largest group of bandits on the continent with their home in the snow-covered mountains of Oren. I can�t believe those stupid thieves were related to the Red-eyed Bandits... I need to make a detailed inquiry into this. Hmm... Anyhow, I will write you a letter of recommendation. Go to Grand Master Ramos at the Fighters Guild and show him my recommendation. Then you can change occupations to a Rogue. Well then, I wish you luck. Oh, and I almost forgot! I will give Neti back her bow and dagger for you. I have to go and thank her, anyway. + \ No newline at end of file diff --git a/Datapack/data/jscript/quests/405_PathToCleric/__init__.py b/Datapack/data/jscript/quests/405_PathToCleric/__init__.py index c4157327..2def71bd 100644 --- a/Datapack/data/jscript/quests/405_PathToCleric/__init__.py +++ b/Datapack/data/jscript/quests/405_PathToCleric/__init__.py @@ -27,23 +27,23 @@ def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) def onEvent (self,event,st) : htmltext = event level = st.getPlayer().getLevel() - classId = st.getPlayer().getClassId().getId() + playerClass = st.getPlayer().getPlayerClass().getId() if event == "1" : st.set("id","0") - if level >= 19 and classId == 0x0a and st.getQuestItemsCount(MARK_OF_FAITH) == 0 : + if level >= 19 and playerClass == 0x0a and st.getQuestItemsCount(MARK_OF_FAITH) == 0 : st.set("cond","1") st.setState(STARTED) st.playSound("ItemSound.quest_accept") st.giveItems(LETTER_OF_ORDER1,1) htmltext = "30022-05.htm" - elif classId != 0x0a : - if classId == 0x0f : + elif playerClass != 0x0a : + if playerClass == 0x0f : htmltext = "30022-02a.htm" else: htmltext = "30022-02.htm" - elif level<19 and classId == 0x0a : + elif level<19 and playerClass == 0x0a : htmltext = "30022-03.htm" - elif level >= 19 and classId == 0x0a and st.getQuestItemsCount(MARK_OF_FAITH) == 1 : + elif level >= 19 and playerClass == 0x0a and st.getQuestItemsCount(MARK_OF_FAITH) == 1 : htmltext = "30022-04.htm" return htmltext diff --git a/Datapack/data/jscript/quests/409_PathToOracle/__init__.py b/Datapack/data/jscript/quests/409_PathToOracle/__init__.py index 1a778b7d..7943b9cb 100644 --- a/Datapack/data/jscript/quests/409_PathToOracle/__init__.py +++ b/Datapack/data/jscript/quests/409_PathToOracle/__init__.py @@ -23,23 +23,23 @@ def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) def onEvent (self,event,st) : htmltext = event level = st.getPlayer().getLevel() - classId = st.getPlayer().getClassId().getId() + playerClass = st.getPlayer().getPlayerClass().getId() if event == "1" : st.set("id","0") - if level >= 19 and classId == 0x19 and st.getQuestItemsCount(LEAF_OF_ORACLE) == 0 : + if level >= 19 and playerClass == 0x19 and st.getQuestItemsCount(LEAF_OF_ORACLE) == 0 : st.set("cond","1") st.setState(STARTED) st.playSound("ItemSound.quest_accept") st.giveItems(CRYSTAL_MEDALLION,1) htmltext = "30293-05.htm" - elif classId != 0x19 : - if classId == 0x1d : + elif playerClass != 0x19 : + if playerClass == 0x1d : htmltext = "30293-02a.htm" else: htmltext = "30293-02.htm" - elif level<19 and classId == 0x19 : + elif level<19 and playerClass == 0x19 : htmltext = "30293-03.htm" - elif level >= 19 and classId == 0x19 and st.getQuestItemsCount(LEAF_OF_ORACLE) == 1 : + elif level >= 19 and playerClass == 0x19 and st.getQuestItemsCount(LEAF_OF_ORACLE) == 1 : htmltext = "30293-04.htm" elif event == "30424-08.htm" : if st.getInt("cond") : diff --git a/Datapack/data/jscript/quests/410_PathToPalusKnight/__init__.py b/Datapack/data/jscript/quests/410_PathToPalusKnight/__init__.py index eb036220..05ecf0eb 100644 --- a/Datapack/data/jscript/quests/410_PathToPalusKnight/__init__.py +++ b/Datapack/data/jscript/quests/410_PathToPalusKnight/__init__.py @@ -24,7 +24,7 @@ def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) def onEvent (self,event,st) : htmltext = event level = st.getPlayer().getLevel() - classId = st.getPlayer().getClassId().getId() + playerClass = st.getPlayer().getPlayerClass().getId() if event == "1" : st.set("id","0") st.set("cond","1") @@ -33,17 +33,17 @@ def onEvent (self,event,st) : htmltext = "30329-06.htm" st.giveItems(PALLUS_TALISMAN,1) elif event == "410_1" : - if level >= 19 and classId == 0x1f and st.getQuestItemsCount(GAZE_OF_ABYSS) == 0 : + if level >= 19 and playerClass == 0x1f and st.getQuestItemsCount(GAZE_OF_ABYSS) == 0 : htmltext = "30329-05.htm" return htmltext - elif classId != 0x1f : - if classId == 0x20 : + elif playerClass != 0x1f : + if playerClass == 0x20 : htmltext = "30329-02a.htm" else: htmltext = "30329-03.htm" - elif level<19 and classId == 0x1f : + elif level<19 and playerClass == 0x1f : htmltext = "30329-02.htm" - elif level >= 19 and classId == 0x1f and st.getQuestItemsCount(GAZE_OF_ABYSS) == 1 : + elif level >= 19 and playerClass == 0x1f and st.getQuestItemsCount(GAZE_OF_ABYSS) == 1 : htmltext = "30329-04.htm" elif event == "30329_2" : htmltext = "30329-10.htm" diff --git a/Datapack/data/jscript/quests/411_PathToAssassin/__init__.py b/Datapack/data/jscript/quests/411_PathToAssassin/__init__.py index 0a17534d..019e09c5 100644 --- a/Datapack/data/jscript/quests/411_PathToAssassin/__init__.py +++ b/Datapack/data/jscript/quests/411_PathToAssassin/__init__.py @@ -23,24 +23,24 @@ def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) def onEvent (self,event,st) : htmltext = event level = st.getPlayer().getLevel() - classId = st.getPlayer().getClassId().getId() + playerClass = st.getPlayer().getPlayerClass().getId() if event == "1" : - if level >= 19 and classId == 0x1f and st.getQuestItemsCount(IRON_HEART) == 0 : + if level >= 19 and playerClass == 0x1f and st.getQuestItemsCount(IRON_HEART) == 0 : st.set("cond","1") st.setState(STARTED) st.playSound("ItemSound.quest_accept") st.giveItems(SHILENS_CALL,1) htmltext = "30416-05.htm" - elif classId != 0x1f : - if classId == 0x23 : + elif playerClass != 0x1f : + if playerClass == 0x23 : htmltext = "30416-02a.htm" else: htmltext = "30416-02.htm" st.exitQuest(1) - elif level<19 and classId == 0x1f : + elif level<19 and playerClass == 0x1f : htmltext = "30416-03.htm" st.exitQuest(1) - elif level >= 19 and classId == 0x1f and st.getQuestItemsCount(IRON_HEART) == 1 : + elif level >= 19 and playerClass == 0x1f and st.getQuestItemsCount(IRON_HEART) == 1 : htmltext = "30416-04.htm" elif event == "30419_1" : htmltext = "30419-05.htm" diff --git a/Datapack/data/jscript/quests/412_PathToDarkwizard/__init__.py b/Datapack/data/jscript/quests/412_PathToDarkwizard/__init__.py index b2e2e084..3b77aa1d 100644 --- a/Datapack/data/jscript/quests/412_PathToDarkwizard/__init__.py +++ b/Datapack/data/jscript/quests/412_PathToDarkwizard/__init__.py @@ -27,24 +27,24 @@ def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) def onEvent (self,event,st) : htmltext = event level = st.getPlayer().getLevel() - classId = st.getPlayer().getClassId().getId() + playerClass = st.getPlayer().getPlayerClass().getId() if event == "1" : st.set("id","0") if st.getInt("cond") == 0 : - if level >= 19 and classId == 0x26 and st.getQuestItemsCount(JEWEL_OF_DARKNESS) == 0 : + if level >= 19 and playerClass == 0x26 and st.getQuestItemsCount(JEWEL_OF_DARKNESS) == 0 : st.set("cond","1") st.setState(STARTED) st.playSound("ItemSound.quest_accept") st.giveItems(SEEDS_OF_DESPAIR,1) htmltext = "30421-05.htm" - elif classId != 0x26 : - if classId == 0x27 : + elif playerClass != 0x26 : + if playerClass == 0x27 : htmltext = "30421-02a.htm" else: htmltext = "30421-03.htm" - elif level<19 and classId == 0x26 : + elif level<19 and playerClass == 0x26 : htmltext = "30421-02.htm" - elif level >= 19 and classId == 0x26 and st.getQuestItemsCount(JEWEL_OF_DARKNESS) == 1 : + elif level >= 19 and playerClass == 0x26 and st.getQuestItemsCount(JEWEL_OF_DARKNESS) == 1 : htmltext = "30421-04.htm" elif event == "412_1" : if st.getQuestItemsCount(SEEDS_OF_ANGER) : diff --git a/Datapack/data/jscript/quests/413_PathToShillienOracle/__init__.py b/Datapack/data/jscript/quests/413_PathToShillienOracle/__init__.py index e88bd37f..fff1d4f4 100644 --- a/Datapack/data/jscript/quests/413_PathToShillienOracle/__init__.py +++ b/Datapack/data/jscript/quests/413_PathToShillienOracle/__init__.py @@ -25,7 +25,7 @@ def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) def onEvent (self,event,st) : htmltext = event level = st.getPlayer().getLevel() - classId = st.getPlayer().getClassId().getId() + playerClass = st.getPlayer().getPlayerClass().getId() if event == "1" : st.set("id","0") htmltext = "30330-06.htm" @@ -34,17 +34,17 @@ def onEvent (self,event,st) : st.playSound("ItemSound.quest_accept") st.giveItems(SIDRAS_LETTER1,1) elif event == "413_1" : - if level >= 19 and classId == 0x26 and st.getQuestItemsCount(ORB_OF_ABYSS) == 0 : + if level >= 19 and playerClass == 0x26 and st.getQuestItemsCount(ORB_OF_ABYSS) == 0 : htmltext = "30330-05.htm" return htmltext - elif classId != 0x26 : - if classId == 0x2a : + elif playerClass != 0x26 : + if playerClass == 0x2a : htmltext = "30330-02a.htm" else: htmltext = "30330-03.htm" - elif level<19 and classId == 0x26 : + elif level<19 and playerClass == 0x26 : htmltext = "30330-02.htm" - elif level >= 19 and classId == 0x26 and st.getQuestItemsCount(ORB_OF_ABYSS) == 1 : + elif level >= 19 and playerClass == 0x26 and st.getQuestItemsCount(ORB_OF_ABYSS) == 1 : htmltext = "30330-04.htm" elif event == "30377_1" : htmltext = "30377-02.htm" diff --git a/Datapack/data/jscript/quests/417_PathToScavenger/__init__.py b/Datapack/data/jscript/quests/417_PathToScavenger/__init__.py index f5ab5581..414fb0d6 100644 --- a/Datapack/data/jscript/quests/417_PathToScavenger/__init__.py +++ b/Datapack/data/jscript/quests/417_PathToScavenger/__init__.py @@ -32,23 +32,23 @@ def __init__(self,id,name,descr): JQuest.__init__(self,id,name,descr) def onEvent (self,event,st) : htmltext = event level = st.getPlayer().getLevel() - classId = st.getPlayer().getClassId().getId() + playerClass = st.getPlayer().getPlayerClass().getId() if event == "1" : st.set("id","0") - if level >= 19 and classId == 0x35 and st.getQuestItemsCount(RING_OF_RAVEN) == 0 : + if level >= 19 and playerClass == 0x35 and st.getQuestItemsCount(RING_OF_RAVEN) == 0 : st.set("cond","1") st.setState(STARTED) st.playSound("ItemSound.quest_accept") st.giveItems(PIPIS_LETTER,1) htmltext = "30524-05.htm" - elif classId != 0x35 : - if classId == 0x36 : + elif playerClass != 0x35 : + if playerClass == 0x36 : htmltext = "30524-02a.htm" else: htmltext = "30524-08.htm" - elif level < 19 and classId == 0x35 : + elif level < 19 and playerClass == 0x35 : htmltext = "30524-02.htm" - elif level >= 19 and classId == 0x35 and st.getQuestItemsCount(RING_OF_RAVEN) == 1 : + elif level >= 19 and playerClass == 0x35 and st.getQuestItemsCount(RING_OF_RAVEN) == 1 : htmltext = "30524-04.htm" elif event == "30519_1" : if st.getQuestItemsCount(PIPIS_LETTER): diff --git a/Datapack/data/jscript/quests/503_PursuitClanAmbition/__init__.py b/Datapack/data/jscript/quests/503_PursuitClanAmbition/__init__.py index 01b22176..cf8f7d43 100644 --- a/Datapack/data/jscript/quests/503_PursuitClanAmbition/__init__.py +++ b/Datapack/data/jscript/quests/503_PursuitClanAmbition/__init__.py @@ -2,13 +2,16 @@ # questdevs Team import sys -from java.util import Iterator -from com.l2jbr.commons.util import Rnd -from com.l2jbr.gameserver.serverpackets import CreatureSay -from com.l2jbr.gameserver.model.quest import State -from com.l2jbr.gameserver.model.quest import QuestState -from com.l2jbr.gameserver.model.quest.jython import QuestJython as JQuest -from com.l2jbr.commons import L2DatabaseFactory +from java.util import Iterator +from com.l2jbr.commons.util import Rnd +from com.l2jbr.gameserver.serverpackets import CreatureSay +from com.l2jbr.gameserver.model.quest import State +from com.l2jbr.gameserver.model.quest import QuestState +from com.l2jbr.gameserver.model.quest.jython import QuestJython as JQuest +from com.l2jbr.commons.database import L2DatabaseFactory +from com.l2jbr.commons.database import DatabaseAccess +from com.l2jbr.gameserver.model.entity.database.repository import CharacterQuestsRepository +from com.l2jbr.gameserver.model.entity.database import CharacterQuests qn = "503_PursuitClanAmbition" qd = "Pursuit Clan Ambition" @@ -64,21 +67,13 @@ def suscribe_members(st) : clan=st.getPlayer().getClan().getClanId() con=L2DatabaseFactory.getInstance().getConnection() offline=con.prepareStatement("SELECT obj_Id FROM characters WHERE clanid=? AND online=0") + repository = DatabaseAccess.getRepository(CharacterQuestsRepository) offline.setInt(1, clan) rs=offline.executeQuery() while (rs.next()) : char_id=rs.getInt("obj_Id") - try : - insertion = con.prepareStatement("INSERT INTO character_quests (char_id,name,var,value) VALUES (?,?,?,?)") - insertion.setInt(1, char_id) - insertion.setString(2, qn) - insertion.setString(3, "") - insertion.setString(4, "Progress") - insertion.executeUpdate() - insertion.close(); - except : - try : insertion.close() - except : pass + characterQuest = CharacterQuests(char_id, qn, "", "Progress") + repository.save(characterQuest) try : con.close() except : @@ -86,17 +81,8 @@ def suscribe_members(st) : def offlineMemberExit(st) : clan=st.getPlayer().getClan().getClanId() - con=L2DatabaseFactory.getInstance().getConnection() - offline=con.prepareStatement("DELETE FROM character_quests WHERE name = ? and char_id IN (SELECT obj_id FROM characters WHERE clanId =? AND online=0") - offline.setString(1, qn) - offline.setInt(2, clan) - try : - offline.executeUpdate() - offline.close() - con.close() - except : - try : con.close() - except : pass + repository = DatabaseAccess.getRepository(CharacterQuestsRepository) + repository.deleteAllByOfflineClanMembers(qn, clan) # returns leaders quest cond, if he is offline will read out of database :) def getLeaderVar(st, var) : @@ -110,23 +96,11 @@ def getLeaderVar(st, var) : except : pass leaderId=st.getPlayer().getClan().getLeaderId() - con=L2DatabaseFactory.getInstance().getConnection() - offline=con.prepareStatement("SELECT value FROM character_quests WHERE char_id=? AND var=? AND name=?") - offline.setInt(1, leaderId) - offline.setString(2, var) - offline.setString(3, qn) - rs=offline.executeQuery() - if rs : - rs.next() - try : - val=rs.getInt("value") - con.close() - except : - val=-1 - try : con.close() - except : pass - else : - val=-1 + repository = DatabaseAccess.getRepository(CharacterQuestsRepository) + characterQuests = repository.findByNameAndVar(leaderId, qn, var); + val = -1 + for characterQuest in characterQuests: + val = characterQuest.getValue() return int(val) # set's leaders quest cond, if he is offline will read out of database :) @@ -140,19 +114,8 @@ def setLeaderVar(st, var, value) : leader.getQuestState(qn).set(var,value) else : leaderId=st.getPlayer().getClan().getLeaderId() - con=L2DatabaseFactory.getInstance().getConnection() - offline=con.prepareStatement("UPDATE character_quests SET value=? WHERE char_id=? AND var=? AND name=?") - offline.setString(1, value) - offline.setInt(2, leaderId) - offline.setString(3, var) - offline.setString(4, qn) - try : - offline.executeUpdate() - offline.close() - con.close() - except : - try : con.close() - except : pass + repository = DatabaseAccess.getRepository(CharacterQuestsRepository) + repository.updateQuestVar(leaderId, qn, var, value) return def checkEggs(st): @@ -224,7 +187,7 @@ def onEvent (self,event,st) : elif event == "30645-03.htm": st.takeItems(G_Let_Martien,-1) st.set("cond","2") - suscribe_members(st) + suscribe_members(st) try: members = st.getPlayer().getClan().getOnlineMembers("")[0] for i in members: diff --git a/Datapack/data/jscript/quests/SagasSuperclass/__init__.py b/Datapack/data/jscript/quests/SagasSuperclass/__init__.py index 1bbecdd5..c81413fe 100644 --- a/Datapack/data/jscript/quests/SagasSuperclass/__init__.py +++ b/Datapack/data/jscript/quests/SagasSuperclass/__init__.py @@ -6,8 +6,8 @@ from com.l2jbr.gameserver.serverpackets import CreatureSay from com.l2jbr.gameserver.datatables import SpawnTable from com.l2jbr.gameserver.model import L2Spawn -from com.l2jbr.gameserver.ai import CtrlIntention -from com.l2jbr.gameserver.ai import CtrlEvent +from com.l2jbr.gameserver.ai import Intention +from com.l2jbr.gameserver.ai import Event from com.l2jbr.gameserver.serverpackets import MagicSkillUser from com.l2jbr.gameserver.model import L2World from java.util import Iterator @@ -140,7 +140,7 @@ def giveHallishaMark(self, st2) : st2.startQuestTimer("Archon Hellisha has despawned",600000,Archon) self.AutoChat(Archon,self.Text[13].replace('PLAYERNAME',st2.getPlayer().getName())) Archon.addDamageHate(st2.getPlayer(),0,99999) - Archon.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK,st2.getPlayer(),None) + Archon.getAI().setIntention(Intention.AI_INTENTION_ATTACK,st2.getPlayer(),None) else : st2.giveItems(self.Items[3],1) return @@ -334,9 +334,9 @@ def onAdvEvent (self,event,npc, player) : Mob_2 = self.FindSpawn(player,st.getInt("Mob_2")) if npc.getKnownList().knowsObject(Mob_2) : npc.addDamageHate(Mob_2,0,99999) - npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK,Mob_2,None) + npc.getAI().setIntention(Intention.AI_INTENTION_ATTACK,Mob_2,None) #Mob_2.addDamageHate(npc,0,99999) - Mob_2.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK,npc,None) + Mob_2.getAI().setIntention(Intention.AI_INTENTION_ATTACK,npc,None) self.AutoChat(npc,self.Text[14].replace('PLAYERNAME',player.getName())) else : st.startQuestTimer("Mob_3 Timer 1",500,npc) diff --git a/Datapack/data/jscript/village_master/9001_alliance/9001-02.htm b/Datapack/data/jscript/village_master/9001_alliance/9001-02.htm index 968b956d..c6a7da0e 100644 --- a/Datapack/data/jscript/village_master/9001_alliance/9001-02.htm +++ b/Datapack/data/jscript/village_master/9001_alliance/9001-02.htm @@ -1,38 +1,39 @@ - - - -Create Alliance: -
-Enter Alliance Name: -
- -
-