commit fc4c6bd340eb6870fa69ae56f28453e96f957ee6 Author: Emmanuel BenoƮt Date: Tue Oct 23 09:38:02 2018 +0200 Importing SVN archives - B6M1 diff --git a/.project b/.project new file mode 100644 index 0000000..b09df49 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + legacyworlds + + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.maven.ide.eclipse.maven2Nature + + diff --git a/build-tools/BUILD.sh b/build-tools/BUILD.sh new file mode 100755 index 0000000..b76b7f5 --- /dev/null +++ b/build-tools/BUILD.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +cd `dirname $0`/.. +SRCDIR=`pwd` +if [ "x$1" = "x" ]; then + OUTDIR="$SRCDIR"; +else + OUTDIR="$1"; +fi + +echo "Building Legacy Worlds..." +mvn clean || { echo "Maven clean-up failed"; exit 1; }; +mvn package || { echo "Maven build failed"; exit 1; }; + +echo "Copying files..." + +TEMPDIR=`mktemp -d` +mkdir $TEMPDIR/legacyworlds +mkdir $TEMPDIR/legacyworlds/server +mkdir $TEMPDIR/legacyworlds/server/data +mkdir $TEMPDIR/legacyworlds/web +mkdir $TEMPDIR/legacyworlds/sql + +# Database and initial data +cp -Rapv legacyworlds-server/legacyworlds-server-data/db-structure/database.sql $TEMPDIR/legacyworlds/sql +cp -Rapv legacyworlds-server/legacyworlds-server-data/db-structure/db-config.txt $TEMPDIR/legacyworlds/sql/db-config-example.txt +cp -Rapv legacyworlds-server/legacyworlds-server-data/db-structure/parts $TEMPDIR/legacyworlds/sql +cp -Rapv legacyworlds-server/legacyworlds-server-main/data/* $TEMPDIR/legacyworlds/server/data +# Server +cp -Rapv legacyworlds-server/legacyworlds-server-main/target/*.jar $TEMPDIR/legacyworlds/server +cp -Rapv legacyworlds-server/legacyworlds-server-main/target/lib $TEMPDIR/legacyworlds/server +cp -Rapv legacyworlds-server/legacyworlds-server-main/data-source.xml $TEMPDIR/legacyworlds/server/data-source-example.xml +# Tools +cp -Rapv build-tools/server-config-example.sh $TEMPDIR/legacyworlds +cp -Rapv build-tools/start-server.sh $TEMPDIR/legacyworlds +cp -Rapv build-tools/stop-server.sh $TEMPDIR/legacyworlds +cp -Rapv build-tools/execute-clit.sh $TEMPDIR/legacyworlds +cp -Rapv build-tools/deploy.sh $TEMPDIR/legacyworlds +# Web sites +cp -Rapv legacyworlds-web/legacyworlds-web-*/target/*.war $TEMPDIR/legacyworlds/web + +echo "Preparing archive..." +cd $TEMPDIR +find $TEMPDIR/legacyworlds -type d -name .svn | xargs rm -rf +tar cvjf $OUTDIR/legacyworlds.tar.bz2 legacyworlds || { echo "Archive generation failed"; exit 1; }; + +echo "Removing temporary directory..." +cd $SRCDIR +rm -rf $TEMPDIR + +echo "All done. Legacy Worlds archive: $OUTDIR/legacyworlds.tar.bz2" diff --git a/build-tools/deploy.sh b/build-tools/deploy.sh new file mode 100755 index 0000000..5edbf77 --- /dev/null +++ b/build-tools/deploy.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +COREDIR="$1" +if [ "x$COREDIR" = "x" ] || ! [ -d "$COREDIR" ]; then + echo "Syntax: $0 main_dir tomcat_dir web_dir" + exit 1; +fi + +TOMCATDIR="$2" +if [ "x$TOMCATDIR" = "x" ] || ! [ -d "$TOMCATDIR" ]; then + echo "Syntax: $0 main_dir tomcat_dir web_dir" + exit 1; +fi + +WEBDIR="$3" +if [ "x$WEBDIR" = "x" ] || ! [ -d "$WEBDIR" ]; then + echo "Syntax: $0 main_dir tomcat_dir web_dir" + exit 1; +fi + + +cd `dirname $0` +SRCDIR=`pwd` +cp -Rap server web *-*.sh $COREDIR + +cd "$TOMCATDIR" +if [ -L "lwmain.war" ]; then + rm -f lwmain.war lwadmin.war +fi +ln -s "$COREDIR/web/legacyworlds-web-main-"*.war lwmain.war +ln -s "$COREDIR/web/legacyworlds-web-admin-"*.war lwadmin.war + +cd $WEBDIR +unzip -o $COREDIR/web/legacyworlds-web-main-*.war "css/*" "js/*" "pjirc/*" "img/*" diff --git a/build-tools/execute-clit.sh b/build-tools/execute-clit.sh new file mode 100755 index 0000000..7119874 --- /dev/null +++ b/build-tools/execute-clit.sh @@ -0,0 +1,5 @@ +#!/bin/sh +BASE="`dirname $0`" +cd "$BASE/server" +source server-config.sh +java $LOG -jar legacyworlds-server-main-*.jar --run-tool $1 "$2" diff --git a/build-tools/server-config-example.sh b/build-tools/server-config-example.sh new file mode 100644 index 0000000..f962497 --- /dev/null +++ b/build-tools/server-config-example.sh @@ -0,0 +1 @@ +LOG="-Dlog4j.configuration=log4j.properties" diff --git a/build-tools/start-server.sh b/build-tools/start-server.sh new file mode 100755 index 0000000..bed8582 --- /dev/null +++ b/build-tools/start-server.sh @@ -0,0 +1,9 @@ +#!/bin/sh +BASE="`dirname $0`" +cd "$BASE/server" +source server-config.sh +if [ "x$1" = "x--debug" ]; then + java $LOG -jar legacyworlds-server-main-*.jar +else + ( java $LOG -jar legacyworlds-server-main-*.jar /dev/null 2>&1 & ) /dev/null 2>&1 & +fi diff --git a/build-tools/stop-server.sh b/build-tools/stop-server.sh new file mode 100755 index 0000000..8b2703d --- /dev/null +++ b/build-tools/stop-server.sh @@ -0,0 +1,2 @@ +#!/bin/sh +"`dirname $0`"/execute-clit.sh Stop diff --git a/eclipse-code-format.xml b/eclipse-code-format.xml new file mode 100644 index 0000000..bbde209 --- /dev/null +++ b/eclipse-code-format.xml @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/.project b/legacyworlds-server/.project new file mode 100644 index 0000000..5ff6ca3 --- /dev/null +++ b/legacyworlds-server/.project @@ -0,0 +1,17 @@ + + + legacyworlds-server + + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/.project b/legacyworlds-server/legacyworlds-server-beans/.project new file mode 100644 index 0000000..7f3bd93 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/.project @@ -0,0 +1,17 @@ + + + legacyworlds-server-beans + + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.project new file mode 100644 index 0000000..a5031a0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-accounts + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..cb25da1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 09 10:19:20 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/pom.xml new file mode 100644 index 0000000..093cc46 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-beans-accounts + Legacy Worlds account management + 5.99.1 + This package contains the beans responsible for managing accounts, including registration, inactivity checks, bans and authentication. + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountCleanupBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountCleanupBean.java new file mode 100644 index 0000000..510bc6e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountCleanupBean.java @@ -0,0 +1,75 @@ +package com.deepclone.lw.beans.acm; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class AccountCleanupBean + implements InitializingBean , DisposableBean +{ + + private TransactionTemplate tTemplate; + + private Ticker ticker; + + private UsersDAO usersDao; + + private Mailer mailer; + + private AccountCleanupTask cleanupTask; + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setUsersDAO( UsersDAO usersDao ) + { + this.usersDao = usersDao; + } + + + @Autowired( required = true ) + public void setMailer( Mailer mailer ) + { + this.mailer = mailer; + } + + + @Override + public void afterPropertiesSet( ) + throws Exception + { + this.cleanupTask = new AccountCleanupTask( this.tTemplate , this.usersDao , this.mailer ); + this.ticker.registerTask( Frequency.MEDIUM , "Accounts clean-up task" , this.cleanupTask ); + } + + + @Override + public void destroy( ) + { + this.cleanupTask = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountCleanupTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountCleanupTask.java new file mode 100644 index 0000000..5eb5ea9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountCleanupTask.java @@ -0,0 +1,96 @@ +package com.deepclone.lw.beans.acm; + + +import java.util.List; + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.sqld.accounts.QuittingAccount; + + + +class AccountCleanupTask + implements Runnable +{ + + private TransactionTemplate tTemplate; + private UsersDAO usersDao; + private Mailer mailer; + + + public AccountCleanupTask( TransactionTemplate tTemplate , UsersDAO usersDao , Mailer mailer ) + { + this.tTemplate = tTemplate; + this.usersDao = usersDao; + this.mailer = mailer; + } + + + @Override + public void run( ) + { + this.sendInactivityWarnings( ); + this.disableInactiveAccounts( ); + this.dropOldAccounts( ); + } + + + private void sendInactivityWarnings( ) + { + List< QuittingAccount > toWarn; + toWarn = this.tTemplate.execute( new TransactionCallback< List< QuittingAccount >>( ) { + @Override + public List< QuittingAccount > doInTransaction( TransactionStatus status ) + { + return usersDao.getInactivesToWarn( ); + } + } ); + + for ( QuittingAccount account : toWarn ) { + try { + this.mailer.createMail( account.getLanguage( ) , "inactivityWarningMail" , account.getAddress( ) ) + .queue( ); + } catch ( Exception e ) { + continue; + } + } + } + + + private void disableInactiveAccounts( ) + { + List< QuittingAccount > toDisable; + toDisable = this.tTemplate.execute( new TransactionCallback< List< QuittingAccount >>( ) { + @Override + public List< QuittingAccount > doInTransaction( TransactionStatus status ) + { + return usersDao.getInactivesToDisable( ); + } + } ); + + for ( QuittingAccount account : toDisable ) { + try { + this.mailer.createMail( account.getLanguage( ) , "inactivityQuitMail" , account.getAddress( ) ).queue( ); + } catch ( Exception e ) { + continue; + } + } + } + + + private void dropOldAccounts( ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + usersDao.deleteOldAccounts( ); + } + } ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountManagementBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountManagementBean.java new file mode 100644 index 0000000..38a9ffc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/AccountManagementBean.java @@ -0,0 +1,757 @@ +package com.deepclone.lw.beans.acm; + + +import java.net.InetAddress; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.bans.ValidatedBanRequest; +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.admin.users.AccountListEntry; +import com.deepclone.lw.cmd.admin.users.AccountSessionEntry; +import com.deepclone.lw.cmd.admin.users.AccountStatus; +import com.deepclone.lw.cmd.admin.users.AccountViewEntry; +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.cmd.admin.users.UserSession; +import com.deepclone.lw.cmd.ext.ListLanguagesResponse; +import com.deepclone.lw.cmd.player.account.BanDetailsResponse; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; +import com.deepclone.lw.cmd.player.gdata.account.PrefCategory; +import com.deepclone.lw.cmd.player.gdata.account.PrefChoice; +import com.deepclone.lw.cmd.player.gdata.account.PrefType; +import com.deepclone.lw.cmd.player.gdata.account.PrefValue; +import com.deepclone.lw.interfaces.acm.*; +import com.deepclone.lw.interfaces.admin.BansDAO; +import com.deepclone.lw.interfaces.eventlog.*; +import com.deepclone.lw.interfaces.i18n.*; +import com.deepclone.lw.interfaces.mailer.*; +import com.deepclone.lw.interfaces.naming.NamingDAO; +import com.deepclone.lw.interfaces.prefs.Preference; +import com.deepclone.lw.interfaces.prefs.PreferenceGroup; +import com.deepclone.lw.interfaces.prefs.PreferenceType; +import com.deepclone.lw.interfaces.prefs.PreferencesDAO; +import com.deepclone.lw.sqld.accounts.*; +import com.deepclone.lw.utils.*; + + + +public class AccountManagementBean + implements AccountManagement +{ + + private TransactionTemplate tTemplate; + private Mailer mailer; + private Logger logger; + private UsersDAO usersDao; + private UserSessionDAO sessionDao; + private NamingDAO namingDao; + private Translator translator; + private PreferencesDAO prefsDao; + private BansDAO bansDao; + + + @Autowired( required = true ) + public void setTransactionTemplate( PlatformTransactionManager transactionManager ) + { + this.tTemplate = new TransactionTemplate( transactionManager ); + } + + + @Autowired( required = true ) + public void setMailer( Mailer mailer ) + { + this.mailer = mailer; + } + + + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger; + } + + + @Autowired( required = true ) + public void setUsersDao( UsersDAO usersDao ) + { + this.usersDao = usersDao; + } + + + @Autowired( required = true ) + public void setSessionDao( UserSessionDAO sessionDao ) + { + this.sessionDao = sessionDao; + } + + + @Autowired( required = true ) + public void setNamingDao( NamingDAO namingDao ) + { + this.namingDao = namingDao; + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Autowired( required = true ) + public void setPrefsDao( PreferencesDAO prefsDao ) + { + this.prefsDao = prefsDao; + } + + + @Autowired( required = true ) + public void setBansDao( BansDAO bansDao ) + { + this.bansDao = bansDao; + } + + + @Override + public void createAccount( final EmailAddress address , final Password password , final String language ) + throws AccountMailException , MailerException , TranslationException + { + SystemLogger sLog = this.logger.getSystemLogger( "AccountManagement" ); + sLog.log( LogLevel.INFO , "Attempting to create account '" + address.getAddress( ) + "'" ).flush( ); + + // Create credentials + AccountOperationResult result; + result = this.tTemplate.execute( new TransactionCallback< AccountOperationResult >( ) { + + @Override + public AccountOperationResult doInTransaction( TransactionStatus status ) + { + AccountOperationResult r = usersDao.createAccount( address , password , language ); + if ( r.getErrorCode( ) != 0 ) { + status.setRollbackOnly( ); + } + return r; + } + + } ); + + // Check creation status + switch ( result.getErrorCode( ) ) { + case 0: + break; + + case -1: + sLog.log( LogLevel.INFO , "Could not create account '" + address.getAddress( ) + "' - it exists" ) + .flush( ); + throw new AccountMailException( ); + + case -2: + sLog + .log( LogLevel.INFO , + "Could not create account '" + address.getAddress( ) + "' - unknown language" ).flush( ); + throw new UnknownLanguageException( language ); + + default: + sLog.log( + LogLevel.ERROR , + "Could not create account '" + address.getAddress( ) + "' - unknown error code " + + result.getErrorCode( ) ).flush( ); + throw new RuntimeException( ); + } + + // Send email + Account account = result.getAccount( ); + MailData data = this.mailer.createMail( language , "registrationMail" , address.getAddress( ) ); + data.setData( "address" , address.getAddress( ) ); + data.setData( "validationKey" , account.getValidationToken( ) ); + try { + data.sendNow( ); + } catch ( MailerException e ) { + this.cancelValidation( account ); + sLog.log( LogLevel.INFO , "Could not create account '" + address.getAddress( ) + "'" , e ).flush( ); + if ( e instanceof NotSentException ) { + throw e; + } + throw new RuntimeException( e ); + } + } + + + private void cancelValidation( final Account account ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + usersDao.cancelAccountValidation( account ); + } + } ); + } + + + @Override + public void reactivateAccount( final EmailAddress address ) + throws AccountMailException , MailerException + { + SystemLogger sLog = this.logger.getSystemLogger( "AccountManagement" ); + sLog.log( LogLevel.INFO , "trying to re-activate account " + address.getAddress( ) ).flush( ); + + // Check status + Account account = this.tTemplate.execute( new TransactionCallback< Account >( ) { + + @Override + public Account doInTransaction( TransactionStatus status ) + { + Account r = usersDao.reactivateAccount( address ); + if ( r == null ) { + status.setRollbackOnly( ); + } + return r; + } + + } ); + if ( account == null ) { + throw new AccountMailException( ); + } + + // Send email + MailData data; + try { + data = this.mailer.createMail( account.getLanguage( ) , "reactivationMail" , address.getAddress( ) ); + } catch ( TranslationException e ) { + sLog.log( LogLevel.ERROR , "'" + address.getAddress( ) + "' - error while preparing reactivation mail" , e ) + .flush( ); + this.cancelValidation( account ); + throw new RuntimeException( e ); + } + + data.setData( "address" , account.getAddress( ) ); + data.setData( "token" , account.getValidationToken( ) ); + try { + data.sendNow( ); + } catch ( MailerException e ) { + this.cancelValidation( account ); + if ( e instanceof NotSentException ) { + throw e; + } + throw new RuntimeException( e ); + } + } + + + @Override + public ValidationResult validateAccount( final EmailAddress address , final String token , final String empire , + final String planet ) + { + SystemLogger sLog = this.logger.getSystemLogger( "AccountManagement" ); + sLog.log( LogLevel.INFO , "trying to validate account '" + address.getAddress( ) + "'" ).flush( ); + return this.tTemplate.execute( new TransactionCallback< ValidationResult >( ) { + + @Override + public ValidationResult doInTransaction( TransactionStatus status ) + { + ValidationResult r = usersDao.validateAccount( address , token , empire , planet ); + if ( r.isError( ) ) { + status.setRollbackOnly( ); + } + return r; + } + + } ); + } + + + @Override + public void requestPasswordRecovery( final EmailAddress address ) + throws AccountMailException , MailerException , PasswordRecoveryException + { + SystemLogger sLog = this.logger.getSystemLogger( "AccountManagement" ); + sLog.log( LogLevel.INFO , "'" + address.getAddress( ) + "' requesting password recovery" ).flush( ); + + AccountOperationResult result = this.tTemplate.execute( new TransactionCallback< AccountOperationResult >( ) { + + @Override + public AccountOperationResult doInTransaction( TransactionStatus status ) + { + AccountOperationResult r = usersDao.requestPasswordRecovery( address ); + if ( r.getErrorCode( ) != 0 ) { + status.setRollbackOnly( ); + } + return r; + } + + } ); + + // Throw exceptions as needed + switch ( result.getErrorCode( ) ) { + case 0: + break; + + case 1: + sLog.log( LogLevel.INFO , "'" + address.getAddress( ) + "' - duplicate password recovery request" ) + .flush( ); + throw new PasswordRecoveryException( false ); + + case 2: + sLog.log( LogLevel.INFO , "'" + address.getAddress( ) + "' - account does not exist" ).flush( ); + throw new AccountMailException( ); + + default: + sLog.log( LogLevel.ERROR , "Unknown error code " + result.getErrorCode( ) ).flush( ); + throw new RuntimeException( ); + } + + // Send email + MailData data; + Account account = result.getAccount( ); + try { + data = this.mailer.createMail( account.getLanguage( ) , "passwordRecoveryMail" , address.getAddress( ) ); + } catch ( TranslationException e ) { + sLog.log( LogLevel.ERROR , "'" + address.getAddress( ) + "' - error while preparing recovery mail" , e ) + .flush( ); + this.cancelPasswordRecovery( account ); + throw new RuntimeException( e ); + } + + data.setData( "address" , address.getAddress( ) ); + data.setData( "token" , account.getPwdRecoveryToken( ) ); + + try { + data.sendNow( ); + } catch ( MailerException e ) { + this.cancelPasswordRecovery( account ); + if ( e instanceof NotSentException ) { + throw e; + } + throw new RuntimeException( e ); + } + } + + + private void cancelPasswordRecovery( final Account account ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + usersDao.cancelPasswordRecovery( account ); + } + } ); + } + + + @Override + public void recoverPassword( final EmailAddress address , final String token , final Password password ) + throws AccountMailException , PasswordRecoveryException , PasswordProhibitedException + { + SystemLogger sLog = this.logger.getSystemLogger( "AccountManagement" ); + sLog.log( LogLevel.INFO , "'" + address.getAddress( ) + "' confirming password recovery" ).flush( ); + + AccountOperationResult result = this.tTemplate.execute( new TransactionCallback< AccountOperationResult >( ) { + + @Override + public AccountOperationResult doInTransaction( TransactionStatus status ) + { + AccountOperationResult r = usersDao.confirmPasswordRecovery( address , token , password ); + if ( r.getErrorCode( ) != 0 ) { + status.setRollbackOnly( ); + } + return r; + } + + } ); + + // Handle errors + switch ( result.getErrorCode( ) ) { + case 0: + break; + + case 1: + throw new AccountMailException( ); + + case 2: + throw new PasswordProhibitedException( ); + + default: + sLog.log( LogLevel.ERROR , "Unknown error code " + result.getErrorCode( ) ).flush( ); + throw new RuntimeException( ); + + } + } + + + @Override + @Transactional + public AccountSession login( final EmailAddress address , String challenge , String sha1Hash , String md5Hash , + InetAddress ipAddress , String clientType , String sessionName ) + { + Account account = this.usersDao.getAccount( address ); + + // Check account + if ( account == null ) { + SystemLogger sLog = this.logger.getSystemLogger( "AccountManagement" ); + sLog.log( LogLevel.INFO , "login attempt for unknown address '" + address.getAddress( ) + "'" ).flush( ); + return null; + } + + // Check challenge response + String eSha1 = DigestHelper.digest( "sha-1" , challenge + " " + account.getPassSha1( ) ); + String eMd5 = DigestHelper.digest( "md5" , challenge + " " + account.getPassMd5( ) ); + + if ( ! ( eSha1.equals( sha1Hash ) && eMd5.equals( md5Hash ) ) ) { + return null; + } + + // Create session + long sId = this.sessionDao.startSession( account.getId( ) , sessionName , clientType , ipAddress.toString( ) ); + return new AccountSession( account , sId ); + } + + + @Override + @Transactional + public void logout( long session , SessionTerminationType reason ) + { + this.sessionDao.endSession( session , reason ); + } + + + @Override + @Transactional + public Account restoreSession( long session ) + { + UserSession sData = this.sessionDao.getSession( session ); + if ( sData == null || sData.getEndType( ) != null ) { + return null; + } + return this.usersDao.getAccount( sData.getCredentialsId( ) ); + } + + + @Override + @Transactional + public Account getAccount( final EmailAddress address ) + { + return this.usersDao.getAccount( address ); + } + + + @Override + @Transactional + public List< String > getEmpireNames( final EmailAddress address ) + { + Account accnt = this.usersDao.getAccount( address ); + if ( accnt == null ) { + return null; + } + return this.namingDao.getEmpireNames( accnt.getId( ) ); + } + + + @Override + @Transactional + public AccountData getAccountPage( EmailAddress address ) + { + Account account = this.getAccount( address ); + return this.accountToPage( account ); + } + + + private AccountData accountToPage( Account account ) + { + AccountData data = new AccountData( ); + data.setAddress( account.getAddress( ) ); + data.setGameCredits( account.getGameCredits( ) ); + data.setLanguage( account.getLanguage( ) ); + data.setQuitGame( account.getInactivityStart( ) ); + data.setVacCredits( account.getVacationCredits( ) ); + data.setVacTime( account.getVacationTime( ) ); + data.setVacStart( account.getVacationStart( ) ); + data.setMailChange( this.usersDao.getMailChange( account.getId( ) ) ); + + // Get supported languages + Map< String , String > languages = new HashMap< String , String >( ); + try { + for ( String lId : this.translator.getSupportedLanguages( ) ) { + languages.put( lId , this.translator.getLanguageName( lId ) ); + } + } catch ( UnknownLanguageException e ) { + throw new RuntimeException( e ); + } + data.setSupportedLanguages( new ListLanguagesResponse( languages ) ); + + // Extract account preferences + for ( PreferenceGroup group : this.prefsDao.getPreferences( account ).getGroups( ) ) { + PrefCategory pCat = new PrefCategory( ); + pCat.setName( group.getDisplay( ) ); + for ( Preference pref : group.getPreferences( ) ) { + PrefValue pValue = new PrefValue( ); + + pValue.setId( pref.getName( ) ); + pValue.setName( pref.getDisplayName( ) ); + pValue.setDescription( pref.getDescription( ) ); + + PreferenceType< ? > dType = pref.getType( ); + if ( dType.getType( ) == String.class ) { + pValue.setType( PrefType.STRING ); + } else if ( dType.getType( ) == Integer.class ) { + pValue.setType( PrefType.INTEGER ); + } else if ( dType.getType( ) == Boolean.class ) { + pValue.setType( PrefType.BOOLEAN ); + } else { + Map< String , String > choices = dType.getChoices( ); + List< PrefChoice > cList = new LinkedList< PrefChoice >( ); + for ( Map.Entry< String , String > entry : choices.entrySet( ) ) { + String name; + try { + name = this.translator.translate( data.getLanguage( ) , entry.getValue( ) ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + cList.add( new PrefChoice( entry.getKey( ) , name ) ); + } + pValue.setType( PrefType.CHOICE ); + pValue.setChoices( cList ); + } + + pValue.setValue( pref.getDBValue( ) ); + pCat.addValue( pValue ); + } + data.addPreferenceCategory( pCat ); + } + + return data; + } + + + @Override + @Transactional + public void setLanguage( EmailAddress address , String language ) + { + this.usersDao.setLanguage( address , language ); + } + + + @Override + @Transactional + public boolean setPassword( final EmailAddress address , String challenge , String sha1Hash , String md5Hash , + Password newPassword ) + throws PasswordProhibitedException + { + Account account = this.usersDao.getAccount( address ); + + // Check challenge response + String eSha1 = DigestHelper.digest( "sha-1" , challenge + " " + account.getPassSha1( ) ); + String eMd5 = DigestHelper.digest( "md5" , challenge + " " + account.getPassMd5( ) ); + if ( ! ( eSha1.equals( sha1Hash ) && eMd5.equals( md5Hash ) ) ) { + return false; + } + + if ( !this.usersDao.setPassword( account , newPassword ) ) { + throw new PasswordProhibitedException( ); + } + + return true; + } + + + @Override + @Transactional( rollbackFor = { + RuntimeException.class , AccountMailException.class , MailerException.class + } ) + public boolean setAddress( EmailAddress address , String challenge , String sha1Hash , String md5Hash , + EmailAddress nAddress ) + throws AccountMailException , MailerException + { + Account account = this.usersDao.getAccount( address ); + + // Check challenge response + String eSha1 = DigestHelper.digest( "sha-1" , challenge + " " + account.getPassSha1( ) ); + String eMd5 = DigestHelper.digest( "md5" , challenge + " " + account.getPassMd5( ) ); + if ( ! ( eSha1.equals( sha1Hash ) && eMd5.equals( md5Hash ) ) ) { + return false; + } + + int errCode = this.usersDao.setAddress( account , nAddress ); + switch ( errCode ) { + case -1: + return true; + case -2: + throw new AccountMailException( ); + } + + // Send email + SystemLogger sLog = this.logger.getSystemLogger( "AccountManagement" ); + MailData data; + account = this.usersDao.getAccount( address ); + try { + data = this.mailer.createMail( account.getLanguage( ) , "addressChangeMail" , nAddress.getAddress( ) ); + } catch ( TranslationException e ) { + sLog.log( LogLevel.ERROR , "'" + address.getAddress( ) + "' - error while preparing recovery mail" , e ) + .flush( ); + this.cancelPasswordRecovery( account ); + throw new RuntimeException( e ); + } + + data.setData( "address" , nAddress.getAddress( ) ); + data.setData( "token" , account.getAddressChangeToken( ) ); + + try { + data.sendNow( ); + } catch ( MailerException e ) { + if ( e instanceof NotSentException ) { + throw e; + } + throw new RuntimeException( e ); + } + + return true; + } + + + @Override + @Transactional + public void cancelAddressChange( EmailAddress cAddress ) + { + this.usersDao.cancelAddressChange( this.usersDao.getAccount( cAddress ) ); + } + + + @Override + @Transactional + public AccountData confirmAddressChange( EmailAddress cAddress , String code ) + { + Account account = this.usersDao.getAccount( cAddress ); + if ( account.getAddressChangeToken( ) != null ) { + int newId = this.usersDao.confirmAddressChange( account , code ); + account = this.usersDao.getAccount( newId ); + } + return this.accountToPage( account ); + } + + + @Override + @Transactional + public void resetPreferences( EmailAddress address ) + { + Account account = this.usersDao.getAccount( address ); + this.prefsDao.resetPreferences( account ); + } + + + @Override + @Transactional + public void setPreferences( EmailAddress address , Map< String , String > values ) + { + Account account = this.usersDao.getAccount( address ); + this.prefsDao.setPreferences( account , values ); + } + + + @Override + @Transactional + public void setQuit( EmailAddress address , String reason ) + { + Account account = this.usersDao.getAccount( address ); + if ( account.getStatus( ) == AccountStatus.ACTIVE ) { + this.usersDao.setQuit( account , reason ); + } + } + + + @Override + @Transactional + public void cancelQuit( EmailAddress address ) + { + Account account = this.usersDao.getAccount( address ); + if ( account.getStatus( ) == AccountStatus.QUITTING ) { + this.usersDao.cancelQuit( account ); + } + } + + + @Override + @Transactional + public void toggleVacation( EmailAddress address ) + { + Account account = this.usersDao.getAccount( address ); + AccountStatus status = account.getStatus( ); + if ( status == AccountStatus.ACTIVE ) { + this.usersDao.enterVacation( account ); + } else if ( status == AccountStatus.START_VACATION || status == AccountStatus.VACATION ) { + this.usersDao.leaveVacation( account ); + } + } + + + @Override + @Transactional + public List< AccountListEntry > listAccounts( AccountStatus status , boolean online ) + { + if ( online ) { + return this.usersDao.listOnlineAccounts( status ); + } + return this.usersDao.listAccounts( status ); + } + + + @Override + @Transactional + public AccountViewEntry getAccountView( int id ) + { + AccountViewEntry basics = this.usersDao.viewAccount( id ); + if ( basics == null ) { + return null; + } + basics.setOnline( this.sessionDao.isOnline( id ) ); + basics.setEmpireNames( this.namingDao.getEmpireNames( id ) ); + return basics; + } + + + @Override + @Transactional + public AccountSessionEntry viewSessions( int id ) + { + AccountViewEntry basics = this.usersDao.viewAccount( id ); + if ( basics == null ) { + return null; + } + + AccountSessionEntry entry = new AccountSessionEntry( basics ); + entry.setSessions( this.sessionDao.getSessions( id ) ); + return entry; + } + + + @Override + @Transactional + public void giveCredits( Administrator admin , int id , int credits ) + { + this.usersDao.giveCredits( admin.getId( ) , id , credits ); + } + + + @Override + @Transactional + public BanDetailsResponse getBanDetails( EmailAddress address ) + { + ValidatedBanRequest ban = this.bansDao.getActiveBan( address ); + if ( ban == null ) { + throw new RuntimeException( "account not banned" ); + } + return new BanDetailsResponse( ban.getUpdate( ) , ban.getReason( ) , ban.isRedeemable( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/QuitProcessorBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/QuitProcessorBean.java new file mode 100644 index 0000000..9e35dd2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/QuitProcessorBean.java @@ -0,0 +1,75 @@ +package com.deepclone.lw.beans.acm; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class QuitProcessorBean + implements InitializingBean , DisposableBean +{ + + private TransactionTemplate tTemplate; + + private Ticker ticker; + + private UsersDAO usersDao; + + private Mailer mailer; + + private QuitProcessorTask quitProcessor; + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setUsersDAO( UsersDAO usersDao ) + { + this.usersDao = usersDao; + } + + + @Autowired( required = true ) + public void setMailer( Mailer mailer ) + { + this.mailer = mailer; + } + + + @Override + public void afterPropertiesSet( ) + throws Exception + { + this.quitProcessor = new QuitProcessorTask( this.tTemplate , this.usersDao , this.mailer ); + this.ticker.registerTask( Frequency.MEDIUM , "Quitting accounts processor" , this.quitProcessor ); + } + + + @Override + public void destroy( ) + { + this.quitProcessor = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/QuitProcessorTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/QuitProcessorTask.java new file mode 100644 index 0000000..ca67534 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/QuitProcessorTask.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.beans.acm; + + +import java.util.List; + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.sqld.accounts.QuittingAccount; + + + +class QuitProcessorTask + implements Runnable +{ + + private TransactionTemplate tTemplate; + private UsersDAO usersDao; + private Mailer mailer; + + + public QuitProcessorTask( TransactionTemplate tTemplate , UsersDAO usersDao , Mailer mailer ) + { + this.tTemplate = tTemplate; + this.usersDao = usersDao; + this.mailer = mailer; + } + + + @Override + public void run( ) + { + List< QuittingAccount > quitters; + quitters = this.tTemplate.execute( new TransactionCallback< List< QuittingAccount >>( ) { + @Override + public List< QuittingAccount > doInTransaction( TransactionStatus status ) + { + return usersDao.processQuits( ); + } + } ); + + for ( QuittingAccount quitter : quitters ) { + try { + this.mailer.createMail( quitter.getLanguage( ) , "quitMail" , quitter.getAddress( ) ).queue( ); + } catch ( Exception e ) { + continue; + } + } + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/RequestsExpirationBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/RequestsExpirationBean.java new file mode 100644 index 0000000..9e295b5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/RequestsExpirationBean.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.beans.acm; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class RequestsExpirationBean + implements InitializingBean , DisposableBean +{ + + private TransactionTemplate tTemplate; + + private Ticker ticker; + + private UsersDAO usersDao; + + private RequestsExpirationTask expiration; + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setUsersDAO( UsersDAO usersDao ) + { + this.usersDao = usersDao; + } + + + @Override + public void afterPropertiesSet( ) + throws Exception + { + this.expiration = new RequestsExpirationTask( this.tTemplate , this.usersDao ); + this.ticker.registerTask( Frequency.MEDIUM , "Account requests expiration" , this.expiration ); + } + + + @Override + public void destroy( ) + { + this.expiration = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/RequestsExpirationTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/RequestsExpirationTask.java new file mode 100644 index 0000000..4cde6eb --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/RequestsExpirationTask.java @@ -0,0 +1,38 @@ +package com.deepclone.lw.beans.acm; + + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.acm.UsersDAO; + + + +class RequestsExpirationTask + implements Runnable +{ + + private TransactionTemplate tTemplate; + private UsersDAO usersDao; + + + public RequestsExpirationTask( TransactionTemplate tTemplate , UsersDAO usersDao ) + { + this.tTemplate = tTemplate; + this.usersDao = usersDao; + } + + + @Override + public void run( ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + usersDao.expireRequests( ); + } + } ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/UserSessionDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/UserSessionDAOBean.java new file mode 100644 index 0000000..cdb5fb0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/UserSessionDAOBean.java @@ -0,0 +1,137 @@ +package com.deepclone.lw.beans.acm; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.cmd.admin.users.UserSession; +import com.deepclone.lw.interfaces.acm.UserSessionDAO; +import com.deepclone.lw.utils.StoredProc; + + + +public class UserSessionDAOBean + implements UserSessionDAO , InitializingBean +{ + + private SimpleJdbcTemplate dTemplate; + + private final RowMapper< UserSession > mSession; + + private StoredProc fSessionStart; + private StoredProc fSessionEnd; + + + public UserSessionDAOBean( ) + { + this.mSession = new RowMapper< UserSession >( ) { + @Override + public UserSession mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + UserSession session = new UserSession( ); + + session.setId( rs.getLong( "id" ) ); + session.setCredentialsId( rs.getInt( "credentials_id" ) ); + session.setSessionName( rs.getString( "session" ) ); + session.setClientName( rs.getString( "client_name" ) ); + session.setExclusive( rs.getBoolean( "exclusive" ) ); + session.setFromAddress( rs.getString( "from_address" ) ); + if ( session.getFromAddress( ).startsWith( "/" )) { + session.setFromAddress( session.getFromAddress( ).substring( 1 ) ); + } + session.setStarted( rs.getTimestamp( "started" ) ); + session.setEnded( rs.getTimestamp( "ended" ) ); + if ( session.getEnded( ) != null ) { + session.setEndType( SessionTerminationType.valueOf( rs.getString( "end_type" ) ) ); + } + + return session; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fSessionStart = new StoredProc( dataSource , "users" , "sessions_login" ); + this.fSessionStart.addParameter( "credentials_id" , Types.INTEGER ); + this.fSessionStart.addParameter( "session_name" , Types.VARCHAR ); + this.fSessionStart.addParameter( "client_type" , Types.VARCHAR ); + this.fSessionStart.addParameter( "ip_address" , Types.VARCHAR ); + this.fSessionStart.addOutput( "s_id" , Types.BIGINT ); + + this.fSessionEnd = new StoredProc( dataSource , "users" , "sessions_terminate" ); + this.fSessionEnd.addParameter( "session_id" , Types.BIGINT ); + this.fSessionEnd.addParameter( "end_type" , "session_termination_type" ); + } + + + @Override + public void afterPropertiesSet( ) + { + this.dTemplate.getJdbcOperations( ).execute( "SELECT users.sessions_server_restart()" ); + } + + + @Override + public long startSession( int id , String sName , String client , String address ) + { + return (Long) this.fSessionStart.execute( id , sName , client , address ).get( "s_id" ); + } + + + @Override + public void endSession( long session , SessionTerminationType termination ) + { + this.fSessionEnd.execute( session , termination.toString( ) ); + } + + + @Override + public UserSession getSession( long id ) + { + String sql = "SELECT * FROM users.sessions WHERE id = ?"; + try { + return this.dTemplate.queryForObject( sql , this.mSession , id ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public boolean isOnline( int id ) + { + String sql = "SELECT credentials_id FROM users.sessions WHERE credentials_id = ? AND end_type IS NULL AND exclusive"; + try { + this.dTemplate.queryForInt( sql , id ); + return true; + } catch ( EmptyResultDataAccessException e ) { + return false; + } + } + + + @Override + public List< UserSession > getSessions( int id ) + { + String sql = "SELECT * FROM users.sessions WHERE credentials_id = ?"; + return this.dTemplate.query( sql , this.mSession , id ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/UsersDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/UsersDAOBean.java new file mode 100644 index 0000000..7e5d421 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/UsersDAOBean.java @@ -0,0 +1,550 @@ +package com.deepclone.lw.beans.acm; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.admin.users.AccountBanEntry; +import com.deepclone.lw.cmd.admin.users.AccountListEntry; +import com.deepclone.lw.cmd.admin.users.AccountStatus; +import com.deepclone.lw.cmd.admin.users.AccountViewEntry; +import com.deepclone.lw.cmd.player.gdata.account.MailChangeData; +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.sqld.accounts.AccountOperationResult; +import com.deepclone.lw.sqld.accounts.QuittingAccount; +import com.deepclone.lw.sqld.accounts.ValidationResult; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; +import com.deepclone.lw.utils.StoredProc; + + + +public class UsersDAOBean + implements UsersDAO +{ + private static abstract class AccountListMapper< T extends AccountListEntry > + implements RowMapper< T > + { + + protected void getCommonColumns( AccountListEntry e , ResultSet rs ) + throws SQLException + { + e.setId( rs.getInt( "id" ) ); + e.setAddress( rs.getString( "address" ) ); + e.setLanguage( rs.getString( "language" ) ); + e.setStatus( AccountStatus.valueOf( rs.getString( "status" ) ) ); + e.setCurrentEmpire( rs.getString( "current_empire" ) ); + } + + } + + private final RowMapper< Account > accountMapper; + private final RowMapper< QuittingAccount > quitMapper; + private final RowMapper< MailChangeData > mailChangeMapper; + private final AccountListMapper< AccountListEntry > mAccountList; + private final AccountListMapper< AccountViewEntry > mAccountView; + + private SimpleJdbcTemplate dTemplate; + + private StoredProc fCreateAccount; + private StoredProc fMailFailure; + private StoredProc fValidate; + private StoredProc fReactivate; + private StoredProc fRequestPasswordRecovery; + private StoredProc fCancelPasswordRecovery; + private StoredProc fConfirmPasswordRecovery; + private StoredProc fSetLanguage; + private StoredProc fSetPassword; + private StoredProc fSetAddress; + private StoredProc fCancelAddressChange; + private StoredProc fConfirmAddressChange; + private StoredProc fSetQuit; + private StoredProc fCancelQuit; + private StoredProc fEnterVacation; + private StoredProc fLeaveVacation; + private StoredProc fGrantCredits; + + + public UsersDAOBean( ) + { + this.accountMapper = new RowMapper< Account >( ) { + @Override + public Account mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + Account account = new Account( ); + + account.setId( rs.getInt( "id" ) ); + account.setAddress( rs.getString( "address" ) ); + account.setLanguage( rs.getString( "language" ) ); + account.setPassMd5( rs.getString( "pass_md5" ) ); + account.setPassSha1( rs.getString( "pass_sha1" ) ); + account.setGameCredits( rs.getInt( "game_credits" ) ); + account.setStatus( AccountStatus.valueOf( rs.getString( "status" ) ) ); + account.setValidationToken( rs.getString( "validation_token" ) ); + account.setPwdRecoveryToken( rs.getString( "pwd_recovery_token" ) ); + account.setAddressChangeToken( rs.getString( "address_change_token" ) ); + account.setNewAddress( rs.getString( "new_address" ) ); + account.setVacationCredits( rs.getInt( "vacation_credits" ) ); + account.setVacationTime( rs.getInt( "vacation_time" ) ); + account.setVacationStart( rs.getTimestamp( "vacation_start" ) ); + account.setInactivityStart( rs.getTimestamp( "inactivity_begin" ) ); + account.setInactivityReason( rs.getString( "inactivity_reason" ) ); + account.setBanRequestId( rs.getInt( "ban_request_id" ) ); + + return account; + } + }; + + this.mailChangeMapper = new RowMapper< MailChangeData >( ) { + @Override + public MailChangeData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + if ( rs.getBoolean( "used" ) ) { + return new MailChangeData( rs.getTimestamp( "expires" ) ); + } + return new MailChangeData( rs.getTimestamp( "expires" ) , rs.getString( "new_address" ) ); + } + }; + + this.quitMapper = new RowMapper< QuittingAccount >( ) { + @Override + public QuittingAccount mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + QuittingAccount acc = new QuittingAccount( ); + acc.setId( rs.getInt( "id" ) ); + acc.setAddress( rs.getString( "address" ) ); + acc.setLanguage( rs.getString( "language" ) ); + return acc; + } + }; + + this.mAccountList = new AccountListMapper< AccountListEntry >( ) { + @Override + public AccountListEntry mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + AccountListEntry e = new AccountListEntry( ); + this.getCommonColumns( e , rs ); + return e; + } + }; + + this.mAccountView = new AccountListMapper< AccountViewEntry >( ) { + @Override + public AccountViewEntry mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + AccountViewEntry e = new AccountViewEntry( ); + this.getCommonColumns( e , rs ); + e.setGameCredits( rs.getInt( "game_credits" ) ); + e.setVacationCredits( rs.getInt( "vacation_credits" ) ); + if ( !e.getStatus( ).isActive( ) && e.getStatus( ) != AccountStatus.UNCONFIRMED ) { + e.setStatusStart( rs.getTimestamp( "inactivity_begin" ) ); + } else { + e.setStatusStart( rs.getTimestamp( "vacation_start" ) ); + } + e.setInactivityReason( rs.getString( "inactivity_reason" ) ); + e.setEmpireId( (Integer) rs.getObject( "current_empire_id" ) ); + + if ( e.getStatus( ) == AccountStatus.BANNED ) { + AccountBanEntry ban = new AccountBanEntry( ); + ban.setRequestedById( rs.getInt( "ban_req_id" ) ); + ban.setRequestedByName( rs.getString( "ban_req_name" ) ); + ban.setConfirmedById( rs.getInt( "ban_val_id" ) ); + ban.setConfirmedByName( rs.getString( "ban_val_name" ) ); + e.setBan( ban ); + } + + e.setWarnings( rs.getInt( "warnings_count" ) ); + e.setLastWarning( rs.getTimestamp( "warnings_last" ) ); + + return e; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fCreateAccount = new StoredProc( dataSource , "users" , "create_credentials" ); + this.fCreateAccount.addParameter( "address" , Types.VARCHAR ); + this.fCreateAccount.addParameter( "lang_id" , Types.VARCHAR ); + this.fCreateAccount.addParameter( "pass_md5" , Types.VARCHAR ); + this.fCreateAccount.addParameter( "pass_sha1" , Types.VARCHAR ); + this.fCreateAccount.addOutput( "err_code" , Types.INTEGER ); + this.fCreateAccount.addOutput( "a_id" , Types.INTEGER ); + + this.fMailFailure = new StoredProc( dataSource , "users" , "validation_mail_failure" ); + this.fMailFailure.addParameter( "a_id" , Types.INTEGER ); + + this.fValidate = new StoredProc( dataSource , "users" , "validate" ); + this.fValidate.addParameter( "addr" , Types.VARCHAR ); + this.fValidate.addParameter( "vtoken" , Types.VARCHAR ); + this.fValidate.addParameter( "empname" , Types.VARCHAR ); + this.fValidate.addParameter( "plname" , Types.VARCHAR ); + this.fValidate.addOutput( "account_error" , Types.INTEGER ); + this.fValidate.addOutput( "empire_error" , Types.INTEGER ); + this.fValidate.addOutput( "planet_error" , Types.INTEGER ); + + this.fReactivate = new StoredProc( dataSource , "users" , "reactivate" ); + this.fReactivate.addParameter( "addr" , Types.VARCHAR ); + this.fReactivate.addOutput( "success" , Types.BOOLEAN ); + this.fReactivate.addOutput( "a_id" , Types.INTEGER ); + + this.fRequestPasswordRecovery = new StoredProc( dataSource , "users" , "request_password_recovery" ); + this.fRequestPasswordRecovery.addParameter( "addr" , Types.VARCHAR ); + this.fRequestPasswordRecovery.addOutput( "err_code" , Types.INTEGER ); + this.fRequestPasswordRecovery.addOutput( "a_id" , Types.INTEGER ); + + this.fCancelPasswordRecovery = new StoredProc( dataSource , "users" , "cancel_password_recovery" ); + this.fCancelPasswordRecovery.addParameter( "a_id" , Types.INTEGER ); + + this.fConfirmPasswordRecovery = new StoredProc( dataSource , "users" , "confirm_password_recovery" ); + this.fConfirmPasswordRecovery.addParameter( "umail" , Types.VARCHAR ); + this.fConfirmPasswordRecovery.addParameter( "tok" , Types.VARCHAR ); + this.fConfirmPasswordRecovery.addParameter( "pmd5" , Types.VARCHAR ); + this.fConfirmPasswordRecovery.addParameter( "psha1" , Types.VARCHAR ); + this.fConfirmPasswordRecovery.addOutput( "err_code" , Types.INTEGER ); + this.fConfirmPasswordRecovery.addOutput( "a_id" , Types.INTEGER ); + + this.fSetLanguage = new StoredProc( dataSource , "users" , "set_language" ); + this.fSetLanguage.addParameter( "umail" , Types.VARCHAR ); + this.fSetLanguage.addParameter( "lang_id" , Types.VARCHAR ); + + this.fSetPassword = new StoredProc( dataSource , "users" , "set_password" ); + this.fSetPassword.addParameter( "u_id" , Types.INTEGER ); + this.fSetPassword.addParameter( "pmd5" , Types.VARCHAR ); + this.fSetPassword.addParameter( "psha1" , Types.VARCHAR ); + this.fSetPassword.addOutput( "success" , Types.BOOLEAN ); + + this.fSetAddress = new StoredProc( dataSource , "users" , "request_address_change" ); + this.fSetAddress.addParameter( "u_id" , Types.INTEGER ); + this.fSetAddress.addParameter( "n_address" , Types.VARCHAR ); + this.fSetAddress.addOutput( "err_code" , Types.INTEGER ); + + this.fCancelAddressChange = new StoredProc( dataSource , "users" , "cancel_address_change" ); + this.fCancelAddressChange.addParameter( "u_id" , Types.INTEGER ); + + this.fConfirmAddressChange = new StoredProc( dataSource , "users" , "confirm_address_change" ); + this.fConfirmAddressChange.addParameter( "u_id" , Types.INTEGER ); + this.fConfirmAddressChange.addParameter( "token" , Types.VARCHAR ); + this.fConfirmAddressChange.addOutput( "n_id" , Types.INTEGER ); + + this.fSetQuit = new StoredProc( dataSource , "users" , "set_account_quit" ); + this.fSetQuit.addParameter( "accound_id" , Types.INTEGER ); + this.fSetQuit.addParameter( "reason_text" , Types.VARCHAR ); + + this.fCancelQuit = new StoredProc( dataSource , "users" , "cancel_account_quit" ); + this.fCancelQuit.addParameter( "account_id" , Types.INTEGER ); + + this.fEnterVacation = new StoredProc( dataSource , "users" , "set_vacation" ); + this.fEnterVacation.addParameter( "account_id" , Types.INTEGER ); + + this.fLeaveVacation = new StoredProc( dataSource , "users" , "leave_vacation" ); + this.fLeaveVacation.addParameter( "account_id" , Types.INTEGER ); + + this.fGrantCredits = new StoredProc( dataSource , "admin" , "grant_user_credits" ); + this.fGrantCredits.addParameter( "admin_id" , Types.INTEGER ); + this.fGrantCredits.addParameter( "account_id" , Types.INTEGER ); + this.fGrantCredits.addParameter( "credits" , Types.INTEGER ); + } + + + @Override + public Account getAccount( EmailAddress address ) + { + String sql = "SELECT * FROM users.accounts_view WHERE address = ?"; + try { + return this.dTemplate.queryForObject( sql , this.accountMapper , address.getAddress( ) ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public Account getAccount( int id ) + { + String sql = "SELECT * FROM users.accounts_view WHERE id = ?"; + try { + return this.dTemplate.queryForObject( sql , this.accountMapper , id ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + private AccountOperationResult mapToResult( Map< String , Object > m ) + { + int errCode = (Integer) m.get( "err_code" ); + + AccountOperationResult result = new AccountOperationResult( ); + result.setErrorCode( errCode ); + if ( errCode == 0 ) { + result.setAccount( this.getAccount( (Integer) m.get( "a_id" ) ) ); + } + + return result; + } + + + @Override + public AccountOperationResult createAccount( EmailAddress address , Password password , String language ) + { + Map< String , Object > m = this.fCreateAccount.execute( address.getAddress( ) , language , password.getMd5( ) , + password.getSha1( ) ); + return this.mapToResult( m ); + } + + + @Override + public void cancelAccountValidation( Account account ) + { + this.fMailFailure.execute( account.getId( ) ); + } + + + @Override + public ValidationResult validateAccount( EmailAddress address , String token , String eName , String pName ) + { + Map< String , Object > m = this.fValidate.execute( address.getAddress( ) , token , eName , pName ); + ValidationResult vr = new ValidationResult( ); + vr.setAccountError( (Integer) m.get( "account_error" ) ); + vr.setEmpireError( (Integer) m.get( "empire_error" ) ); + vr.setPlanetError( (Integer) m.get( "planet_error" ) ); + return vr; + } + + + @Override + public Account reactivateAccount( EmailAddress address ) + { + Map< String , Object > m = this.fReactivate.execute( address.getAddress( ) ); + + boolean success = (Boolean) m.get( "success" ); + if ( !success ) { + return null; + } + + return this.getAccount( (Integer) m.get( "a_id" ) ); + } + + + @Override + public AccountOperationResult requestPasswordRecovery( EmailAddress address ) + { + Map< String , Object > m = this.fRequestPasswordRecovery.execute( address.getAddress( ) ); + return this.mapToResult( m ); + } + + + @Override + public void cancelPasswordRecovery( Account account ) + { + this.fCancelPasswordRecovery.execute( account.getId( ) ); + } + + + @Override + public AccountOperationResult confirmPasswordRecovery( EmailAddress address , String token , Password nPassword ) + { + Map< String , Object > m = this.fConfirmPasswordRecovery.execute( address.getAddress( ) , token , nPassword + .getMd5( ) , nPassword.getSha1( ) ); + return this.mapToResult( m ); + } + + + @Override + public MailChangeData getMailChange( int accountId ) + { + String sql = "SELECT * FROM users.mail_change_view WHERE id = ?"; + try { + return this.dTemplate.queryForObject( sql , this.mailChangeMapper , accountId ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public void setLanguage( EmailAddress address , String language ) + { + this.fSetLanguage.execute( address.getAddress( ) , language ); + } + + + @Override + public boolean setPassword( Account account , Password newPassword ) + { + int id = account.getId( ); + String sha1 = newPassword.getSha1( ); + String md5 = newPassword.getMd5( ); + return (Boolean) this.fSetPassword.execute( id , sha1 , md5 ).get( "success" ); + } + + + @Override + public int setAddress( Account account , EmailAddress nAddress ) + { + return (Integer) this.fSetAddress.execute( account.getId( ) , nAddress.getAddress( ) ).get( "err_code" ); + } + + + @Override + public void cancelAddressChange( Account account ) + { + this.fCancelAddressChange.execute( account.getId( ) ); + } + + + @Override + public int confirmAddressChange( Account account , String code ) + { + Integer nv; + nv = (Integer) this.fConfirmAddressChange.execute( account.getId( ) , code ).get( "n_id" ); + return ( nv == null ) ? account.getId( ) : nv.intValue( ); + } + + + @Override + public void expireRequests( ) + { + this.dTemplate.getJdbcOperations( ).execute( "SELECT users.expire_requests( )" ); + } + + + @Override + public void setQuit( Account account , String reason ) + { + this.fSetQuit.execute( account.getId( ) , reason ); + } + + + @Override + public void cancelQuit( Account account ) + { + this.fCancelQuit.execute( account.getId( ) ); + } + + + @Override + public List< QuittingAccount > processQuits( ) + { + String sql = "SELECT * FROM users.process_quit_requests( )"; + return this.dTemplate.query( sql , this.quitMapper ); + } + + + @Override + public void enterVacation( Account account ) + { + this.fEnterVacation.execute( account.getId( ) ); + } + + + @Override + public void leaveVacation( Account account ) + { + this.fLeaveVacation.execute( account.getId( ) ); + } + + + @Override + public void processVacations( ) + { + this.dTemplate.getJdbcOperations( ).execute( "SELECT users.process_vacations( )" ); + } + + + @Override + public List< AccountListEntry > listAccounts( AccountStatus status ) + { + String sql = "SELECT * FROM admin.users_list"; + Object[] params; + if ( status != null ) { + sql += " WHERE status = ?"; + params = new Object[] { + status.toString( ) + }; + } else { + params = new Object[] { }; + } + return this.dTemplate.query( sql , this.mAccountList , params ); + } + + + @Override + public List< AccountListEntry > listOnlineAccounts( AccountStatus status ) + { + String sql = "SELECT u.* FROM admin.users_list u INNER JOIN users.sessions s ON s.credentials_id = u.id AND s.end_type IS NULL AND s.exclusive"; + Object[] params; + if ( status != null ) { + sql += " WHERE u.status = ?"; + params = new Object[] { + status.toString( ) + }; + } else { + params = new Object[] { }; + } + return this.dTemplate.query( sql , this.mAccountList , params ); + } + + + @Override + public AccountViewEntry viewAccount( int id ) + { + String sql = "SELECT * FROM admin.users_list WHERE id = ?"; + try { + return this.dTemplate.queryForObject( sql , this.mAccountView , id ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public void giveCredits( int adminId , int accountId , int credits ) + { + this.fGrantCredits.execute( adminId , accountId , credits ); + } + + + @Override + public void deleteOldAccounts( ) + { + this.dTemplate.getJdbcOperations( ).execute( "SELECT users.delete_old_accounts( )" ); + } + + + @Override + public List< QuittingAccount > getInactivesToWarn( ) + { + String sql = "SELECT * FROM users.check_inactivity_emails( )"; + return this.dTemplate.query( sql , this.quitMapper ); + } + + + @Override + public List< QuittingAccount > getInactivesToDisable( ) + { + String sql = "SELECT * FROM users.check_inactivity( )"; + return this.dTemplate.query( sql , this.quitMapper ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/VacationProcessorBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/VacationProcessorBean.java new file mode 100644 index 0000000..02a2dfd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/VacationProcessorBean.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.beans.acm; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class VacationProcessorBean + implements InitializingBean , DisposableBean +{ + + private TransactionTemplate tTemplate; + + private Ticker ticker; + + private UsersDAO usersDao; + + private VacationProcessorTask vacationProcessor; + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setUsersDAO( UsersDAO usersDao ) + { + this.usersDao = usersDao; + } + + + @Override + public void afterPropertiesSet( ) + throws Exception + { + this.vacationProcessor = new VacationProcessorTask( this.tTemplate , this.usersDao ); + this.ticker.registerTask( Frequency.MINUTE , "Vacation processor" , this.vacationProcessor ); + } + + + @Override + public void destroy( ) + { + this.vacationProcessor = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/VacationProcessorTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/VacationProcessorTask.java new file mode 100644 index 0000000..95d6571 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/acm/VacationProcessorTask.java @@ -0,0 +1,38 @@ +package com.deepclone.lw.beans.acm; + + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.acm.UsersDAO; + + + +class VacationProcessorTask + implements Runnable +{ + + private TransactionTemplate tTemplate; + private UsersDAO usersDao; + + + public VacationProcessorTask( TransactionTemplate tTemplate , UsersDAO usersDao ) + { + this.tTemplate = tTemplate; + this.usersDao = usersDao; + } + + + @Override + public void run( ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + usersDao.processVacations( ); + } + } ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminDAOBean.java new file mode 100644 index 0000000..84a3a7a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminDAOBean.java @@ -0,0 +1,251 @@ +package com.deepclone.lw.beans.admin; + + +import java.net.InetAddress; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.admin.adata.AdminOverview; +import com.deepclone.lw.interfaces.admin.AdminDAO; +import com.deepclone.lw.interfaces.admin.AdminDAOException; +import com.deepclone.lw.sqld.admin.AdminConnection; +import com.deepclone.lw.sqld.admin.AdminRecord; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.StoredProc; + + + +public class AdminDAOBean + implements AdminDAO +{ + private static final String sGetAdminById = "SELECT * FROM admin.admins_view WHERE administrator_id = ?"; + private static final String sGetAdminByAddress = "SELECT * FROM admin.admins_view WHERE address = ?"; + private static final String sGetAdminByName = "SELECT * FROM admin.admins_view WHERE lower( name ) = ?"; + private static final String sListAdministrators = "SELECT * FROM admin.admins_view ORDER BY active DESC , name"; + + private SimpleJdbcTemplate dTemplate; + + private final RowMapper< AdminRecord > mAdminRecord; + private final RowMapper< AdminOverview > mAdminOverview; + + private StoredProc fCreateAdmin; + private StoredProc fLogConnection; + private StoredProc fLogDisconnection; + private StoredProc fSetPassword; + private StoredProc fResetPassword; + private StoredProc fSetPrivileges; + + + public AdminDAOBean( ) + { + this.mAdminRecord = new RowMapper< AdminRecord >( ) { + @Override + public AdminRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + AdminRecord admin = new AdminRecord( ); + admin.setId( rs.getInt( "administrator_id" ) ); + admin.setName( rs.getString( "name" ) ); + admin.setPrivileges( rs.getInt( "privileges" ) ); + admin.setActive( rs.getBoolean( "active" ) ); + admin.setAccount( (Integer) rs.getObject( "account_id" ) ); + admin.setAddress( rs.getString( "address" ) ); + admin.setpMd5( rs.getString( "pass_md5" ) ); + admin.setpSha1( rs.getString( "pass_sha1" ) ); + admin.setPassChangeRequired( (Boolean) rs.getObject( "pass_change_required" ) ); + return admin; + } + }; + this.mAdminOverview = new RowMapper< AdminOverview >( ) { + @Override + public AdminOverview mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + AdminOverview ov = new AdminOverview( ); + ov.setId( rs.getInt( "admin_id" ) ); + ov.setNewMessages( rs.getLong( "new_messages" ) ); + ov.setPendingNames( rs.getLong( "pending_names" ) ); + ov.setPendingBans( rs.getLong( "pending_bans" ) ); + ov.setPendingBugs( rs.getLong( "pending_bugs" ) ); + ov.setOpenBugs( rs.getLong( "open_bugs" ) ); + ov.setUpdatedBugs( rs.getLong( "updated_bugs" ) ); + return ov; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fCreateAdmin = new StoredProc( dataSource , "admin" , "create_admin" ); + this.fCreateAdmin.addParameter( "address" , Types.VARCHAR ); + this.fCreateAdmin.addParameter( "admin_name" , Types.VARCHAR ); + this.fCreateAdmin.addParameter( "privileges" , Types.INTEGER ); + this.fCreateAdmin.addOutput( "err_code" , Types.INTEGER ); + this.fCreateAdmin.addOutput( "admin_id" , Types.INTEGER ); + + this.fLogConnection = new StoredProc( dataSource , "admin" , "log_connection" ); + this.fLogConnection.addParameter( "admin_id" , Types.INTEGER ); + this.fLogConnection.addParameter( "result" , "admin_connection_result" ); + this.fLogConnection.addParameter( "ip_address" , Types.VARCHAR ); + + this.fLogDisconnection = new StoredProc( dataSource , "admin" , "log_disconnection" ); + this.fLogDisconnection.addParameter( "admin_id" , Types.INTEGER ); + + this.fSetPassword = new StoredProc( dataSource , "admin" , "set_password" ); + this.fSetPassword.addParameter( "admin_id" , Types.INTEGER ); + this.fSetPassword.addParameter( "pass_sha1" , Types.VARCHAR ); + this.fSetPassword.addParameter( "pass_md5" , Types.VARCHAR ); + this.fSetPassword.addOutput( "success" , Types.BOOLEAN ); + + this.fResetPassword = new StoredProc( dataSource , "admin" , "reset_password" ); + this.fResetPassword.addParameter( "admin_id" , Types.INTEGER ); + this.fResetPassword.addParameter( "superuser_id" , Types.INTEGER ); + this.fResetPassword.addOutput( "success" , Types.BOOLEAN ); + + this.fSetPrivileges = new StoredProc( dataSource , "admin" , "set_privileges" ); + this.fSetPrivileges.addParameter( "admin_id" , Types.INTEGER ); + this.fSetPrivileges.addParameter( "superuser_id" , Types.INTEGER ); + this.fSetPrivileges.addParameter( "privileges" , Types.INTEGER ); + this.fSetPrivileges.addOutput( "success" , Types.BOOLEAN ); + } + + + @Override + public AdminRecord getAdmin( int id ) + { + try { + return this.dTemplate.queryForObject( sGetAdminById , this.mAdminRecord , id ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public AdminRecord getAdmin( EmailAddress address ) + { + try { + return this.dTemplate.queryForObject( sGetAdminByAddress , this.mAdminRecord , address.getAddress( ) ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public AdminRecord getAdmin( String name ) + { + try { + return this.dTemplate.queryForObject( sGetAdminByName , this.mAdminRecord , name.toLowerCase( ) ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public int createAdmin( String address , String name , int privileges ) + throws AdminDAOException + { + Map< String , Object > result = this.fCreateAdmin.execute( address , name , privileges ); + int errCode = (Integer) result.get( "err_code" ); + if ( errCode != 0 ) { + throw new AdminDAOException( errCode ); + } + return (Integer) result.get( "admin_id" ); + } + + + @Override + public void logConnectionAttempt( int id , AdminConnection status , InetAddress address ) + { + this.fLogConnection.execute( id , status.toString( ) , address.getHostAddress( ) ); + } + + + @Override + public void logDisconnection( int id ) + { + this.fLogDisconnection.execute( id ); + } + + + @Override + public boolean setPassword( int id , String sha1 , String md5 ) + { + return (Boolean) this.fSetPassword.execute( id , sha1 , md5 ).get( "success" ); + } + + + @Override + public List< AdminRecord > listAdministrators( ) + { + return this.dTemplate.query( sListAdministrators , this.mAdminRecord ); + } + + + @Override + public boolean resetPassword( int identifier , int superuser ) + { + return (Boolean) this.fResetPassword.execute( identifier , superuser ).get( "success" ); + } + + + @Override + public boolean setPrivileges( int identifier , int superuser , int privileges ) + { + return (Boolean) this.fSetPrivileges.execute( identifier , superuser , privileges ).get( "success" ); + } + + + @Override + public AdminOverview getOverview( int id ) + { + String sql = "SELECT * FROM admin.overview WHERE admin_id = ?"; + try { + return this.dTemplate.queryForObject( sql , this.mAdminOverview , id ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public List< AdminOverview > getOverviews( ) + { + String sql = "SELECT * FROM admin.overview"; + return this.dTemplate.query( sql , this.mAdminOverview ); + } + + + @Override + public Timestamp isRecapTime( ) + { + String sql = "SELECT * FROM admin.is_recap_time( )"; + RowMapper< Timestamp > mapper = new RowMapper< Timestamp >( ) { + @Override + public Timestamp mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return rs.getTimestamp( 1 ); + } + }; + return this.dTemplate.queryForObject( sql , mapper ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminRecapBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminRecapBean.java new file mode 100644 index 0000000..19a155a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminRecapBean.java @@ -0,0 +1,78 @@ +package com.deepclone.lw.beans.admin; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.admin.AdminDAO; +import com.deepclone.lw.interfaces.eventlog.LogReader; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class AdminRecapBean + implements InitializingBean , DisposableBean +{ + private AdminRecapTask task; + private TransactionTemplate tTemplate; + private Ticker ticker; + private Mailer mailer; + private AdminDAO adminDao; + private LogReader logReader; + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setMailer( Mailer mailer ) + { + this.mailer = mailer; + } + + + @Autowired( required = true ) + public void setAdminDao( AdminDAO adminDao ) + { + this.adminDao = adminDao; + } + + + @Autowired( required = true ) + public void setLogReader( LogReader logReader ) + { + this.logReader = logReader; + } + + + @Override + public void afterPropertiesSet( ) + { + this.task = new AdminRecapTask( this.tTemplate , this.mailer , this.adminDao , this.logReader ); + this.ticker.registerTask( Frequency.LOW , "Admin recap task" , this.task ); + } + + + @Override + public void destroy( ) + { + this.task = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminRecapTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminRecapTask.java new file mode 100644 index 0000000..2183670 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdminRecapTask.java @@ -0,0 +1,162 @@ +package com.deepclone.lw.beans.admin; + + +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.adata.AdminOverview; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.logs.LogEntry; +import com.deepclone.lw.interfaces.admin.AdminDAO; +import com.deepclone.lw.interfaces.eventlog.LogReader; +import com.deepclone.lw.interfaces.mailer.MailData; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.sqld.admin.AdminRecord; + + + +public class AdminRecapTask + implements Runnable +{ + + private final TransactionTemplate tTemplate; + private final Mailer mailer; + private final AdminDAO adminDao; + private final LogReader logReader; + + private Timestamp isTime; + private List< AdminRecord > admins; + private final Map< Integer , AdminOverview > overviews = new HashMap< Integer , AdminOverview >( ); + private List< LogEntry > logs; + + + public AdminRecapTask( TransactionTemplate tTemplate , Mailer mailer , AdminDAO adminDao , LogReader logReader ) + { + this.tTemplate = tTemplate; + this.mailer = mailer; + this.adminDao = adminDao; + this.logReader = logReader; + } + + + @Override + public void run( ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + checkRecap( ); + } + } ); + + if ( this.isTime == null ) { + return; + } + + String logs = this.buildLogsString( ); + for ( AdminRecord admin : this.admins ) { + if ( !admin.isActive( ) ) { + continue; + } + + String mailContents = this.buildMailContents( admin , logs ); + if ( "".equals( mailContents ) ) { + continue; + } + + MailData mail; + try { + mail = this.mailer.createMail( "en" , "adminRecapMail" , admin.getAddress( ) ); + mail.setData( "contents" , mailContents ); + mail.queue( ); + } catch ( Exception e ) { + continue; + } + } + } + + + private String buildMailContents( AdminRecord admin , String logs ) + { + AdminOverview overview = this.overviews.get( admin.getId( ) ); + if ( overview == null ) { + return ""; + } + + StringBuilder mail = new StringBuilder( ); + if ( overview.getNewMessages( ) > 0 ) { + mail.append( "Unread messages: " ).append( overview.getNewMessages( ) ).append( "\n" ); + } + + int privs = admin.getPrivileges( ); + if ( Privileges.NAME.hasPrivilege( privs ) && overview.getPendingNames( ) > 0 ) { + mail.append( "Unvalidated map names: " ).append( overview.getPendingNames( ) ).append( "\n" ); + } + if ( Privileges.BANH.hasPrivilege( privs ) && overview.getPendingBans( ) > 0 ) { + mail.append( "Pending ban requests: " ).append( overview.getPendingBans( ) ).append( "\n" ); + } + if ( Privileges.BUGT.hasPrivilege( privs ) ) { + boolean showBugs = false; + if ( overview.getPendingBugs( ) > 0 ) { + mail.append( "Bug reports pending validation: " ).append( overview.getPendingBugs( ) ).append( "\n" ); + showBugs = true; + } + if ( overview.getUpdatedBugs( ) > 0 ) { + mail.append( "Updated bug reports: " ).append( overview.getUpdatedBugs( ) ).append( "\n" ); + showBugs = true; + } + if ( showBugs && overview.getOpenBugs( ) > 0 ) { + mail.append( "Open bug reports: " ).append( overview.getOpenBugs( ) ).append( "\n" ); + } + } + if ( !"".equals( logs ) && Privileges.LOGS.hasPrivilege( privs ) ) { + mail.append( "\n" ).append( logs ); + } + + return mail.toString( ); + } + + + private String buildLogsString( ) + { + if ( this.logs.isEmpty( ) ) { + return ""; + } + + StringBuilder builder = new StringBuilder( ).append( "Administrative actions log\n\n" ); + SimpleDateFormat dfmt = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); + for ( LogEntry entry : this.logs ) { + builder.append( dfmt.format( entry.getTimestamp( ) ) ); + builder.append( " - " ).append( entry.getLevel( ).toString( ) ); + builder.append( " - " ).append( entry.getAbout( ) ); + builder.append( " - " ).append( entry.getEntry( ) ); + builder.append( "\n" ); + } + + return builder.toString( ); + } + + + private void checkRecap( ) + { + this.isTime = this.adminDao.isRecapTime( ); + if ( this.isTime == null ) { + return; + } + + this.admins = this.adminDao.listAdministrators( ); + for ( AdminOverview ov : this.adminDao.getOverviews( ) ) { + this.overviews.put( ov.getId( ) , ov ); + } + this.logs = this.logReader.getAdminLogSince( this.isTime ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdministrationBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdministrationBean.java new file mode 100644 index 0000000..0da764d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/AdministrationBean.java @@ -0,0 +1,356 @@ +package com.deepclone.lw.beans.admin; + + +import java.net.InetAddress; +import java.util.List; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.AdminOverviewResponse; +import com.deepclone.lw.cmd.admin.adata.AdminOverview; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.BanRequest; +import com.deepclone.lw.cmd.admin.bans.BanType; +import com.deepclone.lw.cmd.admin.bans.BansSummaryResponse; +import com.deepclone.lw.cmd.admin.bans.ListBansResponse; +import com.deepclone.lw.cmd.admin.bans.RequestBanResponse; +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.admin.su.AddAdministratorResponse; +import com.deepclone.lw.cmd.admin.su.AddAdministratorResponse.AddressError; +import com.deepclone.lw.interfaces.acm.PasswordProhibitedException; +import com.deepclone.lw.interfaces.admin.AdminDAO; +import com.deepclone.lw.interfaces.admin.AdminDAOException; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.admin.BanMailData; +import com.deepclone.lw.interfaces.admin.BansDAO; +import com.deepclone.lw.interfaces.admin.IpBan; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.mailer.MailData; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.sqld.admin.AdminConnection; +import com.deepclone.lw.sqld.admin.AdminRecord; +import com.deepclone.lw.utils.DigestHelper; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; + + + +@Transactional +public class AdministrationBean + implements Administration +{ + + private SystemLogger sysLog; + private AdminDAO adminDao; + private IpBan ipBan; + private BansDAO bansDao; + private Mailer mailer; + + + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.sysLog = logger.getSystemLogger( "Administration" ); + } + + + @Autowired( required = true ) + public void setAdminDao( AdminDAO adminDao ) + { + this.adminDao = adminDao; + } + + + @Autowired( required = true ) + public void setIpBan( IpBan ipBan ) + { + this.ipBan = ipBan; + } + + + @Autowired( required = true ) + public void setBansDao( BansDAO bansDao ) + { + this.bansDao = bansDao; + } + + + @Autowired( required = true ) + public void setMailer( Mailer mailer ) + { + this.mailer = mailer; + } + + + @Override + public AdminRecord getAdmin( int id ) + { + return this.adminDao.getAdmin( id ); + } + + + @Override + public AdminRecord login( EmailAddress address , String challenge , String sha1Hash , String md5Hash , + InetAddress ipAddress ) + { + // Check IP ban + if ( this.ipBan.isBanned( ipAddress ) ) { + return null; + } + + // Find admin record + AdminRecord record = this.adminDao.getAdmin( address ); + if ( record == null ) { + this.ipBan.increaseBanCounter( ipAddress ); + this.sysLog.log( LogLevel.WARNING , + "failed login attempt from unknown address '" + address.getAddress( ) + "'" ).flush( ); + return null; + } + + // Make sure the administrator is active + if ( !record.isActive( ) ) { + this.ipBan.increaseBanCounter( ipAddress ); + this.adminDao.logConnectionAttempt( record.getId( ) , AdminConnection.INACTIVE , ipAddress ); + return null; + } + + // Check password + String eSha1 = DigestHelper.digest( "sha-1" , challenge + " " + record.getpSha1( ) ); + String eMd5 = DigestHelper.digest( "md5" , challenge + " " + record.getpMd5( ) ); + if ( eSha1.equals( sha1Hash ) && eMd5.equals( md5Hash ) ) { + this.adminDao.logConnectionAttempt( record.getId( ) , AdminConnection.SUCCESS , ipAddress ); + return record; + } + + this.ipBan.increaseBanCounter( ipAddress ); + this.adminDao.logConnectionAttempt( record.getId( ) , AdminConnection.PASSWORD , ipAddress ); + return null; + } + + + @Override + public void logout( int adminId ) + { + this.adminDao.logDisconnection( adminId ); + } + + + @Override + public boolean setPassword( int id , String challenge , String sha1Auth , String md5Auth , Password password ) + throws PasswordProhibitedException + { + AdminRecord admin = this.getAdmin( id ); + + // Check challenge response + String eSha1 = DigestHelper.digest( "sha-1" , challenge + " " + admin.getpSha1( ) ); + String eMd5 = DigestHelper.digest( "md5" , challenge + " " + admin.getpMd5( ) ); + if ( ! ( eSha1.equals( sha1Auth ) && eMd5.equals( md5Auth ) ) ) { + return false; + } + + // Try setting the password + if ( !this.adminDao.setPassword( id , password.getSha1( ) , password.getMd5( ) ) ) { + throw new PasswordProhibitedException( ); + } + + return true; + } + + + @Override + public List< AdminRecord > listAdministrators( ) + { + return this.adminDao.listAdministrators( ); + } + + + @Override + public AddAdministratorResponse createAdmin( Administrator creator , String address , String name , int privileges ) + { + int errCode; + try { + this.adminDao.createAdmin( address , name , privileges ); + return new AddAdministratorResponse( creator , false ); + } catch ( AdminDAOException e ) { + errCode = e.getErrorCode( ); + } + + AddressError aError; + ObjectNameError nError; + switch ( errCode ) { + case 1: + aError = AddressError.NOT_FOUND; + nError = null; + break; + case 2: + aError = AddressError.STATUS; + nError = null; + break; + case 3: + aError = null; + nError = ObjectNameError.UNAVAILABLE; + break; + case 4: + aError = AddressError.ALREADY_ADMIN; + nError = null; + break; + default: + throw new RuntimeException( "unknown error code " + errCode ); + } + + return new AddAdministratorResponse( creator , aError , address , nError , name , false , privileges ); + } + + + @Override + public AdminRecord resetPassword( Administrator admin , int identifier ) + { + if ( this.adminDao.resetPassword( identifier , admin.getId( ) ) ) { + return this.adminDao.getAdmin( identifier ); + } + return null; + } + + + @Override + public AdminRecord setPrivileges( Administrator admin , int identifier , Set< Privileges > privileges ) + { + int privs = 0; + for ( Privileges p : privileges ) { + privs = p.grant( privs ); + } + if ( this.adminDao.setPrivileges( identifier , admin.getId( ) , privs ) ) { + return this.adminDao.getAdmin( identifier ); + } + return null; + } + + + @Override + public BansSummaryResponse getBansSummary( Administrator admin ) + { + return new BansSummaryResponse( admin , this.bansDao.getSummary( ) ); + } + + + @Override + public ListBansResponse getBans( Administrator admin , BanType type ) + { + List< BanRequest > bans; + switch ( type ) { + case PENDING: + bans = this.bansDao.getPending( ); + break; + case ARCHIVED: + bans = this.bansDao.getArchived( ); + break; + case VALIDATED: + bans = this.bansDao.getActive( ); + break; + default: + throw new RuntimeException( "unknown ban type " + type ); + } + return new ListBansResponse( admin , type , bans ); + } + + + @Override + public RequestBanResponse requestBan( Administrator admin , String user , boolean empire , String reason ) + { + int errCode; + if ( empire ) { + errCode = this.bansDao.requestBan( admin.getId( ) , user , reason ); + } else { + EmailAddress address = new EmailAddress( user ); + if ( !address.isValid( ) ) { + errCode = 1; + } else { + errCode = this.bansDao.requestBan( admin.getId( ) , address , reason ); + } + } + + if ( errCode == 0 ) { + return new RequestBanResponse( admin , false ); + } + + RequestBanResponse.Error error; + switch ( errCode ) { + case 1: + error = RequestBanResponse.Error.NOT_FOUND; + break; + case 2: + error = RequestBanResponse.Error.BANNED; + break; + default: + throw new RuntimeException( "unknown error code " + errCode ); + } + + return new RequestBanResponse( admin , error , user , empire , reason ); + } + + + @Override + public void rejectBan( Administrator admin , int id , String reason ) + { + this.bansDao.rejectBan( admin.getId( ) , id , reason ); + } + + + @Override + public void confirmBan( Administrator admin , int id ) + { + BanMailData result = this.bansDao.validateBan( admin.getId( ) , id ); + if ( result == null ) { + return; + } + + try { + MailData mail = this.mailer.createMail( result.language , "bannedMail" , result.address ); + mail.setData( "reason" , result.reason ); + mail.queue( ); + } catch ( Exception e ) { + throw new RuntimeException( e ); + } + } + + + @Override + public void liftBan( Administrator admin , int id ) + { + BanMailData result = this.bansDao.liftBan( admin.getId( ) , id ); + if ( result == null ) { + return; + } + + try { + MailData mail = this.mailer.createMail( result.language , "banLiftedMail" , result.address ); + mail.queue( ); + } catch ( Exception e ) { + throw new RuntimeException( e ); + } + } + + + @Override + public AdminOverviewResponse getOverview( Administrator admin ) + { + AdminOverview overview = this.adminDao.getOverview( admin.getId( ) ); + if ( !admin.hasPrivilege( Privileges.NAME ) ) { + overview.setPendingNames( null ); + } + if ( !admin.hasPrivilege( Privileges.BANH ) ) { + overview.setPendingBans( null ); + } + if ( !admin.hasPrivilege( Privileges.BUGT ) ) { + overview.setPendingBugs( null ); + overview.setOpenBugs( null ); + overview.setUpdatedBugs( null ); + } + return new AdminOverviewResponse( admin , overview ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansDAOBean.java new file mode 100644 index 0000000..ec5f1a9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansDAOBean.java @@ -0,0 +1,284 @@ +package com.deepclone.lw.beans.admin; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.admin.bans.ArchivedBanRequest; +import com.deepclone.lw.cmd.admin.bans.BanRequest; +import com.deepclone.lw.cmd.admin.bans.BanType; +import com.deepclone.lw.cmd.admin.bans.SummaryEntry; +import com.deepclone.lw.cmd.admin.bans.ValidatedBanRequest; +import com.deepclone.lw.interfaces.admin.BanMailData; +import com.deepclone.lw.interfaces.admin.BansDAO; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.StoredProc; + + + +public class BansDAOBean + implements BansDAO +{ + private static final String sGetPending = "SELECT * FROM admin.pending_bans ORDER BY requested DESC"; + private static final String sGetArchived = "SELECT * FROM admin.cancelled_bans ORDER BY updated DESC"; + private static final String sGetValidated = "SELECT * FROM admin.active_bans ORDER BY updated DESC"; + private static final String sGetBan = "SELECT * FROM admin.active_bans WHERE account_mail = ?"; + + private static abstract class BanRequestMapper< T extends BanRequest > + implements RowMapper< T > + { + protected void getCommonData( BanRequest br , ResultSet rs ) + throws SQLException + { + br.setId( rs.getInt( "id" ) ); + br.setRequestedById( rs.getInt( "requested_by_id" ) ); + br.setRequestedByName( rs.getString( "requested_by_name" ) ); + br.setAccountId( rs.getInt( "account_id" ) ); + br.setAccountMail( rs.getString( "account_mail" ) ); + br.setTimestamp( rs.getTimestamp( "requested" ) ); + br.setReason( rs.getString( "reason" ) ); + } + } + + private SimpleJdbcTemplate dTemplate; + + private final BanRequestMapper< BanRequest > mPending; + private final BanRequestMapper< BanRequest > mArchived; + private final BanRequestMapper< BanRequest > mValidated; + private final RowMapper< Boolean > mBoolean; + + private StoredProc fRequestBanAddress; + private StoredProc fRequestBanEmpire; + private StoredProc fRejectBan; + private StoredProc fValidateBan; + private StoredProc fLiftBan; + + + public BansDAOBean( ) + { + this.mPending = new BanRequestMapper< BanRequest >( ) { + @Override + public BanRequest mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BanRequest br = new BanRequest( ); + this.getCommonData( br , rs ); + return br; + } + }; + this.mArchived = new BanRequestMapper< BanRequest >( ) { + @Override + public BanRequest mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + ArchivedBanRequest br = new ArchivedBanRequest( ); + this.getCommonData( br , rs ); + br.setUpdate( rs.getTimestamp( "updated" ) ); + br.setExpired( rs.getBoolean( "expired" ) ); + if ( !br.isExpired( ) ) { + br.setRejectedById( rs.getInt( "rejected_by_id" ) ); + br.setRejectedByName( rs.getString( "rejected_by_name" ) ); + br.setRejectionReason( rs.getString( "rejection_reason" ) ); + } + return br; + } + }; + this.mValidated = new BanRequestMapper< BanRequest >( ) { + @Override + public BanRequest mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + ValidatedBanRequest br = new ValidatedBanRequest( ); + this.getCommonData( br , rs ); + br.setUpdate( rs.getTimestamp( "updated" ) ); + br.setRedeemable( rs.getBoolean( "redeemable" ) ); + br.setValidatedById( rs.getInt( "validated_by_id" ) ); + br.setValidatedByName( rs.getString( "validated_by_name" ) ); + return br; + } + }; + this.mBoolean = new RowMapper< Boolean >( ) { + @Override + public Boolean mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return rs.getBoolean( 1 ); + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fRequestBanAddress = new StoredProc( dataSource , "admin" , "request_ban_on_address" ); + this.fRequestBanAddress.addParameter( "admin_id" , Types.INTEGER ); + this.fRequestBanAddress.addParameter( "user_address" , Types.VARCHAR ); + this.fRequestBanAddress.addParameter( "reason" , Types.VARCHAR ); + this.fRequestBanAddress.addOutput( "err_code" , Types.INTEGER ); + + this.fRequestBanEmpire = new StoredProc( dataSource , "admin" , "request_ban_on_empire" ); + this.fRequestBanEmpire.addParameter( "admin_id" , Types.INTEGER ); + this.fRequestBanEmpire.addParameter( "user_address" , Types.VARCHAR ); + this.fRequestBanEmpire.addParameter( "reason" , Types.VARCHAR ); + this.fRequestBanEmpire.addOutput( "err_code" , Types.INTEGER ); + + this.fRejectBan = new StoredProc( dataSource , "admin" , "reject_ban_request" ); + this.fRejectBan.addParameter( "admin_id" , Types.INTEGER ); + this.fRejectBan.addParameter( "request_id" , Types.INTEGER ); + this.fRejectBan.addParameter( "reason" , Types.VARCHAR ); + + this.fValidateBan = new StoredProc( dataSource , "admin" , "confirm_ban_request" ); + this.fValidateBan.addParameter( "admin_id" , Types.INTEGER ); + this.fValidateBan.addParameter( "request_id" , Types.INTEGER ); + this.fValidateBan.addOutput( "success" , Types.BOOLEAN ); + this.fValidateBan.addOutput( "addr" , Types.VARCHAR ); + this.fValidateBan.addOutput( "lang" , Types.VARCHAR ); + this.fValidateBan.addOutput( "r_txt" , Types.VARCHAR ); + + this.fLiftBan = new StoredProc( dataSource , "admin" , "lift_ban" ); + this.fLiftBan.addParameter( "admin_id" , Types.INTEGER ); + this.fLiftBan.addParameter( "request_id" , Types.INTEGER ); + this.fLiftBan.addOutput( "success" , Types.BOOLEAN ); + this.fLiftBan.addOutput( "addr" , Types.VARCHAR ); + this.fLiftBan.addOutput( "lang" , Types.VARCHAR ); + } + + + @Override + public List< SummaryEntry > getSummary( ) + { + List< SummaryEntry > result = new ArrayList< SummaryEntry >( 3 ); + final String names[] = { + "pending" , "cancelled" , "active" + }; + + for ( int i = 0 ; i < 3 ; i++ ) { + long count = this.dTemplate.queryForLong( "SELECT count(*) FROM admin." + names[ i ] + "_bans" ); + result.add( new SummaryEntry( BanType.values( )[ i ] , count ) ); + } + + return result; + } + + + @Override + public List< BanRequest > getPending( ) + { + return this.dTemplate.query( sGetPending , this.mPending ); + } + + + @Override + public List< BanRequest > getArchived( ) + { + return this.dTemplate.query( sGetArchived , this.mArchived ); + } + + + @Override + public List< BanRequest > getActive( ) + { + return this.dTemplate.query( sGetValidated , this.mValidated ); + } + + + private int requestBan( StoredProc fRequestBan , int administrator , String address , String reason ) + { + return (Integer) fRequestBan.execute( administrator , address , reason ).get( "err_code" ); + } + + + @Override + public int requestBan( int administrator , EmailAddress address , String reason ) + { + return this.requestBan( this.fRequestBanAddress , administrator , address.getAddress( ) , reason ); + } + + + @Override + public int requestBan( int administrator , String empire , String reason ) + { + return this.requestBan( this.fRequestBanEmpire , administrator , empire , reason ); + } + + + @Override + public void rejectBan( int administrator , int requestId , String reason ) + { + this.fRejectBan.execute( administrator , requestId , reason ); + } + + + @Override + public BanMailData validateBan( int administrator , int requestId ) + { + Map< String , Object > result = this.fValidateBan.execute( administrator , requestId ); + boolean success = (Boolean) result.get( "success" ); + if ( !success ) { + return null; + } + return new BanMailData( (String) result.get( "addr" ) , (String) result.get( "lang" ) , (String) result + .get( "r_txt" ) ); + } + + + @Override + public BanMailData liftBan( int administrator , int requestId ) + { + Map< String , Object > result = this.fLiftBan.execute( administrator , requestId ); + boolean success = (Boolean) result.get( "success" ); + if ( !success ) { + return null; + } + return new BanMailData( (String) result.get( "addr" ) , (String) result.get( "lang" ) ); + } + + + @Override + public void expireBanRequests( ) + { + this.dTemplate.getJdbcOperations( ).execute( "SELECT admin.expire_ban_requests( )" ); + } + + + @Override + public void expireWarnings( ) + { + this.dTemplate.getJdbcOperations( ).execute( "SELECT admin.expire_warnings( )" ); + } + + + @Override + public boolean finaliseBan( ) + { + String sql = "SELECT admin.delete_banned_empires( )"; + return this.dTemplate.queryForObject( sql , this.mBoolean ); + } + + + @Override + public ValidatedBanRequest getActiveBan( EmailAddress address ) + { + try { + return (ValidatedBanRequest) this.dTemplate.queryForObject( sGetBan , this.mValidated , address + .getAddress( ) ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansProcessorBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansProcessorBean.java new file mode 100644 index 0000000..a04af93 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansProcessorBean.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.beans.admin; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.admin.BansDAO; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class BansProcessorBean + implements InitializingBean , DisposableBean +{ + + private Ticker ticker; + private BansProcessorTask task; + private TransactionTemplate tTemplate; + private BansDAO bansDao; + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Autowired( required = true ) + public void setBansDao( BansDAO bansDao ) + { + this.bansDao = bansDao; + } + + + @Override + public void afterPropertiesSet( ) + throws Exception + { + this.task = new BansProcessorTask( this.tTemplate , this.bansDao ); + this.ticker.registerTask( Frequency.LOW , "Bans processor" , this.task ); + } + + + @Override + public void destroy( ) + throws Exception + { + this.task = null; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansProcessorTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansProcessorTask.java new file mode 100644 index 0000000..72c6077 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/BansProcessorTask.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.beans.admin; + + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.admin.BansDAO; + + + +class BansProcessorTask + implements Runnable +{ + + private final TransactionTemplate tTemplate; + private final BansDAO bansDao; + + + public BansProcessorTask( TransactionTemplate tTemplate , BansDAO bansDao ) + { + this.tTemplate = tTemplate; + this.bansDao = bansDao; + } + + + @Override + public void run( ) + { + this.expire( ); + while ( this.finaliseBans( ) ) { + // EMPTY + } + } + + + private boolean finaliseBans( ) + { + return this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + return bansDao.finaliseBan( ); + } + } ); + } + + + private void expire( ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + bansDao.expireBanRequests( ); + bansDao.expireWarnings( ); + } + } ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/IpBanBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/IpBanBean.java new file mode 100644 index 0000000..841c90d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/admin/IpBanBean.java @@ -0,0 +1,87 @@ +package com.deepclone.lw.beans.admin; + + +import java.net.InetAddress; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.deepclone.lw.interfaces.admin.IpBan; + + + +/** + * The IP Ban bean specifies a private map container to hold IP Address ban entries. It also + * provides a public method to check whether a specified IP address is banned and a public method to + * increaes the counter of a given IP address. + * + * @author tseeker + * + */ +public class IpBanBean + implements IpBan +{ + + /** + * Static class with the date the ban was last increased and the counter of times increased. + */ + private static class BanEntry + { + public Date lastIncrease = new Date( ); + public int counter = 1; + } + + /** Private HashMap containing current IP addresses and their associated BanEntry's */ + private final Map< InetAddress , BanEntry > entries = new HashMap< InetAddress , BanEntry >( ); + + + /** + * Checks if an IP address is banned. An address is banned if an entry already exists for it, if + * the ban's duration has been reset in the last hour and the IP address's counter has been + * increased 3 or more times. If the ban is more than an hour old it is removed. + */ + @Override + public boolean isBanned( InetAddress address ) + { + synchronized ( this.entries ) { + BanEntry entry = this.entries.get( address ); + if ( entry == null ) { + return false; + } + + if ( entry.lastIncrease.before( new Date( new Date( ).getTime( ) - 60 * 60 * 1000 ) ) ) { + this.entries.remove( address ); + return false; + } + + if ( entry.counter < 3 ) { + return false; + } + + entry.lastIncrease = new Date( ); + return true; + } + } + + + /** + * If the given IP address does not already have an entry associated with it, one is created for + * it. If it does, the entries counter is increased by 1. + */ + @Override + public void increaseBanCounter( InetAddress address ) + { + synchronized ( this.entries ) { + BanEntry entry = this.entries.get( address ); + if ( entry == null ) { + entry = new BanEntry( ); + this.entries.put( address , entry ); + return; + } + + entry.counter++; + entry.lastIncrease = new Date( ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/BoolPreferenceType.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/BoolPreferenceType.java new file mode 100644 index 0000000..c379f10 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/BoolPreferenceType.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.beans.prefs; + + +class BoolPreferenceType + extends PreferenceTypeImpl< Boolean > +{ + + public BoolPreferenceType( ) + { + super( Boolean.class ); + } + + + @Override + public String convert( Object value ) + { + Boolean v = (Boolean) value; + return ( v != null && v ) ? "1" : "0"; + } + + + @Override + public Boolean valueOf( String dbValue , Class< Boolean > type ) + { + return "1".equals( dbValue ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/DefaultPreferencesBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/DefaultPreferencesBean.java new file mode 100644 index 0000000..3791181 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/DefaultPreferencesBean.java @@ -0,0 +1,79 @@ +package com.deepclone.lw.beans.prefs; + + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.cmd.player.gdata.MailPreference; +import com.deepclone.lw.cmd.player.gdata.MapSize; +import com.deepclone.lw.interfaces.prefs.PreferenceDefinitions; + + + +public class DefaultPreferencesBean + implements InitializingBean +{ + + private PreferenceDefinitions pDefs; + private PreferenceTypesRegistryBean registry; + + + @Autowired( required = true ) + public void setTypesRegistry( PreferenceTypesRegistryBean registry ) + { + this.registry = registry; + } + + + @Autowired( required = true ) + public void setPreferenceDefinitions( PreferenceDefinitions preferenceDefinitions ) + { + this.pDefs = preferenceDefinitions; + } + + + @Override + public void afterPropertiesSet( ) + throws Exception + { + this.createTypes( ); + + this.pDefs.registerGroup( "display" , "pgDisplay" ); + this.pDefs.registerPreference( "useRLTime" , "display" , "pUseRLTime" , "pUseRLTimeDescription" , + (Boolean) false ); + + this.pDefs.registerGroup( "map" , "pgMap" ); + this.pDefs.registerPreference( "mapX" , "map" , "pMapX" , "pMapXDescription" , (Integer) 0 ); + this.pDefs.registerPreference( "mapY" , "map" , "pMapY" , "pMapYDescription" , (Integer) 0 ); + this.pDefs.registerPreference( "mapSize" , "map" , "pMapSize" , "pMapSizeDescription" , MapSize.MEDIUM ); + + this.pDefs.registerGroup( "mail" , "pgMail" ); + this.pDefs.registerPreference( "mailOnPM" , "mail" , "pMailOnPM" , "pMailOnPMDescription" , + MailPreference.INSTANT ); + this.pDefs.registerPreference( "mailOnAlliance" , "mail" , "pMailOnAlliance" , "pMailOnAllianceDescription" , + MailPreference.DAILY_RECAP ); + this.pDefs.registerPreference( "mailOnIM" , "mail" , "pMailOnIM" , "pMailOnIMDescription" , + MailPreference.DAILY_RECAP ); + this.pDefs.registerPreference( "mailOnAdmin" , "mail" , "pMailOnAdmin" , "pMailOnAdminDescription" , + MailPreference.INSTANT ); + } + + + private void createTypes( ) + { + EnumPreferenceType< MapSize > mapSizeType; + mapSizeType = new EnumPreferenceType< MapSize >( MapSize.class ); + mapSizeType.setTranslation( MapSize.SMALL , "mapSizeSmall" ); + mapSizeType.setTranslation( MapSize.MEDIUM , "mapSizeMedium" ); + mapSizeType.setTranslation( MapSize.LARGE , "mapSizeLarge" ); + this.registry.register( mapSizeType ); + + EnumPreferenceType< MailPreference > mailPrefType; + mailPrefType = new EnumPreferenceType< MailPreference >( MailPreference.class ); + mailPrefType.setTranslation( MailPreference.NO_MAIL , "mailPrefNo" ); + mailPrefType.setTranslation( MailPreference.DAILY_RECAP , "mailPrefRecap" ); + mailPrefType.setTranslation( MailPreference.INSTANT , "mailPrefInstant" ); + this.registry.register( mailPrefType ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/EnumPreferenceType.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/EnumPreferenceType.java new file mode 100644 index 0000000..6b221bf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/EnumPreferenceType.java @@ -0,0 +1,63 @@ +package com.deepclone.lw.beans.prefs; + + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + + + +public class EnumPreferenceType< T > + extends PreferenceTypeImpl< T > +{ + + private SortedMap< T , String > choices = new TreeMap< T , String >( ); + + + public EnumPreferenceType( Class< T > type ) + { + super( type ); + if ( !type.isEnum( ) ) { + throw new IllegalArgumentException( "Enumerated type expected" ); + } + } + + + @Override + public Map< String , String > getChoices( ) + { + Map< String , String > r = new LinkedHashMap< String , String >( ); + for ( Map.Entry< T , String > entry : this.choices.entrySet( ) ) { + r.put( this.convert( entry.getKey( ) ) , entry.getValue( ) ); + } + return r; + } + + + public void setTranslation( T value , String textId ) + { + this.choices.put( value , textId ); + } + + + @Override + @SuppressWarnings( "unchecked" ) + public String convert( Object value ) + { + return ( (T) value ).toString( ); + } + + + @SuppressWarnings( "unchecked" ) + @Override + public T valueOf( String dbValue , Class< T > type ) + { + try { + return (T) type.getMethod( "valueOf" , String.class ).invoke( null , dbValue ); + } catch ( Exception e ) { + throw new RuntimeException( e ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/IntPreferenceType.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/IntPreferenceType.java new file mode 100644 index 0000000..2ba13bf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/IntPreferenceType.java @@ -0,0 +1,31 @@ +package com.deepclone.lw.beans.prefs; + + +class IntPreferenceType + extends PreferenceTypeImpl< Integer > +{ + + public IntPreferenceType( ) + { + super( Integer.class ); + } + + + @Override + public String convert( Object value ) + { + return ( value == null ) ? "0" : ( (Integer) value ).toString( ); + } + + + @Override + public Integer valueOf( String dbValue , Class< Integer > type ) + { + try { + return Integer.parseInt( dbValue ); + } catch ( NumberFormatException e ) { + return null; + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceDefinitionsBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceDefinitionsBean.java new file mode 100644 index 0000000..05a1603 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceDefinitionsBean.java @@ -0,0 +1,278 @@ +package com.deepclone.lw.beans.prefs; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.player.gdata.account.PrefCategory; +import com.deepclone.lw.cmd.player.gdata.account.PrefChoice; +import com.deepclone.lw.cmd.player.gdata.account.PrefType; +import com.deepclone.lw.cmd.player.gdata.account.PrefValue; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.prefs.PreferenceDefinitionException; +import com.deepclone.lw.interfaces.prefs.PreferenceDefinitions; +import com.deepclone.lw.interfaces.prefs.PreferenceType; +import com.deepclone.lw.interfaces.prefs.PreferenceTypesRegistry; +import com.deepclone.lw.utils.StoredProc; + + + +public class PreferenceDefinitionsBean + implements PreferenceDefinitions +{ + private static class PrefDefRecord + { + final String groupName; + final String groupDisplay; + final String name; + final String dName; + final String dDescription; + final String type; + final String value; + + + public PrefDefRecord( ResultSet rs ) + throws SQLException + { + this.groupName = rs.getString( "group_name" ); + this.groupDisplay = rs.getString( "group_display" ); + this.name = rs.getString( "name" ); + this.dName = rs.getString( "d_name" ); + this.dDescription = rs.getString( "d_desc" ); + this.type = rs.getString( "java_type" ); + this.value = rs.getString( "default_value" ); + } + } + + private TransactionTemplate tTemplate; + private PreferenceTypesRegistry registry; + private SystemLogger logger; + private Translator translator; + + private SimpleJdbcTemplate dTemplate; + + private StoredProc uocGroup; + private StoredProc uocDef; + private StoredProc fSetDefault; + + private final RowMapper< PrefDefRecord > mPrefDef; + + + public PreferenceDefinitionsBean( ) + { + this.mPrefDef = new RowMapper< PrefDefRecord >( ) { + @Override + public PrefDefRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return new PrefDefRecord( rs ); + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.uocGroup = new StoredProc( dataSource , "defs" , "uoc_preference_group" ); + this.uocGroup.addParameter( "name" , Types.VARCHAR ); + this.uocGroup.addParameter( "display" , Types.VARCHAR ); + this.uocGroup.addOutput( "success" , Types.BOOLEAN ); + + this.uocDef = new StoredProc( dataSource , "defs" , "uoc_preference" ); + this.uocDef.addParameter( "g_name" , Types.VARCHAR ); + this.uocDef.addParameter( "p_name" , Types.VARCHAR ); + this.uocDef.addParameter( "d_name" , Types.VARCHAR ); + this.uocDef.addParameter( "d_desc" , Types.VARCHAR ); + this.uocDef.addParameter( "j_type" , Types.VARCHAR ); + this.uocDef.addParameter( "d_val" , Types.VARCHAR ); + this.uocDef.addOutput( "err_code" , Types.INTEGER ); + + this.fSetDefault = new StoredProc( dataSource , "defs" , "set_preference_default" ); + this.fSetDefault.addParameter( "admin_id" , Types.INTEGER ); + this.fSetDefault.addParameter( "pref_name" , Types.VARCHAR ); + this.fSetDefault.addParameter( "default_value" , Types.VARCHAR ); + } + + + @Autowired( required = true ) + public void setTypesRegistry( PreferenceTypesRegistry registry ) + { + this.registry = registry; + } + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager transactionManager ) + { + this.tTemplate = new TransactionTemplate( transactionManager ); + } + + + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger.getSystemLogger( "PreferenceDefinitions" ); + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public void registerGroup( final String name , final String displayName ) + throws PreferenceDefinitionException + { + boolean success = this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + return (Boolean) uocGroup.execute( name , displayName ).get( "success" ); + } + } ); + if ( !success ) { + throw new PreferenceDefinitionException( PreferenceDefinitionException.Error.MISSING_STRING ); + } + this.logger.log( LogLevel.DEBUG , "registered preference group '" + name + "'" ); + } + + + @Override + public void registerPreference( final String name , final String group , final String displayName , + final String displayDescription , final Object defaultValue ) + throws PreferenceDefinitionException + { + final Class< ? > type = defaultValue.getClass( ); + final PreferenceType< ? > pType = this.registry.getType( type ); + + int errCode = this.tTemplate.execute( new TransactionCallback< Integer >( ) { + @Override + public Integer doInTransaction( TransactionStatus status ) + { + return (Integer) uocDef.execute( group , name , displayName , displayDescription , + type.getSimpleName( ) , pType.convert( defaultValue ) ).get( "err_code" ); + } + } ); + + switch ( errCode ) { + case 0: + break; + case 1: + throw new PreferenceDefinitionException( PreferenceDefinitionException.Error.MISSING_GROUP ); + case 2: + throw new PreferenceDefinitionException( PreferenceDefinitionException.Error.MISSING_STRING ); + case 3: + throw new PreferenceDefinitionException( PreferenceDefinitionException.Error.INVALID_TYPE ); + default: + throw new RuntimeException( "unknown error code " + errCode ); + } + + this.logger.log( LogLevel.DEBUG , "registered preference '" + name + "' in group '" + group + "'" ); + } + + + private String translate( String strName ) + { + try { + return this.translator.translate( "en" , strName ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + } + + + @Override + @Transactional + public List< PrefCategory > getDefaults( ) + { + List< PrefCategory > categories = new LinkedList< PrefCategory >( ); + PrefCategory currentCategory = null; + String catName = ""; + for ( PrefDefRecord def : this.dTemplate.query( "SELECT * FROM defs.preferences_view" , this.mPrefDef ) ) { + // Make sure we're modifying the right category + if ( currentCategory == null || !def.groupName.equals( catName ) ) { + currentCategory = new PrefCategory( ); + catName = def.groupName; + currentCategory.setName( this.translate( def.groupDisplay ) ); + categories.add( currentCategory ); + } + + // Add value + PrefValue value = new PrefValue( ); + value.setId( def.name ); + value.setName( this.translate( def.dName ) ); + value.setDescription( this.translate( def.dDescription ) ); + value.setValue( def.value ); + + PreferenceType< ? > dType = this.registry.getType( def.type ); + if ( dType.getType( ) == String.class ) { + value.setType( PrefType.STRING ); + } else if ( dType.getType( ) == Integer.class ) { + value.setType( PrefType.INTEGER ); + } else if ( dType.getType( ) == Boolean.class ) { + value.setType( PrefType.BOOLEAN ); + } else { + Map< String , String > choices = dType.getChoices( ); + List< PrefChoice > cList = new LinkedList< PrefChoice >( ); + for ( Map.Entry< String , String > entry : choices.entrySet( ) ) { + cList.add( new PrefChoice( entry.getKey( ) , this.translate( entry.getValue( ) ) ) ); + } + value.setType( PrefType.CHOICE ); + value.setChoices( cList ); + } + + currentCategory.addValue( value ); + } + + return categories; + } + + + @Override + @Transactional + public void setDefault( Administrator admin , String preference , String value ) + { + String sql = "SELECT * FROM defs.preferences_view WHERE name = ?"; + PrefDefRecord def; + try { + def = this.dTemplate.queryForObject( sql , this.mPrefDef , preference ); + } catch ( EmptyResultDataAccessException e ) { + return; + } + + PreferenceType< ? > pType = this.registry.getType( def.type ); + Object inObject = pType.valueOf( value ); + if ( inObject != null ) { + String dbValue = pType.convert( inObject ); + this.fSetDefault.execute( admin.getId( ) , preference , dbValue ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceTypeImpl.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceTypeImpl.java new file mode 100644 index 0000000..7f9fc98 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceTypeImpl.java @@ -0,0 +1,42 @@ +package com.deepclone.lw.beans.prefs; + + +import java.util.Map; + +import com.deepclone.lw.interfaces.prefs.PreferenceType; + + + +abstract class PreferenceTypeImpl< T > + implements PreferenceType< T > +{ + + private final Class< T > type; + + + public PreferenceTypeImpl( Class< T > type ) + { + this.type = type; + } + + + @Override + public Object valueOf( String inValue ) + { + return this.valueOf( inValue , this.type ); + } + + + @Override + public Map< String , String > getChoices( ) + { + return null; + } + + + public Class< T > getType( ) + { + return type; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceTypesRegistryBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceTypesRegistryBean.java new file mode 100644 index 0000000..e10ff59 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferenceTypesRegistryBean.java @@ -0,0 +1,66 @@ +package com.deepclone.lw.beans.prefs; + + +import java.util.HashMap; +import java.util.Map; + +import com.deepclone.lw.interfaces.prefs.PreferenceType; +import com.deepclone.lw.interfaces.prefs.PreferenceTypesRegistry; + + + +public class PreferenceTypesRegistryBean + implements PreferenceTypesRegistry +{ + + private final Map< String , PreferenceType< ? >> types = new HashMap< String , PreferenceType< ? > >( ); + + + public PreferenceTypesRegistryBean( ) + { + this.register( new StringPreferenceType( ) ); + this.register( new IntPreferenceType( ) ); + this.register( new BoolPreferenceType( ) ); + } + + + void register( PreferenceType< ? > type ) + { + String name = type.getType( ).getSimpleName( ); + synchronized ( this.types ) { + if ( this.types.containsKey( name ) ) { + throw new IllegalArgumentException( "Type '" + name + "' already registered." ); + } + this.types.put( name , type ); + } + } + + + @Override + @SuppressWarnings( "unchecked" ) + public < T > PreferenceType< T > getType( Class< T > jType ) + { + PreferenceType< T > type; + synchronized ( this.types ) { + type = (PreferenceType< T >) this.types.get( jType.getSimpleName( ) ); + } + if ( type == null ) { + throw new IllegalArgumentException( "Type '" + jType.getSimpleName( ) + "' is not registered." ); + } + return type; + } + + + @Override + public PreferenceType< ? > getType( String typeName ) + { + PreferenceType< ? > type; + synchronized ( this.types ) { + type = (PreferenceType< ? >) this.types.get( typeName ); + } + if ( type == null ) { + throw new IllegalArgumentException( "Type '" + typeName + "' is not registered." ); + } + return type; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferencesDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferencesDAOBean.java new file mode 100644 index 0000000..6387587 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/PreferencesDAOBean.java @@ -0,0 +1,164 @@ +package com.deepclone.lw.beans.prefs; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.interfaces.prefs.AccountPreferences; +import com.deepclone.lw.interfaces.prefs.Preference; +import com.deepclone.lw.interfaces.prefs.PreferenceGroup; +import com.deepclone.lw.interfaces.prefs.PreferenceType; +import com.deepclone.lw.interfaces.prefs.PreferenceTypesRegistry; +import com.deepclone.lw.interfaces.prefs.PreferencesDAO; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.utils.StoredProc; + + + +public class PreferencesDAOBean + implements PreferencesDAO +{ + + private SimpleJdbcTemplate dTemplate; + private PreferenceTypesRegistry registry; + private StoredProc fReset; + private StoredProc fSetPref; + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fReset = new StoredProc( dataSource , "users" , "reset_preferences" ); + this.fReset.addParameter( "a_id" , Types.INTEGER ); + + this.fSetPref = new StoredProc( dataSource , "users" , "set_preference" ); + this.fSetPref.addParameter( "a_id" , Types.INTEGER ); + this.fSetPref.addParameter( "p_name" , Types.VARCHAR ); + this.fSetPref.addParameter( "p_value" , Types.VARCHAR ); + } + + + @Autowired( required = true ) + public void setTypesRegistry( PreferenceTypesRegistry registry ) + { + this.registry = registry; + } + + + @Override + public AccountPreferences getPreferences( int accountId ) + { + String sql = "SELECT * FROM users.preferences_view WHERE account_id = ?"; + RowMapper< Map< String , String > > mapper = new RowMapper< Map< String , String > >( ) { + + @Override + public Map< String , String > mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + final String[] names = { + "group_name" , "group_i18n_name" , "pref_name" , "pref_i18n_name" , "pref_i18n_description" , + "pref_type" , "value" + }; + Map< String , String > data = new HashMap< String , String >( ); + for ( String n : names ) { + data.put( n , rs.getString( n ) ); + } + return data; + } + + }; + + List< PreferenceGroup > groups = new LinkedList< PreferenceGroup >( ); + Map< String , String > prefGroups = new HashMap< String , String >( ); + String last = null; + PreferenceGroup lg = null; + for ( Map< String , String > data : this.dTemplate.query( sql , mapper , accountId ) ) { + String gName = data.get( "group_name" ); + if ( last == null || !last.equals( gName ) ) { + lg = new PreferenceGroup( gName , data.get( "group_i18n_name" ) ); + groups.add( lg ); + last = gName; + } + + String pName = data.get( "pref_name" ); + prefGroups.put( pName , gName ); + + PreferenceType< ? > prefType = this.registry.getType( data.get( "pref_type" ) ); + + new Preference( pName , lg , data.get( "pref_i18n_name" ) , data.get( "pref_i18n_description" ) , prefType , + data.get( "value" ) ); + } + + return new AccountPreferences( groups , prefGroups ); + } + + + @Override + public AccountPreferences getPreferences( Account account ) + { + return this.getPreferences( account.getId( ) ); + } + + + @Override + public void setPreferences( Account account , Map< String , String > values ) + { + String sql = "SELECT pref_name , pref_type FROM users.preferences_view WHERE account_id = ?"; + RowMapper< Map< String , String > > mapper = new RowMapper< Map< String , String > >( ) { + + @Override + public Map< String , String > mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + final String[] names = { + "pref_name" , "pref_type" + }; + Map< String , String > data = new HashMap< String , String >( ); + for ( String n : names ) { + data.put( n , rs.getString( n ) ); + } + return data; + } + + }; + + for ( Map< String , String > def : this.dTemplate.query( sql , mapper , account.getId( ) ) ) { + String pName = def.get( "pref_name" ); + PreferenceType< ? > pType = this.registry.getType( def.get( "pref_type" ) ); + + String inValue = values.get( pName ); + if ( inValue == null ) { + continue; + } + + Object inObject = pType.valueOf( inValue ); + if ( inObject == null ) { + continue; + } + + String dbValue = pType.convert( inObject ); + this.fSetPref.execute( account.getId( ) , pName , dbValue ); + } + } + + + @Override + public void resetPreferences( Account account ) + { + this.fReset.execute( account.getId( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/StringPreferenceType.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/StringPreferenceType.java new file mode 100644 index 0000000..72c1af9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/java/com/deepclone/lw/beans/prefs/StringPreferenceType.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.beans.prefs; + + +class StringPreferenceType + extends PreferenceTypeImpl< String > +{ + + public StringPreferenceType( ) + { + super( String.class ); + } + + + @Override + public String convert( Object value ) + { + return ( value == null ) ? "" : (String) value; + } + + + @Override + public String valueOf( String dbValue , Class< String > type ) + { + return dbValue; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts-beans.xml new file mode 100644 index 0000000..bd7ec9b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts-beans.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/account-cleanup-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/account-cleanup-bean.xml new file mode 100644 index 0000000..e1c6a61 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/account-cleanup-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/account-management-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/account-management-bean.xml new file mode 100644 index 0000000..6062c6a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/account-management-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/admin-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/admin-dao-bean.xml new file mode 100644 index 0000000..8640f69 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/admin-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/admin-recap-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/admin-recap-bean.xml new file mode 100644 index 0000000..4d609ab --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/admin-recap-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/administration-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/administration-bean.xml new file mode 100644 index 0000000..1039d63 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/administration-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/bans-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/bans-dao-bean.xml new file mode 100644 index 0000000..f654c86 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/bans-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/bans-processor-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/bans-processor-bean.xml new file mode 100644 index 0000000..4167e63 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/bans-processor-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/default-preferences-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/default-preferences-bean.xml new file mode 100644 index 0000000..e7bca93 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/default-preferences-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/ip-ban-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/ip-ban-bean.xml new file mode 100644 index 0000000..2c70cf8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/ip-ban-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/preference-definitions-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/preference-definitions-bean.xml new file mode 100644 index 0000000..73dfc57 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/preference-definitions-bean.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/preferences-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/preferences-dao-bean.xml new file mode 100644 index 0000000..42926c3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/preferences-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/quit-processor-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/quit-processor-bean.xml new file mode 100644 index 0000000..a571d09 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/quit-processor-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/requests-expiration-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/requests-expiration-bean.xml new file mode 100644 index 0000000..f4525e4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/requests-expiration-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/user-session-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/user-session-dao-bean.xml new file mode 100644 index 0000000..0c7e785 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/user-session-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/users-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/users-dao-bean.xml new file mode 100644 index 0000000..817940f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/users-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/vacation-processor-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/vacation-processor-bean.xml new file mode 100644 index 0000000..2c67fea --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-accounts/src/main/resources/configuration/accounts/vacation-processor-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.project new file mode 100644 index 0000000..6701380 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-bt + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..1e525bc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Tue Apr 13 08:30:06 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..12bb0a0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Tue Apr 13 08:30:04 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/pom.xml new file mode 100644 index 0000000..35ab5e4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/pom.xml @@ -0,0 +1,25 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + + + + + com.thoughtworks.xstream + xstream + ${com.thoughtworks.xstream.version} + jar + + + + + com.deepclone.lw + legacyworlds-server-beans-bt + 5.99.1 + Legacy Worlds bug tracking system + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/AdminBugsBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/AdminBugsBean.java new file mode 100644 index 0000000..bdb6dc4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/AdminBugsBean.java @@ -0,0 +1,179 @@ +package com.deepclone.lw.beans.bt; + + +import java.util.Iterator; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.bt.BugsSummaryResponse; +import com.deepclone.lw.cmd.admin.bt.GetSnapshotResponse; +import com.deepclone.lw.cmd.admin.bt.ListBugsResponse; +import com.deepclone.lw.cmd.admin.bt.MergeError; +import com.deepclone.lw.cmd.admin.bt.MergeReportsResponse; +import com.deepclone.lw.cmd.admin.bt.PostCommentResponse; +import com.deepclone.lw.cmd.admin.bt.ReportBugResponse; +import com.deepclone.lw.cmd.admin.bt.ViewBugResponse; +import com.deepclone.lw.cmd.bt.data.BugEvent; +import com.deepclone.lw.cmd.bt.data.BugEventType; +import com.deepclone.lw.cmd.bt.data.BugReport; +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.bt.BugsDAO; + + + +@Transactional +public class AdminBugsBean + implements AdminBugs +{ + + private BugsDAO bugsDao; + + + @Autowired( required = true ) + public void setBugsDao( BugsDAO bugsDao ) + { + this.bugsDao = bugsDao; + } + + + private List< BugEvent > getBugEvents( long bugId ) + { + List< BugEvent > events = this.bugsDao.getEvents( bugId ); + Iterator< BugEvent > it = events.iterator( ); + BugStatus status = BugStatus.PENDING; + boolean pub = false; + while ( it.hasNext( ) ) { + BugEvent event = it.next( ); + if ( event.getType( ) == BugEventType.STATUS ) { + if ( event.getStatus( ) == status ) { + it.remove( ); + } else { + status = event.getStatus( ); + } + } else if ( event.getType( ) == BugEventType.VISIBILITY ) { + if ( event.getVisible( ) == pub ) { + it.remove( ); + } else { + pub = event.getVisible( ); + } + } + } + + return events; + } + + + @Override + public BugsSummaryResponse getSummary( Administrator admin ) + { + long pending = this.bugsDao.countReports( admin , BugStatus.PENDING , false ); + long open = this.bugsDao.countReports( admin , BugStatus.OPEN , false ); + long own = this.bugsDao.countReports( admin , null , true ); + long updated = this.bugsDao.countUpdatedReports( admin ); + long total = this.bugsDao.countReports( admin , null , false ); + return new BugsSummaryResponse( admin , pending , open , own , updated , total ); + } + + + @Override + public ListBugsResponse getBugs( Administrator admin , BugStatus status , boolean ownOnly , long first , int count ) + { + long nBugs = this.bugsDao.countReports( admin , status , ownOnly ); + List< BugReport > bugs = this.bugsDao.getReports( admin , status , ownOnly , first , count ); + return new ListBugsResponse( admin , status , ownOnly , first , count , nBugs , bugs ); + } + + + @Override + public ReportBugResponse postReport( Administrator admin , String title , String contents , boolean publicReport ) + { + long bugId = this.bugsDao.postReport( admin , title , contents , publicReport ); + return new ReportBugResponse( admin , bugId ); + } + + + @Override + public ViewBugResponse getReport( Administrator admin , long bugId ) + { + BugReport report = this.bugsDao.getReport( admin , bugId ); + if ( report == null ) { + return new ViewBugResponse( admin , false ); + } + + return new ViewBugResponse( admin , report , this.getBugEvents( bugId ) ); + } + + + @Override + public PostCommentResponse postComment( Administrator admin , long bugId , String comment , boolean publicComment ) + { + this.bugsDao.postComment( admin , bugId , comment , publicComment ); + return new PostCommentResponse( admin ); + } + + + @Override + public void moderateComment( Administrator admin , long commentId , boolean validation ) + { + if ( validation ) { + this.bugsDao.showComment( admin , commentId ); + } else { + this.bugsDao.deleteComment( admin , commentId ); + } + } + + + @Override + public void validateReport( Administrator admin , long bugId , BugStatus status , boolean publicReport , + int credits , boolean snapshot ) + { + this.bugsDao.validateReport( admin , bugId , status , publicReport , credits , snapshot ); + } + + + @Override + public void setStatus( Administrator admin , long bugId , BugStatus status ) + { + this.bugsDao.setStatus( admin , bugId , status ); + } + + + @Override + public void toggleVisibility( Administrator admin , long bugId ) + { + this.bugsDao.toggleVisibility( admin , bugId ); + } + + + @Override + public MergeReportsResponse mergeReports( Administrator admin , long id , long mergeId ) + { + int errCode = this.bugsDao.mergeReports( admin , id , mergeId ); + if ( errCode == 0 ) { + return new MergeReportsResponse( admin ); + } + + BugReport report = this.bugsDao.getReport( admin , id ); + if ( report == null ) { + return new MergeReportsResponse( admin , false ); + } + + return new MergeReportsResponse( admin , report , this.getBugEvents( id ) , + MergeError.values( )[ errCode - 1 ] , mergeId ); + } + + + @Override + public GetSnapshotResponse getSnapshot( Administrator admin , long bugId ) + { + String snapshot = this.bugsDao.getSnapshot( bugId ); + if ( snapshot == null ) { + return new GetSnapshotResponse( admin , false ); + } + return new GetSnapshotResponse( admin , snapshot ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/BugsDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/BugsDAOBean.java new file mode 100644 index 0000000..8f5c37e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/BugsDAOBean.java @@ -0,0 +1,395 @@ +package com.deepclone.lw.beans.bt; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.bt.data.*; +import com.deepclone.lw.interfaces.bt.BugsDAO; +import com.deepclone.lw.utils.StoredProc; + + + +public class BugsDAOBean + implements BugsDAO +{ + + private SimpleJdbcTemplate dTemplate; + + private final RowMapper< BugReport > mBugReport; + private final RowMapper< BugEvent > mBugEvent; + private final RowMapper< String > mString; + + private StoredProc fPostUserReport; + private StoredProc fPostAdminReport; + private StoredProc fPostUserComment; + private StoredProc fPostAdminComment; + private StoredProc fShowComment; + private StoredProc fDeleteComment; + private StoredProc fValidateReport; + private StoredProc fSetStatus; + private StoredProc fToggleVisibility; + private StoredProc fMerge; + + + public BugsDAOBean( ) + { + this.mBugReport = new RowMapper< BugReport >( ) { + @Override + public BugReport mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BugSubmitter sub; + BugReport br = new BugReport( ); + + br.setReportId( rs.getLong( "bug_report_id" ) ); + br.setTitle( rs.getString( "title" ) ); + br.setPosted( rs.getTimestamp( "posted" ) ); + br.setVisible( rs.getBoolean( "visible" ) ); + br.setStatus( BugStatus.valueOf( rs.getString( "status" ) ) ); + br.setLastUpdate( rs.getTimestamp( "last_update" ) ); + br.setUpdated( rs.getBoolean( "updated" ) ); + + sub = new BugSubmitter( ); + sub.setAdmin( rs.getBoolean( "initial_submitter_admin" ) ); + sub.setName( rs.getString( "initial_submitter_name" ) ); + sub.setUserId( (Integer) rs.getObject( "initial_submitter_uid" ) ); + br.setInitialSubmitter( sub ); + + sub = new BugSubmitter( ); + sub.setAdmin( rs.getBoolean( "last_submitter_admin" ) ); + sub.setName( rs.getString( "last_submitter_name" ) ); + sub.setUserId( (Integer) rs.getObject( "last_submitter_uid" ) ); + br.setLatestSubmitter( sub ); + + return br; + } + }; + this.mBugEvent = new RowMapper< BugEvent >( ) { + @Override + public BugEvent mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BugSubmitter sub; + BugEvent be = new BugEvent( ); + + be.setId( rs.getLong( "event_id" ) ); + be.setType( BugEventType.valueOf( rs.getString( "event_type" ) ) ); + be.setTimestamp( rs.getTimestamp( "event_timestamp" ) ); + be.setTitle( rs.getString( "title" ) ); + be.setContents( rs.getString( "contents" ) ); + BugEventType type = be.getType( ); + switch ( type ) { + case STATUS: + be.setStatus( BugStatus.valueOf( rs.getString( "status" ) ) ); + break; + + case COMMENT: + case VISIBILITY: + case INIT: + be.setVisible( rs.getBoolean( "visible" ) ); + break; + + case MERGE: + be.setMergedId( rs.getLong( "merged_report_id" ) ); + break; + } + + sub = new BugSubmitter( ); + sub.setAdmin( rs.getBoolean( "submitter_admin" ) ); + sub.setName( rs.getString( "submitter_name" ) ); + sub.setUserId( (Integer) rs.getObject( "submitter_uid" ) ); + be.setSubmitter( sub ); + + return be; + } + }; + this.mString = new RowMapper< String >( ) { + @Override + public String mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return rs.getString( 1 ); + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fPostUserReport = new StoredProc( dataSource , "bugs" , "post_player_report" ); + this.fPostUserReport.addParameter( "empire_id" , Types.INTEGER ); + this.fPostUserReport.addParameter( "title" , Types.VARCHAR ); + this.fPostUserReport.addParameter( "description" , Types.VARCHAR ); + this.fPostUserReport.addParameter( "extra" , Types.VARCHAR ); + this.fPostUserReport.addOutput( "report_id" , Types.BIGINT ); + this.fPostUserReport.addOutput( "group_id" , Types.BIGINT ); + + this.fPostAdminReport = new StoredProc( dataSource , "bugs" , "post_admin_report" ); + this.fPostAdminReport.addParameter( "admin_id" , Types.INTEGER ); + this.fPostAdminReport.addParameter( "title" , Types.VARCHAR ); + this.fPostAdminReport.addParameter( "description" , Types.VARCHAR ); + this.fPostAdminReport.addParameter( "public_report" , Types.BOOLEAN ); + this.fPostAdminReport.addOutput( "report_id" , Types.BIGINT ); + this.fPostAdminReport.addOutput( "group_id" , Types.BIGINT ); + + this.fPostUserComment = new StoredProc( dataSource , "bugs" , "post_player_comment" ); + this.fPostUserComment.addParameter( "empire_id" , Types.INTEGER ); + this.fPostUserComment.addParameter( "report_id" , Types.BIGINT ); + this.fPostUserComment.addParameter( "comment" , Types.VARCHAR ); + + this.fPostAdminComment = new StoredProc( dataSource , "bugs" , "post_admin_comment" ); + this.fPostAdminComment.addParameter( "admin_id" , Types.INTEGER ); + this.fPostAdminComment.addParameter( "report_id" , Types.BIGINT ); + this.fPostAdminComment.addParameter( "comment" , Types.VARCHAR ); + this.fPostAdminComment.addParameter( "public_comment" , Types.BOOLEAN ); + + this.fShowComment = new StoredProc( dataSource , "bugs" , "show_comment" ); + this.fShowComment.addParameter( "admin_id" , Types.INTEGER ); + this.fShowComment.addParameter( "comment_id" , Types.BIGINT ); + + this.fDeleteComment = new StoredProc( dataSource , "bugs" , "delete_comment" ); + this.fDeleteComment.addParameter( "admin_id" , Types.INTEGER ); + this.fDeleteComment.addParameter( "comment_id" , Types.BIGINT ); + + this.fValidateReport = new StoredProc( dataSource , "bugs" , "validate_report" ); + this.fValidateReport.addParameter( "admin_id" , Types.INTEGER ); + this.fValidateReport.addParameter( "report_id" , Types.BIGINT ); + this.fValidateReport.addParameter( "new_status" , "bug_status_type" ); + this.fValidateReport.addParameter( "public_report" , Types.BOOLEAN ); + this.fValidateReport.addParameter( "grant_credits" , Types.INTEGER ); + this.fValidateReport.addParameter( "keep_snapshot" , Types.BOOLEAN ); + + this.fSetStatus = new StoredProc( dataSource , "bugs" , "set_report_status" ); + this.fSetStatus.addParameter( "admin_id" , Types.INTEGER ); + this.fSetStatus.addParameter( "report_id" , Types.BIGINT ); + this.fSetStatus.addParameter( "new_status" , "bug_status_type" ); + + this.fToggleVisibility = new StoredProc( dataSource , "bugs" , "toggle_report_visibility" ); + this.fToggleVisibility.addParameter( "admin_id" , Types.INTEGER ); + this.fToggleVisibility.addParameter( "report_id" , Types.BIGINT ); + + this.fMerge = new StoredProc( dataSource , "bugs" , "merge_reports" ); + this.fMerge.addParameter( "admin_id" , Types.INTEGER ); + this.fMerge.addParameter( "report1_id" , Types.BIGINT ); + this.fMerge.addParameter( "report2_id" , Types.BIGINT ); + this.fMerge.addOutput( "err_code" , Types.INTEGER ); + } + + + @Override + public long countReports( int empireId , BugStatus status , boolean ownOnly ) + { + StringBuilder builder = new StringBuilder( ); + List< Object > qData = new ArrayList< Object >( ); + qData.add( (Integer) empireId ); + + builder.append( "SELECT count(*) FROM bugs.br_user_view WHERE empire_id = ?" ); + this.addQueryParameters( builder , qData , status , ownOnly ); + + Object[] args = qData.toArray( ); + return this.dTemplate.queryForLong( builder.toString( ) , args ); + } + + + @Override + public long countReports( Administrator admin , BugStatus status , boolean ownOnly ) + { + StringBuilder builder = new StringBuilder( ); + List< Object > qData = new ArrayList< Object >( ); + qData.add( (Integer) admin.getId( ) ); + + builder.append( "SELECT count(*) FROM bugs.br_admin_view WHERE administrator_id = ?" ); + this.addQueryParameters( builder , qData , status , ownOnly ); + + Object[] args = qData.toArray( ); + return this.dTemplate.queryForLong( builder.toString( ) , args ); + } + + + @Override + public long countUpdatedReports( Administrator admin ) + { + String sql = "SELECT count(*) FROM bugs.br_admin_view WHERE administrator_id = ? AND updated"; + return this.dTemplate.queryForLong( sql , admin.getId( ) ); + } + + + @Override + public List< BugReport > getReports( int empireId , BugStatus status , boolean ownOnly , long first , int count ) + { + StringBuilder builder = new StringBuilder( ).append( "SELECT * FROM bugs.br_user_view WHERE empire_id = ?" ); + List< Object > qData = new ArrayList< Object >( ); + qData.add( (Integer) empireId ); + + this.addQueryParameters( builder , qData , status , ownOnly ); + this.addWindowParameters( builder , qData , first , count ); + + Object[] args = qData.toArray( ); + return this.dTemplate.query( builder.toString( ) , this.mBugReport , args ); + } + + + @Override + public List< BugReport > getReports( Administrator admin , BugStatus status , boolean ownOnly , long first , + int count ) + { + StringBuilder builder = new StringBuilder( ); + List< Object > qData = new ArrayList< Object >( ); + qData.add( (Integer) admin.getId( ) ); + + builder.append( "SELECT * FROM bugs.br_admin_view WHERE administrator_id = ?" ); + this.addQueryParameters( builder , qData , status , ownOnly ); + this.addWindowParameters( builder , qData , first , count ); + + Object[] args = qData.toArray( ); + return this.dTemplate.query( builder.toString( ) , this.mBugReport , args ); + } + + + private void addQueryParameters( StringBuilder builder , List< Object > qData , BugStatus status , boolean ownOnly ) + { + if ( status != null ) { + builder.append( " AND status = ?" ); + qData.add( status.toString( ) ); + } + if ( ownOnly ) { + builder.append( " AND own_report" ); + } + } + + + private void addWindowParameters( StringBuilder builder , List< Object > qData , long first , int count ) + { + builder.append( " ORDER BY last_update DESC , bug_report_id DESC OFFSET ? LIMIT ?" ); + qData.add( (Long) first ); + qData.add( (Integer) count ); + } + + + @Override + public BugReport getReport( int empireId , long reportId ) + { + return this.getReport( "player" , empireId , reportId ); + } + + + @Override + public BugReport getReport( Administrator admin , long reportId ) + { + return this.getReport( "admin" , admin.getId( ) , reportId ); + } + + + private BugReport getReport( String viewerType , int viewerId , long reportId ) + { + String sql = "SELECT * FROM bugs.read_" + viewerType + "_report( ? , ? )"; + try { + return this.dTemplate.queryForObject( sql , this.mBugReport , viewerId , reportId ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public long postReport( int empireId , String title , String contents , String extra ) + { + return (Long) this.fPostUserReport.execute( empireId , title , contents , extra ).get( "report_id" ); + } + + + @Override + public long postReport( Administrator admin , String title , String contents , boolean publicReport ) + { + return (Long) this.fPostAdminReport.execute( admin.getId( ) , title , contents , publicReport ).get( + "report_id" ); + } + + + @Override + public void postComment( int empireId , long reportId , String comment ) + { + this.fPostUserComment.execute( empireId , reportId , comment ); + } + + + @Override + public void postComment( Administrator admin , long reportId , String comment , boolean publicComment ) + { + this.fPostAdminComment.execute( admin.getId( ) , reportId , comment , publicComment ); + } + + + @Override + public List< BugEvent > getEvents( long bugId ) + { + String sql = "SELECT * FROM bugs.br_events WHERE bug_report_id = ?"; + return this.dTemplate.query( sql , this.mBugEvent , bugId ); + } + + + @Override + public void showComment( Administrator admin , long commentId ) + { + this.fShowComment.execute( admin.getId( ) , commentId ); + } + + + @Override + public void deleteComment( Administrator admin , long commentId ) + { + this.fDeleteComment.execute( admin.getId( ) , commentId ); + } + + + @Override + public void validateReport( Administrator admin , long bugId , BugStatus status , boolean publicReport , + int credits , boolean snapshot ) + { + this.fValidateReport.execute( admin.getId( ) , bugId , status.toString( ) , publicReport , credits , snapshot ); + } + + + @Override + public void setStatus( Administrator admin , long bugId , BugStatus status ) + { + this.fSetStatus.execute( admin.getId( ) , bugId , status.toString( ) ); + } + + + @Override + public void toggleVisibility( Administrator admin , long bugId ) + { + this.fToggleVisibility.execute( admin.getId( ) , bugId ); + } + + + @Override + public int mergeReports( Administrator admin , long id , long mergeId ) + { + return (Integer) this.fMerge.execute( admin.getId( ) , id , mergeId ).get( "err_code" ); + } + + + @Override + public String getSnapshot( long bugId ) + { + String sql = "SELECT account_status FROM bugs.account_status_data WHERE event_id = ?"; + return this.dTemplate.queryForObject( sql , this.mString , bugId ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/EmpireSummaryBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/EmpireSummaryBean.java new file mode 100644 index 0000000..07c8949 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/EmpireSummaryBean.java @@ -0,0 +1,240 @@ +package com.deepclone.lw.beans.bt; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.beans.bt.esdata.*; +import com.deepclone.lw.interfaces.bt.EmpireSummary; +import com.thoughtworks.xstream.XStream; + + + +public class EmpireSummaryBean + implements EmpireSummary +{ + + private SimpleJdbcTemplate dTemplate; + + private final XStream xStream; + + private final RowMapper< DebugInformation > mMainInfo; + private final RowMapper< ResearchInformation > mResearch; + private final RowMapper< PlanetInformation > mPlanet; + private final RowMapper< QueueItemInformation > mQueueItem; + private final RowMapper< BuildingsInformation > mBuildings; + private final RowMapper< FleetInformation > mFleet; + private final RowMapper< ShipsInformation > mShips; + + + public EmpireSummaryBean( ) + { + this.xStream = new XStream( ); + this.xStream.processAnnotations( new Class< ? >[] { + AccountInformation.class , AllianceInformation.class , BuildingsInformation.class , + DebugInformation.class , EmpireInformation.class , FleetInformation.class , MovementInformation.class , + PlanetInformation.class , QueueInformation.class , QueueItemInformation.class , + ResearchInformation.class , ShipsInformation.class , SystemInformation.class + } ); + + this.mMainInfo = new RowMapper< DebugInformation >( ) { + @Override + public DebugInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + DebugInformation di = new DebugInformation( ); + + di.getSystem( ).setNextTick( rs.getLong( "next_tick" ) ); + di.getSystem( ).setCurrentTick( (Long) rs.getObject( "current_tick" ) ); + + di.getAccount( ).setId( rs.getInt( "account_id" ) ); + di.getAccount( ).setAddress( rs.getString( "account_address" ) ); + di.getAccount( ).setGameCredits( rs.getInt( "game_credits" ) ); + di.getAccount( ).setStatus( rs.getString( "account_status" ) ); + di.getAccount( ).setLanguage( rs.getString( "account_language" ) ); + + di.getEmpire( ).setId( rs.getInt( "empire_id" ) ); + di.getEmpire( ).setName( rs.getString( "empire_name" ) ); + di.getEmpire( ).setCash( rs.getDouble( "cash" ) ); + + String allianceTag = rs.getString( "alliance_tag" ); + if ( allianceTag != null ) { + AllianceInformation alliance = new AllianceInformation( ); + alliance.setId( rs.getInt( "alliance_id" ) ); + alliance.setTag( allianceTag ); + alliance.setPending( rs.getBoolean( "alliance_pending" ) ); + di.getEmpire( ).setAlliance( alliance ); + } + + return di; + } + }; + this.mResearch = new RowMapper< ResearchInformation >( ) { + @Override + public ResearchInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + ResearchInformation ri = new ResearchInformation( ); + ri.setId( rs.getInt( "line_id" ) ); + ri.setCurrentLevel( rs.getInt( "level" ) ); + ri.setLevelName( rs.getString( "name" ) ); + ri.setAccumulated( rs.getDouble( "accumulated" ) ); + return ri; + } + }; + this.mPlanet = new RowMapper< PlanetInformation >( ) { + @Override + public PlanetInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + PlanetInformation pi = new PlanetInformation( ); + pi.setId( rs.getInt( "planet_id" ) ); + pi.setPopulation( rs.getDouble( "population" ) ); + pi.setCurrentHappiness( rs.getDouble( "current_happiness" ) ); + pi.setTargetHappiness( rs.getDouble( "target_happiness" ) ); + pi.getCivilianQueue( ).setAccMoney( rs.getDouble( "civ_money" ) ); + pi.getCivilianQueue( ).setAccWork( rs.getDouble( "civ_work" ) ); + pi.getMilitaryQueue( ).setAccMoney( rs.getDouble( "mil_money" ) ); + pi.getMilitaryQueue( ).setAccWork( rs.getDouble( "mil_work" ) ); + return pi; + } + }; + this.mQueueItem = new RowMapper< QueueItemInformation >( ) { + @Override + public QueueItemInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + QueueItemInformation qii = new QueueItemInformation( ); + qii.setPlanetId( rs.getInt( "planet_id" ) ); + qii.setMilitary( rs.getBoolean( "military" ) ); + qii.setId( rs.getInt( "item_id" ) ); + qii.setName( rs.getString( "item_name" ) ); + qii.setDestroy( rs.getBoolean( "destroy" ) ); + qii.setAmount( rs.getInt( "amount" ) ); + return qii; + } + }; + this.mBuildings = new RowMapper< BuildingsInformation >( ) { + @Override + public BuildingsInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BuildingsInformation bi = new BuildingsInformation( ); + bi.setPlanetId( rs.getInt( "planet_id" ) ); + bi.setId( rs.getInt( "building_id" ) ); + bi.setName( rs.getString( "building_name" ) ); + bi.setAmount( rs.getInt( "amount" ) ); + bi.setDamage( rs.getDouble( "damage" ) ); + return bi; + } + }; + this.mFleet = new RowMapper< FleetInformation >( ) { + @Override + public FleetInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + FleetInformation fi = new FleetInformation( ); + fi.setId( rs.getLong( "fleet_id" ) ); + fi.setName( rs.getString( "fleet_name" ) ); + fi.setStatus( rs.getString( "status" ) ); + fi.setAttacking( rs.getBoolean( "attacking" ) ); + fi.setLocationId( rs.getInt( "location_id" ) ); + fi.setLocationName( rs.getString( "location_name" ) ); + + Integer sourceId = (Integer) rs.getObject( "source_id" ); + if ( sourceId != null ) { + MovementInformation mi = new MovementInformation( ); + mi.setSourceId( sourceId ); + mi.setSourceName( rs.getString( "source_name" ) ); + mi.setTimeLeft( rs.getInt( "time_left" ) ); + mi.setStateTimeLeft( rs.getInt( "state_time_left" ) ); + mi.setNearId( (Integer) rs.getObject( "ref_point_id" ) ); + mi.setNearName( rs.getString( "ref_point_name" ) ); + mi.setOutwards( (Boolean) rs.getObject( "outwards" ) ); + mi.setPastRefPoint( (Boolean) rs.getObject( "past_ref_point" ) ); + mi.setStartX( (Float) rs.getObject( "start_x" ) ); + mi.setStartY( (Float) rs.getObject( "start_y" ) ); + fi.setMovement( mi ); + } + + return fi; + } + }; + this.mShips = new RowMapper< ShipsInformation >( ) { + @Override + public ShipsInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + ShipsInformation si = new ShipsInformation( ); + si.setFleetId( rs.getLong( "fleet_id" ) ); + si.setId( rs.getInt( "ship_id" ) ); + si.setName( rs.getString( "ship_name" ) ); + si.setAmount( rs.getInt( "amount" ) ); + si.setDamage( rs.getDouble( "damage" ) ); + return si; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + } + + + @Override + public String getSummary( int empireId ) + { + String sql = "SELECT * FROM bugs.dump_main_view WHERE empire_id = ?"; + DebugInformation di = this.dTemplate.queryForObject( sql , this.mMainInfo , empireId ); + + sql = "SELECT * FROM bugs.dump_research_view WHERE empire_id = ?"; + for ( ResearchInformation ri : this.dTemplate.query( sql , this.mResearch , empireId ) ) { + di.getResearch( ).add( ri ); + } + + sql = "SELECT * FROM bugs.dump_planets_view WHERE empire_id = ?"; + Map< Integer , PlanetInformation > planets = new HashMap< Integer , PlanetInformation >( ); + for ( PlanetInformation pi : this.dTemplate.query( sql , this.mPlanet , empireId ) ) { + di.getPlanets( ).add( pi ); + planets.put( pi.getId( ) , pi ); + } + + sql = "SELECT * FROM bugs.dump_queues_view WHERE empire_id = ? ORDER BY queue_order"; + for ( QueueItemInformation qii : this.dTemplate.query( sql , this.mQueueItem , empireId ) ) { + PlanetInformation pi = planets.get( qii.getPlanetId( ) ); + QueueInformation qi = ( qii.isMilitary( ) ? pi.getMilitaryQueue( ) : pi.getCivilianQueue( ) ); + qi.getItems( ).add( qii ); + } + + sql = "SELECT * FROM bugs.dump_buildings_view WHERE empire_id = ?"; + for ( BuildingsInformation bi : this.dTemplate.query( sql , this.mBuildings , empireId ) ) { + planets.get( bi.getPlanetId( ) ).getBuildings( ).add( bi ); + } + + sql = "SELECT * FROM bugs.dump_fleets_view WHERE empire_id = ?"; + Map< Long , FleetInformation > fleets = new HashMap< Long , FleetInformation >( ); + for ( FleetInformation fi : this.dTemplate.query( sql , this.mFleet , empireId ) ) { + di.getFleets( ).add( fi ); + fleets.put( fi.getId( ) , fi ); + } + + sql = "SELECT * FROM bugs.dump_ships_view WHERE empire_id = ?"; + for ( ShipsInformation si : this.dTemplate.query( sql , this.mShips , empireId ) ) { + fleets.get( si.getFleetId( ) ).getShips( ).add( si ); + } + + return this.xStream.toXML( di ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/PlayerBugsBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/PlayerBugsBean.java new file mode 100644 index 0000000..29a3b8f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/PlayerBugsBean.java @@ -0,0 +1,114 @@ +package com.deepclone.lw.beans.bt; + + +import java.util.Iterator; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.bt.data.*; +import com.deepclone.lw.cmd.player.bt.*; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.interfaces.bt.*; +import com.deepclone.lw.interfaces.game.EmpireManagement; + + + +@Transactional +public class PlayerBugsBean + implements PlayerBugs +{ + private EmpireManagement empireMgr; + private BugsDAO bugsDao; + private EmpireSummary summary; + + + @Autowired( required = true ) + public void setBugsDao( BugsDAO bugsDao ) + { + this.bugsDao = bugsDao; + } + + + @Autowired( required = true ) + public void setEmpireMgr( EmpireManagement empireMgr ) + { + this.empireMgr = empireMgr; + } + + + @Autowired( required = true ) + public void setSummary( EmpireSummary summary ) + { + this.summary = summary; + } + + + @Override + public ListBugsResponse getBugs( int empireId , BugStatus status , boolean ownOnly , long first , int count ) + { + long nBugs = this.bugsDao.countReports( empireId , status , ownOnly ); + List< BugReport > bugs = this.bugsDao.getReports( empireId , status , ownOnly , first , count ); + GamePageData page = this.empireMgr.getGeneralInformation( empireId ); + return new ListBugsResponse( page , status , ownOnly , first , count , nBugs , bugs ); + } + + + @Override + public ReportBugResponse postReport( int empireId , String title , String desc ) + { + long bugId = this.bugsDao.postReport( empireId , title , desc , this.summary.getSummary( empireId ) ); + return new ReportBugResponse( this.empireMgr.getGeneralInformation( empireId ) , bugId ); + } + + + @Override + public ViewBugResponse getReport( int empireId , long bugId ) + { + GamePageData page = this.empireMgr.getGeneralInformation( empireId ); + + BugReport report = this.bugsDao.getReport( empireId , bugId ); + if ( report == null ) { + return new ViewBugResponse( page ); + } + + List< BugEvent > events = this.bugsDao.getEvents( bugId ); + Iterator< BugEvent > it = events.iterator( ); + BugStatus status = BugStatus.PENDING; + boolean pub = false; + while ( it.hasNext( ) ) { + BugEvent event = it.next( ); + BugEventType type = event.getType( ); + if ( type == BugEventType.STATUS ) { + if ( event.getStatus( ) == status ) { + it.remove( ); + } else { + status = event.getStatus( ); + } + } else if ( type == BugEventType.VISIBILITY ) { + if ( event.getVisible( ) == pub ) { + it.remove( ); + } else { + pub = event.getVisible( ); + } + } else if ( type == BugEventType.COMMENT && !event.getVisible( ) ) { + BugSubmitter submitter = event.getSubmitter( ); + if ( submitter.isAdmin( ) || submitter.getUserId( ) == null + || !page.getEmpire( ).equals( submitter.getName( ) ) ) { + it.remove( ); + } + } + } + return new ViewBugResponse( page , report , events ); + } + + + @Override + public PostCommentResponse postComment( int empireId , long reportId , String comment ) + { + this.bugsDao.postComment( empireId , reportId , comment ); + return new PostCommentResponse( this.empireMgr.getGeneralInformation( empireId ) , true ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/AccountInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/AccountInformation.java new file mode 100644 index 0000000..d6496e8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/AccountInformation.java @@ -0,0 +1,98 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "account" ) +public class AccountInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + @XStreamAlias( "id" ) + private int id; + + @XStreamAsAttribute + @XStreamAlias( "address" ) + private String address; + + @XStreamAsAttribute + @XStreamAlias( "language" ) + private String language; + + @XStreamAsAttribute + @XStreamAlias( "game-credits" ) + private int gameCredits; + + @XStreamAsAttribute + @XStreamAlias( "status" ) + private String status; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getAddress( ) + { + return address; + } + + + public void setAddress( String address ) + { + this.address = address; + } + + + public String getLanguage( ) + { + return language; + } + + + public void setLanguage( String language ) + { + this.language = language; + } + + + public int getGameCredits( ) + { + return gameCredits; + } + + + public void setGameCredits( int gameCredits ) + { + this.gameCredits = gameCredits; + } + + + public String getStatus( ) + { + return status; + } + + + public void setStatus( String status ) + { + this.status = status; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/AllianceInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/AllianceInformation.java new file mode 100644 index 0000000..e156b4b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/AllianceInformation.java @@ -0,0 +1,66 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "alliance" ) +public class AllianceInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + @XStreamAlias( "id" ) + private int id; + + @XStreamAsAttribute + @XStreamAlias( "tag" ) + private String tag; + + @XStreamAsAttribute + @XStreamAlias( "pending" ) + private boolean pending; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getTag( ) + { + return tag; + } + + + public void setTag( String tag ) + { + this.tag = tag; + } + + + public boolean isPending( ) + { + return pending; + } + + + public void setPending( boolean pending ) + { + this.pending = pending; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/BuildingsInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/BuildingsInformation.java new file mode 100644 index 0000000..61a9415 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/BuildingsInformation.java @@ -0,0 +1,96 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "building" ) +public class BuildingsInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private transient int planetId; + + @XStreamAsAttribute + @XStreamAlias( "id" ) + private int id; + + @XStreamAsAttribute + @XStreamAlias( "name" ) + private String name; + + @XStreamAsAttribute + @XStreamAlias( "amount" ) + private int amount; + + @XStreamAsAttribute + @XStreamAlias( "damage" ) + private double damage; + + + public int getPlanetId( ) + { + return planetId; + } + + + public void setPlanetId( int planetId ) + { + this.planetId = planetId; + } + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public int getAmount( ) + { + return amount; + } + + + public void setAmount( int amount ) + { + this.amount = amount; + } + + + public double getDamage( ) + { + return damage; + } + + + public void setDamage( double damage ) + { + this.damage = damage; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/DebugInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/DebugInformation.java new file mode 100644 index 0000000..847fcb1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/DebugInformation.java @@ -0,0 +1,81 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "debug" ) +public class DebugInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + @XStreamAlias( "dump-version" ) + private int version = 1; + + private SystemInformation system = new SystemInformation( ); + + private AccountInformation account = new AccountInformation( ); + + private EmpireInformation empire = new EmpireInformation( ); + + @XStreamAlias( "research" ) + private List< ResearchInformation > research = new LinkedList< ResearchInformation >( ); + + @XStreamAlias( "planets" ) + private List< PlanetInformation > planets = new LinkedList< PlanetInformation >( ); + + @XStreamAlias( "fleets" ) + private List< FleetInformation > fleets = new LinkedList< FleetInformation >( ); + + + public int getVersion( ) + { + return version; + } + + + public SystemInformation getSystem( ) + { + return system; + } + + + public AccountInformation getAccount( ) + { + return account; + } + + + public EmpireInformation getEmpire( ) + { + return empire; + } + + + public List< ResearchInformation > getResearch( ) + { + return research; + } + + + public List< PlanetInformation > getPlanets( ) + { + return planets; + } + + + public List< FleetInformation > getFleets( ) + { + return fleets; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/EmpireInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/EmpireInformation.java new file mode 100644 index 0000000..94825fe --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/EmpireInformation.java @@ -0,0 +1,80 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "empire" ) +public class EmpireInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + @XStreamAlias( "id" ) + private int id; + + @XStreamAsAttribute + @XStreamAlias( "name" ) + private String name; + + @XStreamAsAttribute + @XStreamAlias( "cash" ) + private double cash; + + private AllianceInformation alliance; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public double getCash( ) + { + return cash; + } + + + public void setCash( double cash ) + { + this.cash = cash; + } + + + public AllianceInformation getAlliance( ) + { + return alliance; + } + + + public void setAlliance( AllianceInformation alliance ) + { + this.alliance = alliance; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/FleetInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/FleetInformation.java new file mode 100644 index 0000000..d049007 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/FleetInformation.java @@ -0,0 +1,133 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "fleet" ) +public class FleetInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + private long id; + + @XStreamAsAttribute + private String name; + + @XStreamAsAttribute + private String status; + + @XStreamAsAttribute + private boolean attacking; + + @XStreamAlias( "location-id" ) + private int locationId; + + @XStreamAlias( "location-name" ) + private String locationName; + + @XStreamAlias( "ships" ) + private List< ShipsInformation > ships = new LinkedList< ShipsInformation >( ); + + private MovementInformation movement; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getStatus( ) + { + return status; + } + + + public void setStatus( String status ) + { + this.status = status; + } + + + public boolean isAttacking( ) + { + return attacking; + } + + + public void setAttacking( boolean attacking ) + { + this.attacking = attacking; + } + + + public int getLocationId( ) + { + return locationId; + } + + + public void setLocationId( int locationId ) + { + this.locationId = locationId; + } + + + public String getLocationName( ) + { + return locationName; + } + + + public void setLocationName( String locationName ) + { + this.locationName = locationName; + } + + + public MovementInformation getMovement( ) + { + return movement; + } + + + public void setMovement( MovementInformation movement ) + { + this.movement = movement; + } + + + public List< ShipsInformation > getShips( ) + { + return ships; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/MovementInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/MovementInformation.java new file mode 100644 index 0000000..b3f20a0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/MovementInformation.java @@ -0,0 +1,157 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; + + + +@XStreamAlias( "movement" ) +public class MovementInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int sourceId; + + private String sourceName; + + private int timeLeft; + + private int stateTimeLeft; + + private Float startX; + + private Float startY; + + private Integer nearId; + + private String nearName; + + private Boolean outwards; + + private Boolean pastRefPoint; + + + public int getSourceId( ) + { + return sourceId; + } + + + public void setSourceId( int sourceId ) + { + this.sourceId = sourceId; + } + + + public String getSourceName( ) + { + return sourceName; + } + + + public void setSourceName( String sourceName ) + { + this.sourceName = sourceName; + } + + + public int getTimeLeft( ) + { + return timeLeft; + } + + + public void setTimeLeft( int timeLeft ) + { + this.timeLeft = timeLeft; + } + + + public int getStateTimeLeft( ) + { + return stateTimeLeft; + } + + + public void setStateTimeLeft( int stateTimeLeft ) + { + this.stateTimeLeft = stateTimeLeft; + } + + + public Float getStartX( ) + { + return startX; + } + + + public void setStartX( Float startX ) + { + this.startX = startX; + } + + + public Float getStartY( ) + { + return startY; + } + + + public void setStartY( Float startY ) + { + this.startY = startY; + } + + + public Integer getNearId( ) + { + return nearId; + } + + + public void setNearId( Integer nearId ) + { + this.nearId = nearId; + } + + + public String getNearName( ) + { + return nearName; + } + + + public void setNearName( String nearName ) + { + this.nearName = nearName; + } + + + public Boolean getOutwards( ) + { + return outwards; + } + + + public void setOutwards( Boolean outwards ) + { + this.outwards = outwards; + } + + + public Boolean getPastRefPoint( ) + { + return pastRefPoint; + } + + + public void setPastRefPoint( Boolean pastRefPoint ) + { + this.pastRefPoint = pastRefPoint; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/PlanetInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/PlanetInformation.java new file mode 100644 index 0000000..e2c10a9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/PlanetInformation.java @@ -0,0 +1,124 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "planet" ) +public class PlanetInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + @XStreamAlias( "id" ) + private int id; + + @XStreamAsAttribute + @XStreamAlias( "id" ) + private String name; + + @XStreamAlias( "population" ) + private double population; + + @XStreamAlias( "current-happiness" ) + private double currentHappiness; + + @XStreamAlias( "target-happiness" ) + private double targetHappiness; + + @XStreamAlias( "buildings" ) + private List< BuildingsInformation > buildings = new LinkedList< BuildingsInformation >( ); + + @XStreamAlias( "civ-queue" ) + private QueueInformation civilianQueue = new QueueInformation( ); + + @XStreamAlias( "mil-queue" ) + private QueueInformation militaryQueue = new QueueInformation( ); + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public double getPopulation( ) + { + return population; + } + + + public void setPopulation( double population ) + { + this.population = population; + } + + + public double getCurrentHappiness( ) + { + return currentHappiness; + } + + + public void setCurrentHappiness( double currentHappiness ) + { + this.currentHappiness = currentHappiness; + } + + + public double getTargetHappiness( ) + { + return targetHappiness; + } + + + public void setTargetHappiness( double targetHappiness ) + { + this.targetHappiness = targetHappiness; + } + + + public List< BuildingsInformation > getBuildings( ) + { + return buildings; + } + + + public QueueInformation getCivilianQueue( ) + { + return civilianQueue; + } + + + public QueueInformation getMilitaryQueue( ) + { + return militaryQueue; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/QueueInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/QueueInformation.java new file mode 100644 index 0000000..3aacd7a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/QueueInformation.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + + + +public class QueueInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + @XStreamAlias( "accumulated-work" ) + private double accWork; + + @XStreamAsAttribute + @XStreamAlias( "accumulated-money" ) + private double accMoney; + + @XStreamImplicit( itemFieldName = "item" ) + private List< QueueItemInformation > items = new LinkedList< QueueItemInformation >( ); + + + public double getAccWork( ) + { + return accWork; + } + + + public void setAccWork( double accWork ) + { + this.accWork = accWork; + } + + + public double getAccMoney( ) + { + return accMoney; + } + + + public void setAccMoney( double accMoney ) + { + this.accMoney = accMoney; + } + + + public List< QueueItemInformation > getItems( ) + { + return items; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/QueueItemInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/QueueItemInformation.java new file mode 100644 index 0000000..a96a3d2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/QueueItemInformation.java @@ -0,0 +1,108 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +public class QueueItemInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + transient private int planetId; + + transient private boolean military; + + @XStreamAsAttribute + @XStreamAlias( "id" ) + private int id; + + @XStreamAsAttribute + @XStreamAlias( "name" ) + private String name; + + @XStreamAsAttribute + @XStreamAlias( "destroy" ) + private boolean destroy; + + @XStreamAsAttribute + @XStreamAlias( "amount" ) + private int amount; + + public int getPlanetId( ) + { + return planetId; + } + + + public void setPlanetId( int planetId ) + { + this.planetId = planetId; + } + + + public boolean isMilitary( ) + { + return military; + } + + + public void setMilitary( boolean military ) + { + this.military = military; + } + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public boolean isDestroy( ) + { + return destroy; + } + + + public void setDestroy( boolean destroy ) + { + this.destroy = destroy; + } + + + public int getAmount( ) + { + return amount; + } + + + public void setAmount( int amount ) + { + this.amount = amount; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/ResearchInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/ResearchInformation.java new file mode 100644 index 0000000..69d9f63 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/ResearchInformation.java @@ -0,0 +1,83 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "research-line" ) +public class ResearchInformation + implements Serializable + +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + @XStreamAlias( "line") + private int id; + + @XStreamAsAttribute + @XStreamAlias( "level") + private int currentLevel; + + @XStreamAsAttribute + @XStreamAlias( "name") + private String levelName; + + @XStreamAsAttribute + @XStreamAlias( "accumulated-points") + private double accumulated; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public int getCurrentLevel( ) + { + return currentLevel; + } + + + public void setCurrentLevel( int currentLevel ) + { + this.currentLevel = currentLevel; + } + + + public String getLevelName( ) + { + return levelName; + } + + + public void setLevelName( String levelName ) + { + this.levelName = levelName; + } + + + public double getAccumulated( ) + { + return accumulated; + } + + + public void setAccumulated( double accumulated ) + { + this.accumulated = accumulated; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/ShipsInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/ShipsInformation.java new file mode 100644 index 0000000..047ddfd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/ShipsInformation.java @@ -0,0 +1,96 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "ship-type" ) +public class ShipsInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + transient private long fleetId; + + @XStreamAsAttribute + @XStreamAlias( "id" ) + private int id; + + @XStreamAsAttribute + @XStreamAlias( "name" ) + private String name; + + @XStreamAsAttribute + @XStreamAlias( "amount" ) + private long amount; + + @XStreamAsAttribute + @XStreamAlias( "damage" ) + private double damage; + + + public long getFleetId( ) + { + return fleetId; + } + + + public void setFleetId( long fleetId ) + { + this.fleetId = fleetId; + } + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public long getAmount( ) + { + return amount; + } + + + public void setAmount( long amount ) + { + this.amount = amount; + } + + + public double getDamage( ) + { + return damage; + } + + + public void setDamage( double damage ) + { + this.damage = damage; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/SystemInformation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/SystemInformation.java new file mode 100644 index 0000000..1d51bca --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/java/com/deepclone/lw/beans/bt/esdata/SystemInformation.java @@ -0,0 +1,50 @@ +package com.deepclone.lw.beans.bt.esdata; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@XStreamAlias( "system-info" ) +public class SystemInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + @XStreamAsAttribute + @XStreamAlias( "computing-tick" ) + private Long currentTick; + + @XStreamAsAttribute + @XStreamAlias( "next-tick" ) + private long nextTick; + + + public Long getCurrentTick( ) + { + return currentTick; + } + + + public void setCurrentTick( Long currentTick ) + { + this.currentTick = currentTick; + } + + + public long getNextTick( ) + { + return nextTick; + } + + + public void setNextTick( long nextTick ) + { + this.nextTick = nextTick; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt-beans.xml new file mode 100644 index 0000000..2673721 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt-beans.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/admin-bugs-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/admin-bugs-bean.xml new file mode 100644 index 0000000..5ddaaca --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/admin-bugs-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/bugs-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/bugs-dao-bean.xml new file mode 100644 index 0000000..3850ac1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/bugs-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/empire-summary-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/empire-summary-bean.xml new file mode 100644 index 0000000..bb9f28c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/empire-summary-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/player-bugs-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/player-bugs-bean.xml new file mode 100644 index 0000000..47c377f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-bt/src/main/resources/configuration/bt/player-bugs-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.project new file mode 100644 index 0000000..e52eaf0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-eventlog + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..82cc298 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 09 10:19:28 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/pom.xml new file mode 100644 index 0000000..0305043 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-beans-eventlog + 5.99.1 + Legacy Worlds event log + This package is responsible for all logging in Legacy Worlds through three different beans (system event logger, admin event logger and user event logger). + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/AdminErrorMailBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/AdminErrorMailBean.java new file mode 100644 index 0000000..59d9620 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/AdminErrorMailBean.java @@ -0,0 +1,80 @@ +package com.deepclone.lw.beans.eventlog; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.admin.AdminDAO; +import com.deepclone.lw.interfaces.eventlog.LogReader; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class AdminErrorMailBean + implements InitializingBean , DisposableBean +{ + + private Ticker ticker; + private LogReader logReader; + private AdminDAO adminDao; + private TransactionTemplate tTemplate; + private Mailer mailer; + + private AdminErrorMailTask task; + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setLogReader( LogReader logReader ) + { + this.logReader = logReader; + } + + + @Autowired( required = true ) + public void setAdminDao( AdminDAO adminDao ) + { + this.adminDao = adminDao; + } + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Autowired( required = true ) + public void setMailer( Mailer mailer ) + { + this.mailer = mailer; + } + + + @Override + public void afterPropertiesSet( ) + { + this.task = new AdminErrorMailTask( this.adminDao , this.logReader , this.mailer , this.tTemplate ); + this.ticker.registerTask( Frequency.LOW , "Admin error mail sender" , this.task ); + } + + + @Override + public void destroy( ) + { + this.task = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/AdminErrorMailTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/AdminErrorMailTask.java new file mode 100644 index 0000000..bfb4f12 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/AdminErrorMailTask.java @@ -0,0 +1,135 @@ +package com.deepclone.lw.beans.eventlog; + + +import java.text.SimpleDateFormat; +import java.util.LinkedList; +import java.util.List; + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.logs.ExceptionEntry; +import com.deepclone.lw.cmd.admin.logs.TraceEntry; +import com.deepclone.lw.interfaces.admin.AdminDAO; +import com.deepclone.lw.interfaces.eventlog.ExtendedLogEntry; +import com.deepclone.lw.interfaces.eventlog.LogReader; +import com.deepclone.lw.interfaces.mailer.MailData; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.sqld.admin.AdminRecord; + + + +class AdminErrorMailTask + implements Runnable +{ + private static class ErrorData + { + public final List< AdminRecord > administrators; + public final List< ExtendedLogEntry > logEntries; + + + public ErrorData( List< AdminRecord > administrators , List< ExtendedLogEntry > logEntries ) + { + this.administrators = administrators; + this.logEntries = logEntries; + } + + } + + private final TransactionTemplate tTemplate; + private final AdminDAO adminDao; + private final LogReader logReader; + private final Mailer mailer; + + + public AdminErrorMailTask( AdminDAO adminDao , LogReader logReader , Mailer mailer , TransactionTemplate tTemplate ) + { + this.adminDao = adminDao; + this.logReader = logReader; + this.mailer = mailer; + this.tTemplate = tTemplate; + } + + + @Override + public void run( ) + { + // Get errors and administrators + ErrorData errorData; + errorData = this.tTemplate.execute( new TransactionCallback< ErrorData >( ) { + @Override + public ErrorData doInTransaction( TransactionStatus status ) + { + return getErrorData( ); + } + } ); + + // No receiving administrators or no errors -> exit + if ( errorData.administrators.isEmpty( ) || errorData.logEntries.isEmpty( ) ) { + return; + } + + // Generate message contents + String message = this.buildMessage( errorData.logEntries ); + for ( AdminRecord admin : errorData.administrators ) { + try { + MailData mail = this.mailer.createMail( "en" , "adminErrorMail" , admin.getAddress( ) ); + mail.setData( "contents" , message ); + mail.queue( ); + } catch ( Exception e ) { + throw new RuntimeException( e ); + } + } + } + + + private ErrorData getErrorData( ) + { + List< AdminRecord > admins = new LinkedList< AdminRecord >( ); + for ( AdminRecord admin : this.adminDao.listAdministrators( ) ) { + if ( Privileges.BUGM.hasPrivilege( admin.getPrivileges( ) ) ) { + admins.add( admin ); + } + } + return new ErrorData( admins , this.logReader.getErrorEntries( ) ); + } + + + private String buildMessage( List< ExtendedLogEntry > logEntries ) + { + StringBuilder builder = new StringBuilder( ); + SimpleDateFormat dFmt = new SimpleDateFormat( "yyyy-MM-dd" ); + SimpleDateFormat tFmt = new SimpleDateFormat( "HH:mm:ss" ); + + for ( ExtendedLogEntry entry : logEntries ) { + builder.append( "Date: " ).append( dFmt.format( entry.logEntry.getTimestamp( ) ) ); + builder.append( "\nTime: " ).append( tFmt.format( entry.logEntry.getTimestamp( ) ) ); + builder.append( "\nComponent: " ).append( entry.logEntry.getAbout( ) ); + builder.append( "\nMessage: " ).append( entry.logEntry.getEntry( ) ).append( "\n" ); + + for ( ExceptionEntry eEntry : entry.exceptions ) { + builder.append( "\n " ).append( eEntry.getClassName( ) ); + if ( eEntry.getMessage( ) != null && !"".equals( eEntry ) ) { + builder.append( ": " ).append( eEntry.getMessage( ) ); + } + + int i = 0; + for ( TraceEntry tEntry : eEntry.getTrace( ) ) { + builder.append( "\n " ); + if ( i++ > 5 ) { + builder.append( "..." ); + break; + } + builder.append( tEntry.getLocation( ) ); + } + } + + builder.append( "\n\n\n" ); + } + + return builder.toString( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/EntryQueueItem.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/EntryQueueItem.java new file mode 100644 index 0000000..7e32ec8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/EntryQueueItem.java @@ -0,0 +1,34 @@ +package com.deepclone.lw.beans.eventlog; + + +import com.deepclone.lw.sqld.sys.SystemLogEntry; + + + +/** + * Log writer queue entries only carry a log entry, which may be null to indicate that the log + * writer's task must be terminated. + * + * @author tseeker + */ +class EntryQueueItem +{ + + /** The log entry */ + final SystemLogEntry entry; + + + /** Initialises a "termination" queue entry */ + EntryQueueItem( ) + { + this.entry = null; + } + + + /** Initialises a log-carrying queue entry */ + EntryQueueItem( SystemLogEntry entry ) + { + this.entry = entry; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogCleanerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogCleanerBean.java new file mode 100644 index 0000000..2f88527 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogCleanerBean.java @@ -0,0 +1,107 @@ +package com.deepclone.lw.beans.eventlog; + + +import javax.sql.DataSource; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; + +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +/** + * Log clean-up bean. + * + *

+ * This bean is responsible for removing old log entries from the various logging tables. It + * registers a set of constants which determine the maximal age of a log entry depending on its + * category (administrative, account or system) and starts a ticker task with a high frequency. + * + * @author tseeker + * + */ +public class LogCleanerBean + implements InitializingBean , DisposableBean +{ + /** Ticker bean */ + private Ticker ticker; + + /** Transaction manager */ + private PlatformTransactionManager transactionManager; + + /** Log cleaner task instance */ + private LogCleanerTask cleanerTask; + + private DataSource dataSource; + + + + /** + * Sets the ticker bean reference (DI). + * + * @param ticker + * the ticker bean + */ + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + /** + * Sets the transaction manager reference (DI). + * + * @param manager + * the transaction manager + */ + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager manager ) + { + this.transactionManager = manager; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dataSource = dataSource; + } + + + /** + * Registers constants and initialises the log clean-up task. + * + *

+ * Once the dependencies have been injected, this method will register the + * log.maxAge.admin, log.maxAge.account and log.maxAge.system + * constants, setting their default values to 7 days. It will then create the clean-up task + * instance, register it as a constants user, and add it to the ticker with a high frequency. + */ + @Override + public void afterPropertiesSet( ) + { + // Create clean-up task + this.cleanerTask = new LogCleanerTask( this.dataSource , this.transactionManager ); + this.ticker.registerTask( Frequency.LOW , "Log cleaner" , this.cleanerTask ); + } + + + /** + * Removes references to the clean-up task. + * + *

+ * Before the bean is destroyed, this method will unregister the clean-up task from the + * constants manager and remove the local reference. + */ + @Override + public void destroy( ) + { + this.cleanerTask = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogCleanerTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogCleanerTask.java new file mode 100644 index 0000000..9a04e37 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogCleanerTask.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.eventlog; + + +import javax.sql.DataSource; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + + + +/** + * Log clean-up task. + * + *

+ * This class implements the log clean-up task; it is simultaneously a constants user (as it needs + * to keep informed about log.maxAge.*), a runnable (as it needs to be registered as a + * ticker task) and a transaction callback (to perform the actual clean-up). + * + * @author tseeker + */ +class LogCleanerTask + implements Runnable +{ + + /** Transaction manager interface */ + private final TransactionTemplate tTemplate; + private JdbcTemplate dTemplate; + + + + /** + * @param sessionFactory + * the Hibernate session factory + * @param transactionManager + * the transaction manager + */ + LogCleanerTask( DataSource dataSource , PlatformTransactionManager transactionManager ) + { + this.tTemplate = new TransactionTemplate( transactionManager ); + this.dTemplate = new JdbcTemplate( dataSource ); + } + + + /** + * Executes the clean-up transaction if the constants have been set. + */ + @Override + synchronized public void run( ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + dTemplate.execute( "SELECT sys.clean_logs( )" ); + } + } ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogReaderBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogReaderBean.java new file mode 100644 index 0000000..1476bab --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogReaderBean.java @@ -0,0 +1,284 @@ +package com.deepclone.lw.beans.eventlog; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.logs.ExceptionEntry; +import com.deepclone.lw.cmd.admin.logs.GetEntryResponse; +import com.deepclone.lw.cmd.admin.logs.LogEntry; +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.admin.logs.LogType; +import com.deepclone.lw.cmd.admin.logs.TraceEntry; +import com.deepclone.lw.cmd.admin.logs.ViewLogResponse; +import com.deepclone.lw.interfaces.eventlog.ExtendedLogEntry; +import com.deepclone.lw.interfaces.eventlog.LogReader; +import com.deepclone.lw.sqld.sys.ExceptionLog; +import com.deepclone.lw.sqld.sys.StackTraceLog; + + + +public class LogReaderBean + implements LogReader +{ + + private SimpleJdbcTemplate dTemplate; + private TransactionTemplate tTemplate; + + private final RowMapper< LogEntry > mLogEntry; + private final RowMapper< ExceptionLog > mExceptionLog; + private final RowMapper< StackTraceLog > mTraceLog; + + + public LogReaderBean( ) + { + this.mLogEntry = new RowMapper< LogEntry >( ) { + @Override + public LogEntry mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + LogEntry entry = new LogEntry( ); + entry.setId( (Long) rs.getObject( "id" ) ); + entry.setTimestamp( rs.getTimestamp( "t" ) ); + entry.setAbout( rs.getString( "component" ) ); + entry.setLevel( LogLevel.valueOf( rs.getString( "level" ) ) ); + entry.setEntry( rs.getString( "message" ) ); + entry.setException( (Long) rs.getObject( "exception_id" ) ); + return entry; + } + }; + this.mExceptionLog = new RowMapper< ExceptionLog >( ) { + @Override + public ExceptionLog mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return new ExceptionLog( rs.getLong( "id" ) , rs.getInt( "depth" ) , rs.getString( "exc_class" ) , rs + .getString( "message" ) ); + } + }; + this.mTraceLog = new RowMapper< StackTraceLog >( ) { + @Override + public StackTraceLog mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return new StackTraceLog( rs.getLong( "exception_id" ) , rs.getInt( "depth" ) , rs + .getString( "location" ) , rs.getString( "file_name" ) , (Integer) rs.getObject( "line_number" ) ); + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + } + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Override + public ViewLogResponse getLog( final Administrator admin , final LogType type , final long first , final int count , + final LogLevel minLevel , final String component , final boolean excOnly ) + { + if ( excOnly && type != LogType.SYSTEM ) { + return new ViewLogResponse( admin , 0 , new LinkedList< LogEntry >( ) ); + } + + return this.tTemplate.execute( new TransactionCallback< ViewLogResponse >( ) { + @Override + public ViewLogResponse doInTransaction( TransactionStatus status ) + { + return getLogQueries( admin , type , first , count , minLevel , component , excOnly ); + } + } ); + } + + + private ViewLogResponse getLogQueries( Administrator admin , LogType type , long first , int count , + LogLevel minLevel , String component , boolean excOnly ) + { + String countQuery = this.buildQuery( true , type , first , count , minLevel , component , excOnly ); + Object[] cqParams = this.buildQueryParams( true , first , count , minLevel , component ); + long nEntries = this.dTemplate.queryForLong( countQuery , cqParams ); + + String mainQuery = this.buildQuery( false , type , first , count , minLevel , component , excOnly ); + Object[] mqParams = this.buildQueryParams( false , first , count , minLevel , component ); + List< LogEntry > entries = this.dTemplate.query( mainQuery , this.mLogEntry , mqParams ); + + return new ViewLogResponse( admin , nEntries , entries ); + } + + + private Object[] buildQueryParams( boolean isCount , long first , int count , LogLevel minLevel , String component ) + { + boolean hasComponent = ( component != null && !"".equals( component ) ); + Object[] params = new Object[ ( hasComponent ? 2 : 1 ) + ( isCount ? 0 : 2 ) ]; + int i = 0; + + params[ i++ ] = minLevel.toString( ); + if ( hasComponent ) { + params[ i++ ] = "%" + component + "%"; + } + if ( !isCount ) { + params[ i++ ] = (Long) first; + params[ i++ ] = (Integer) count; + } + + return params; + } + + + private String buildQuery( boolean isCount , LogType type , long first , int count , LogLevel minLevel , + String component , boolean excOnly ) + { + StringBuilder builder = new StringBuilder( ); + + // Selection from the right view + builder.append( "SELECT " ); + if ( isCount ) { + builder.append( "count(*)" ); + } else { + builder.append( "*" ); + } + builder.append( " FROM sys." ).append( type.toString( ).toLowerCase( ) ).append( "_logs_view WHERE " ); + + // Minimal log level + builder.append( "level >= ?::log_level" ); + + // Component + if ( component != null && !"".equals( component ) ) { + builder.append( " AND lower( component ) LIKE ?" ); + } + + // Exception only + if ( excOnly ) { + builder.append( " AND exception_id IS NOT NULL" ); + } + + if ( !isCount ) { + // Ordering, index, count + builder.append( " ORDER BY t DESC OFFSET ? LIMIT ?" ); + } + + return builder.toString( ); + } + + + @Override + public GetEntryResponse getEntry( final Administrator admin , final long id ) + { + return this.tTemplate.execute( new TransactionCallback< GetEntryResponse >( ) { + @Override + public GetEntryResponse doInTransaction( TransactionStatus status ) + { + return doGetEntryResponse( admin , id ); + } + } ); + } + + + private GetEntryResponse doGetEntryResponse( Administrator admin , long id ) + { + ExtendedLogEntry lEntry = this.doGetEntry( id ); + if ( lEntry == null ) { + return new GetEntryResponse( admin , false ); + } + return new GetEntryResponse( admin , lEntry.logEntry , lEntry.exceptions ); + } + + + private ExtendedLogEntry doGetEntry( long id ) + { + String sql = "SELECT * FROM sys.system_logs_view WHERE id = ?"; + + // Get log entry + LogEntry entry; + try { + entry = this.dTemplate.queryForObject( sql , this.mLogEntry , id ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + + // Get exceptions + List< ExceptionLog > eLog; + sql = "SELECT * FROM sys.exceptions WHERE log_id = ? ORDER BY depth"; + eLog = this.dTemplate.query( sql , this.mExceptionLog , id ); + + Map< Long , ExceptionLog > eLogId = new HashMap< Long , ExceptionLog >( ); + for ( ExceptionLog ee : eLog ) { + eLogId.put( ee.getId( ) , ee ); + } + + // Get stack trace entries + sql = "SELECT st.* FROM sys.stack_traces st INNER JOIN sys.exceptions e ON e.id = st.exception_id WHERE e.log_id = ? ORDER BY st.depth DESC"; + for ( StackTraceLog stLog : this.dTemplate.query( sql , this.mTraceLog , id ) ) { + ExceptionLog ee = eLogId.get( stLog.getExcId( ) ); + ee.addStackTrace( stLog ); + } + + // Generate output + List< ExceptionEntry > exceptions = new LinkedList< ExceptionEntry >( ); + for ( ExceptionLog ee : eLog ) { + ExceptionEntry eEntry = new ExceptionEntry( ee.getClassName( ) , ee.getMessage( ) ); + List< TraceEntry > stackTrace = new LinkedList< TraceEntry >( ); + for ( StackTraceLog stLog : ee.getStack( ) ) { + stackTrace.add( new TraceEntry( stLog.getLocation( ) , stLog.getFileName( ) , stLog.getLine( ) ) ); + } + eEntry.setTrace( stackTrace ); + exceptions.add( eEntry ); + } + + return new ExtendedLogEntry( entry , exceptions ); + } + + + @Override + public List< ExtendedLogEntry > getErrorEntries( ) + { + List< ExtendedLogEntry > result = new LinkedList< ExtendedLogEntry >( ); + String sql = "SELECT * FROM admin.get_error_entries( )"; + RowMapper< Long > longLister = new RowMapper< Long >( ) { + @Override + public Long mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return rs.getLong( 1 ); + } + }; + for ( Long id : this.dTemplate.query( sql , longLister ) ) { + result.add( this.doGetEntry( id ) ); + } + return result; + } + + + @Override + public List< LogEntry > getAdminLogSince( Timestamp timestamp ) + { + String sql = "SELECT * FROM sys.admin_logs_view WHERE t >= ? AND level >= 'INFO'::log_level ORDER BY t DESC"; + return this.dTemplate.query( sql , this.mLogEntry , timestamp ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogWriterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogWriterBean.java new file mode 100644 index 0000000..c43d5ae --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogWriterBean.java @@ -0,0 +1,122 @@ +package com.deepclone.lw.beans.eventlog; + + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.eventlog.LogWriter; +import com.deepclone.lw.sqld.sys.SystemLogEntry; + + + +/** + * The log writer bean, once initialised, spawns a task while continuously examines a blocking + * queue. When entries are added to the queue, they are flushed to the database. When the bean + * container destroys the bean, a queue entry carrying the null value is added to the queue, causing + * the task to terminate. + * + * @author tseeker + * + */ +public class LogWriterBean + implements LogWriter , InitializingBean , DisposableBean +{ + + /** Transaction management instance */ + private TransactionTemplate tTemplate; + + /** JDBC data source */ + private DataSource dataSource; + + /** The queue used for log entries */ + private LinkedBlockingQueue< EntryQueueItem > queue = null; + + + /** + * Sets the JDBC data source (DI) + * + * @param dataSource + * the JDBC data source + */ + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dataSource = dataSource; + } + + + /** + * Initialises the interface to the transaction manager (DI) + * + * @param manager + * the transaction manager to use + */ + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager manager ) + { + this.tTemplate = new TransactionTemplate( manager ); + } + + + /* Documentation in LogWriter interface */ + @Override + synchronized public void addEntries( List< SystemLogEntry > entries ) + { + if ( this.queue == null ) { + return; + } + + LinkedList< EntryQueueItem > items = new LinkedList< EntryQueueItem >( ); + for ( SystemLogEntry e : entries ) { + if ( e == null ) { + continue; + } + items.add( new EntryQueueItem( e ) ); + } + this.queue.addAll( items ); + } + + + /** + * Bean initialisation - creates the queue and spawns the log writer task. + */ + @Override + public void afterPropertiesSet( ) + { + this.queue = new LinkedBlockingQueue< EntryQueueItem >( ); + + LogWriterTask task; + task = new LogWriterTask( this.queue , this.dataSource , this.tTemplate ); + + Thread t; + t = new Thread( task ); + t.start( ); + } + + + /** + * Bean destruction - inserts a null entry on the log writer queue, then waits for the task to + * terminate. + */ + @Override + public void destroy( ) + { + this.queue.add( new EntryQueueItem( ) ); + while ( !this.queue.isEmpty( ) ) { + Thread.yield( ); + } + synchronized ( this ) { + this.queue = null; + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogWriterTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogWriterTask.java new file mode 100644 index 0000000..a1fe4cc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LogWriterTask.java @@ -0,0 +1,166 @@ +package com.deepclone.lw.beans.eventlog; + + +import java.sql.Types; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; + +import javax.sql.DataSource; + +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.transaction.CannotCreateTransactionException; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.sqld.sys.ExceptionLog; +import com.deepclone.lw.sqld.sys.StackTraceLog; +import com.deepclone.lw.sqld.sys.SystemLogEntry; +import com.deepclone.lw.utils.StoredProc; + + + +/** + * The log writer task is spawned by the log writer bean. Whenever log entries are pushed to the log + * writer, they are added to a queue which this tasks continuously reads. If a queue item carrying + * the null value is found, the queue is flushed and the task terminates. + * + * @author tseeker + */ +class LogWriterTask + implements Runnable +{ + + /** The queue */ + private final LinkedBlockingQueue< EntryQueueItem > queue; + + /** Transaction management interface */ + private final TransactionTemplate tTemplate; + + private StoredProc fLog; + private StoredProc fException; + private StoredProc fTrace; + + + /** Copies the required references */ + LogWriterTask( LinkedBlockingQueue< EntryQueueItem > queue , DataSource dataSource , TransactionTemplate tTemplate ) + { + this.queue = queue; + this.tTemplate = tTemplate; + + this.fLog = new StoredProc( dataSource , "sys" , "write_log" ); + this.fLog.addParameter( "component" , Types.VARCHAR ); + this.fLog.addParameter( "level" , "log_level" ); + this.fLog.addParameter( "message" , Types.VARCHAR ); + this.fLog.addOutput( "entry_id" , Types.BIGINT ); + + this.fException = new StoredProc( dataSource , "sys" , "append_exception" ); + this.fException.addParameter( "log_id" , Types.BIGINT ); + this.fException.addParameter( "class_name" , Types.VARCHAR ); + this.fException.addParameter( "message" , Types.VARCHAR ); + this.fException.addOutput( "entry_id" , Types.BIGINT ); + + this.fTrace = new StoredProc( dataSource , "sys" , "append_trace" ); + this.fTrace.addParameter( "exc_id" , Types.BIGINT ); + this.fTrace.addParameter( "location" , Types.VARCHAR ); + this.fTrace.addParameter( "file_name" , Types.VARCHAR ); + this.fTrace.addParameter( "line_number" , Types.INTEGER ); + } + + + /** + * Implements the consumer side of the queue; when an item is found, all items are flushed and + * written to the DB in the same transaction. + */ + @Override + public void run( ) + { + boolean keepRunning = true; + while ( keepRunning ) { + LinkedList< EntryQueueItem > items; + items = new LinkedList< EntryQueueItem >( ); + + // Wait for the next queue entry + EntryQueueItem item; + try { + item = this.queue.take( ); + } catch ( InterruptedException e ) { + continue; + } + + // Take everything else on the queue + this.queue.drainTo( items ); + items.add( item ); + + // Process the items obtained from the queue, watching for null values as they will + // interrupt the task + final LinkedList< SystemLogEntry > okItems = new LinkedList< SystemLogEntry >( ); + for ( EntryQueueItem i : items ) { + if ( i.entry == null ) { + keepRunning = false; + } else { + okItems.add( i.entry ); + } + } + + // If there's nothing to write, restart the loop (that usually means we're being + // terminated) + if ( okItems.isEmpty( ) ) { + continue; + } + + // Try writing to the DB + boolean writeSuccess = false; + while ( ! writeSuccess ) { + try { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + writeLogEntries( okItems ); + } + } ); + writeSuccess = true; + } catch ( DataAccessResourceFailureException e ) { + // Do nothing + } catch ( CannotCreateTransactionException e ) { + // Do nothing + } + + if (! writeSuccess ) { + if ( !this.queue.isEmpty( ) ) { + // If there is stuff in the queue, abort writing. + // We might actually need to exit. + break; + } + + try { + Thread.sleep( 2000 ); + } catch ( InterruptedException e1 ) { + break; + } + } + } + } + } + + + private void writeLogEntries( List< SystemLogEntry > entries ) + { + for ( SystemLogEntry entry : entries ) { + Long id = (Long) this.fLog.execute( entry.getComponent( ) , entry.getLevel( ).toString( ) , + entry.getMessage( ) ).get( "entry_id" ); + + for ( ExceptionLog exc : entry.getException( ) ) { + Long eid = (Long) this.fException.execute( id , exc.getClassName( ) , exc.getMessage( ) ).get( + "entry_id" ); + + for ( StackTraceLog st : exc.getStack( ) ) { + this.fTrace.execute( eid , st.getLocation( ) , st.getFileName( ) , st.getLine( ) ); + } + } + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LoggerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LoggerBean.java new file mode 100644 index 0000000..2c7de82 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/LoggerBean.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.eventlog; + + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.interfaces.eventlog.LogWriter; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.sqld.sys.SystemLogEntry; + + + +/** + * The logger bean can be used to generate the various types of log entry generators. It + * communicates with a log writer to which entries produced by the generators will be flushed. + * + * @author tseeker + * + */ +public class LoggerBean + implements Logger +{ + + /** The log writer bean this logger pushes entries to */ + private LogWriter logWriter; + + + /** + * Sets the log writer bean (DI) + * + * @param logWriter + * the log writer bean to push entries to + */ + @Autowired( required = true ) + public void setLogWriter( LogWriter logWriter ) + { + this.logWriter = logWriter; + } + + + /** + * Pushes a set of log entries to the log writer. + * + * @param entries + * the list of log entries to push + */ + void flush( List< SystemLogEntry > entries ) + { + this.logWriter.addEntries( entries ); + } + + + /* Documentation in Logger interface */ + @Override + public SystemLogger getSystemLogger( String component ) + { + return new SystemLoggerImpl( this , component ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/SystemLoggerImpl.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/SystemLoggerImpl.java new file mode 100644 index 0000000..d03a032 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/java/com/deepclone/lw/beans/eventlog/SystemLoggerImpl.java @@ -0,0 +1,183 @@ +package com.deepclone.lw.beans.eventlog; + + +import java.util.LinkedList; +import java.util.List; + +import org.apache.log4j.Logger; + + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.sqld.sys.ExceptionLog; +import com.deepclone.lw.sqld.sys.StackTraceLog; +import com.deepclone.lw.sqld.sys.SystemLogEntry; + + + +/** + * The system logger implementation generates {@link SystemLogEntry} instances, setting their fields + * to the proper values and parsing exceptions as required. When flushed it simply uses the logger + * bean's flush() method to push its contents to the log writer. + * + * @author tseeker + */ +class SystemLoggerImpl + implements SystemLogger +{ + + /** External (log4j) logger */ + private final Logger l4j = Logger.getLogger( SystemLogger.class ); + + /** The logger bean */ + private final LoggerBean logger; + + /** The name of the component this system logger is used by */ + private final String component; + + /** The list of entries that have been created but that haven't been flushed to the logger bean */ + private List< SystemLogEntry > entries = new LinkedList< SystemLogEntry >( ); + + + /** Stores the logger bean reference and the component's name */ + SystemLoggerImpl( LoggerBean logger , String component ) + { + this.logger = logger; + this.component = component; + } + + + /* Documentation in SystemLogger interface */ + @Override + public SystemLogger flush( ) + { + synchronized ( this.entries ) { + if ( !this.entries.isEmpty( ) ) { + this.logger.flush( this.entries ); + this.entries.clear( ); + } + } + return this; + } + + + /* Documentation in SystemLogger interface */ + @Override + public SystemLogger log( LogLevel level , String message ) + { + this.toLog4j( level , message , null ); + + SystemLogEntry entry = this.makeEntry( level , message ); + synchronized ( this.entries ) { + this.entries.add( entry ); + } + + return this; + } + + + /* Documentation in SystemLogger interface */ + @Override + public SystemLogger log( LogLevel level , String message , Throwable exception ) + { + this.toLog4j( level , message , exception ); + + + SystemLogEntry entry = this.makeEntry( level , message ); + this.parseException( entry , exception ); + + synchronized ( this.entries ) { + this.entries.add( entry ); + } + + return this; + } + + + /** + * Logs a message through Log4J (in addition to the DB log). + * + * @param level + * log level + * @param message + * message to log + * @param exception + * optional exception to log along with the message + */ + private void toLog4j( LogLevel level , String message , Throwable exception ) + { + message = this.component + " - " + message; + switch ( level ) { + case DEBUG: + this.l4j.debug( message , exception ); + break; + case ERROR: + this.l4j.error( message , exception ); + break; + case INFO: + this.l4j.info( message , exception ); + break; + case TRACE: + this.l4j.trace( message , exception ); + break; + case WARNING: + this.l4j.warn( message , exception ); + break; + } + } + + + /** + * Generates the basic contents of a log entry using a log level and message + * + * @param level + * the entry's log level + * @param message + * the entry's message + * @return a fully usable {@link SystemLogEntry} instance + */ + private SystemLogEntry makeEntry( LogLevel level , String message ) + { + return new SystemLogEntry( level , this.component , message ); + } + + + /** + * Parses the specified exception so that the ExceptionLog instance and associated data can + * later be retrieved. + * + * @param exception + * the exception to parse + */ + private void parseException( SystemLogEntry logEntry , Throwable exception ) + { + do { + ExceptionLog excData; + excData = new ExceptionLog( logEntry , exception.getClass( ).getCanonicalName( ) , exception.getMessage( ) ); + this.parseTrace( excData , exception ); + exception = exception.getCause( ); + } while ( exception != null ); + } + + + /** + * This method converts an exception's stack trace into TracebackLog instances, adding them to + * the list of associated objects and returning the top-most item. + * + * @param logData + * the exception's log entry + * @param exception + * the exception whose stack trace is to be converted + */ + private void parseTrace( ExceptionLog logData , Throwable exception ) + { + StackTraceElement[] trace = exception.getStackTrace( ); + + for ( int i = trace.length - 1 ; i >= 0 ; i-- ) { + StackTraceElement e = trace[ i ]; + new StackTraceLog( logData , e.getClassName( ) + "." + e.getMethodName( ) , e.getFileName( ) , e + .getLineNumber( ) ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog-beans.xml new file mode 100644 index 0000000..934a2d8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog-beans.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/admin-error-mail-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/admin-error-mail-bean.xml new file mode 100644 index 0000000..f0e6a6e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/admin-error-mail-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-cleaner-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-cleaner-bean.xml new file mode 100644 index 0000000..7773c57 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-cleaner-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-reader-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-reader-bean.xml new file mode 100644 index 0000000..1e56da0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-reader-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-writer-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-writer-bean.xml new file mode 100644 index 0000000..21fc777 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/log-writer-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/logger-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/logger-bean.xml new file mode 100644 index 0000000..22b1347 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-eventlog/src/main/resources/configuration/eventlog/logger-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.project new file mode 100644 index 0000000..dffe14c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-i18n + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..9640d22 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 09 10:19:36 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/pom.xml new file mode 100644 index 0000000..26ad335 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/pom.xml @@ -0,0 +1,16 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-beans-i18n + Legacy Worlds internationalisation + 5.99.1 + This package defines the two beans which control server-side internationalised text management. + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NAdministrationImpl.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NAdministrationImpl.java new file mode 100644 index 0000000..47e8e06 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NAdministrationImpl.java @@ -0,0 +1,232 @@ +package com.deepclone.lw.beans.i18n; + + +import java.util.Map; +import java.util.Set; + +import com.deepclone.lw.interfaces.i18n.*; + + + +/** + * The implementation of the I18N administrative session uses the manager's shared {@link I18NData} + * instance to modify the I18N database, logging all actions in the process. It also provides some + * read access to languages and translations, but (as opposed to access through the + * {@link Translator} bean) completely ignores language support requirements, allowing new or + * incomplete languages to be managed. + * + * @author tseeker + */ +class I18NAdministrationImpl + implements I18NAdministration +{ + + /** The shared I18N data instance */ + private I18NData data; + private int administrator; + + + /** + * Copies the various required references + * + * @param data + * shared I18N data instance + * @param administrator + */ + I18NAdministrationImpl( I18NData data, int administrator ) + { + this.data = data; + this.administrator = administrator; + } + + + /* Documented in I18NAdministration interface */ + @Override + public Set< String > getLanguages( ) + { + this.data.readLock( ).lock( ); + try { + return this.data.getLanguages( ); + } finally { + this.data.readLock( ).unlock( ); + } + } + + + /* Documented in I18NAdministration interface */ + @Override + public String getLanguageName( String language ) + throws UnknownLanguageException + { + String l; + this.data.readLock( ).lock( ); + try { + l = this.data.getLanguageName( language ); + } finally { + this.data.readLock( ).unlock( ); + } + + if ( l == null ) { + throw new UnknownLanguageException( language ); + } + return l; + } + + + /* Documented in I18NAdministration interface */ + @Override + public double getLanguageSupport( String language ) + throws UnknownLanguageException + { + int sCount; + double lSize; + + this.data.readLock( ).lock( ); + try { + if ( !this.data.hasLanguage( language ) ) { + throw new UnknownLanguageException( language ); + } + lSize = this.data.getLanguageSize( language ); + sCount = this.data.getStringsCount( ); + } finally { + this.data.readLock( ).unlock( ); + } + + if ( sCount == 0 ) { + return 0; + } + return lSize / (double) sCount; + } + + + /* Documented in I18NAdministration interface */ + @Override + public void createLanguage( String language , String name ) + throws DuplicateLanguageException + { + this.data.writeLock( ).lock( ); + try { + if ( !this.data.addLanguage( this.administrator , language , name ) ) { + throw new DuplicateLanguageException( language ); + } + } finally { + this.data.writeLock( ).unlock( ); + } + } + + + /* Documented in I18NAdministration interface */ + @Override + public void setLanguageName( String language , String name ) + throws UnknownLanguageException + { + String oldName; + + this.data.writeLock( ).lock( ); + try { + oldName = this.data.updateLanguage( this.administrator , language , name ); + if ( oldName == null ) { + throw new UnknownLanguageException( language ); + } + } finally { + this.data.writeLock( ).unlock( ); + } + } + + + @Override + public Set< String > getStrings( ) + { + this.data.readLock( ).lock( ); + try { + return this.data.getStrings( ); + } finally { + this.data.readLock( ).unlock( ); + } + } + + + /* Documented in I18NAdministration interface */ + @Override + public String getTranslation( String language , String string ) + throws UnknownStringException , UnknownLanguageException + { + this.data.readLock( ).lock( ); + try { + if ( !this.data.hasLanguage( language ) ) { + throw new UnknownLanguageException( language ); + } + if ( !this.data.hasString( string ) ) { + throw new UnknownStringException( string ); + } + return this.data.getTranslation( language , string ); + } finally { + this.data.readLock( ).unlock( ); + } + } + + + @Override + public boolean updateTranslation( String language , String string , String translation ) + throws UnknownStringException , UnknownLanguageException + { + String oldString; + this.data.writeLock( ).lock( ); + try { + if ( !this.data.hasLanguage( language ) ) { + throw new UnknownLanguageException( language ); + } + if ( !this.data.hasString( string ) ) { + throw new UnknownStringException( string ); + } + oldString = this.data.setTranslation( this.administrator , language , string , translation ); + } finally { + this.data.writeLock( ).unlock( ); + } + return ( oldString == null ); + } + + + /* Documented in I18NAdministration interface */ + @Override + public void createString( String string , Map< String , String > translations ) + throws DuplicateStringException , UnknownLanguageException , InvalidUpdateException + { + Set< String > languages; + + this.data.writeLock( ).lock( ); + try { + // Check for duplicate string ID + if ( this.data.hasString( string ) ) { + throw new DuplicateStringException( string ); + } + + // Make sure all specified languages actually exist + languages = this.data.getLanguages( ); + for ( String lId : translations.keySet( ) ) { + if ( !languages.contains( lId ) ) { + throw new UnknownLanguageException( lId ); + } + languages.remove( lId ); + } + + // Make sure no 100% supported language becomes unsupported because a translation is + // missing + int sCount = this.data.getStringsCount( ); + for ( String lId : languages ) { + if ( this.data.getLanguageSize( lId ) < sCount ) { + languages.remove( lId ); + } + } + if ( !languages.isEmpty( ) ) { + throw new InvalidUpdateException( languages ); + } + + // Create the string + this.data.createString( this.administrator , string , translations ); + } finally { + this.data.writeLock( ).unlock( ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NData.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NData.java new file mode 100644 index 0000000..c48b5f6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NData.java @@ -0,0 +1,350 @@ +package com.deepclone.lw.beans.i18n; + + +import java.sql.Types; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import javax.sql.DataSource; + +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.utils.StoredProc; + + + +/** + * This class is used by all parts of the I18N support system; it centralises all I18N-related data, + * providing both read and write access. It implements the {@link ReadWriteLock} interface, although + * only as a convenience. + * + * @author tseeker + */ +class I18NData + implements ReadWriteLock +{ + /** The instance's read/write lock */ + private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock( ); + + /** Database interface */ + private final SimpleJdbcTemplate dTemplate; + + /** Transaction manager interface */ + private final TransactionTemplate tTemplate; + + /** String definitions, by identifier */ + private HashSet< String > strings; + + /** Languages by identifier. Each language is represented by a {@link LanguageStore} */ + private HashMap< String , LanguageStore > languages; + + private StoredProc fUocLanguage; + private StoredProc fUocTranslation; + + + /** Copies the required references then loads all data */ + I18NData( DataSource dataSource , TransactionTemplate tTemplate ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + this.tTemplate = tTemplate; + + this.fUocLanguage = new StoredProc( dataSource , "defs" , "uoc_language" ); + this.fUocLanguage.addParameter( "language" , Types.VARCHAR ); + this.fUocLanguage.addParameter( "name" , Types.VARCHAR ); + this.fUocLanguage.addParameter( "admin_id" , Types.INTEGER ); + + this.fUocTranslation = new StoredProc( dataSource , "defs" , "uoc_translation" ); + this.fUocTranslation.addParameter( "language" , Types.VARCHAR ); + this.fUocTranslation.addParameter( "string_id" , Types.VARCHAR ); + this.fUocTranslation.addParameter( "contents" , Types.VARCHAR ); + this.fUocTranslation.addParameter( "admin_id" , Types.INTEGER ); + + this.loadAll( ); + } + + + /** + * (Re)initialises the strings and languages definition maps, then starts a loader transaction + * to fill them from the database's contents. + */ + void loadAll( ) + { + this.strings = new HashSet< String >( ); + this.languages = new HashMap< String , LanguageStore >( ); + + LoaderTransaction trans = new LoaderTransaction( this.dTemplate , this.strings , this.languages ); + this.tTemplate.execute( trans ); + } + + + /** @return the set of known language identifiers */ + Set< String > getLanguages( ) + { + return new HashSet< String >( this.languages.keySet( ) ); + } + + + /** + * @param identifier + * a language's identifier + * @return whether a language exists or not + */ + boolean hasLanguage( String identifier ) + { + return this.languages.containsKey( identifier ); + } + + + /** + * @param string + * a string identifier + * @return whether such a string definition exists or not + */ + boolean hasString( String string ) + { + return this.strings.contains( string ); + } + + + /** + * @param identifier + * a language's identifier + * @return the amount of translations defined for the specified language, or 0 if the language + * does not exist + */ + int getLanguageSize( String identifier ) + { + if ( !this.hasLanguage( identifier ) ) { + return 0; + } + return this.languages.get( identifier ).getTranslationsCount( ); + } + + + /** @return the amount of defined string identifiers */ + int getStringsCount( ) + { + return this.strings.size( ); + } + + + /** + * Checks whether a language is fully supported. + * + * @param identifier + * the language's identifier + * @return true if there's a translation for each string definition in the specified language. + */ + boolean isLanguageComplete( String identifier ) + { + return this.getLanguageSize( identifier ) == this.getStringsCount( ); + } + + + /** @return the set of defined string identifiers */ + Set< String > getStrings( ) + { + return new HashSet< String >( this.strings ); + } + + + String getLanguageName( String id ) + { + if ( !this.hasLanguage( id ) ) { + return null; + } + return this.languages.get( id ).getLanguageName( ); + } + + + /** + * Creates a new language definition in the database. + * + * @param id + * the new language's identifier + * @param name + * the new language's name + * @return true on success, false otherwise + */ + boolean addLanguage( int administrator , String id , String name ) + { + if ( this.hasLanguage( id ) ) { + return false; + } + this.uocLanguage( administrator , id , name ); + this.languages.put( id , new LanguageStore( id , name ) ); + return true; + } + + + /** + * Modifies the name of a language. + * + * @param administrator + * + * @param id + * the language's identifier + * @param name + * the language's new name + * @return null if the language does not exist, or the old name of the language if it does + */ + String updateLanguage( int administrator , String id , String name ) + { + LanguageStore ls = this.languages.get( id ); + if ( ls == null ) { + return null; + } + + String oldName = ls.getLanguageName( ); + this.uocLanguage( administrator , id , name ); + ls.setLanguageName( name ); + return oldName; + } + + + private void uocLanguage( final int administrator , final String id , final String name ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + fUocLanguage.execute( id , name , administrator ); + } + } ); + } + + + /** + * Accesses the {@link Translation} object for a given language/string identifier pair. + * + * @param language + * the language's identifier + * @param string + * the string's identifier + * @return the translation + * @throws NullPointerException + * if the language does not exist + */ + String getTranslation( String language , String string ) + { + return this.languages.get( language ).getTranslation( string ); + } + + + /** + * Sets or creates the translation for a given language/string identifier pair. + * + * @param administrator + * + * @param language + * the language's identifier + * @param string + * the string's identifier + * @param translation + * the translated text for the string + * @return the old translated text if the translation existed or null if a new translation was + * created + * @throws NullPointerException + * if the language does not exist + * @throws IllegalArgumentException + * if the string does not exist + */ + String setTranslation( final int administrator , final String language , final String string , final String translation ) + { + // Get existing translation + LanguageStore store = this.languages.get( language ); + String old = store.getTranslation( string ); + if ( !this.strings.contains( string ) ) { + throw new IllegalArgumentException( ); + } + + // Create or update the database record + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + fUocTranslation.execute( language , string , translation , administrator ); + } + } ); + + // Store the new translation + store.addTranslation( string , translation ); + return old; + } + + + /** + * Creates a string from scratch, storing initial translations along with it. + * + * @param string + * the new string's identifier + * @param translations + * a language identifiers -> translated text map to use as the string's initial + * translations. + * @throws ConstraintViolationException + * if the string identifier already existed in the DB + * @throws NullPointerException + * if one of the languages does not exist + * @throws IllegalArgumentException + * if the string exists + */ + void createString( final int administrator , final String string , final Map< String , String > translations ) + { + if ( this.strings.contains( string ) ) { + throw new IllegalArgumentException( ); + } + + // Map language stores to translations + Map< LanguageStore , String > nTrans = new HashMap< LanguageStore , String >( ); + for ( String lId : translations.keySet( ) ) { + LanguageStore store = this.languages.get( lId ); + nTrans.put( store , translations.get( lId ) ); + } + + // Update the database + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + for ( Map.Entry< String , String > entry : translations.entrySet( ) ) { + fUocTranslation.execute( entry.getKey( ) , string , entry.getValue( ) , administrator ); + } + } + + } ); + + // Add the string definition to the local cache + this.strings.add( string ); + + // Add the various translations to each language's store + for ( Map.Entry< LanguageStore , String > entry : nTrans.entrySet( ) ) { + entry.getKey( ).addTranslation( string , entry.getValue( ) ); + } + } + + + /** @return the instance's read lock */ + @Override + public Lock readLock( ) + { + return this.lock.readLock( ); + } + + + /** @return the instance's write lock */ + @Override + public Lock writeLock( ) + { + return this.lock.writeLock( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NManagerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NManagerBean.java new file mode 100644 index 0000000..056a618 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/I18NManagerBean.java @@ -0,0 +1,97 @@ +package com.deepclone.lw.beans.i18n; + + +import javax.sql.DataSource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.i18n.I18NAdministration; +import com.deepclone.lw.interfaces.i18n.I18NManager; + + + +/** + * The I18N manager bean creates the {@link I18NData} instance on initialisation, which it then + * shares with translator beans and administrative session instances. + * + * @author tseeker + */ +public class I18NManagerBean + implements I18NManager , InitializingBean +{ + + /** Transaction manager interface */ + private TransactionTemplate tTemplate; + + /** Database interface */ + private DataSource dataSource; + + /** Data store shared amongst the translator beans and administrative session instances */ + private I18NData data; + + + /** + * Sets the transaction manager interface (DI) + * + * @param manager + * the transaction manager + */ + @Autowired( required = true ) + public void setTransactionManager( DataSourceTransactionManager manager ) + { + this.tTemplate = new TransactionTemplate( manager ); + } + + + /** + * Sets the JBDC interface (DI) + * + * @param dSource + * the data source + */ + @Autowired( required = true ) + public void setDataSource( DataSource dSource ) + { + this.dataSource = dSource; + } + + + /** Creates the shared {@link I18NData} instance on initialisation */ + @Override + public void afterPropertiesSet( ) + { + this.data = new I18NData( this.dataSource , this.tTemplate ); + } + + + /** @return the shared {@link I18NData} instance */ + I18NData getData( ) + { + return this.data; + } + + + /* Documentation in I18NManager interface */ + @Override + public I18NAdministration getAdminSession( int administrator ) + { + return new I18NAdministrationImpl( this.data , administrator ); + } + + + /* Documentation in I18NManager interface */ + @Override + public void reload( ) + { + this.data.writeLock( ).lock( ); + try { + this.data.loadAll( ); + } finally { + this.data.writeLock( ).unlock( ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/LanguageStore.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/LanguageStore.java new file mode 100644 index 0000000..dce2219 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/LanguageStore.java @@ -0,0 +1,79 @@ +package com.deepclone.lw.beans.i18n; + + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + + + +/** + * A language store encapsulates all data that defines a language - from the language definition + * itself to the various translations available in this language. + * + * @author tseeker + */ +class LanguageStore + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final String languageId; + + private String languageName; + + private final Map translations = new HashMap< String , String >( ); + + + public LanguageStore( String languageId , String languageName ) + { + this.languageId = languageId; + this.languageName = languageName; + } + + + /** @return the store's language identifier */ + String getLanguageIdentifier( ) + { + return this.languageId; + } + + + /** @return the name of the language encapsulated by the store */ + String getLanguageName( ) + { + return this.languageName; + } + + + /** @return the amount of translations available from the store */ + int getTranslationsCount( ) + { + return this.translations.size( ); + } + + + /** + * @param string + * a string identifier + * @return the translated string + */ + String getTranslation( String string ) + { + return this.translations.get( string ); + } + + + void addTranslation( String stringId , String translation ) + { + this.translations.put( stringId , translation ); + } + + + void setLanguageName( String name ) + { + this.languageName = name; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/LoaderTransaction.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/LoaderTransaction.java new file mode 100644 index 0000000..ffedd04 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/LoaderTransaction.java @@ -0,0 +1,86 @@ +package com.deepclone.lw.beans.i18n; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.HashSet; + +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; + +import com.deepclone.lw.sqld.i18n.Translation; + + + + +/** + * The I18N data loader transaction reads all string definitions and language definitions from the + * database, creating {@link LanguageStore} instances for each language. + * + * @author tseeker + */ +class LoaderTransaction + extends TransactionCallbackWithoutResult +{ + + /** Database interface */ + private final SimpleJdbcTemplate dTemplate; + + /** String definition map being initialised */ + private final HashSet< String > strings; + + /** Language definition map being initialised */ + private final HashMap< String , LanguageStore > languages; + + + /** Copies the required references */ + LoaderTransaction( SimpleJdbcTemplate dTemplate , HashSet< String > strings , + HashMap< String , LanguageStore > languages ) + { + this.dTemplate = dTemplate; + this.strings = strings; + this.languages = languages; + } + + + /** + * The transaction loads all string definitions, storing them in the string definition map, then + * loads all languages, creating a {@link LanguageStore} for each instance. + */ + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + String sql; + RowMapper< Translation > mapper = new RowMapper< Translation >( ) { + + @Override + public Translation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + Translation t = new Translation( ); + t.setLanguageId( rs.getString( "language_id" ) ); + t.setLanguageName( rs.getString( "language_name" ) ); + t.setStringId( rs.getString( "string_id" ) ); + t.setTranslation( rs.getString( "translation" ) ); + return t; + } + + }; + + sql = "SELECT language_id , language_name , string_id , translation FROM defs.translations_view"; + for ( Translation trans : this.dTemplate.query( sql , mapper ) ) { + this.strings.add( trans.getStringId( ) ); + + LanguageStore ls = this.languages.get( trans.getLanguageId( ) ); + if ( ls == null ) { + ls = new LanguageStore( trans.getLanguageId( ) , trans.getLanguageName( ) ); + this.languages.put( trans.getLanguageId( ) , ls ); + } + ls.addTranslation( trans.getStringId( ) , trans.getTranslation( ) ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/TranslatorBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/TranslatorBean.java new file mode 100644 index 0000000..7ce8046 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/java/com/deepclone/lw/beans/i18n/TranslatorBean.java @@ -0,0 +1,122 @@ +package com.deepclone.lw.beans.i18n; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.i18n.UnknownLanguageException; +import com.deepclone.lw.interfaces.i18n.UnknownStringException; + + + +/** + * The translator bean's implementation uses the contents of the {@link I18NData} instance, which it + * only accesses in read-only mode. + * + * @author tseeker + */ +public class TranslatorBean + implements Translator +{ + private I18NData data; + + + /** + * Sets the bean's I18N manager (DI) + * + * @param manager + * the I18N manager to use + */ + @Autowired( required = true ) + public void setI18NManager( I18NManagerBean manager ) + { + this.data = manager.getData( ); + } + + + /* Documentation in Translator interface */ + @Override + public Set< String > getSupportedLanguages( ) + { + Set< String > supported = new HashSet< String >( ); + int sCount , lSize; + + this.data.readLock( ).lock( ); + try { + sCount = this.data.getStringsCount( ); + if ( sCount == 0 ) { + return supported; + } + + for ( String lId : this.data.getLanguages( ) ) { + lSize = this.data.getLanguageSize( lId ); + if ( lSize == sCount ) { + supported.add( lId ); + } + } + + return supported; + } finally { + this.data.readLock( ).unlock( ); + } + } + + + /* Documentation in Translator interface */ + @Override + public boolean isLanguageSupported( String language ) + { + int lSize , sCount; + + this.data.readLock( ).lock( ); + try { + lSize = this.data.getLanguageSize( language ); + sCount = this.data.getStringsCount( ); + + return ( sCount > 0 && lSize == sCount ); + } finally { + this.data.readLock( ).unlock( ); + } + } + + + /* Documentation in Translator interface */ + @Override + public String translate( String language , String string ) + throws UnknownStringException , UnknownLanguageException + { + this.data.readLock( ).lock( ); + try { + if ( !this.data.hasString( string ) ) { + throw new UnknownStringException( string ); + } + if ( !this.data.isLanguageComplete( language ) ) { + throw new UnknownLanguageException( language ); + } + return this.data.getTranslation( language , string ); + } finally { + this.data.readLock( ).unlock( ); + } + } + + + /* Documentation in Translator interface */ + @Override + public String getLanguageName( String language ) + throws UnknownLanguageException + { + this.data.readLock( ).lock( ); + try { + if ( !this.data.isLanguageComplete( language ) ) { + throw new UnknownLanguageException( language ); + } + return this.data.getLanguageName( language ); + } finally { + this.data.readLock( ).unlock( ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n-beans.xml new file mode 100644 index 0000000..bfaaebb --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n-beans.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n/i18n-manager-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n/i18n-manager-bean.xml new file mode 100644 index 0000000..a683f48 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n/i18n-manager-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n/i18n-translator-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n/i18n-translator-bean.xml new file mode 100644 index 0000000..9118332 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-i18n/src/main/resources/configuration/i18n/i18n-translator-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.project new file mode 100644 index 0000000..1c8b8cf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-mailer + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..0a8422b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 09 10:19:43 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/pom.xml new file mode 100644 index 0000000..9b2eba1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/pom.xml @@ -0,0 +1,35 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-beans-mailer + 5.99.1 + Legacy Worlds mailer + + This package contains the mailer component, which uses LW's i18n system and Spring's mail sending interfaces. +It is capable of sending mails synchronously or asynchronously. + + + + + org.springframework + spring-context-support + ${org.springframework.version} + jar + + + + javax.mail + mail + ${javax.mail.version} + runtime + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailDataImpl.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailDataImpl.java new file mode 100644 index 0000000..052cf6c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailDataImpl.java @@ -0,0 +1,170 @@ +package com.deepclone.lw.beans.mailer; + + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.deepclone.lw.interfaces.mailer.AlreadySentException; +import com.deepclone.lw.interfaces.mailer.MailData; +import com.deepclone.lw.interfaces.mailer.MissingDataException; +import com.deepclone.lw.interfaces.mailer.NotSentException; + + + +/** + * The mail data implementation consists in a single-use message sender that includes templating + * capabilities. + * + * @author tseeker + */ +class MailDataImpl + implements MailData +{ + + /* Regular expressions used to identify template variables */ + private static final String camelCase = "[a-z]+([A-Z][a-z]*)*"; + private static final String fieldName = camelCase + "(\\." + camelCase + ")*"; + private static final String field = "\\$\\{(" + fieldName + ")\\}"; + private static final Pattern fPattern = Pattern.compile( field ); + + /** Queue-handling task */ + private final MailQueueHandler mailQueueTask; + + /** Address of the message's recipient */ + private final String mailTo; + + /** Template string of the message */ + private final String template; + + /** Field values to use when replacing */ + private Map< String , Object > fields = new HashMap< String , Object >( ); + + /** Flag indicating whether the message has already been sent */ + private Boolean sent = false; + + + /** + * Initialise the instance's data then extract variable names from the template string.f + * + * @param task + * the queue-handling task + * @param target + * the address of the message's recipient + * @param template + * the message's template + */ + MailDataImpl( MailQueueHandler task , String target , String template ) + { + this.mailQueueTask = task; + this.mailTo = target; + this.template = template; + this.parseTemplate( ); + } + + + /** + * Extracts variable names from the template. + */ + private void parseTemplate( ) + { + Matcher m = fPattern.matcher( this.template ); + while ( m.find( ) ) { + this.fields.put( m.group( 1 ) , null ); + } + } + + + /** + * Makes sure a message is never sent twice. + * + * @throws AlreadySentException + * if the message had already been sent. + */ + private void checkSent( ) + throws AlreadySentException + { + synchronized ( this.sent ) { + if ( this.sent ) { + throw new AlreadySentException( ); + } + this.sent = true; + } + } + + + /** + * Prepares the message's data. + * + * This method will check that the message has not been sent, then start replacing variables by + * their assigned values in the template. It will return the fully-substituted message text. + * + * @return the message's text after variable substitution + * @throws AlreadySentException + * if the message has already been sent + * @throws MissingDataException + * if one of the variables has no value + */ + private String prepareMail( ) + throws AlreadySentException , MissingDataException + { + this.checkSent( ); + + String message = this.template; + for ( String fName : this.fields.keySet( ) ) { + Object value = this.fields.get( fName ); + if ( value == null ) { + synchronized ( this.sent ) { + this.sent = false; + } + throw new MissingDataException( fName ); + } + + String regexp = "\\$\\{"; + regexp += fName.replace( (CharSequence) "." , (CharSequence) "\\." ); + regexp += "\\}"; + + Pattern p = Pattern.compile( regexp ); + message = p.matcher( message ).replaceAll( value.toString( ).replace( "$" , "\\$" ) ); + } + + return message; + } + + + /* Documented in MailData interface */ + @Override + public void queue( ) + throws AlreadySentException , MissingDataException + { + this.mailQueueTask.queueMessage( this.mailTo , this.prepareMail( ) ); + } + + + /* Documented in MailData interface */ + @Override + public void sendNow( ) + throws AlreadySentException , NotSentException , MissingDataException + { + this.mailQueueTask.sendMessage( this.mailTo , this.prepareMail( ) ); + } + + + /* Documented in MailData interface */ + @Override + public void setData( String identifier , Object value ) + { + if ( !this.fields.containsKey( identifier ) ) { + throw new IllegalArgumentException( "unknown field '" + identifier + "'" ); + } + if ( this.fields.get( identifier ) != null ) { + throw new IllegalArgumentException( "field '" + identifier + "' already set" ); + } + if ( value == null ) { + throw new IllegalArgumentException( "field value may not be null" ); + } + this.fields.put( identifier , value ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueHandler.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueHandler.java new file mode 100644 index 0000000..8b35e5c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueHandler.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.mailer; + + +import com.deepclone.lw.interfaces.mailer.NotSentException; + + + +/** + * Mail queue handler interface + * + * This interface is normally implemented by the mail queue task. However, it is required in order + * to test the MailData implementation separately. + * + * @author tseeker + */ +interface MailQueueHandler +{ + + /** + * Stops the queue-handling task. + * + * This method inserts a terminator into the queue, then waits for the queue to be + * de-initialised (which indicates that the main loop ended). + */ + public void stop( ); + + + /** + * Adds a message to the queue. + * + * @param mailTo + * the address of the email's recipient. + * @param message + * the contents of the email + */ + public void queueMessage( String mailTo , String message ); + + + /** + * Sends a message. + * + * @param mailTo + * address of the email's recipient + * @param message + * contents of the message + * @throws NotSentException + * if the mail could not be sent for some reason + */ + public void sendMessage( String mailTo , String message ) + throws NotSentException; + +} \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueItem.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueItem.java new file mode 100644 index 0000000..d882c66 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueItem.java @@ -0,0 +1,13 @@ +package com.deepclone.lw.beans.mailer; + + +/** + * This empty abstract class is used as the base class for both queued mails and termination + * signals. + * + * @author tseeker + */ +abstract class MailQueueItem +{ + // EMPTY +} \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueTask.java new file mode 100644 index 0000000..4b5d478 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueTask.java @@ -0,0 +1,211 @@ +package com.deepclone.lw.beans.mailer; + + +import java.util.concurrent.LinkedBlockingQueue; + +import org.springframework.mail.MailException; +import org.springframework.mail.MailSender; +import org.springframework.mail.SimpleMailMessage; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.mailer.NotSentException; + + + +/** + * This class implements the queue-handling task of the mailer bean. This task is responsible for + * sending mail asynchronously, but it also provides a method allowing mails to be sent + * synchronously by {@link MailData} instances. + * + * @author tseeker + */ +class MailQueueTask + implements Runnable , MailQueueHandler +{ + + /** The bean's system logger */ + private final SystemLogger logger; + + /** The From: address */ + private final String mailFrom; + + /** The mail sender bean */ + private final MailSender mailSender; + + /** The mail queue */ + private LinkedBlockingQueue< MailQueueItem > queue; + + + /** Copies the various data and references */ + MailQueueTask( SystemLogger logger , String mailFrom , LinkedBlockingQueue< MailQueueItem > queue , + MailSender mailSender ) + { + this.logger = logger; + this.mailFrom = mailFrom; + this.queue = queue; + this.mailSender = mailSender; + } + + + /** + * Stops the queue-handling task. + * + * This method inserts a terminator into the queue, then waits for the queue to be + * de-initialised (which indicates that the main loop ended). + */ + @Override + public void stop( ) + { + this.queue.add( new MailQueueTerminator( ) ); + while ( this.queue != null ) { + Thread.yield( ); + } + } + + + /** + * Adds a message to the queue. + * + * This method adds a new {@link QueuedMail} instance to the queue, initialising it using the + * specified parameters. Should the queueing fail for some reason, the error is logged. + * + * @param mailTo + * the address of the email's recipient. + * @param message + * the contents of the email + */ + @Override + public void queueMessage( String mailTo , String message ) + { + try { + this.queue.put( new QueuedMail( mailTo , message ) ); + this.logger.log( LogLevel.DEBUG , "queued mail to " + mailTo ); + } catch ( InterruptedException e ) { + // This should never happen, as the queue is non-blocking on this end + this.logger.log( LogLevel.ERROR , "could not queue mail to " + mailTo , e ); + } + this.logger.flush( ); + } + + + /** + * Sends a message. + * + * This method splits the message into two parts (subject and body), then initialises the + * {@link SimpleMailMessage} instance corresponding to the mail, before finally trying to send + * it through the mail sender bean. + * + * @param mailTo + * address of the email's recipient + * @param message + * contents of the message + * @throws NotSentException + * if the mail could not be sent for some reason + */ + @Override + public void sendMessage( String mailTo , String message ) + throws NotSentException + { + // Extract title and body from message + // FIXME: there are better ways to do this + String title = ""; + int i = 0; + while ( i < message.length( ) && message.charAt( i ) != '\n' ) { + title += message.charAt( i ); + i++; + } + while ( i < message.length( ) && message.charAt( i ) == '\n' ) { + i++; + } + String body = ( i == message.length( ) ) ? "" : message.substring( i ); + + // Write log if the title or the body are empty + if ( title.equals( "" ) ) { + this.logger.log( LogLevel.WARNING , "sending email with no title" ); + } + if ( body.equals( "" ) ) { + this.logger.log( LogLevel.WARNING , "sending email with empty body" ); + } + this.logger.flush( ); + + // Create actual mail data + SimpleMailMessage smm = new SimpleMailMessage( ); + smm.setFrom( this.mailFrom ); + smm.setTo( mailTo ); + smm.setSubject( title ); + smm.setText( body ); + + // Try to send it + synchronized ( this.mailSender ) { + try { + this.mailSender.send( smm ); + } catch ( MailException e ) { + this.logger.log( LogLevel.INFO , "could not send mail to " + mailTo , e ).flush( ); + throw new NotSentException( e ); + } + } + this.logger.log( LogLevel.DEBUG , "sent mail to " + mailTo ).flush( ); + } + + + /** + * Main queue-handling loop. + * + * This method contains the task's main loop. It constantly polls the queue for incoming + * information, sending queued email. All errors while sending messages are ignored. When a + * terminator is found on the queue, all remaining messages will be flushed and the main loop + * will exit. + */ + @Override + public void run( ) + { + boolean keepRunning = true; + LinkedBlockingQueue< MailQueueItem > queue = this.queue; + while ( keepRunning ) { + MailQueueItem item; + + // Wait for items to send + try { + item = queue.take( ); + } catch ( InterruptedException e ) { + this.logger.log( LogLevel.WARNING , "mail queue consumer interrupted" ).flush( ); + continue; + } + + // Handle terminators + if ( item instanceof MailQueueTerminator ) { + keepRunning = false; + this.logger.log( LogLevel.INFO , "termination order received" ).flush( ); + } + + do { + // Send mail + if ( item instanceof QueuedMail ) { + QueuedMail mail = (QueuedMail) item; + try { + this.sendMessage( mail.mailTo , mail.message ); + } catch ( NotSentException e ) { + // Unable to send; it's been logged, so we ignore it + } + } + // If we're terminating, flush the queue + if ( ! ( keepRunning || queue.isEmpty( ) ) ) { + boolean fail; + do { + try { + item = queue.take( ); + fail = false; + } catch ( InterruptedException e ) { + fail = true; + } + } while ( fail ); + } + } while ( !keepRunning && !queue.isEmpty( ) ); + } + + // Kill the queue + this.queue = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueTerminator.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueTerminator.java new file mode 100644 index 0000000..d8f6fd3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailQueueTerminator.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.beans.mailer; + + +/** + * This empty class is a mail queue item which indicates that the mail queue handling task should + * terminate. + * + * @author tseeker + */ +class MailQueueTerminator + extends MailQueueItem +{ + // EMPTY +} \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailerBean.java new file mode 100644 index 0000000..c57f329 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/MailerBean.java @@ -0,0 +1,140 @@ +package com.deepclone.lw.beans.mailer; + + +import java.util.concurrent.LinkedBlockingQueue; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.MailSender; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.interfaces.eventlog.*; +import com.deepclone.lw.interfaces.i18n.*; +import com.deepclone.lw.interfaces.mailer.*; + + + +/** + * The mailer bean spawns a queue-handling task on initialisation. It is responsible for + * initialising mail data instances, giving them access to the queue-handling task. When the + * container destroys the bean, it inserts a terminator in the mail queue then waits for the task to + * end. + * + * @author tseeker + */ +public class MailerBean + implements Mailer , InitializingBean , DisposableBean +{ + /** The default From: address for mails sent by the bean */ + private final static String defaultSender = "webmaster@legacyworlds.com"; + + /** Translator bean */ + private Translator translator; + + /** Spring mail sender bean */ + private MailSender mailSender; + + /** System logger for the mailer bean */ + private SystemLogger logger; + + /** From: address to use when sending mails */ + private String mailFrom = defaultSender; + + /** Mail queue */ + private LinkedBlockingQueue< MailQueueItem > queue; + + /** Queue-handling task */ + private MailQueueTask task; + + + /** + * Sets the translator bean (DI) + * + * @param translator + * the translator bean + */ + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + /** + * Sets the mail sender bean (DI) + * + * @param mailSender + * the mail sender bean + */ + @Autowired( required = true ) + public void setMailSender( MailSender mailSender ) + { + this.mailSender = mailSender; + } + + + /** + * Initialises the system logger (DI) + * + * @param logger + * the logger bean + */ + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger.getSystemLogger( "Mailer" ); + } + + + /** + * Changes the From: address. + * + * @param mailFrom + * the new From: address + */ + public void setMailFrom( String mailFrom ) + { + this.mailFrom = mailFrom; + } + + + /** + * Creates the mail queue and spawns the queue-handling task when the bean is initialised. + */ + @Override + public void afterPropertiesSet( ) + { + this.logger.log( LogLevel.INFO , "mailer task initialising" ).flush( ); + + this.queue = new LinkedBlockingQueue< MailQueueItem >( ); + this.task = new MailQueueTask( this.logger , this.mailFrom , this.queue , this.mailSender ); + + Thread t = new Thread( this.task ); + t.start( ); + } + + + /** + * Terminates and waits for the queue-handling task when the bean is destroyed. + */ + @Override + public void destroy( ) + { + this.task.stop( ); + this.task = null; + this.queue = null; + } + + + /* Documentation in Mailer interface */ + @Override + public MailData createMail( String language , String contentsDef , String target ) + throws TranslationException + { + + String template = this.translator.translate( language , contentsDef ); + return new MailDataImpl( this.task , target , template ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/QueuedMail.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/QueuedMail.java new file mode 100644 index 0000000..c01b9da --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/java/com/deepclone/lw/beans/mailer/QueuedMail.java @@ -0,0 +1,26 @@ +package com.deepclone.lw.beans.mailer; + + +/** + * This class represents a queued mail on the mail task's queue. It carries both the target address + * and the message's contents. + * + * @author tseeker + */ +class QueuedMail + extends MailQueueItem +{ + /** The target mail address */ + final String mailTo; + + /** The contents of the email */ + final String message; + + + /** Initialises the queued mail */ + QueuedMail( String mailTo , String message ) + { + this.mailTo = mailTo; + this.message = message; + } +} \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/resources/configuration/mailer-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/resources/configuration/mailer-beans.xml new file mode 100644 index 0000000..e5e284f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/resources/configuration/mailer-beans.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/resources/configuration/mailer/mailer-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/resources/configuration/mailer/mailer-bean.xml new file mode 100644 index 0000000..a430dd0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-mailer/src/main/resources/configuration/mailer/mailer-bean.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.project new file mode 100644 index 0000000..f7bc35d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-naming + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..d627e17 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Thu Feb 25 09:52:02 CET 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..8e6c298 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Thu Feb 25 09:52:02 CET 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/pom.xml new file mode 100644 index 0000000..00964d7 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-beans-naming + 5.99.1 + Legacy Worlds object naming system + This module contains the beans responsible for managing the names of the various objects (players and planets). + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/java/com/deepclone/lw/beans/naming/NamesManagerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/java/com/deepclone/lw/beans/naming/NamesManagerBean.java new file mode 100644 index 0000000..c246ffc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/java/com/deepclone/lw/beans/naming/NamesManagerBean.java @@ -0,0 +1,98 @@ +package com.deepclone.lw.beans.naming; + + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.naming.GetNamesResponse; +import com.deepclone.lw.cmd.admin.naming.NameType; +import com.deepclone.lw.cmd.admin.naming.NamesSummaryResponse; +import com.deepclone.lw.cmd.admin.naming.NamesSummaryResponse.Entry; +import com.deepclone.lw.interfaces.naming.NamesManager; +import com.deepclone.lw.interfaces.naming.NamingDAO; + + + +@Transactional +public class NamesManagerBean + implements NamesManager +{ + + private NamingDAO namingDao; + + + @Autowired( required = true ) + public void setNamingDao( NamingDAO namingDao ) + { + this.namingDao = namingDao; + } + + + @Override + public NamesSummaryResponse getSummary( Administrator admin ) + { + List< Entry > entries = new LinkedList< Entry >( ); + for ( Map.Entry< NameType , Long > entry : this.namingDao.countNames( ).entrySet( ) ) { + entries.add( new Entry( entry.getKey( ) , entry.getValue( ) ) ); + } + return new NamesSummaryResponse( admin , entries ); + } + + + @Override + public GetNamesResponse getNames( Administrator admin , NameType type ) + { + return new GetNamesResponse( admin , type , this.namingDao.getNames( type ) ); + } + + + @Override + public void validateMapNames( Administrator admin , int[] ids ) + { + for ( int id : ids ) { + this.namingDao.validateMapName( admin.getId( ) , id ); + } + } + + + @Override + public void allowMapNameChanges( Administrator admin , int[] ids ) + { + for ( int id : ids ) { + this.namingDao.allowMapNameChange( admin.getId( ) , id ); + } + } + + + @Override + public void rejectMapNames( Administrator admin , int[] ids , boolean ban ) + { + for ( int id : ids ) { + this.namingDao.rejectMapName( admin.getId( ) , id , ban ); + } + } + + + @Override + public void rejectEmpireNames( Administrator admin , int[] ids , boolean ban ) + { + for ( int id : ids ) { + this.namingDao.rejectEmpireName( admin.getId( ) , id , ban ); + } + } + + + @Override + public void rejectAllianceNames( Administrator admin , int[] ids ) + { + for ( int id : ids ) { + this.namingDao.rejectAllianceName( admin.getId( ) , id ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/java/com/deepclone/lw/beans/naming/NamingDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/java/com/deepclone/lw/beans/naming/NamingDAOBean.java new file mode 100644 index 0000000..2c2be52 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/java/com/deepclone/lw/beans/naming/NamingDAOBean.java @@ -0,0 +1,215 @@ +package com.deepclone.lw.beans.naming; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.admin.naming.Name; +import com.deepclone.lw.cmd.admin.naming.NameType; +import com.deepclone.lw.interfaces.naming.NamingDAO; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.utils.StoredProc; + + + +public class NamingDAOBean + implements NamingDAO +{ + private static final String sCountNames = "SELECT * FROM naming.names_status_view ORDER BY status"; + + private static class CountRow + { + String status; + long count; + } + + private SimpleJdbcTemplate dTemplate; + + private StoredProc fGetEmpire; + private StoredProc fRenamePlanet; + private StoredProc fValidateMapName; + private StoredProc fAllowMapRename; + private StoredProc fRejectMapName; + private StoredProc fRejectEmpireName; + private StoredProc fRejectAllianceName; + + private final RowMapper< Name > mName; + private final RowMapper< CountRow > mCount; + + + public NamingDAOBean( ) + { + this.mName = new RowMapper< Name >( ) { + @Override + public Name mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return new Name( rs.getInt( "id" ) , rs.getString( "name" ) , rs.getString( "extra" ) , NameType + .valueOf( rs.getString( "status" ) ) ); + } + }; + this.mCount = new RowMapper< CountRow >( ) { + @Override + public CountRow mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + CountRow cRow = new CountRow( ); + cRow.count = rs.getLong( "count" ); + cRow.status = rs.getString( "status" ); + return cRow; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fGetEmpire = new StoredProc( dataSource , "emp" , "get_current" ); + this.fGetEmpire.addParameter( "account_id" , Types.INTEGER ); + this.fGetEmpire.addOutput( "empire_id" , Types.INTEGER ); + + this.fRenamePlanet = new StoredProc( dataSource , "verse" , "rename_planet" ); + this.fRenamePlanet.addParameter( "planet_id" , Types.INTEGER ); + this.fRenamePlanet.addParameter( "new_name" , Types.VARCHAR ); + this.fRenamePlanet.addOutput( "err_code" , Types.INTEGER ); + + this.fValidateMapName = new StoredProc( dataSource , "naming" , "validate_map_name" ); + this.fValidateMapName.addParameter( "admin_id" , Types.INTEGER ); + this.fValidateMapName.addParameter( "name_id" , Types.INTEGER ); + + this.fAllowMapRename = new StoredProc( dataSource , "naming" , "allow_map_name_change" ); + this.fAllowMapRename.addParameter( "admin_id" , Types.INTEGER ); + this.fAllowMapRename.addParameter( "name_id" , Types.INTEGER ); + + this.fRejectMapName = new StoredProc( dataSource , "naming" , "reject_map_name" ); + this.fRejectMapName.addParameter( "admin_id" , Types.INTEGER ); + this.fRejectMapName.addParameter( "name_id" , Types.INTEGER ); + this.fRejectMapName.addParameter( "ban_name" , Types.BOOLEAN ); + + this.fRejectEmpireName = new StoredProc( dataSource , "naming" , "reject_empire_name" ); + this.fRejectEmpireName.addParameter( "admin_id" , Types.INTEGER ); + this.fRejectEmpireName.addParameter( "name_id" , Types.INTEGER ); + this.fRejectEmpireName.addParameter( "ban_name" , Types.BOOLEAN ); + + this.fRejectAllianceName = new StoredProc( dataSource , "naming" , "reject_alliance_name" ); + this.fRejectAllianceName.addParameter( "admin_id" , Types.INTEGER ); + this.fRejectAllianceName.addParameter( "alliance_id" , Types.INTEGER ); + } + + + @Override + public List< String > getEmpireNames( int account ) + { + String sql = "SELECT name FROM naming.empire_names WHERE owner_id = ? ORDER BY name"; + RowMapper< String > mapper = new RowMapper< String >( ) { + @Override + public String mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return rs.getString( "name" ); + } + }; + + return this.dTemplate.query( sql , mapper , account ); + } + + + @Override + public Integer getCurrentEmpire( Account account ) + { + return (Integer) this.fGetEmpire.execute( account.getId( ) ).get( "empire_id" ); + } + + + @Override + public int renamePlanet( int id , String name ) + { + return (Integer) this.fRenamePlanet.execute( id , name ).get( "err_code" ); + } + + + @Override + public Map< NameType , Long > countNames( ) + { + Map< NameType , Long > result = new HashMap< NameType , Long >( ); + for ( NameType t : NameType.values( ) ) { + result.put( t , 0L ); + } + + for ( CountRow qr : this.dTemplate.query( sCountNames , this.mCount ) ) { + NameType type = NameType.valueOf( qr.status ); + result.put( type , qr.count ); + } + + result.put( NameType.MAP_CHANGED , result.get( NameType.MAP_PENDING ) + result.get( NameType.MAP_VALIDATED ) ); + + return result; + } + + + @Override + public List< Name > getNames( NameType type ) + { + String sql = "SELECT * FROM naming.names_view WHERE status "; + if ( type == NameType.MAP_CHANGED ) { + sql += "IN ('MAP_PENDING','MAP_VALIDATED')"; + } else { + sql += "= '" + type + "'"; + } + if ( type == NameType.ALLIANCE || type == NameType.EMPIRE ) { + sql += " ORDER BY id DESC"; + } else { + sql += " ORDER BY name"; + } + + return this.dTemplate.query( sql , this.mName ); + } + + + @Override + public void validateMapName( int administrator , int name ) + { + this.fValidateMapName.execute( administrator , name ); + } + + + @Override + public void allowMapNameChange( int administrator , int name ) + { + this.fAllowMapRename.execute( administrator , name ); + } + + + @Override + public void rejectMapName( int administrator , int name , boolean ban ) + { + this.fRejectMapName.execute( administrator , name , ban ); + } + + + @Override + public void rejectEmpireName( int administrator , int empire , boolean ban ) + { + this.fRejectEmpireName.execute( administrator , empire , ban ); + } + + + @Override + public void rejectAllianceName( int administrator , int alliance ) + { + this.fRejectAllianceName.execute( administrator , alliance ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming-beans.xml new file mode 100644 index 0000000..f4ab8cc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming-beans.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming/names-manager-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming/names-manager-bean.xml new file mode 100644 index 0000000..060f506 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming/names-manager-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming/naming-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming/naming-dao-bean.xml new file mode 100644 index 0000000..0a3dfe5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-naming/src/main/resources/configuration/naming/naming-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.project new file mode 100644 index 0000000..e30c96f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-simple + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..a82c1db --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Thu Apr 22 11:23:34 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..fa121cb --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Thu Apr 22 11:23:34 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/pom.xml new file mode 100644 index 0000000..e1929cf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/pom.xml @@ -0,0 +1,13 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + com.deepclone.lw + legacyworlds-server-beans-simple + 5.99.1 + Legacy Worlds simple game + This module contains code that corresponds to a simple "placeholder" game. This code should become obsolete over time, as it is being replaced with actual LWB6 code, until the module can finally be removed. + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/AllianceDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/AllianceDAOBean.java new file mode 100644 index 0000000..df2d7cc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/AllianceDAOBean.java @@ -0,0 +1,265 @@ +package com.deepclone.lw.beans.empire; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceLeaderData; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceMemberData; +import com.deepclone.lw.cmd.player.gdata.alliance.AlliancePlanetData; +import com.deepclone.lw.cmd.player.gdata.alliance.PublicAllianceInformation; +import com.deepclone.lw.interfaces.game.AllianceDAO; +import com.deepclone.lw.sqld.game.AllianceMembership; +import com.deepclone.lw.utils.StoredProc; + + + +public class AllianceDAOBean + implements AllianceDAO +{ + + private SimpleJdbcTemplate dTemplate; + private StoredProc fCreateAlliance; + private StoredProc fJoinAlliance; + private StoredProc fCancelJoin; + private StoredProc fLeaveAlliance; + private StoredProc fTransferLeadership; + private StoredProc fAcceptMembers; + private StoredProc fRejectMembers; + private StoredProc fKickMembers; + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fCreateAlliance = new StoredProc( dataSource , "emp" , "create_alliance" ); + this.fCreateAlliance.addParameter( "empire_id" , Types.INTEGER ); + this.fCreateAlliance.addParameter( "alliance_tag" , Types.VARCHAR ); + this.fCreateAlliance.addParameter( "alliance_name" , Types.VARCHAR ); + this.fCreateAlliance.addOutput( "alliance_id" , Types.INTEGER ); + + this.fJoinAlliance = new StoredProc( dataSource , "emp" , "join_alliance" ); + this.fJoinAlliance.addParameter( "empire_id" , Types.INTEGER ); + this.fJoinAlliance.addParameter( "alliance_id" , Types.INTEGER ); + this.fJoinAlliance.addOutput( "success" , Types.BOOLEAN ); + + this.fCancelJoin = new StoredProc( dataSource , "emp" , "cancel_join" ); + this.fCancelJoin.addParameter( "empire_id" , Types.INTEGER ); + + this.fLeaveAlliance = new StoredProc( dataSource , "emp" , "leave_alliance" ); + this.fLeaveAlliance.addParameter( "empire_id" , Types.INTEGER ); + + this.fTransferLeadership = new StoredProc( dataSource , "emp" , "transfer_leadership" ); + this.fTransferLeadership.addParameter( "empire_id" , Types.INTEGER ); + this.fTransferLeadership.addParameter( "target_id" , Types.INTEGER ); + + this.fAcceptMembers = new StoredProc( dataSource , "emp" , "accept_members" ); + this.fAcceptMembers.addParameter( "empire_id" , Types.INTEGER ); + this.fAcceptMembers.addParameter( "member_ids" , "INT[]" ); + + this.fRejectMembers = new StoredProc( dataSource , "emp" , "reject_members" ); + this.fRejectMembers.addParameter( "empire_id" , Types.INTEGER ); + this.fRejectMembers.addParameter( "member_ids" , "INT[]" ); + + this.fKickMembers = new StoredProc( dataSource , "emp" , "kick_members" ); + this.fKickMembers.addParameter( "empire_id" , Types.INTEGER ); + this.fKickMembers.addParameter( "member_ids" , "INT[]" ); + } + + + @Override + public Integer findAlliance( String tag ) + { + String sql = "SELECT id FROM emp.alliances_public WHERE lower( tag ) = ?"; + try { + return this.dTemplate.queryForInt( sql , tag.toLowerCase( ) ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public AllianceMembership getAlliance( int empireId ) + { + String sql = "SELECT alliance , pending FROM emp.alliance_membership WHERE id = ?"; + RowMapper< AllianceMembership > mapper = new RowMapper< AllianceMembership >( ) { + @Override + public AllianceMembership mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + AllianceMembership am = new AllianceMembership( ); + am.setAllianceId( rs.getInt( "alliance" ) ); + am.setPending( rs.getBoolean( "pending" ) ); + return am; + } + }; + try { + return this.dTemplate.queryForObject( sql , mapper , empireId ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public Integer createAlliance( int empireId , String tag , String name ) + { + return (Integer) this.fCreateAlliance.execute( empireId , tag , name ).get( "alliance_id" ); + } + + + @Override + public PublicAllianceInformation getPublicInformation( int allianceId ) + { + String sql = "SELECT * FROM emp.alliances_public WHERE id = ?"; + RowMapper< PublicAllianceInformation > mapper = new RowMapper< PublicAllianceInformation >( ) { + @Override + public PublicAllianceInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return new PublicAllianceInformation( rs.getInt( "id" ) , rs.getString( "tag" ) , + rs.getString( "name" ) , rs.getInt( "leader_id" ) , rs.getString( "leader_name" ) , rs + .getLong( "planets" ) ); + } + }; + + try { + return this.dTemplate.queryForObject( sql , mapper , allianceId ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + private List< NameIdPair > getMembers( int allianceId , boolean pending ) + { + String mSql = "SELECT id , name FROM emp.alliance_membership WHERE alliance = ? AND "; + if ( !pending ) { + mSql += "NOT "; + } + mSql += "pending"; + RowMapper< NameIdPair > mMapper = new RowMapper< NameIdPair >( ) { + @Override + public NameIdPair mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return new NameIdPair( rs.getInt( 1 ) , rs.getString( 2 ) ); + } + }; + List< NameIdPair > members = this.dTemplate.query( mSql , mMapper , allianceId ); + return members; + } + + + private List< AlliancePlanetData > getPlanets( int allianceId ) + { + String pSql = "SELECT * FROM emp.alliance_planets WHERE alliance = ?"; + RowMapper< AlliancePlanetData > pMapper = new RowMapper< AlliancePlanetData >( ) { + @Override + public AlliancePlanetData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + AlliancePlanetData apd = new AlliancePlanetData( ); + + apd.setId( rs.getInt( "planet_id" ) ); + apd.setName( rs.getString( "planet_name" ) ); + apd.setX( rs.getInt( "x" ) ); + apd.setY( rs.getInt( "y" ) ); + apd.setOrbit( rs.getInt( "orbit" ) ); + apd.setOwnerId( rs.getInt( "owner_id" ) ); + apd.setOwner( rs.getString( "owner_name" ) ); + + apd.setBattle( rs.getBoolean( "battle" ) ); + apd.setAttack( rs.getLong( "attack" ) ); + apd.setDefence( rs.getLong( "defence" ) ); + + return apd; + } + }; + return this.dTemplate.query( pSql , pMapper , allianceId ); + } + + + @Override + public AllianceMemberData getMemberData( int allianceId ) + { + List< NameIdPair > members = this.getMembers( allianceId , false ); + List< AlliancePlanetData > planets = this.getPlanets( allianceId ); + return new AllianceMemberData( members , planets ); + } + + + @Override + public AllianceLeaderData getLeaderData( int allianceId ) + { + return new AllianceLeaderData( this.getMembers( allianceId , true ) ); + } + + + @Override + public boolean requestJoin( int empireId , int allianceId ) + { + return (Boolean) this.fJoinAlliance.execute( empireId , allianceId ).get( "success" ); + } + + + @Override + public void cancelJoin( int empireId ) + { + this.fCancelJoin.execute( empireId ); + } + + + @Override + public void leave( int empireId ) + { + this.fLeaveAlliance.execute( empireId ); + } + + + @Override + public void transferLeadership( int empireId , int toMember ) + { + this.fTransferLeadership.execute( empireId , toMember ); + } + + + private String toSQLArray( int[] members ) + { + StringBuilder mArray = new StringBuilder( ).append( "{" ); + for ( int i = 0 ; i < members.length ; i++ ) { + mArray.append( members[ i ] ).append( ( i == members.length - 1 ) ? '}' : ',' ); + } + String mStr = mArray.toString( ); + return mStr; + } + + + @Override + public void manageRequests( int empireId , boolean accept , int[] members ) + { + StoredProc proc = accept ? this.fAcceptMembers : this.fRejectMembers; + proc.execute( empireId , this.toSQLArray( members ) ); + } + + + @Override + public void kick( int empireId , int[] members ) + { + this.fKickMembers.execute( empireId , this.toSQLArray( members ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/AllianceManagementBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/AllianceManagementBean.java new file mode 100644 index 0000000..0d77488 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/AllianceManagementBean.java @@ -0,0 +1,176 @@ +package com.deepclone.lw.beans.empire; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.alliances.AllianceStatusResponse; +import com.deepclone.lw.cmd.player.alliances.CreateAllianceResponse; +import com.deepclone.lw.cmd.player.alliances.JoinAllianceResponse; +import com.deepclone.lw.cmd.player.alliances.ViewAllianceResponse; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceCreationStatus; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceData; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceLeaderData; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceMemberData; +import com.deepclone.lw.cmd.player.gdata.alliance.PublicAllianceInformation; +import com.deepclone.lw.interfaces.game.AllianceDAO; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.sqld.game.AllianceMembership; + + + +@Transactional +public class AllianceManagementBean + implements AllianceManagement +{ + + private EmpireManagement empireManagement; + private AllianceDAO allianceDao; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Autowired( required = true ) + public void setAllianceDao( AllianceDAO allianceDao ) + { + this.allianceDao = allianceDao; + } + + + private AllianceData getAllianceData( int empireId ) + { + PublicAllianceInformation pub = null; + AllianceMemberData member = null; + AllianceLeaderData leader = null; + + AllianceMembership m = this.allianceDao.getAlliance( empireId ); + if ( m != null ) { + int allianceId = m.getAllianceId( ); + pub = this.allianceDao.getPublicInformation( allianceId ); + if ( !m.isPending( ) ) { + member = this.allianceDao.getMemberData( allianceId ); + if ( empireId == pub.getLeaderId( ) ) { + leader = this.allianceDao.getLeaderData( allianceId ); + } + } + } + + return new AllianceData( pub , member , leader ); + } + + + @Override + public AllianceStatusResponse getView( int empireId ) + { + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + AllianceData alliance = this.getAllianceData( empireId ); + return new AllianceStatusResponse( page , alliance ); + } + + + @Override + public AllianceStatusResponse getInformation( int empireId , String tag ) + { + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + AllianceData alliance = this.getAllianceData( empireId ); + + if ( "".equals( tag ) ) { + return new AllianceStatusResponse( page , alliance ); + } + + Integer allianceId = this.allianceDao.findAlliance( tag ); + PublicAllianceInformation pub; + if ( allianceId == null ) { + pub = null; + } else { + pub = this.allianceDao.getPublicInformation( allianceId ); + } + + return new ViewAllianceResponse( page , alliance , tag , pub ); + } + + + @Override + public AllianceStatusResponse create( int empireId , String tag , String name ) + { + Integer aId = this.allianceDao.createAlliance( empireId , tag , name ); + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + AllianceData alliance = this.getAllianceData( empireId ); + + if ( aId == null ) { + AllianceCreationStatus acs = new AllianceCreationStatus( tag , ObjectNameError.UNAVAILABLE , name , null ); + return new CreateAllianceResponse( page , alliance , acs ); + } + + return new AllianceStatusResponse( page , alliance ); + } + + + @Override + public AllianceStatusResponse requestJoin( int empireId , String tag ) + { + Integer aId = this.allianceDao.findAlliance( tag ); + boolean joined; + if ( aId == null ) { + joined = false; + } else { + joined = this.allianceDao.requestJoin( empireId , aId ); + } + + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + AllianceData alliance = this.getAllianceData( empireId ); + + return joined + ? new AllianceStatusResponse( page , alliance ) + : new JoinAllianceResponse( page , alliance , tag ); + } + + + @Override + public AllianceStatusResponse cancelJoin( int empireId ) + { + this.allianceDao.cancelJoin( empireId ); + return this.getView( empireId ); + } + + + @Override + public AllianceStatusResponse leave( int empireId ) + { + this.allianceDao.leave( empireId ); + return this.getView( empireId ); + } + + + @Override + public AllianceStatusResponse transferLeadership( int empireId , int toMember ) + { + this.allianceDao.transferLeadership( empireId , toMember ); + return this.getView( empireId ); + } + + + @Override + public AllianceStatusResponse manageRequests( int empireId , boolean accept , int[] members ) + { + this.allianceDao.manageRequests( empireId , accept , members ); + return this.getView( empireId ); + } + + + @Override + public AllianceStatusResponse kick( int empireId , int[] members ) + { + this.allianceDao.kick( empireId , members ); + return this.getView( empireId ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireDAOBean.java new file mode 100644 index 0000000..daaa57b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireDAOBean.java @@ -0,0 +1,289 @@ +package com.deepclone.lw.beans.empire; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.PlanetListData; +import com.deepclone.lw.cmd.player.gdata.empire.OverviewData; +import com.deepclone.lw.interfaces.game.EmpireDAO; +import com.deepclone.lw.sqld.game.EmpireTechLine; +import com.deepclone.lw.sqld.game.EmpireTechnology; +import com.deepclone.lw.sqld.game.GeneralInformation; +import com.deepclone.lw.utils.StoredProc; + + + +public class EmpireDAOBean + implements EmpireDAO +{ + private SimpleJdbcTemplate dTemplate; + private StoredProc fImplementTech; + private StoredProc fAddEmpEnemy; + private StoredProc fAddAllEnemy; + private StoredProc fRemoveEmpEnemy; + private StoredProc fRemoveAllEnemy; + private StoredProc fGetNewPlanet; + + private final PlanetListMapper mPlanetList = new PlanetListMapper( ); + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fImplementTech = new StoredProc( dataSource , "emp" , "implement_tech" ); + this.fImplementTech.addParameter( "empire_id" , Types.INTEGER ); + this.fImplementTech.addParameter( "line_id" , Types.INTEGER ); + + this.fAddEmpEnemy = new StoredProc( dataSource , "emp" , "add_enemy_empire" ); + this.fAddEmpEnemy.addParameter( "empire_id" , Types.INTEGER ); + this.fAddEmpEnemy.addParameter( "enemy_name" , Types.VARCHAR ); + this.fAddEmpEnemy.addOutput( "err_code" , Types.INTEGER ); + + this.fAddAllEnemy = new StoredProc( dataSource , "emp" , "add_enemy_alliance" ); + this.fAddAllEnemy.addParameter( "empire_id" , Types.INTEGER ); + this.fAddAllEnemy.addParameter( "enemy_tag" , Types.VARCHAR ); + this.fAddAllEnemy.addOutput( "err_code" , Types.INTEGER ); + + this.fRemoveEmpEnemy = new StoredProc( dataSource , "emp" , "remove_enemy_empires" ); + this.fRemoveEmpEnemy.addParameter( "empire_id" , Types.INTEGER ); + this.fRemoveEmpEnemy.addParameter( "to_remove" , "INT[]" ); + + this.fRemoveAllEnemy = new StoredProc( dataSource , "emp" , "remove_enemy_alliances" ); + this.fRemoveAllEnemy.addParameter( "empire_id" , Types.INTEGER ); + this.fRemoveAllEnemy.addParameter( "to_remove" , "INT[]" ); + + this.fGetNewPlanet = new StoredProc( dataSource , "emp" , "get_new_planet" ); + this.fGetNewPlanet.addParameter( "empire_id" , Types.INTEGER ); + this.fGetNewPlanet.addParameter( "planet_name" , Types.VARCHAR ); + this.fGetNewPlanet.addOutput( "err_code" , Types.INTEGER ); + } + + + @Override + public GeneralInformation getInformation( int empireId ) + { + String sql = "SELECT * FROM emp.general_information WHERE id = ?"; + RowMapper< GeneralInformation > mapper = new RowMapper< GeneralInformation >( ) { + @Override + public GeneralInformation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + String st = rs.getString( "status" ); + Character status = ( st == null ) ? null : st.charAt( 0 ); + return new GeneralInformation( status , rs.getString( "name" ) , rs.getString( "alliance" ) , rs + .getLong( "cash" ) , rs.getLong( "game_time" ) , rs.getInt( "account_id" ) ); + } + }; + try { + return this.dTemplate.queryForObject( sql , mapper , empireId ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public List< NameIdPair > getPlanets( int empireId ) + { + String sql = "SELECT id , name FROM emp.planets_view WHERE empire = ?"; + RowMapper< NameIdPair > mapper = new RowMapper< NameIdPair >( ) { + @Override + public NameIdPair mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return new NameIdPair( rs.getInt( "id" ) , rs.getString( "name" ) ); + } + }; + return this.dTemplate.query( sql , mapper , empireId ); + } + + + @Override + public OverviewData getOverview( int empireId ) + { + String sql = "SELECT * FROM emp.overview WHERE empire = ?"; + RowMapper< OverviewData > mapper = new RowMapper< OverviewData >( ) { + @Override + public OverviewData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + OverviewData info = new OverviewData( ); + info.setPlanets( rs.getLong( "planets" ) ); + + Double dTemp; + dTemp = rs.getDouble( "population" ); + info.setPopulation( dTemp == null ? 0 : dTemp.longValue( ) ); + dTemp = rs.getDouble( "avg_happiness" ); + info.setAvgHappiness( dTemp == null ? 0 : dTemp.intValue( ) ); + dTemp = rs.getDouble( "planet_income" ); + info.setPlanetIncome( dTemp == null ? 0 : dTemp.longValue( ) ); + dTemp = rs.getDouble( "planet_upkeep" ); + info.setPlanetUpkeep( dTemp == null ? 0 : dTemp.longValue( ) ); + + Long lTemp; + lTemp = rs.getLong( "fleet_power" ); + info.setFleetPower( lTemp == null ? 0 : lTemp ); + lTemp = rs.getLong( "fleet_upkeep" ); + info.setFleetUpkeep( lTemp == null ? 0 : lTemp ); + + Long lTemp2; + lTemp = rs.getLong( "civ_investment" ); + lTemp2 = rs.getLong( "mil_investment" ); + info.setInvestment( ( lTemp == null ? 0 : lTemp ) + ( lTemp2 == null ? 0 : lTemp2 ) ); + + info.setNewMessages( rs.getInt( "new_messages" ) ); + + return info; + } + }; + return this.dTemplate.queryForObject( sql , mapper , empireId ); + } + + + @Override + public List< EmpireTechLine > getTechnology( int empireId ) + { + String sql = "SELECT * FROM emp.tech_lines_view WHERE empire = ?"; + RowMapper< EmpireTechLine > lineMapper = new RowMapper< EmpireTechLine >( ) { + @Override + public EmpireTechLine mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EmpireTechLine etl = new EmpireTechLine( ); + etl.setId( rs.getInt( "tech_line" ) ); + etl.setName( rs.getString( "name" ) ); + etl.setDescription( rs.getString( "description" ) ); + return etl; + } + }; + + List< EmpireTechLine > lines = this.dTemplate.query( sql , lineMapper , empireId ); + if ( lines.isEmpty( ) ) { + return lines; + } + + Map< Integer , EmpireTechLine > linesById = new HashMap< Integer , EmpireTechLine >( ); + for ( EmpireTechLine etl : lines ) { + linesById.put( etl.getId( ) , etl ); + } + + sql = "SELECT * FROM emp.technologies_view WHERE empire = ?"; + RowMapper< EmpireTechnology > techMapper = new RowMapper< EmpireTechnology >( ) { + @Override + public EmpireTechnology mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EmpireTechnology et = new EmpireTechnology( ); + et.setLine( rs.getInt( "tech_line" ) ); + et.setName( rs.getString( "name" ) ); + et.setDescription( rs.getString( "description" ) ); + et.setImplemented( rs.getBoolean( "implemented" ) ); + et.setProgress( (int) rs.getDouble( "progress" ) ); + et.setCost( rs.getInt( "cost" ) ); + return et; + } + }; + + for ( EmpireTechnology et : this.dTemplate.query( sql , techMapper , empireId ) ) { + linesById.get( et.getLine( ) ).addTechnology( et ); + } + + return lines; + } + + + @Override + public void implementTechnology( int empireId , int lineId ) + { + this.fImplementTech.execute( empireId , lineId ); + } + + + @Override + public List< PlanetListData > getPlanetList( int empireId ) + { + String sql = "SELECT * FROM emp.planets_list WHERE empire = ?"; + return this.dTemplate.query( sql , this.mPlanetList , empireId ); + } + + + @Override + public List< NameIdPair > getEnemies( int empireId , boolean alliances ) + { + String sql = "SELECT id , name FROM emp.enemy_lists WHERE empire = ? AND "; + if ( !alliances ) { + sql += "NOT "; + } + sql += "alliance"; + + RowMapper< NameIdPair > mapper = new RowMapper< NameIdPair >( ) { + @Override + public NameIdPair mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + return new NameIdPair( rs.getInt( "id" ) , rs.getString( "name" ) ); + } + }; + + return this.dTemplate.query( sql , mapper , empireId ); + } + + + @Override + public ObjectNameError addEnemy( int empireId , boolean alliance , String name ) + { + StoredProc addProc = alliance ? this.fAddAllEnemy : this.fAddEmpEnemy; + int rv = (Integer) addProc.execute( empireId , name ).get( "err_code" ); + + switch ( rv ) { + case 0: + return null; + case 1: + return ObjectNameError.INVALID; + case 2: + return ObjectNameError.BANNED; + case 3: + return ObjectNameError.UNAVAILABLE; + default: + throw new RuntimeException( "unexpected error code " + rv ); + } + } + + + @Override + public void removeEnemies( int empireId , boolean alliance , int[] ids ) + { + StoredProc remProc = alliance ? this.fRemoveAllEnemy : this.fRemoveEmpEnemy; + StringBuilder idArray = new StringBuilder( ).append( "{" ); + + for ( int i = 0 ; i < ids.length ; i++ ) { + idArray.append( ids[ i ] ).append( ( i == ids.length - 1 ) ? "}" : "," ); + } + + remProc.execute( empireId , idArray.toString( ) ); + } + + + @Override + public int getNewPlanet( int empireId , String name ) + { + return (Integer) this.fGetNewPlanet.execute( empireId , name ).get( "err_code" ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java new file mode 100644 index 0000000..18a9571 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java @@ -0,0 +1,238 @@ +package com.deepclone.lw.beans.empire; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.EmpireResponse; +import com.deepclone.lw.cmd.player.GetNewPlanetResponse; +import com.deepclone.lw.cmd.player.ListPlanetsResponse; +import com.deepclone.lw.cmd.player.elist.AddEnemyResponse; +import com.deepclone.lw.cmd.player.elist.EnemyListResponse; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.PlanetListData; +import com.deepclone.lw.cmd.player.gdata.battles.BattleListEntry; +import com.deepclone.lw.cmd.player.gdata.empire.OverviewData; +import com.deepclone.lw.cmd.player.gdata.empire.ResearchLineData; +import com.deepclone.lw.cmd.player.gdata.empire.TechnologyData; +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.game.BattlesCache; +import com.deepclone.lw.interfaces.game.BattlesDAO; +import com.deepclone.lw.interfaces.game.EmpireDAO; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.naming.NamingDAO; +import com.deepclone.lw.interfaces.prefs.AccountPreferences; +import com.deepclone.lw.interfaces.prefs.PreferencesDAO; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.sqld.game.EmpireTechLine; +import com.deepclone.lw.sqld.game.EmpireTechnology; +import com.deepclone.lw.sqld.game.GeneralInformation; +import com.deepclone.lw.sqld.game.battle.BattleListRecord; +import com.deepclone.lw.utils.EmailAddress; + + + +@Transactional +public class EmpireManagementBean + implements EmpireManagement +{ + private NamingDAO namingDao; + private UsersDAO usersDao; + private EmpireDAO empireDao; + private PreferencesDAO prefsDao; + private BattlesDAO battlesDao; + + + @Autowired( required = true ) + public void setUsersDao( UsersDAO usersDao ) + { + this.usersDao = usersDao; + } + + + @Autowired( required = true ) + public void setNamingDao( NamingDAO namingDao ) + { + this.namingDao = namingDao; + } + + + @Autowired( required = true ) + public void setEmpireDao( EmpireDAO empireDao ) + { + this.empireDao = empireDao; + } + + + @Autowired( required = true ) + public void setPrefsDao( PreferencesDAO prefsDao ) + { + this.prefsDao = prefsDao; + } + + + @Autowired( required = true ) + public void setBattlesDao( BattlesCache battlesDao ) + { + this.battlesDao = battlesDao; + } + + + @Override + public Integer getEmpireId( EmailAddress address ) + { + Account acnt = usersDao.getAccount( address ); + if ( acnt == null || !acnt.getStatus( ).isActive( ) ) { + return null; + } + return namingDao.getCurrentEmpire( acnt ); + } + + + @Override + public GamePageData getGeneralInformation( int empireId ) + { + GeneralInformation generalInformation = this.empireDao.getInformation( empireId ); + List< NameIdPair > planets = this.empireDao.getPlanets( empireId ); + + AccountPreferences prefs = this.prefsDao.getPreferences( generalInformation.getAccountId( ) ); + boolean rlTime = prefs.getPreference( "useRLTime" , Boolean.class ); + + return new GamePageData( generalInformation.getName( ) , generalInformation.getStatus( ) , generalInformation + .getTag( ) , generalInformation.getCash( ) , generalInformation.getNextTick( ) , planets , rlTime ); + } + + + @Override + public EmpireResponse getOverview( int empireId ) + { + OverviewData overview = this.empireDao.getOverview( empireId ); + List< ResearchLineData > research = new LinkedList< ResearchLineData >( ); + + for ( EmpireTechLine etl : this.empireDao.getTechnology( empireId ) ) { + List< TechnologyData > implemented = new LinkedList< TechnologyData >( ); + TechnologyData current = null; + + for ( EmpireTechnology et : etl.getTechnologies( ) ) { + if ( et.isImplemented( ) ) { + implemented.add( new TechnologyData( et.getName( ) , et.getDescription( ) ) ); + } else if ( et.getProgress( ) == 100 ) { + current = new TechnologyData( et.getName( ) , et.getDescription( ) , 100 , et.getCost( ) ); + } else { + current = new TechnologyData( et.getName( ) , et.getDescription( ) , et.getProgress( ) ); + } + } + + research.add( new ResearchLineData( etl.getId( ) , etl.getName( ) , etl.getDescription( ) , implemented , + current ) ); + } + + List< BattleListEntry > battles = new LinkedList< BattleListEntry >( ); + for ( BattleListRecord record : this.battlesDao.getBattles( empireId ) ) { + if ( record.getLastTick( ) != null ) { + break; + } + BattleListEntry entry = new BattleListEntry( ); + entry.setId( record.getBattle( ) ); + entry.setLocation( new NameIdPair( record.getPlanetId( ) , record.getName( ) ) ); + entry.setX( record.getX( ) ); + entry.setY( record.getY( ) ); + entry.setOrbit( record.getOrbit( ) ); + entry.setFirst( record.getFirstTick( ) ); + if ( record.getLastTick( ) != null ) { + entry.setLast( record.getLastTick( ) ); + } + battles.add( entry ); + } + + return new EmpireResponse( this.getGeneralInformation( empireId ) , overview , research , battles ); + } + + + @Override + public EmpireResponse implementTechnology( int empireId , int techId ) + { + this.empireDao.implementTechnology( empireId , techId ); + return this.getOverview( empireId ); + } + + + @Override + public ListPlanetsResponse getPlanetList( int empireId ) + { + GamePageData page = this.getGeneralInformation( empireId ); + List< PlanetListData > planets = this.empireDao.getPlanetList( empireId ); + return new ListPlanetsResponse( page , planets ); + } + + + @Override + public EnemyListResponse getEnemyLists( int empireId ) + { + GamePageData page = this.getGeneralInformation( empireId ); + List< NameIdPair > empires = this.empireDao.getEnemies( empireId , false ); + List< NameIdPair > alliances = this.empireDao.getEnemies( empireId , true ); + return new EnemyListResponse( page , empires , alliances ); + } + + + @Override + public EnemyListResponse addEnemy( int empireId , boolean alliance , String name ) + { + ObjectNameError error = this.empireDao.addEnemy( empireId , alliance , name ); + GamePageData page = this.getGeneralInformation( empireId ); + List< NameIdPair > empires = this.empireDao.getEnemies( empireId , false ); + List< NameIdPair > alliances = this.empireDao.getEnemies( empireId , true ); + if ( error == null ) { + return new EnemyListResponse( page , empires , alliances ); + } + return new AddEnemyResponse( page , empires , alliances , error , alliance , name ); + } + + + @Override + public EnemyListResponse removeEnemies( int empireId , boolean alliance , int[] ids ) + { + this.empireDao.removeEnemies( empireId , alliance , ids ); + return this.getEnemyLists( empireId ); + } + + + @Override + public GetNewPlanetResponse getNewPlanet( int empireId , String name ) + { + int errCode = this.empireDao.getNewPlanet( empireId , name ); + ObjectNameError error; + switch ( errCode ) { + case 0: + error = null; + break; + case 1: + error = ObjectNameError.BANNED; + break; + case 2: + error = ObjectNameError.UNAVAILABLE; + break; + default: + return new GetNewPlanetResponse( this.getGeneralInformation( empireId ) , null , null ); + } + + Integer planetId; + if ( error == null ) { + planetId = this.empireDao.getPlanetList( empireId ).get( 0 ).getId( ); + } else { + planetId = null; + } + + if ( planetId == null ) { + return new GetNewPlanetResponse( this.getGeneralInformation( empireId ) , name , error ); + } + + return new GetNewPlanetResponse( this.getGeneralInformation( empireId ) , planetId ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/PlanetListMapper.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/PlanetListMapper.java new file mode 100644 index 0000000..7a89808 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/PlanetListMapper.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.beans.empire; + + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.jdbc.core.RowMapper; + +import com.deepclone.lw.cmd.player.gdata.PlanetListData; + + + +final class PlanetListMapper + implements RowMapper< PlanetListData > +{ + + @Override + public PlanetListData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + PlanetListData pl = new PlanetListData( ); + + pl.setId( rs.getInt( "id" ) ); + pl.setName( rs.getString( "name" ) ); + + pl.setX( rs.getInt( "x" ) ); + pl.setY( rs.getInt( "y" ) ); + pl.setOrbit( rs.getInt( "orbit" ) ); + + pl.setPopulation( rs.getLong( "population" ) ); + pl.setHappiness( rs.getInt( "happiness" ) ); + + pl.setIncome( rs.getLong( "income" ) ); + pl.setUpkeep( rs.getLong( "upkeep" ) ); + + pl.setMilitaryProduction( rs.getLong( "military_production" ) ); + pl.setIndustrialProduction( rs.getLong( "industrial_production" ) ); + pl.setGrowthProduction( rs.getLong( "growth_production" ) ); + + pl.setCivInvestment( rs.getLong( "civ_investment" ) ); + pl.setCivAmount( rs.getInt( "civ_amount" ) ); + pl.setCivDestroy( rs.getBoolean( "civ_destroy" ) ); + pl.setCivName( rs.getString( "civ_name" ) ); + + pl.setMilInvestment( rs.getLong( "mil_investment" ) ); + pl.setMilAmount( rs.getInt( "mil_amount" ) ); + pl.setMilName( rs.getString( "mil_name" ) ); + + pl.setFpStatic( rs.getLong( "static_defence" ) ); + pl.setFpOwn( rs.getLong( "own_fleet" ) ); + pl.setFpFriendly( rs.getLong( "friendly_fleet" ) ); + pl.setFpHostile( rs.getLong( "hostile_fleet" ) ); + + pl.setBattle( (Long) rs.getObject( "battle" ) ); + + return pl; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattleViewerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattleViewerBean.java new file mode 100644 index 0000000..de6038b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattleViewerBean.java @@ -0,0 +1,359 @@ +package com.deepclone.lw.beans.fleets; + + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.cmd.player.battles.GetBattleResponse; +import com.deepclone.lw.cmd.player.battles.ListBattlesResponse; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.PlanetRelationType; +import com.deepclone.lw.cmd.player.gdata.TimeCombo; +import com.deepclone.lw.cmd.player.gdata.battles.*; +import com.deepclone.lw.interfaces.game.BattleViewer; +import com.deepclone.lw.interfaces.game.BattlesCache; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.sqld.game.battle.*; + + + +public class BattleViewerBean + implements BattleViewer +{ + + private static final int pageSize = 10; + + private EmpireManagement empireManagement; + private BattlesCache battlesDao; + + + @Autowired( required = true ) + public void setEmpireManagement( EmpireManagement empireManagement ) + { + this.empireManagement = empireManagement; + } + + + @Autowired( required = true ) + public void setBattlesDao( BattlesCache dao ) + { + this.battlesDao = dao; + } + + + @Override + public GetBattleResponse getBattle( int empireId , long battleId ) + { + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + BattleView battle = this.createBattleView( empireId , battleId , null ); + return new GetBattleResponse( page , battle ); + } + + + @Override + public GetBattleResponse getBattle( int empireId , long battleId , long tick ) + { + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + BattleView battle = this.createBattleView( empireId , battleId , tick ); + return new GetBattleResponse( page , battle ); + } + + + private BattleView createBattleView( int empireId , long battleId , Long tick ) + { + EmpireBattleRecord battle = this.battlesDao.getBattleRecord( empireId , battleId ); + if ( battle == null ) { + return null; + } + + BattleView view = new BattleView( ); + BattleDescription bDescription = new BattleDescription( ); + BattleDisplay bDisplay = new BattleDisplay( ); + view.setDescription( bDescription ); + view.setDisplay( bDisplay ); + + // Generate main battle description + bDescription.setId( battleId ); + bDescription.setLocation( new NameIdPair( battle.getPlanetId( ) , battle.getPlanetName( ) ) ); + bDescription.setX( battle.getX( ) ); + bDescription.setY( battle.getY( ) ); + bDescription.setOrbit( battle.getOrbit( ) ); + + // Generate list of ticks + List< PresenceRecord > presence = this.battlesDao.getPresence( battle ); + Long previous = null; + Long next = null; + Long display = null; + boolean planetOwner = false; + boolean wasPresent = false; + for ( PresenceRecord pRec : presence ) { + if ( !pRec.isPresent( ) && !wasPresent ) { + continue; + } + + long prTick = pRec.getTick( ); + if ( tick == null || display == null || display < tick ) { + previous = display; + display = prTick; + planetOwner = pRec.isPlanetOwner( ); + } else if ( next == null ) { + next = prTick; + } + bDisplay.addTime( prTick ); + wasPresent = pRec.isPresent( ); + } + if ( display == null && presence.size( ) == 1 ) { + display = presence.get( 0 ).getTick( ); + bDisplay.addTime( display ); + } + bDisplay.setCurrent( display ); + if ( previous != null ) { + bDisplay.setPrevious( previous ); + } + if ( next != null ) { + bDisplay.setNext( next ); + } + + // Get the status at the current tick + Map< Long , Map< Long , ProtagonistRecord >> protagonists = this.battlesDao.getProtagonists( battle ); + view.setShips( this.getBattleStatus( battle , display , protagonists , planetOwner ) ); + + // Determine history intervals to display + List< BattleHistoryInterval > intervals = this.getIntervals( battle , presence , display ); + + // Add battle history + Collections.reverse( intervals ); + this.addEvents( battle , intervals , protagonists , display ); + for ( BattleHistoryInterval i : intervals ) { + view.addHistoryInterval( i ); + } + + return view; + } + + + private List< BattleHistoryInterval > getIntervals( EmpireBattleRecord battle , List< PresenceRecord > presence , + long display ) + { + List< BattleHistoryInterval > intervals = new LinkedList< BattleHistoryInterval >( ); + for ( PresenceRecord pRec : presence ) { + long prTick = pRec.getTick( ); + if ( prTick > display ) { + break; + } + + if ( intervals.isEmpty( ) || intervals.get( intervals.size( ) - 1 ).getEnd( ) != null ) { + if ( !pRec.isPresent( ) ) { + continue; + } + + BattleHistoryInterval interval = new BattleHistoryInterval( ); + interval.setBegin( prTick , prTick == battle.getFirstTick( ) ); + intervals.add( interval ); + } else if ( !pRec.isPresent( ) ) { + BattleHistoryInterval interval = intervals.get( intervals.size( ) - 1 ); + interval.setEnd( prTick , false ); + } else if ( battle.getLastTick( ) != null && prTick == battle.getLastTick( ) ) { + BattleHistoryInterval interval = intervals.get( intervals.size( ) - 1 ); + interval.setEnd( prTick , true ); + } + } + if ( intervals.isEmpty( ) && presence.size( ) == 1 ) { + PresenceRecord pRec = presence.get( 0 ); + BattleHistoryInterval interval = new BattleHistoryInterval( ); + interval.setBegin( pRec.getTick( ) , true ); + interval.setEnd( pRec.getTick( ) , true ); + intervals.add( interval ); + } + return intervals; + } + + + private void addEvents( EmpireBattleRecord battle , List< BattleHistoryInterval > intervals , + Map< Long , Map< Long , ProtagonistRecord >> protagonists , long display ) + { + Map< Boolean , Map< Long , List< EventItemRecord >>> eItems = this.battlesDao.getEventItems( battle ); + ListIterator< BattleHistoryInterval > bhIterator = intervals.listIterator( ); + BattleHistoryInterval cInterval = bhIterator.next( ); + BattleHistoryTick cTick = null; + + for ( EventRecord event : this.battlesDao.getEvents( battle ) ) { + long eTick = event.getTick( ); + if ( eTick > display ) { + continue; + } + + // Do not add events after the end of the current interval + TimeCombo intEnd = cInterval.getEnd( ); + if ( intEnd != null && eTick > intEnd.getTicks( ) ) { + continue; + } + + // If the event is before the current interval, try fetching the "next" (previous in + // terms of ticks) interval + if ( eTick < cInterval.getBegin( ).getTicks( ) ) { + if ( !bhIterator.hasNext( ) ) { + break; + } + cInterval = bhIterator.next( ); + cTick = null; + if ( eTick > cInterval.getEnd( ).getTicks( ) ) { + continue; + } + } + + // Create and add the event's tick if necessary + if ( cTick == null || cTick.getTime( ).getTicks( ) != eTick ) { + cTick = new BattleHistoryTick( eTick ); + cInterval.addEntry( cTick ); + } + + // Create the event's record + BattleEvent bEvent = new BattleEvent( ); + bEvent.setType( BattleEventType.valueOf( event.getEventType( ) ) ); + bEvent.setPlanet( event.isPlanet( ) ); + bEvent.setName( event.getName( ) ); + if ( event.getAttack( ) != null ) { + ProtagonistRecord self = protagonists.get( eTick ).get( battle.getProtagonistId( ) ); + if ( !event.isPlanet( ) && self.getName( ).equals( event.getName( ) ) ) { + bEvent.setHostile( event.getAttack( ) ); + } else { + bEvent.setHostile( self.isAttacking( ) != event.getAttack( ) ); + } + } + + // Add event to history + cTick.addEvent( bEvent ); + + // Add ships/buildings + if ( event.getEventId( ) == null ) { + continue; + } + + List< EventItemRecord > items = eItems.get( event.isPlanet( ) ).get( event.getEventId( ) ); + if ( items == null ) { + continue; + } + for ( EventItemRecord eir : items ) { + BattleShipType item = new BattleShipType( ); + item.setName( eir.getNature( ) ); + item.setcAmount( eir.getAmount( ) ); + bEvent.addShip( item ); + } + } + } + + + private BattleShipsView getBattleStatus( EmpireBattleRecord battle , Long display , + Map< Long , Map< Long , ProtagonistRecord >> pHistory , boolean planetOwner ) + { + BattleShipsView view = new BattleShipsView( ); + Map< Long , ProtagonistRecord > protagonists = pHistory.get( display ); + Map< Long , List< ShipHistoryRecord >> ships = this.battlesDao.getShipsHistory( battle ).get( display ); + boolean vMode = protagonists.get( battle.getProtagonistId( ) ).isAttacking( ); + + // Handle fleets + for ( ProtagonistRecord protagonist : protagonists.values( ) ) { + BattlePlayerShips pShips; + boolean isSelf = ( protagonist.getProtagonistId( ) == battle.getProtagonistId( ) ); + if ( isSelf ) { + pShips = view.getOwn( ); + } else { + pShips = new BattlePlayerShips( ); + } + + // Add ships + List< ShipHistoryRecord > pShipList = ships.get( protagonist.getProtagonistId( ) ); + if ( pShipList == null ) { + continue; + } + for ( ShipHistoryRecord shr : pShipList ) { + BattleShipType shipType = new BattleShipType( ); + shipType.setName( shr.getNature( ) ); + shipType.setcAmount( shr.getCurrent( ) ); + shipType.setcPower( shr.getCurrent( ) * shr.getPower( ) ); + shipType.setlAmount( shr.getLost( ) ); + shipType.setlPower( shr.getLost( ) * shr.getPower( ) ); + pShips.addShip( shipType ); + } + + // Set empire name & identifier + int eId = protagonist.getEmpireId( ) == null ? -1 : protagonist.getEmpireId( ).intValue( ); + pShips.setPlayer( new NameIdPair( eId , protagonist.getName( ) ) ); + + // Add to the appropriate list + if ( isSelf || pShips.getcPower( ) == 0 && pShips.getlPower( ) == 0 ) { + continue; + } + BattleSideShips side = ( protagonist.isAttacking( ) == vMode ) ? view.getFriendly( ) : view.getHostile( ); + side.addPlayer( pShips ); + } + + // Handle planet + BattlePlanetBuildings planet = view.getPlanet( ); + if ( planetOwner ) { + planet.setRelation( PlanetRelationType.OWN ); + } else { + planet.setRelation( vMode ? PlanetRelationType.ENEMY : PlanetRelationType.ALLIED ); + } + + List< BuildingHistoryRecord > toDisplay = this.battlesDao.getBuildingsHistory( battle ).get( display ); + if ( toDisplay != null ) { + for ( BuildingHistoryRecord bhr : toDisplay ) { + BattleShipType building = new BattleShipType( ); + building.setName( bhr.getNature( ) ); + building.setcAmount( bhr.getCurrent( ) ); + building.setcPower( bhr.getCurrent( ) * bhr.getPower( ) ); + building.setlAmount( bhr.getLost( ) ); + building.setlPower( bhr.getLost( ) * bhr.getPower( ) ); + planet.addShip( building ); + } + } + + return view; + } + + + @Override + public ListBattlesResponse getBattles( int empireId , int page ) + { + List< BattleListRecord > records = this.battlesDao.getBattles( empireId ); + int rSize = records.size( ); + int mod = rSize % BattleViewerBean.pageSize; + int pages = ( rSize - mod ) / BattleViewerBean.pageSize + ( mod > 0 ? 1 : 0 ); + if ( page < 0 ) { + page = 0; + } else if ( page >= pages ) { + page = pages - 1; + } + + List< BattleListEntry > entries = new LinkedList< BattleListEntry >( ); + if ( pages > 0 ) { + records = records.subList( page * BattleViewerBean.pageSize , Math.min( ( page + 1 ) + * BattleViewerBean.pageSize , rSize ) ); + + for ( BattleListRecord record : records ) { + BattleListEntry entry = new BattleListEntry( ); + entry.setId( record.getBattle( ) ); + entry.setLocation( new NameIdPair( record.getPlanetId( ) , record.getName( ) ) ); + entry.setX( record.getX( ) ); + entry.setY( record.getY( ) ); + entry.setOrbit( record.getOrbit( ) ); + entry.setFirst( record.getFirstTick( ) ); + if ( record.getLastTick( ) != null ) { + entry.setLast( record.getLastTick( ) ); + } + entries.add( entry ); + } + } + + return new ListBattlesResponse( this.empireManagement.getGeneralInformation( empireId ) , entries , page , + pages ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattlesCacheBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattlesCacheBean.java new file mode 100644 index 0000000..cdb4703 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattlesCacheBean.java @@ -0,0 +1,336 @@ +package com.deepclone.lw.beans.fleets; + + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.game.BattlesCache; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; +import com.deepclone.lw.sqld.game.battle.*; + + + +public class BattlesCacheBean + implements BattlesCache , Runnable +{ + private static final int cacheTime = 6; // Half an hour + + private static class CacheKey + { + private final int empireId; + private final long battleId; + + + public CacheKey( int empireId , long battleId ) + { + this.empireId = empireId; + this.battleId = battleId; + } + + + @Override + public int hashCode( ) + { + final int prime = 31; + int result = 1; + result = prime * result + (int) ( battleId ^ ( battleId >>> 32 ) ); + result = prime * result + empireId; + return result; + } + + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + return true; + if ( obj == null ) + return false; + if ( getClass( ) != obj.getClass( ) ) + return false; + CacheKey other = (CacheKey) obj; + if ( battleId != other.battleId ) + return false; + if ( empireId != other.empireId ) + return false; + return true; + } + + } + + private static class CacheData + { + public int timeLeft = BattlesCacheBean.cacheTime; + public EmpireBattleRecord battle; + public List< PresenceRecord > presence; + public Map< Long , Map< Long , ProtagonistRecord >> protagonists; + public List< EventRecord > events; + public Map< Boolean , Map< Long , List< EventItemRecord >>> eventItems; + public Map< Long , List< BuildingHistoryRecord >> buildings; + public Map< Long , Map< Long , List< ShipHistoryRecord >>> ships; + }; + + private static class ListCache + { + public int timeLeft = BattlesCacheBean.cacheTime; + public Long lastUpdate; + public List< BattleListRecord > list = new LinkedList< BattleListRecord >( ); + }; + + private BattlesDAOBean battlesDao; + private SystemLogger logger; + private final Map< CacheKey , CacheData > cache = new HashMap< CacheKey , CacheData >( ); + private final Map< Integer , ListCache > listCache = new HashMap< Integer , ListCache >( ); + + + @Autowired( required = true ) + public void setBattlesDAO( BattlesDAOBean battlesDao ) + { + this.battlesDao = battlesDao; + } + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + ticker.registerTask( Frequency.LOW , "Battles cache cleaner" , this ); + } + + + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger.getSystemLogger( "BattlesCache" ); + } + + + private void initCache( CacheKey cKey , EmpireBattleRecord record ) + { + this.logger.log( LogLevel.TRACE , + "Adding battle #" + record.getBattleId( ) + " for empire #" + record.getEmpireId( ) + " to the cache" ) + .flush( ); + + CacheData data = new CacheData( ); + data.battle = record; + data.presence = this.battlesDao.getPresence( record ); + data.protagonists = this.battlesDao.getProtagonists( record ); + data.events = this.battlesDao.getEvents( record ); + data.eventItems = this.battlesDao.getEventItems( record ); + data.buildings = this.battlesDao.getBuildingsHistory( record ); + data.ships = this.battlesDao.getShipsHistory( record ); + this.cache.put( cKey , data ); + } + + + private CacheData getCached( EmpireBattleRecord record ) + { + CacheKey cKey = new CacheKey( record.getEmpireId( ) , record.getBattleId( ) ); + CacheData data; + synchronized ( this.cache ) { + data = this.cache.get( cKey ); + if ( data != null ) { + data.timeLeft = BattlesCacheBean.cacheTime; + } + } + return data; + } + + + @Override + public void run( ) + { + + // Battle data cache + synchronized ( this.cache ) { + List< CacheKey > toRemove = new LinkedList< CacheKey >( ); + for ( Map.Entry< CacheKey , CacheData > entry : this.cache.entrySet( ) ) { + CacheData data = entry.getValue( ); + data.timeLeft--; + if ( data.timeLeft < 0 ) { + toRemove.add( entry.getKey( ) ); + } + } + + for ( CacheKey k : toRemove ) { + this.cache.remove( k ); + } + + if ( !toRemove.isEmpty( ) ) { + this.logger.log( LogLevel.DEBUG , + "data cache - " + toRemove.size( ) + " entries removed; cache size: " + this.cache.size( ) ) + .flush( ); + } + } + + // Battle lists cache + synchronized ( this.listCache ) { + List< Integer > toRemove = new LinkedList< Integer >( ); + for ( Map.Entry< Integer , ListCache > entry : this.listCache.entrySet( ) ) { + ListCache data = entry.getValue( ); + data.timeLeft--; + if ( data.timeLeft < 0 ) { + toRemove.add( entry.getKey( ) ); + } + } + + for ( Integer k : toRemove ) { + this.listCache.remove( k ); + } + + if ( !toRemove.isEmpty( ) ) { + this.logger.log( LogLevel.DEBUG , + "list cache - " + toRemove.size( ) + " entries removed; cache size: " + this.listCache.size( ) ) + .flush( ); + } + } + } + + + @Override + public EmpireBattleRecord getBattleRecord( int empireId , long battleId ) + { + CacheKey cKey = new CacheKey( empireId , battleId ); + synchronized ( this.cache ) { + CacheData data = this.cache.get( cKey ); + if ( data != null ) { + data.timeLeft = BattlesCacheBean.cacheTime; + return data.battle; + } + + EmpireBattleRecord record = this.battlesDao.getBattleRecord( empireId , battleId ); + if ( record != null && record.getLastTick( ) != null ) { + this.initCache( cKey , record ); + } + return record; + } + } + + + @Override + public List< PresenceRecord > getPresence( EmpireBattleRecord record ) + { + CacheData cData = this.getCached( record ); + if ( cData != null ) { + return cData.presence; + } + return this.battlesDao.getPresence( record ); + } + + + @Override + public Map< Long , Map< Long , ProtagonistRecord >> getProtagonists( EmpireBattleRecord record ) + { + CacheData cData = this.getCached( record ); + if ( cData != null ) { + return cData.protagonists; + } + return this.battlesDao.getProtagonists( record ); + } + + + @Override + public List< EventRecord > getEvents( EmpireBattleRecord record ) + { + CacheData cData = this.getCached( record ); + if ( cData != null ) { + return cData.events; + } + return this.battlesDao.getEvents( record ); + } + + + @Override + public Map< Boolean , Map< Long , List< EventItemRecord >>> getEventItems( EmpireBattleRecord record ) + { + CacheData cData = this.getCached( record ); + if ( cData != null ) { + return cData.eventItems; + } + return this.battlesDao.getEventItems( record ); + } + + + @Override + public Map< Long , List< BuildingHistoryRecord >> getBuildingsHistory( EmpireBattleRecord record ) + { + CacheData cData = this.getCached( record ); + if ( cData != null ) { + return cData.buildings; + } + return this.battlesDao.getBuildingsHistory( record ); + } + + + @Override + public Map< Long , Map< Long , List< ShipHistoryRecord >>> getShipsHistory( EmpireBattleRecord record ) + { + CacheData cData = this.getCached( record ); + if ( cData != null ) { + return cData.ships; + } + return this.battlesDao.getShipsHistory( record ); + } + + + @Override + public List< BattleListRecord > getBattles( int empireId ) + { + List< BattleListRecord > results; + synchronized ( this.listCache ) { + ListCache lcEntry = this.listCache.get( empireId ); + int nCached; + + if ( lcEntry == null ) { + // No cached data, get the whole list and add finished battles to the cache + lcEntry = new ListCache( ); + nCached = 0; + results = this.battlesDao.getBattles( empireId ); + + for ( BattleListRecord record : results ) { + if ( !record.isFinished( ) ) { + continue; + } + if ( lcEntry.lastUpdate == null ) { + lcEntry.lastUpdate = record.getLastUpdate( ); + } + lcEntry.list.add( record ); + } + if ( !lcEntry.list.isEmpty( ) ) { + this.listCache.put( empireId , lcEntry ); + } + } else { + // Cached data present, get updates + results = new LinkedList< BattleListRecord >( ); + nCached = lcEntry.list.size( ); + int i = 0; + for ( BattleListRecord record : this.battlesDao.getBattles( empireId , lcEntry.lastUpdate ) ) { + if ( !record.isFinished( ) ) { + results.add( record ); + continue; + } + if ( i == 0 ) { + lcEntry.lastUpdate = record.getLastUpdate( ); + } + lcEntry.list.add( i++ , record ); + } + results.addAll( lcEntry.list ); + lcEntry.timeLeft = BattlesCacheBean.cacheTime; + } + + nCached = lcEntry.list.size( ) - nCached; + this.logger.log( + LogLevel.TRACE , + "List of battles for empire #" + empireId + ": " + nCached + " new items cached (" + + lcEntry.list.size( ) + " total), " + results.size( ) + " items returned" ).flush( ); + } + return results; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattlesDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattlesDAOBean.java new file mode 100644 index 0000000..f7ce1a4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/BattlesDAOBean.java @@ -0,0 +1,309 @@ +package com.deepclone.lw.beans.fleets; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.interfaces.game.BattlesDAO; +import com.deepclone.lw.sqld.game.battle.*; + + + +public class BattlesDAOBean + implements BattlesDAO +{ + + private static final String sGetBattleRecord = "SELECT * FROM battles.empire_list_view WHERE empire = ? AND battle = ?"; + private static final String sGetPresenceList = "SELECT * FROM battles.protagonist_presence WHERE protagonist = ?"; + private static final String sGetEvents = "SELECT e.* FROM battles.events_history e WHERE e.battle = ? AND e.tick IN ( SELECT tick FROM battles.protagonist_presence WHERE protagonist = ? AND present )"; + private static final String sGetEventItems = "SELECT is_planet , event_id , nature , amount FROM battles.event_items i WHERE empire = ? AND battle = ?"; + private static final String sGetProtagonists = "SELECT * FROM battles.mode_history_view WHERE battle = ?"; + private static final String sGetBuildings = "SELECT * FROM battles.buildings_history WHERE empire = ? AND battle = ?"; + private static final String sGetShips = "SELECT * FROM battles.fleets_history WHERE empire = ? AND battle = ?"; + private static final String sGetAllBattles = "SELECT * FROM battles.battles_list WHERE empire = ? ORDER BY last_tick DESC NULLS FIRST , first_tick DESC , x , y , orbit"; + private static final String sGetNewBattles = "SELECT * FROM battles.battles_list WHERE empire = ? AND ( last_update > ? OR NOT finished ) ORDER BY last_tick DESC NULLS FIRST , first_tick DESC , x , y , orbit"; + + private SimpleJdbcTemplate dTemplate; + + private final RowMapper< EmpireBattleRecord > mGetBattleRecord; + private final RowMapper< PresenceRecord > mGetPresenceList; + private final RowMapper< EventRecord > mGetEvents; + private final RowMapper< EventItemRecord > mGetEventItems; + private final RowMapper< ProtagonistRecord > mGetProtagonists; + private final RowMapper< BuildingHistoryRecord > mGetBuildings; + private final RowMapper< ShipHistoryRecord > mGetShips; + private final RowMapper< BattleListRecord > mBattleListEntry; + + + public BattlesDAOBean( ) + { + this.mGetBattleRecord = new RowMapper< EmpireBattleRecord >( ) { + @Override + public EmpireBattleRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EmpireBattleRecord r = new EmpireBattleRecord( ); + r.setFirstTick( rs.getLong( "first_tick" ) ); + r.setLastTick( (Long) rs.getObject( "last_tick" ) ); + r.setPlanetId( rs.getInt( "planet" ) ); + r.setPlanetName( rs.getString( "name" ) ); + r.setX( rs.getInt( "x" ) ); + r.setY( rs.getInt( "y" ) ); + r.setOrbit( rs.getInt( "orbit" ) ); + r.setProtagonistId( rs.getLong( "protagonist" ) ); + return r; + } + }; + this.mGetPresenceList = new RowMapper< PresenceRecord >( ) { + @Override + public PresenceRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + PresenceRecord pView = new PresenceRecord( ); + pView.setTick( rs.getLong( "tick" ) ); + pView.setPresent( rs.getBoolean( "present" ) ); + pView.setPlanetOwner( rs.getBoolean( "planet_owner" ) ); + return pView; + } + }; + this.mGetEvents = new RowMapper< EventRecord >( ) { + @Override + public EventRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EventRecord r = new EventRecord( ); + r.setEventType( rs.getString( "event_type" ) ); + r.setTick( rs.getLong( "tick" ) ); + r.setPlanet( rs.getBoolean( "is_planet" ) ); + r.setAttack( (Boolean) rs.getObject( "attack" ) ); + r.setEventId( (Long) rs.getObject( "event_id" ) ); + r.setName( rs.getString( "name" ) ); + return r; + } + }; + this.mGetEventItems = new RowMapper< EventItemRecord >( ) { + @Override + public EventItemRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EventItemRecord r = new EventItemRecord( ); + r.setPlanetEvent( rs.getBoolean( "is_planet" ) ); + r.setEventId( rs.getLong( "event_id" ) ); + r.setNature( rs.getString( "nature" ) ); + r.setAmount( rs.getInt( "amount" ) ); + return r; + } + }; + this.mGetProtagonists = new RowMapper< ProtagonistRecord >( ) { + @Override + public ProtagonistRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + ProtagonistRecord p = new ProtagonistRecord( ); + p.setTick( rs.getLong( "tick" ) ); + p.setProtagonistId( rs.getLong( "protagonist" ) ); + p.setEmpireId( (Long) rs.getObject( "empire_id" ) ); + p.setName( rs.getString( "empire_name" ) ); + p.setAttacking( rs.getBoolean( "attacking" ) ); + return p; + } + }; + this.mGetBuildings = new RowMapper< BuildingHistoryRecord >( ) { + @Override + public BuildingHistoryRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BuildingHistoryRecord bhr = new BuildingHistoryRecord( ); + bhr.setTick( rs.getLong( "tick" ) ); + bhr.setNature( rs.getString( "building" ) ); + bhr.setCurrent( rs.getLong( "current" ) ); + bhr.setLost( rs.getLong( "lost" ) ); + bhr.setPower( (long) Math.floor( rs.getDouble( "power" ) ) ); + return bhr; + } + }; + this.mGetShips = new RowMapper< ShipHistoryRecord >( ) { + @Override + public ShipHistoryRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + ShipHistoryRecord shr = new ShipHistoryRecord( ); + shr.setProtagonist( rs.getLong( "protagonist" ) ); + shr.setTick( rs.getLong( "tick" ) ); + shr.setNature( rs.getString( "ship_type" ) ); + shr.setCurrent( rs.getLong( "current" ) ); + shr.setLost( rs.getLong( "lost" ) ); + shr.setPower( rs.getInt( "ship_power" ) ); + return shr; + } + }; + this.mBattleListEntry = new RowMapper< BattleListRecord >( ) { + @Override + public BattleListRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BattleListRecord entry = new BattleListRecord( ); + entry.setBattle( rs.getLong( "battle" ) ); + entry.setPlanetId( rs.getInt( "planet" ) ); + entry.setX( rs.getInt( "x" ) ); + entry.setY( rs.getInt( "y" ) ); + entry.setOrbit( rs.getInt( "orbit" ) ); + entry.setName( rs.getString( "name" ) ); + entry.setFirstTick( rs.getLong( "first_tick" ) ); + entry.setLastTick( (Long) rs.getObject( "last_tick" ) ); + entry.setLastUpdate( rs.getLong( "last_update" ) ); + entry.setFinished( rs.getBoolean( "finished" ) ); + return entry; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + } + + + @Override + public EmpireBattleRecord getBattleRecord( int empireId , long battleId ) + { + EmpireBattleRecord ebv; + try { + ebv = this.dTemplate.queryForObject( sGetBattleRecord , this.mGetBattleRecord , empireId , battleId ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + ebv.setBattleId( battleId ); + ebv.setEmpireId( empireId ); + return ebv; + } + + + @Override + public List< PresenceRecord > getPresence( EmpireBattleRecord record ) + { + return this.dTemplate.query( sGetPresenceList , this.mGetPresenceList , record.getProtagonistId( ) ); + } + + + @Override + public Map< Long , Map< Long , ProtagonistRecord > > getProtagonists( EmpireBattleRecord record ) + { + List< ProtagonistRecord > all; + all = this.dTemplate.query( sGetProtagonists , this.mGetProtagonists , record.getBattleId( ) ); + + Map< Long , Map< Long , ProtagonistRecord >> result = new HashMap< Long , Map< Long , ProtagonistRecord > >( ); + for ( ProtagonistRecord r : all ) { + Map< Long , ProtagonistRecord > atTick = result.get( r.getTick( ) ); + if ( atTick == null ) { + atTick = new HashMap< Long , ProtagonistRecord >( ); + result.put( r.getTick( ) , atTick ); + } + atTick.put( r.getProtagonistId( ) , r ); + } + return result; + } + + + @Override + public List< EventRecord > getEvents( EmpireBattleRecord record ) + { + return this.dTemplate.query( sGetEvents , this.mGetEvents , record.getBattleId( ) , record.getProtagonistId( ) ); + } + + + @Override + public Map< Boolean , Map< Long , List< EventItemRecord >>> getEventItems( EmpireBattleRecord record ) + { + List< EventItemRecord > raw; + raw = this.dTemplate + .query( sGetEventItems , this.mGetEventItems , record.getEmpireId( ) , record.getBattleId( ) ); + + Map< Boolean , Map< Long , List< EventItemRecord >>> result = new HashMap< Boolean , Map< Long , List< EventItemRecord >> >( ); + result.put( true , new HashMap< Long , List< EventItemRecord >>( ) ); + result.put( false , new HashMap< Long , List< EventItemRecord >>( ) ); + for ( EventItemRecord eir : raw ) { + List< EventItemRecord > event = result.get( eir.isPlanetEvent( ) ).get( eir.getEventId( ) ); + if ( event == null ) { + event = new LinkedList< EventItemRecord >( ); + result.get( eir.isPlanetEvent( ) ).put( eir.getEventId( ) , event ); + } + event.add( eir ); + } + + return result; + } + + + @Override + public Map< Long , List< BuildingHistoryRecord >> getBuildingsHistory( EmpireBattleRecord record ) + { + List< BuildingHistoryRecord > records; + records = this.dTemplate.query( sGetBuildings , this.mGetBuildings , record.getEmpireId( ) , record + .getBattleId( ) ); + + Map< Long , List< BuildingHistoryRecord > > result = new HashMap< Long , List< BuildingHistoryRecord > >( ); + for ( BuildingHistoryRecord bhr : records ) { + List< BuildingHistoryRecord > atTick = result.get( bhr.getTick( ) ); + if ( atTick == null ) { + atTick = new LinkedList< BuildingHistoryRecord >( ); + result.put( bhr.getTick( ) , atTick ); + } + atTick.add( bhr ); + } + + return result; + } + + + @Override + public Map< Long , Map< Long , List< ShipHistoryRecord >>> getShipsHistory( EmpireBattleRecord record ) + { + List< ShipHistoryRecord > records; + records = this.dTemplate.query( sGetShips , this.mGetShips , record.getEmpireId( ) , record.getBattleId( ) ); + + Map< Long , Map< Long , List< ShipHistoryRecord > >> result = new HashMap< Long , Map< Long , List< ShipHistoryRecord > > >( ); + for ( ShipHistoryRecord shr : records ) { + Map< Long , List< ShipHistoryRecord > > atTick = result.get( shr.getTick( ) ); + if ( atTick == null ) { + atTick = new HashMap< Long , List< ShipHistoryRecord > >( ); + result.put( shr.getTick( ) , atTick ); + } + + List< ShipHistoryRecord > pShips = atTick.get( shr.getProtagonist( ) ); + if ( pShips == null ) { + pShips = new LinkedList< ShipHistoryRecord >( ); + atTick.put( shr.getProtagonist( ) , pShips ); + } + pShips.add( shr ); + } + + return result; + } + + + @Override + public List< BattleListRecord > getBattles( int empireId ) + { + return this.dTemplate.query( sGetAllBattles , this.mBattleListEntry , empireId ); + } + + + public List< BattleListRecord > getBattles( int empireId , long after ) + { + return this.dTemplate.query( sGetNewBattles , this.mBattleListEntry , empireId , after ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/FleetManagementBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/FleetManagementBean.java new file mode 100644 index 0000000..57fb1b0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/FleetManagementBean.java @@ -0,0 +1,236 @@ +package com.deepclone.lw.beans.fleets; + + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.player.fleets.DisbandFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.MergeFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.MoveFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.MultiFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.RenameFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.SetFleetsModeResponse; +import com.deepclone.lw.cmd.player.fleets.SplitFleetResponse; +import com.deepclone.lw.cmd.player.fleets.ViewFleetsResponse; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.fleets.FleetStatus; +import com.deepclone.lw.cmd.player.gdata.fleets.FleetsView; +import com.deepclone.lw.cmd.player.gdata.fleets.ShortFleetView; +import com.deepclone.lw.cmd.player.gdata.fleets.SplitShips; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.game.FleetManagement; +import com.deepclone.lw.interfaces.game.FleetsDAO; + + + +@Transactional +public class FleetManagementBean + implements FleetManagement +{ + private EmpireManagement empireManagement; + private FleetsDAO fleetsDao; + + + @Autowired( required = true ) + public void setEmpireManagement( EmpireManagement empireManagement ) + { + this.empireManagement = empireManagement; + } + + + @Autowired( required = true ) + public void setFleetsDao( FleetsDAO fleetsDao ) + { + this.fleetsDao = fleetsDao; + } + + + @Override + public ViewFleetsResponse getFleets( int empireId ) + { + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + FleetsView fleets = this.fleetsDao.getFleets( empireId ); + return new ViewFleetsResponse( page , fleets ); + } + + + @Override + public MultiFleetsResponse setMode( int empireId , long[] fleets , boolean attack , boolean doIt ) + { + SetFleetsModeResponse response; + response = new SetFleetsModeResponse( this.empireManagement.getGeneralInformation( empireId ) ); + + List< ShortFleetView > sFleets = new LinkedList< ShortFleetView >( ); + for ( ShortFleetView sfv : this.fleetsDao.getShortFleets( empireId , fleets , false ) ) { + if ( sfv.isAttack( ) != attack ) { + sFleets.add( sfv ); + } + } + + if ( sFleets.isEmpty( ) ) { + return response; + } + + if ( doIt ) { + this.fleetsDao.setMode( empireId , fleets , attack ); + return response; + } + + for ( ShortFleetView sfv : sFleets ) { + response.addFleet( sfv ); + } + response.setAttack( attack ); + return response; + } + + + @Override + public MultiFleetsResponse move( int empireId , long[] fleets , String destination , boolean attack ) + { + MoveFleetsResponse response = new MoveFleetsResponse( this.empireManagement.getGeneralInformation( empireId ) ); + List< ShortFleetView > sFleets = this.fleetsDao.getShortFleets( empireId , fleets , true ); + if ( sFleets.isEmpty( ) ) { + return response; + } + + boolean moved; + if ( destination != null && !sFleets.isEmpty( ) ) { + moved = this.fleetsDao.move( empireId , fleets , destination ); + if ( !moved ) { + response.setError( true ); + response.setDestination( destination ); + response.setMode( attack ); + } else { + this.fleetsDao.setMode( empireId , fleets , attack ); + } + } else { + moved = false; + } + + if ( !moved ) { + for ( ShortFleetView sfv : sFleets ) { + response.addFleet( sfv ); + } + } + + return response; + } + + + @Override + public MultiFleetsResponse rename( int empireId , long[] fleets , String name ) + { + RenameFleetsResponse response; + response = new RenameFleetsResponse( this.empireManagement.getGeneralInformation( empireId ) ); + + List< ShortFleetView > sFleets = this.fleetsDao.getShortFleets( empireId , fleets , false ); + if ( sFleets.isEmpty( ) ) { + return response; + } + + if ( name != null ) { + this.fleetsDao.rename( empireId , fleets , name ); + } else { + for ( ShortFleetView sfv : sFleets ) { + response.addFleet( sfv ); + } + } + + return response; + } + + + @Override + public MultiFleetsResponse merge( int empireId , long[] fleets ) + { + MergeFleetsResponse response = new MergeFleetsResponse( this.empireManagement.getGeneralInformation( empireId ) ); + List< ShortFleetView > sFleets = this.fleetsDao.getShortFleets( empireId , fleets , true ); + if ( !sFleets.isEmpty( ) ) { + this.fleetsDao.merge( empireId , fleets ); + } + return response; + } + + + @Override + public SplitFleetResponse split( int empireId , long fleetId , Map< Integer , Integer > ships , int nFleets , + String name , boolean simulate ) + { + SplitFleetResponse response = new SplitFleetResponse( this.empireManagement.getGeneralInformation( empireId ) ); + if ( fleetId == -1 ) { + return response; + } + + // Try finding the fleet + ShortFleetView fleet = this.fleetsDao.getShortFleet( empireId , fleetId ); + if ( fleet == null || fleet.getStatus( ) != FleetStatus.AVAILABLE ) { + return response; + } + + // If the name is not set, this is the initial request + if ( name == null ) { + for ( SplitShips sShips : this.fleetsDao.getShips( empireId , fleetId ) ) { + sShips.setSelectedAmount( 0 ); + response.addShips( sShips ); + } + response.setInitialFleet( fleet ); + return response; + } + + // Try splitting / simulating the split + boolean splitOk; + splitOk = this.fleetsDao.initSplit( fleetId , nFleets , name ); + if ( splitOk ) { + for ( Map.Entry< Integer , Integer > entry : ships.entrySet( ) ) { + this.fleetsDao.setSplitShips( entry.getKey( ) , entry.getValue( ) ); + } + splitOk = this.fleetsDao.executeSplit( simulate ); + } + + // If there was an error, or if we were simulating + if ( !splitOk || simulate ) { + for ( SplitShips sShips : this.fleetsDao.getShips( empireId , fleetId ) ) { + Integer amount = ships.get( sShips.getType( ) ); + if ( amount == null ) { + amount = 0; + } + sShips.setSelectedAmount( amount ); + response.addShips( sShips ); + } + response.setInitialFleet( fleet ); + response.setShipsError( !splitOk ); + response.setnFleets( nFleets ); + response.setName( name ); + } + + return response; + } + + + @Override + public MultiFleetsResponse disband( int empireId , long[] fleets , boolean doIt ) + { + DisbandFleetsResponse response; + response = new DisbandFleetsResponse( this.empireManagement.getGeneralInformation( empireId ) ); + + List< ShortFleetView > sFleets = this.fleetsDao.getShortFleets( empireId , fleets , false ); + if ( sFleets.isEmpty( ) ) { + return response; + } + + if ( doIt ) { + this.fleetsDao.disband( empireId , fleets ); + } else { + for ( ShortFleetView sfv : sFleets ) { + response.addFleet( sfv ); + } + } + + return response; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/FleetsDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/FleetsDAOBean.java new file mode 100644 index 0000000..3fdbb24 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/fleets/FleetsDAOBean.java @@ -0,0 +1,446 @@ +package com.deepclone.lw.beans.fleets; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.PlanetRelationType; +import com.deepclone.lw.cmd.player.gdata.ShortBattleView; +import com.deepclone.lw.cmd.player.gdata.fleets.*; +import com.deepclone.lw.interfaces.game.FleetsDAO; +import com.deepclone.lw.sqld.game.RawFleetOwner; +import com.deepclone.lw.sqld.game.RawFleetShip; +import com.deepclone.lw.sqld.game.RawStaticFleet; +import com.deepclone.lw.utils.StoredProc; + + + +public class FleetsDAOBean + implements FleetsDAO +{ + private static String sqlLocations = "SELECT * FROM fleets.locations_view WHERE empire = ?"; + private static String sqlOwners = "SELECT * FROM fleets.owners_view WHERE empire = ? ORDER BY relation"; + private static String sqlStaticFleets = "SELECT * FROM fleets.static_fleets WHERE empire = ? ORDER BY power DESC, name NULLS LAST, id DESC"; + private static String sqlMovingFleets = "SELECT * FROM fleets.moving_fleets WHERE empire = ? ORDER BY time_left + penalty, name NULLS LAST, id DESC"; + private static String sqlShips = "SELECT * FROM fleets.ships_view WHERE empire = ?"; + private static String sqlShortStatic = "SELECT * FROM fleets.short_static_fleets WHERE empire = ? AND id IN ( SELECT unnest AS id FROM unnest( ?::BIGINT[] ) )"; + private static String sqlShortMoving = "SELECT * FROM fleets.moving_fleets WHERE empire = ? AND id IN ( SELECT unnest AS id FROM unnest( ?::BIGINT[] ) )"; + private static String sqlSingleShort = "SELECT * FROM fleets.short_static_fleets WHERE empire = ? AND id = ?"; + private static String sqlSingleMoving = "SELECT * FROM fleets.moving_fleets WHERE empire = ? AND id = ?"; + private static String sqlFleetShips = "SELECT * FROM fleets.ships_view WHERE empire = ? AND id = ?"; + + private SimpleJdbcTemplate dTemplate; + + private RowMapper< FleetLocation > mLocations; + private RowMapper< RawFleetOwner > mOwners; + private RowMapper< RawStaticFleet > mStaticFleets; + private RowMapper< MovingFleet > mMovingFleets; + private RowMapper< RawFleetShip > mShips; + private RowMapper< ShortFleetView > mShortStatic; + private RowMapper< ShortFleetView > mShortMoving; + + private StoredProc fMoveFleets; + private StoredProc fSetMode; + private StoredProc fRenameFleets; + private StoredProc fMergeFleets; + private StoredProc fDisbandFleets; + private StoredProc fInitSplit; + private StoredProc fSetSplitShips; + private StoredProc fExecuteSplit; + + + public FleetsDAOBean( ) + { + this.mLocations = new RowMapper< FleetLocation >( ) { + @Override + public FleetLocation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + FleetLocation location = new FleetLocation( rs.getInt( "location" ) , rs.getString( "name" ) ); + location.setOwn( rs.getBoolean( "is_own" ) ); + location.setAttacking( rs.getBoolean( "attacking" ) ); + location.setX( rs.getInt( "x" ) ); + location.setY( rs.getInt( "y" ) ); + location.setOrbit( rs.getInt( "orbit" ) ); + location.setTag( rs.getString( "tag" ) ); + location.setPicture( rs.getInt( "picture" ) ); + location.setPopulation( rs.getLong( "population" ) ); + location.setDefence( rs.getLong( "defence" ) ); + if ( rs.getObject( "battle" ) == null ) { + location.setBattle( null ); + location.setOnVacation( rs.getBoolean( "on_vacation" ) ); + } else { + ShortBattleView battle = new ShortBattleView( ); + battle.setId( rs.getLong( "battle" ) ); + battle.setFriendly( rs.getLong( "friendly_power" ) ); + battle.setHostile( rs.getLong( "hostile_power" ) ); + location.setBattle( battle ); + location.setOnVacation( false ); + } + return location; + } + }; + + this.mOwners = new RowMapper< RawFleetOwner >( ) { + @Override + public RawFleetOwner mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + RawFleetOwner info = new RawFleetOwner( ); + info.setLocation( rs.getInt( "location" ) ); + info.setId( rs.getInt( "id" ) ); + info.setName( rs.getString( "name" ) ); + info.setRelation( rs.getString( "relation" ) ); + return info; + } + }; + + this.mStaticFleets = new RowMapper< RawStaticFleet >( ) { + @Override + public RawStaticFleet mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + RawStaticFleet info = new RawStaticFleet( ); + info.setLocation( rs.getInt( "location" ) ); + info.setOwner( rs.getInt( "owner" ) ); + info.setId( rs.getLong( "id" ) ); + info.setName( rs.getString( "name" ) ); + info.setStatus( rs.getString( "status" ) ); + info.setPenalty( rs.getInt( "penalty" ) ); + info.setPower( rs.getLong( "power" ) ); + info.setFlightTime( rs.getInt( "flight_time" ) ); + return info; + } + }; + + this.mMovingFleets = new RowMapper< MovingFleet >( ) { + @Override + public MovingFleet mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + MovingFleet fleet = new MovingFleet( rs.getLong( "id" ) , rs.getString( "name" ) ); + fleet.setAttacking( rs.getBoolean( "attacking" ) ); + fleet.setStatus( FleetStatus.valueOf( rs.getString( "status" ) ) ); + fleet.setPenalty( rs.getInt( "penalty" ) ); + fleet.setFlightTime( rs.getInt( "flight_time" ) ); + fleet.setPower( rs.getLong( "power" ) ); + fleet.setTimeLeft( rs.getInt( "time_left" ) ); + fleet.setSource( new NameIdPair( rs.getInt( "from_id" ) , rs.getString( "from_name" ) ) ); + fleet.setDestination( new NameIdPair( rs.getInt( "to_id" ) , rs.getString( "to_name" ) ) ); + fleet.setCurrentX( rs.getDouble( "cx" ) ); + fleet.setCurrentY( rs.getDouble( "cy" ) ); + if ( rs.getString( "nearest_name" ) != null ) { + fleet.setNearest( new NameIdPair( rs.getInt( "nearest_id" ) , rs.getString( "nearest_name" ) ) ); + } + return fleet; + } + }; + + this.mShips = new RowMapper< RawFleetShip >( ) { + @Override + public RawFleetShip mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + RawFleetShip ship = new RawFleetShip( ); + ship.setFleet( rs.getLong( "id" ) ); + ship.setShipType( rs.getInt( "ship_id" ) ); + ship.setAmount( rs.getInt( "amount" ) ); + ship.setPower( rs.getInt( "power" ) ); + ship.setName( rs.getString( "name" ) ); + return ship; + } + }; + + this.mShortStatic = new RowMapper< ShortFleetView >( ) { + @Override + public ShortFleetView mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + ShortFleetView sfv = new ShortFleetView( rs.getLong( "id" ) , rs.getString( "name" ) ); + sfv.setFlightTime( rs.getInt( "flight_time" ) ); + sfv.setStatus( FleetStatus.valueOf( rs.getString( "status" ) ) ); + sfv.setPenalty( rs.getInt( "penalty" ) ); + sfv.setPower( rs.getLong( "power" ) ); + sfv.setAttack( rs.getBoolean( "attacking" ) ); + sfv.setAtPlanet( true ); + sfv.setX( rs.getDouble( "x" ) ); + sfv.setY( rs.getDouble( "y" ) ); + sfv.setNearest( new NameIdPair( rs.getInt( "location_id" ) , rs.getString( "location_name" ) ) ); + return sfv; + } + }; + + this.mShortMoving = new RowMapper< ShortFleetView >( ) { + @Override + public ShortFleetView mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + ShortFleetView sfv = new ShortFleetView( rs.getLong( "id" ) , rs.getString( "name" ) ); + sfv.setFlightTime( rs.getInt( "flight_time" ) ); + sfv.setStatus( FleetStatus.valueOf( rs.getString( "status" ) ) ); + sfv.setPenalty( rs.getInt( "penalty" ) ); + sfv.setPower( rs.getLong( "power" ) ); + sfv.setAttack( rs.getBoolean( "attacking" ) ); + sfv.setAtPlanet( false ); + sfv.setX( rs.getDouble( "cx" ) ); + sfv.setY( rs.getDouble( "cy" ) ); + if ( rs.getString( "nearest_name" ) != null ) { + sfv.setNearest( new NameIdPair( rs.getInt( "nearest_id" ) , rs.getString( "nearest_name" ) ) ); + } + return sfv; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fMoveFleets = new StoredProc( dataSource , "fleets" , "move_fleets" ); + this.fMoveFleets.addParameter( "empire_id" , Types.INTEGER ); + this.fMoveFleets.addParameter( "fleet_ids" , "BIGINT[]" ); + this.fMoveFleets.addParameter( "destination" , Types.VARCHAR ); + this.fMoveFleets.addOutput( "success" , Types.BOOLEAN ); + + this.fSetMode = new StoredProc( dataSource , "fleets" , "set_mode" ); + this.fSetMode.addParameter( "empire_id" , Types.INTEGER ); + this.fSetMode.addParameter( "fleet_ids" , "BIGINT[]" ); + this.fSetMode.addParameter( "attack" , Types.BOOLEAN ); + + this.fRenameFleets = new StoredProc( dataSource , "fleets" , "rename_fleets" ); + this.fRenameFleets.addParameter( "empire_id" , Types.INTEGER ); + this.fRenameFleets.addParameter( "fleet_ids" , "BIGINT[]" ); + this.fRenameFleets.addParameter( "new_name" , Types.VARCHAR ); + + this.fMergeFleets = new StoredProc( dataSource , "fleets" , "merge" ); + this.fMergeFleets.addParameter( "empire_id" , Types.INTEGER ); + this.fMergeFleets.addParameter( "fleet_ids" , "BIGINT[]" ); + + this.fDisbandFleets = new StoredProc( dataSource , "fleets" , "disband" ); + this.fDisbandFleets.addParameter( "empire_id" , Types.INTEGER ); + this.fDisbandFleets.addParameter( "fleet_ids" , "BIGINT[]" ); + + this.fInitSplit = new StoredProc( dataSource , "fleets" , "init_split" ); + this.fInitSplit.addParameter( "fleet_id" , Types.BIGINT ); + this.fInitSplit.addParameter( "n_fleets" , Types.INTEGER ); + this.fInitSplit.addParameter( "name" , Types.VARCHAR ); + this.fInitSplit.addOutput( "success" , Types.BOOLEAN ); + + this.fSetSplitShips = new StoredProc( dataSource , "fleets" , "set_split_ships" ); + this.fSetSplitShips.addParameter( "ships_type" , Types.INTEGER ); + this.fSetSplitShips.addParameter( "split_amount" , Types.INTEGER ); + + this.fExecuteSplit = new StoredProc( dataSource , "fleets" , "execute_split" ); + this.fExecuteSplit.addParameter( "simulate" , Types.BOOLEAN ); + this.fExecuteSplit.addOutput( "success" , Types.BOOLEAN ); + } + + + private String getSQLArray( long[] fleets ) + { + StringBuilder fArray = new StringBuilder( ).append( "{" ); + for ( int i = 0 ; i < fleets.length ; i++ ) { + fArray.append( fleets[ i ] ); + if ( i != fleets.length - 1 ) { + fArray.append( "," ); + } + } + fArray.append( "}" ); + return fArray.toString( ); + } + + + @Override + public FleetsView getFleets( int empireId ) + { + FleetsView result = new FleetsView( ); + + // Get visible locations + Map< Integer , FleetLocation > locations = new HashMap< Integer , FleetLocation >( ); + Map< Integer , Map< Integer , FleetOwner >> owners = new HashMap< Integer , Map< Integer , FleetOwner > >( ); + for ( FleetLocation l : this.dTemplate.query( FleetsDAOBean.sqlLocations , this.mLocations , empireId ) ) { + locations.put( (int) l.getId( ) , l ); + owners.put( (int) l.getId( ) , new HashMap< Integer , FleetOwner >( ) ); + result.addLocation( l ); + } + + // Get visible fleet owners + for ( RawFleetOwner rfo : this.dTemplate.query( FleetsDAOBean.sqlOwners , this.mOwners , empireId ) ) { + FleetOwner owner; + int ownerId = rfo.getId( ); + owner = new FleetOwner( ownerId , rfo.getName( ) , PlanetRelationType.valueOf( rfo.getRelation( ) ) ); + + int locationId = rfo.getLocation( ); + FleetLocation location = locations.get( locationId ); + Map< Integer , FleetOwner > lOwners = owners.get( locationId ); + location.addFleetOwner( owner ); + lOwners.put( ownerId , owner ); + } + + // Get static fleets + Map< Long , StaticFleet > fleets = new HashMap< Long , StaticFleet >( ); + for ( RawStaticFleet rsf : this.dTemplate.query( FleetsDAOBean.sqlStaticFleets , this.mStaticFleets , empireId ) ) { + int ownerId = rsf.getOwner( ); + int locationId = rsf.getLocation( ); + long fleetId = rsf.getId( ); + + StaticFleet fleet = new StaticFleet( fleetId , rsf.getName( ) ); + fleet.setFlightTime( rsf.getFlightTime( ) ); + fleet.setStatus( FleetStatus.valueOf( rsf.getStatus( ) ) ); + fleet.setPenalty( rsf.getPenalty( ) ); + fleet.setPower( rsf.getPower( ) ); + + fleets.put( fleetId , fleet ); + owners.get( locationId ).get( ownerId ).addFleet( fleet ); + } + + // Get moving fleets + for ( MovingFleet f : this.dTemplate.query( FleetsDAOBean.sqlMovingFleets , this.mMovingFleets , empireId ) ) { + result.addMovingFleet( f ); + fleets.put( f.getId( ) , f ); + } + + // Fetch fleet ships + for ( RawFleetShip rfs : this.dTemplate.query( FleetsDAOBean.sqlShips , this.mShips , empireId ) ) { + FleetShips ships = new FleetShips( ); + ships.setAmount( rfs.getAmount( ) ); + ships.setPower( rfs.getPower( ) ); + ships.setName( rfs.getName( ) ); + fleets.get( rfs.getFleet( ) ).addShips( ships ); + } + + return result; + } + + + @Override + public List< ShortFleetView > getShortFleets( int empireId , long[] fleets , boolean needsAvailable ) + { + String fArray = this.getSQLArray( fleets ); + + List< ShortFleetView > result = new LinkedList< ShortFleetView >( ); + for ( ShortFleetView sfv : this.dTemplate.query( FleetsDAOBean.sqlShortStatic , this.mShortStatic , empireId , + fArray ) ) { + if ( needsAvailable && sfv.getStatus( ) != FleetStatus.AVAILABLE ) { + continue; + } + result.add( sfv ); + } + for ( ShortFleetView sfv : this.dTemplate.query( FleetsDAOBean.sqlShortMoving , this.mShortMoving , empireId , + fArray ) ) { + if ( needsAvailable && sfv.getStatus( ) != FleetStatus.AVAILABLE ) { + continue; + } + result.add( sfv ); + } + + return result; + } + + + @Override + public boolean move( int empireId , long[] fleets , String destination ) + { + return (Boolean) this.fMoveFleets.execute( empireId , this.getSQLArray( fleets ) , destination ) + .get( "success" ); + } + + + @Override + public void setMode( int empireId , long[] fleets , boolean attack ) + { + this.fSetMode.execute( empireId , this.getSQLArray( fleets ) , attack ); + } + + + @Override + public void rename( int empireId , long[] fleets , String name ) + { + this.fRenameFleets.execute( empireId , this.getSQLArray( fleets ) , name ); + } + + + @Override + public void merge( int empireId , long[] fleets ) + { + this.fMergeFleets.execute( empireId , this.getSQLArray( fleets ) ); + } + + + @Override + public void disband( int empireId , long[] fleets ) + { + this.fDisbandFleets.execute( empireId , this.getSQLArray( fleets ) ); + } + + + @Override + public ShortFleetView getShortFleet( int empireId , long fleetId ) + { + try { + return this.dTemplate.queryForObject( sqlSingleShort , mShortStatic , empireId , fleetId ); + } catch ( EmptyResultDataAccessException e ) { + // EMPTY + } + + try { + return this.dTemplate.queryForObject( sqlSingleMoving , mShortMoving , empireId , fleetId ); + } catch ( EmptyResultDataAccessException e ) { + return null; + } + } + + + @Override + public List< SplitShips > getShips( int empireId , long fleetId ) + { + List< SplitShips > result = new LinkedList< SplitShips >( ); + for ( RawFleetShip rfs : this.dTemplate.query( sqlFleetShips , mShips , empireId , fleetId ) ) { + SplitShips ships = new SplitShips( ); + ships.setId( rfs.getShipType( ) ); + ships.setType( rfs.getShipType( ) ); + ships.setAmount( rfs.getAmount( ) ); + ships.setPower( rfs.getPower( ) ); + ships.setName( rfs.getName( ) ); + result.add( ships ); + } + return result; + } + + + @Override + public boolean initSplit( long fleetId , int nFleets , String name ) + { + return (Boolean) this.fInitSplit.execute( fleetId , nFleets , name ).get( "success" ); + } + + + @Override + public void setSplitShips( int shipType , int amount ) + { + this.fSetSplitShips.execute( shipType , amount ); + } + + + @Override + public boolean executeSplit( boolean simulate ) + { + return (Boolean) this.fExecuteSplit.execute( simulate ).get( "success" ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/MapViewerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/MapViewerBean.java new file mode 100644 index 0000000..a15b69b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/MapViewerBean.java @@ -0,0 +1,96 @@ +package com.deepclone.lw.beans.map; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.player.gdata.MapSize; +import com.deepclone.lw.cmd.player.gdata.PlanetRelationType; +import com.deepclone.lw.cmd.player.gdata.map.MapPlanetData; +import com.deepclone.lw.cmd.player.gdata.map.MapSystemData; +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.game.MapViewParameters; +import com.deepclone.lw.interfaces.game.MapViewer; +import com.deepclone.lw.interfaces.game.UniverseDAO; +import com.deepclone.lw.interfaces.prefs.AccountPreferences; +import com.deepclone.lw.interfaces.prefs.PreferencesDAO; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.sqld.game.MapData; +import com.deepclone.lw.utils.EmailAddress; + + + +@Transactional +public class MapViewerBean + implements MapViewer +{ + + private UsersDAO usersDao; + private PreferencesDAO preferencesDao; + private UniverseDAO universeDao; + + + @Autowired( required = true ) + public void setUsersDao( UsersDAO usersDao ) + { + this.usersDao = usersDao; + } + + + @Autowired( required = true ) + public void setPreferencesDao( PreferencesDAO preferencesDao ) + { + this.preferencesDao = preferencesDao; + } + + + @Autowired( required = true ) + public void setUniverseDao( UniverseDAO universeDao ) + { + this.universeDao = universeDao; + } + + + @Override + public MapViewParameters getDefaults( EmailAddress address ) + { + Account accnt = this.usersDao.getAccount( address ); + AccountPreferences prefs = this.preferencesDao.getPreferences( accnt ); + int x = (Integer) prefs.getPreference( "mapX" , Integer.class ); + int y = (Integer) prefs.getPreference( "mapY" , Integer.class ); + MapSize size = (MapSize) prefs.getPreference( "mapSize" , MapSize.class ); + return new MapViewParameters( x , y , size ); + } + + + @Override + public MapSystemData[][] getMapView( int empireId , MapViewParameters parameters ) + { + int size = 3 + ( 2 * parameters.size.ordinal( ) ); + int minX = parameters.x - ( size >> 1 ); + int maxX = parameters.x + ( size >> 1 ); + int minY = parameters.y - ( size >> 1 ); + int maxY = parameters.y + ( size >> 1 ); + + MapSystemData[][] results = new MapSystemData[ size ][ size ]; + for ( MapData entry : this.universeDao.getMap( empireId , minX , minY , maxX , maxY ) ) { + int x = entry.getX( ) - minX; + int y = maxY - entry.getY( ); + if ( entry.getOrbit( ) == 1 ) { + results[ y ][ x ] = new MapSystemData( ); + } + + PlanetRelationType relation; + String rValue = entry.getDisplay( ); + relation = ( rValue == null ) ? null : PlanetRelationType.valueOf( rValue ); + + MapPlanetData planet; + planet = new MapPlanetData( entry.getId( ) , entry.getPicture( ) , entry.getName( ) , entry.getTag( ) , + relation ); + results[ y ][ x ].setPlanet( entry.getOrbit( ) , planet ); + } + + return results; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetDAOBean.java new file mode 100644 index 0000000..8fe710b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetDAOBean.java @@ -0,0 +1,341 @@ +package com.deepclone.lw.beans.map; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.player.gdata.planets.BuildableBuildingData; +import com.deepclone.lw.cmd.player.gdata.planets.BuildableShipData; +import com.deepclone.lw.cmd.player.gdata.planets.BuildingData; +import com.deepclone.lw.cmd.player.gdata.planets.QueueData; +import com.deepclone.lw.cmd.player.gdata.planets.QueueItemData; +import com.deepclone.lw.interfaces.game.PlanetDAO; +import com.deepclone.lw.sqld.game.PlanetData.AccessType; +import com.deepclone.lw.sqld.game.PlanetData.Basic; +import com.deepclone.lw.sqld.game.PlanetData.Orbital; +import com.deepclone.lw.sqld.game.PlanetData.Owner; +import com.deepclone.lw.utils.StoredProc; + + + +public class PlanetDAOBean + implements PlanetDAO +{ + + private SimpleJdbcTemplate dTemplate; + + private RowMapper< Basic > mPlanetBasics; + private RowMapper< Orbital > mPlanetOrbital; + private RowMapper< Owner > mPlanetOwner; + private RowMapper< BuildingData > mOwnerBuildings; + private RowMapper< BuildingData > mOrbitalBuildings; + private RowMapper< QueueItemData > mQueueItem; + private RowMapper< BuildableBuildingData > mAvailableBuilding; + private RowMapper< BuildableShipData > mAvailableShip; + + private StoredProc fFlushBuildQueue; + private StoredProc fFlushMilitaryQueue; + private StoredProc fAddToMilitaryQueue; + private StoredProc fConstructBuildings; + private StoredProc fDestroyBuildings; + private StoredProc fAbandon; + private StoredProc fCancelAbandon; + + + public PlanetDAOBean( ) + { + this.mPlanetBasics = new RowMapper< Basic >( ) { + @Override + public Basic mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + if ( rs.getString( "access" ) == null ) { + return null; + } + + Basic info = new Basic( ); + info.setAccess( AccessType.valueOf( rs.getString( "access" ) ) ); + info.setX( rs.getInt( "x" ) ); + info.setY( rs.getInt( "y" ) ); + info.setOrbit( rs.getInt( "orbit" ) ); + info.setPicture( rs.getInt( "picture" ) ); + info.setName( rs.getString( "name" ) ); + info.setTag( rs.getString( "tag" ) ); + return info; + } + }; + + this.mPlanetOrbital = new RowMapper< Orbital >( ) { + @Override + public Orbital mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + Orbital info = new Orbital( ); + info.setPopulation( rs.getLong( "population" ) ); + info.setDefence( rs.getLong( "defence" ) ); + info.setOwnPower( rs.getLong( "own_power" ) ); + info.setFriendlyPower( rs.getLong( "friendly_power" ) ); + info.setHostilePower( rs.getLong( "hostile_power" ) ); + info.setBattle( (Long) rs.getObject( "battle_id" ) ); + return info; + } + }; + + this.mPlanetOwner = new RowMapper< Owner >( ) { + @Override + public Owner mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + Owner info = new Owner( ); + info.setHappiness( rs.getInt( "happiness" ) ); + info.sethChange( rs.getInt( "h_change" ) ); + info.setIncome( rs.getLong( "income" ) ); + info.setUpkeep( rs.getLong( "upkeep" ) ); + info.setRenamePossible( rs.getBoolean( "can_rename" ) ); + info.setAbandonPossible( rs.getBoolean( "can_abandon" ) ); + info.setAbandonTime( rs.getInt( "abandon_time" ) ); + return info; + } + }; + + this.mOrbitalBuildings = new RowMapper< BuildingData >( ) { + @Override + public BuildingData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BuildingData info = new BuildingData( ); + info.setAmount( rs.getInt( "amount" ) ); + info.setName( rs.getString( "name" ) ); + info.setDescription( rs.getString( "description" ) ); + return info; + } + }; + + this.mOwnerBuildings = new RowMapper< BuildingData >( ) { + @Override + public BuildingData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BuildingData info = new BuildingData( ); + info.setId( rs.getInt( "id" ) ); + info.setAmount( rs.getInt( "amount" ) ); + info.setName( rs.getString( "name" ) ); + info.setDescription( rs.getString( "description" ) ); + info.setJobs( rs.getInt( "jobs" ) ); + info.setUpkeep( rs.getLong( "upkeep" ) ); + info.setProduces( rs.getString( "p_type" ) ); + info.setOutput( rs.getLong( "p_value" ) ); + return info; + } + }; + + this.mQueueItem = new RowMapper< QueueItemData >( ) { + @Override + public QueueItemData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + QueueItemData item = new QueueItemData( ); + item.setName( rs.getString( "name" ) ); + item.setDescription( rs.getString( "description" ) ); + item.setAmount( rs.getInt( "amount" ) ); + item.setDestroy( rs.getBoolean( "destroy" ) ); + item.setInvested( rs.getLong( "investment" ) ); + item.setTimeLeft( (Long) rs.getObject( "time_left" ) ); + return item; + } + }; + + this.mAvailableBuilding = new RowMapper< BuildableBuildingData >( ) { + @Override + public BuildableBuildingData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BuildableBuildingData info = new BuildableBuildingData( ); + info.setId( rs.getInt( "id" ) ); + info.setName( rs.getString( "name" ) ); + info.setDescription( rs.getString( "description" ) ); + info.setCost( rs.getInt( "cost" ) ); + info.setTime( (Long) rs.getObject( "time_to_build" ) ); + info.setUpkeep( rs.getInt( "upkeep" ) ); + info.setWorkers( rs.getInt( "workers" ) ); + info.setProdType( rs.getString( "p_type" ) ); + info.setOutput( rs.getInt( "p_value" ) ); + return info; + } + }; + + this.mAvailableShip = new RowMapper< BuildableShipData >( ) { + @Override + public BuildableShipData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BuildableShipData info = new BuildableShipData( ); + info.setId( rs.getInt( "id" ) ); + info.setName( rs.getString( "name" ) ); + info.setDescription( rs.getString( "description" ) ); + info.setCost( rs.getInt( "cost" ) ); + info.setTime( (Long) rs.getObject( "time_to_build" ) ); + info.setUpkeep( rs.getInt( "upkeep" ) ); + info.setFlightTime( rs.getInt( "flight_time" ) ); + info.setPower( rs.getInt( "power" ) ); + return info; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fFlushBuildQueue = new StoredProc( dataSource , "verse" , "flush_build_queue" ); + this.fFlushBuildQueue.addParameter( "planet_id" , Types.INTEGER ); + + this.fFlushMilitaryQueue = new StoredProc( dataSource , "verse" , "flush_military_queue" ); + this.fFlushMilitaryQueue.addParameter( "planet_id" , Types.INTEGER ); + + this.fAddToMilitaryQueue = new StoredProc( dataSource , "verse" , "add_military_item" ); + this.fAddToMilitaryQueue.addParameter( "planet_id" , Types.INTEGER ); + this.fAddToMilitaryQueue.addParameter( "ship_id" , Types.INTEGER ); + this.fAddToMilitaryQueue.addParameter( "amount" , Types.INTEGER ); + + this.fConstructBuildings = new StoredProc( dataSource , "verse" , "construct_buildings" ); + this.fConstructBuildings.addParameter( "planet_id" , Types.INTEGER ); + this.fConstructBuildings.addParameter( "building_id" , Types.INTEGER ); + this.fConstructBuildings.addParameter( "amount" , Types.INTEGER ); + + this.fDestroyBuildings = new StoredProc( dataSource , "verse" , "destroy_buildings" ); + this.fDestroyBuildings.addParameter( "planet_id" , Types.INTEGER ); + this.fDestroyBuildings.addParameter( "building_id" , Types.INTEGER ); + this.fDestroyBuildings.addParameter( "amount" , Types.INTEGER ); + this.fDestroyBuildings.addOutput( "success" , Types.BOOLEAN ); + + this.fAbandon = new StoredProc( dataSource , "verse" , "abandon" ); + this.fAbandon.addParameter( "planet_id" , Types.INTEGER ); + this.fAbandon.addOutput( "tta" , Types.INTEGER ); + + this.fCancelAbandon = new StoredProc( dataSource , "verse" , "cancel_abandon" ); + this.fCancelAbandon.addParameter( "planet_id" , Types.INTEGER ); + } + + + @Override + public Basic getBasicInformation( int empireId , int planetId ) + { + String sql = "SELECT * FROM verse.get_planet_basics( ? , ? )"; + return this.dTemplate.queryForObject( sql , this.mPlanetBasics , empireId , planetId ); + } + + + @Override + public Orbital getOrbitalInformation( int empireId , int planetId ) + { + String sql = "SELECT * FROM verse.get_orbital_view( ? , ? )"; + return this.dTemplate.queryForObject( sql , this.mPlanetOrbital , empireId , planetId ); + } + + + @Override + public Owner getOwnerInformation( int empireId , int planetId ) + { + String sql = "SELECT * FROM verse.get_owner_view( ? , ? )"; + return this.dTemplate.queryForObject( sql , this.mPlanetOwner , empireId , planetId ); + } + + + @Override + public List< BuildingData > getBuildings( int empireId , int planetId , boolean isOwner ) + { + RowMapper< BuildingData > mapper = isOwner ? this.mOwnerBuildings : this.mOrbitalBuildings; + String sql = "SELECT * FROM verse.get_buildings_view( ? , ? )"; + return this.dTemplate.query( sql , mapper , empireId , planetId ); + } + + + @Override + public QueueData getConstructionQueue( int planetId ) + { + String sql = "SELECT * FROM verse.get_build_queue( ? )"; + List< QueueItemData > items = this.dTemplate.query( sql , this.mQueueItem , planetId ); + return new QueueData( ( items.size( ) < 5 ) , items ); + } + + + @Override + public QueueData getMilitaryQueue( int planetId ) + { + String sql = "SELECT * FROM verse.get_military_queue( ? )"; + List< QueueItemData > items = this.dTemplate.query( sql , this.mQueueItem , planetId ); + return new QueueData( ( items.size( ) < 5 ) , items ); + } + + + @Override + public List< BuildableBuildingData > getAvailableBuildings( int planetId ) + { + String sql = "SELECT * FROM verse.get_available_buildings( ? )"; + return this.dTemplate.query( sql , this.mAvailableBuilding , planetId ); + } + + + @Override + public List< BuildableShipData > getAvailableShips( int planetId ) + { + String sql = "SELECT * FROM verse.get_available_ships( ? )"; + return this.dTemplate.query( sql , this.mAvailableShip , planetId ); + } + + + @Override + public void flushQueue( int planetId , boolean military ) + { + StoredProc proc = military ? this.fFlushMilitaryQueue : this.fFlushBuildQueue; + proc.execute( planetId ); + } + + + @Override + public void addToMilitaryQueue( int planetId , int sType , int amount ) + { + this.fAddToMilitaryQueue.execute( planetId , sType , amount ); + } + + + @Override + public void constructBuildings( int planetId , int bType , int amount ) + { + this.fConstructBuildings.execute( planetId , bType , amount ); + } + + + @Override + public boolean destroyBuildings( int planetId , int bType , int amount ) + { + return (Boolean) this.fDestroyBuildings.execute( planetId , bType , amount ).get( "success" ); + } + + + @Override + public Integer abandon( int planetId ) + { + int v; + v = (Integer) this.fAbandon.execute( planetId ).get( "tta" ); + return v == 0 ? null : v; + } + + + @Override + public void cancelAbandon( int planetId ) + { + this.fCancelAbandon.execute( planetId ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetsManagementBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetsManagementBean.java new file mode 100644 index 0000000..709fe4b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetsManagementBean.java @@ -0,0 +1,302 @@ +package com.deepclone.lw.beans.map; + + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.planets.BuildingData; +import com.deepclone.lw.cmd.player.gdata.planets.OwnPlanetStatusData; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetBasicView; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetOrbitalView; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetOwnView; +import com.deepclone.lw.cmd.player.planets.BuildingActionResponse; +import com.deepclone.lw.cmd.player.planets.RenamePlanetResponse; +import com.deepclone.lw.cmd.player.planets.ViewPlanetResponse; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.game.PlanetDAO; +import com.deepclone.lw.interfaces.game.PlanetsManagement; +import com.deepclone.lw.interfaces.naming.NamingDAO; +import com.deepclone.lw.sqld.game.PlanetData; +import com.deepclone.lw.sqld.game.PlanetData.AccessType; +import com.deepclone.lw.sqld.game.PlanetData.Basic; +import com.deepclone.lw.sqld.game.PlanetData.Orbital; +import com.deepclone.lw.sqld.game.PlanetData.Owner; + + + +@Transactional +public class PlanetsManagementBean + implements PlanetsManagement +{ + + private EmpireManagement empireManagement; + private PlanetDAO planetDao; + private NamingDAO namingDao; + + + @Autowired( required = true ) + public void setEmpireManagement( EmpireManagement empireManagement ) + { + this.empireManagement = empireManagement; + } + + + @Autowired( required = true ) + public void setPlanetDAO( PlanetDAO planetDao ) + { + this.planetDao = planetDao; + } + + + @Autowired( required = true ) + public void setNamingDao( NamingDAO namingDao ) + { + this.namingDao = namingDao; + } + + + private PlanetOrbitalView getOrbitalView( int empireId , int planetId , AccessType access ) + { + if ( access == AccessType.BASIC ) { + return null; + } + + Orbital orbital = this.planetDao.getOrbitalInformation( empireId , planetId ); + List< BuildingData > buildings = this.planetDao.getBuildings( empireId , planetId , + ( access == AccessType.OWNER ) ); + + PlanetOrbitalView view = new PlanetOrbitalView( ); + view.setPopulation( orbital.getPopulation( ) ); + view.setDefencePoints( orbital.getDefence( ) ); + view.setOwnFleet( orbital.getOwnPower( ) ); + view.setFriendlyFleet( orbital.getFriendlyPower( ) ); + view.setHostileFleet( orbital.getHostilePower( ) ); + view.setBattle( orbital.getBattle( ) ); + view.setBuildings( buildings ); + + return view; + } + + + private PlanetOwnView getOwnerView( int empireId , int planetId , AccessType access ) + { + if ( access != AccessType.OWNER ) { + return null; + } + + Owner data = this.planetDao.getOwnerInformation( empireId , planetId ); + OwnPlanetStatusData status = new OwnPlanetStatusData( ); + status.setRenamePossible( data.isRenamePossible( ) ); + status.setAbandonPossible( data.isAbandonPossible( ) ); + status.setAbandonTime( data.getAbandonTime( ) ); + + PlanetOwnView view = new PlanetOwnView( ); + view.setStatus( status ); + view.setHappiness( data.getHappiness( ) ); + view.sethChange( data.gethChange( ) ); + view.setIncome( data.getIncome( ) ); + view.setUpkeep( data.getUpkeep( ) ); + + view.setCivQueue( this.planetDao.getConstructionQueue( planetId ) ); + view.setMilQueue( this.planetDao.getMilitaryQueue( planetId ) ); + + view.setbBuildings( this.planetDao.getAvailableBuildings( planetId ) ); + view.setbShips( this.planetDao.getAvailableShips( planetId ) ); + + return view; + } + + + private PlanetBasicView getBasicView( Basic data ) + { + return new PlanetBasicView( data.getName( ) , data.getPicture( ) , data.getTag( ) , data.getX( ) , + data.getY( ) , data.getOrbit( ) ); + } + + + private ViewPlanetResponse planetNotFound( int empireId ) + { + return new ViewPlanetResponse( this.empireManagement.getGeneralInformation( empireId ) ); + } + + + private ViewPlanetResponse ownershipError( int empireId , int planetId , Basic basic ) + { + AccessType access = basic.getAccess( ); + PlanetOrbitalView orbital = this.getOrbitalView( empireId , planetId , access ); + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + return new ViewPlanetResponse( planetId , page , this.getBasicView( basic ) , orbital ); + } + + + private ViewPlanetResponse fullView( int empireId , int planetId , Basic basic ) + { + AccessType access = basic.getAccess( ); + PlanetOrbitalView orbital = this.getOrbitalView( empireId , planetId , access ); + PlanetOwnView owner = this.getOwnerView( empireId , planetId , access ); + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + return new ViewPlanetResponse( planetId , page , this.getBasicView( basic ) , orbital , owner ); + + } + + + @Override + public ViewPlanetResponse viewPlanet( int empireId , int planetId ) + { + PlanetData.Basic basic = this.planetDao.getBasicInformation( empireId , planetId ); + if ( basic == null ) { + return this.planetNotFound( empireId ); + } + + AccessType access = basic.getAccess( ); + PlanetOrbitalView orbital = this.getOrbitalView( empireId , planetId , access ); + PlanetOwnView owner = this.getOwnerView( empireId , planetId , access ); + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + return new ViewPlanetResponse( planetId , page , this.getBasicView( basic ) , orbital , owner ); + } + + + @Override + public ViewPlanetResponse renamePlanet( int empireId , int planetId , String name ) + { + PlanetData.Basic basic = this.planetDao.getBasicInformation( empireId , planetId ); + if ( basic == null ) { + return this.planetNotFound( empireId ); + } + + AccessType access = basic.getAccess( ); + if ( access != AccessType.OWNER ) { + return this.ownershipError( empireId , planetId , basic ); + } + + int rv = this.namingDao.renamePlanet( planetId , name ); + ObjectNameError one = null; + switch ( rv ) { + case 0: + basic.setName( name ); + break; + case 1: + one = ObjectNameError.BANNED; + break; + case 2: + one = ObjectNameError.UNAVAILABLE; + break; + case 3: + // "Too early" - someone probably pressed F5 + break; + default: + throw new RuntimeException( "unknown error code " + rv ); + } + + PlanetOrbitalView orbital = this.getOrbitalView( empireId , planetId , access ); + PlanetOwnView owner = this.getOwnerView( empireId , planetId , access ); + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + + if ( one == null ) { + return new ViewPlanetResponse( planetId , page , this.getBasicView( basic ) , orbital , owner ); + } + return new RenamePlanetResponse( planetId , page , this.getBasicView( basic ) , orbital , owner , name , one + .toString( ) ); + } + + + @Override + public ViewPlanetResponse flushQueue( int empireId , int planetId , boolean military ) + { + PlanetData.Basic basic = this.planetDao.getBasicInformation( empireId , planetId ); + if ( basic == null ) { + return this.planetNotFound( empireId ); + } else if ( basic.getAccess( ) != AccessType.OWNER ) { + return this.ownershipError( empireId , planetId , basic ); + } + this.planetDao.flushQueue( planetId , military ); + + return this.fullView( empireId , planetId , basic ); + } + + + @Override + public ViewPlanetResponse addToMilitaryQueue( int empireId , int planetId , int sType , int amount ) + { + PlanetData.Basic basic = this.planetDao.getBasicInformation( empireId , planetId ); + if ( basic == null ) { + return this.planetNotFound( empireId ); + } else if ( basic.getAccess( ) != AccessType.OWNER ) { + return this.ownershipError( empireId , planetId , basic ); + } + this.planetDao.addToMilitaryQueue( planetId , sType , amount ); + return this.fullView( empireId , planetId , basic ); + } + + + @Override + public ViewPlanetResponse addToCivilianQueue( int empireId , int planetId , int bType , boolean destroy , int amount ) + { + PlanetData.Basic basic = this.planetDao.getBasicInformation( empireId , planetId ); + if ( basic == null ) { + return this.planetNotFound( empireId ); + } else if ( basic.getAccess( ) != AccessType.OWNER ) { + return this.ownershipError( empireId , planetId , basic ); + } + + if ( !destroy ) { + this.planetDao.constructBuildings( planetId , bType , amount ); + } else if ( !this.planetDao.destroyBuildings( planetId , bType , amount ) ) { + AccessType access = basic.getAccess( ); + PlanetOrbitalView orbital = this.getOrbitalView( empireId , planetId , access ); + PlanetOwnView owner = this.getOwnerView( empireId , planetId , access ); + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + return new BuildingActionResponse( planetId , page , this.getBasicView( basic ) , orbital , owner ); + } + return this.fullView( empireId , planetId , basic ); + } + + + @Override + public ViewPlanetResponse abandon( int empireId , int planetId ) + { + PlanetData.Basic basic = this.planetDao.getBasicInformation( empireId , planetId ); + if ( basic == null ) { + return this.planetNotFound( empireId ); + } else if ( basic.getAccess( ) != AccessType.OWNER ) { + return this.ownershipError( empireId , planetId , basic ); + } + + AccessType access = basic.getAccess( ); + PlanetOrbitalView orbital = this.getOrbitalView( empireId , planetId , access ); + PlanetOwnView owner = this.getOwnerView( empireId , planetId , access ); + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + + Integer x; + if ( owner.getStatus( ).isAbandonPossible( ) ) { + x = this.planetDao.abandon( planetId ); + } else { + x = null; + } + + if ( x != null ) { + owner.getStatus( ).setAbandonPossible( false ); + owner.getStatus( ).setAbandonTime( x ); + } + + return new ViewPlanetResponse( planetId , page , this.getBasicView( basic ) , orbital , owner ); + } + + + @Override + public ViewPlanetResponse cancelAbandon( int empireId , int planetId ) + { + PlanetData.Basic basic = this.planetDao.getBasicInformation( empireId , planetId ); + if ( basic == null ) { + return this.planetNotFound( empireId ); + } else if ( basic.getAccess( ) != AccessType.OWNER ) { + return this.ownershipError( empireId , planetId , basic ); + } + this.planetDao.cancelAbandon( planetId ); + return this.fullView( empireId , planetId , basic ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseDAOBean.java new file mode 100644 index 0000000..b7dfe92 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseDAOBean.java @@ -0,0 +1,67 @@ +package com.deepclone.lw.beans.map; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.interfaces.game.UniverseDAO; +import com.deepclone.lw.sqld.game.MapData; + + + +public class UniverseDAOBean + implements UniverseDAO +{ + private SimpleJdbcTemplate dTemplate; + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + } + + + @Override + public void generate( ) + { + this.dTemplate.getJdbcOperations( ).execute( "SELECT verse.generate( )" ); + } + + + @Override + public List< MapData > getMap( int empireId , int minX , int minY , int maxX , int maxY ) + { + String sql = "SELECT * FROM verse.get_map( ? , ? , ? , ? , ? )"; + + RowMapper< MapData > mapper = new RowMapper< MapData >( ) { + @Override + public MapData mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + MapData entry = new MapData( ); + + entry.setX( rs.getInt( "x" ) ); + entry.setY( rs.getInt( "y" ) ); + entry.setOrbit( rs.getInt( "orbit" ) ); + entry.setId( rs.getInt( "id" ) ); + entry.setPicture( rs.getInt( "picture" ) ); + entry.setName( rs.getString( "name" ) ); + entry.setTag( rs.getString( "tag" ) ); + entry.setDisplay( rs.getString( "display" ) ); + + return entry; + } + }; + + return this.dTemplate.query( sql , mapper , empireId , minX , minY , maxX , maxY ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseGeneratorBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseGeneratorBean.java new file mode 100644 index 0000000..e2aba49 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseGeneratorBean.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.beans.map; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.game.UniverseDAO; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class UniverseGeneratorBean + implements InitializingBean , DisposableBean +{ + + private TransactionTemplate tTemplate; + + private Ticker ticker; + + private UniverseDAO universeDao; + + private UniverseGeneratorTask generator; + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tTemplate = new TransactionTemplate( tManager ); + } + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setUniverseDAO( UniverseDAO universeDao ) + { + this.universeDao = universeDao; + } + + + @Override + public void afterPropertiesSet( ) + { + // Create ticker task + this.generator = new UniverseGeneratorTask( this.tTemplate , this.universeDao ); + this.ticker.registerTask( Frequency.HIGH , "Universe generator" , this.generator ); + } + + + @Override + public void destroy( ) + { + this.generator = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseGeneratorTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseGeneratorTask.java new file mode 100644 index 0000000..b123053 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/UniverseGeneratorTask.java @@ -0,0 +1,38 @@ +package com.deepclone.lw.beans.map; + + +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.game.UniverseDAO; + + + +class UniverseGeneratorTask + implements Runnable +{ + private final TransactionTemplate tTemplate; + private final UniverseDAO universeDao; + + + UniverseGeneratorTask( TransactionTemplate tTemplate , UniverseDAO universeDao ) + { + this.tTemplate = tTemplate; + this.universeDao = universeDao; + } + + + @Override + public void run( ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + universeDao.generate( ); + } + } ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/AdminMessagesBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/AdminMessagesBean.java new file mode 100644 index 0000000..0f07a8f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/AdminMessagesBean.java @@ -0,0 +1,344 @@ +package com.deepclone.lw.beans.msgs; + + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.msgdata.*; +import com.deepclone.lw.cmd.admin.msg.*; +import com.deepclone.lw.interfaces.admin.AdminDAO; +import com.deepclone.lw.interfaces.game.EmpireDAO; +import com.deepclone.lw.interfaces.msg.AdminMessages; +import com.deepclone.lw.interfaces.msg.MessageBoxDAO; +import com.deepclone.lw.interfaces.msg.MessageContentCache; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatRegistry; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Transactional +public class AdminMessagesBean + implements AdminMessages +{ + + private MessageBoxDAO mboxDao; + private MessageContentCache contentCache; + private MessageFormatRegistry formats; + private EmpireDAO empireDao; + private AdminDAO adminDao; + + + @Autowired( required = true ) + public void setMboxDao( MessageBoxDAO mboxDao ) + { + this.mboxDao = mboxDao; + } + + + @Autowired( required = true ) + public void setContentCache( MessageContentCache contentCache ) + { + this.contentCache = contentCache; + } + + + @Autowired( required = true ) + public void setFormats( MessageFormatRegistry formats ) + { + this.formats = formats; + } + + + @Autowired( required = true ) + public void setEmpireDao( EmpireDAO empireDao ) + { + this.empireDao = empireDao; + } + + + @Autowired( required = true ) + public void setAdminDao( AdminDAO adminDao ) + { + this.adminDao = adminDao; + } + + + private Message readMessage( Administrator admin , boolean inbox , long id ) + { + // Get list of messages + List< InboxRecord > mbox = this.mboxDao.getList( true , admin.getId( ) , inbox ); + Map< Long , MessageDataRecord > contents = this.contentCache.getContent( mbox ); + if ( !contents.containsKey( id ) ) { + return null; + } + + // Find next and previous messages + Long previous = null; + Long next = null; + InboxRecord record = null; + boolean found = false; + for ( InboxRecord message : mbox ) { + if ( !found ) { + if ( message.getId( ) == id ) { + found = true; + record = message; + } else { + previous = message.getId( ); + } + } else if ( next == null ) { + next = message.getId( ); + break; + } + } + + MessageDataRecord content = contents.get( record.getId( ) ); + MessageExtractor formatter = this.formats.getFormatter( content ).getExtractor( record , content , "en" ); + + // Extract basic information + Message message = new Message( ); + message.setId( id ); + message.setNext( next ); + message.setPrevious( previous ); + message.setTime( record.getReceived( ) ); + message.setSender( inbox ? formatter.getSender( ) : record.getSenderName( ) ); + message.setReceiver( record.getReceiverName( ) ); + message.setTitle( formatter.getSubject( ) ); + message.setContents( formatter.getContents( ) ); + message.setUnread( !record.isRead( ) ); + message.setGameTime( content.getTick( ) ); + + // Handle message type + String type = inbox ? record.getSenderType( ) : record.getReceiverType( ); + if ( "EMP".equals( type ) ) { + message.setType( MessageType.EMPIRE ); + } else if ( "ADM".equals( type ) ) { + message.setType( MessageType.ADMINISTRATOR ); + } else { + throw new RuntimeException( "unknown message type " + type ); + } + + return message; + } + + + @Override + public GetMessagesResponse getMessages( Administrator admin , boolean inbox ) + { + // Get list of messages + List< InboxRecord > mbox = this.mboxDao.getList( true , admin.getId( ) , inbox ); + Map< Long , MessageDataRecord > contents = this.contentCache.getContent( mbox ); + + // Format messages and create list of entries + List< MessageListEntry > results = new LinkedList< MessageListEntry >( ); + for ( InboxRecord mRecord : mbox ) { + MessageDataRecord content = contents.get( mRecord.getId( ) ); + MessageExtractor formatter = this.formats.getFormatter( content ).getExtractor( mRecord , content , "en" ); + + MessageListEntry result = new MessageListEntry( ); + result.setId( mRecord.getId( ) ); + result.setTime( mRecord.getReceived( ) ); + result.setRead( mRecord.isRead( ) ); + result.setTitle( formatter.getSubject( ) ); + result.setSender( inbox ? formatter.getSender( ) : mRecord.getReceiverName( ) ); + + String type = inbox ? mRecord.getSenderType( ) : mRecord.getReceiverType( ); + if ( "ADM".equals( type ) ) { + result.setType( MessageType.ADMINISTRATOR ); + } else if ( "EMP".equals( type ) ) { + result.setType( MessageType.EMPIRE ); + } else { + throw new RuntimeException( "unknown message type " + type ); + } + results.add( result ); + } + + return new GetMessagesResponse( admin , results ); + } + + + @Override + public ReadMessageResponse getMessage( Administrator admin , boolean inbox , long id ) + { + // Get list of messages + Message message = this.readMessage( admin , inbox , id ); + if ( message == null ) { + return new ReadMessageResponse( admin , inbox ); + } + + // Mark message as read + if ( inbox && message.isUnread( ) ) { + this.mboxDao.markRead( true , admin.getId( ) , new long[] { + id + } ); + } + + return new ReadMessageResponse( admin , inbox , message ); + } + + + @Override + public void deleteMessages( Administrator admin , boolean inbox , long[] selection ) + { + if ( selection == null ) { + this.mboxDao.delete( true , admin.getId( ) , inbox ); + } else { + this.mboxDao.delete( true , admin.getId( ) , inbox , selection ); + } + } + + + @Override + public void markRead( Administrator admin , long[] selection ) + { + if ( selection == null ) { + this.mboxDao.markRead( true , admin.getId( ) ); + } else { + this.mboxDao.markRead( true , admin.getId( ) , selection ); + } + } + + + @Override + public void markUnread( Administrator admin , long[] selection ) + { + if ( selection == null ) { + this.mboxDao.markUnread( true , admin.getId( ) ); + } else { + this.mboxDao.markUnread( true , admin.getId( ) , selection ); + } + } + + + @Override + public ComposeMessageResponse prepareBlankMessage( Administrator admin ) + { + ComposeMessageResponse response = new ComposeMessageResponse( admin ); + response.setMessageType( MessageType.ADMINISTRATOR ); + response.setTarget( "" ); + response.setTitle( "" ); + response.setContents( "" ); + return response; + } + + + @Override + public ComposeMessageResponse prepareMessageTo( Administrator admin , MessageType type , int id ) + { + ComposeMessageResponse response = this.prepareBlankMessage( admin ); + response.setMessageType( type ); + try { + switch ( type ) { + case EMPIRE: + response.setTarget( this.empireDao.getInformation( id ).getName( ) ); + break; + case ADMINISTRATOR: + response.setTarget( this.adminDao.getAdmin( id ).getName( ) ); + break; + default: + throw new RuntimeException( "unsupported target type " + type ); + } + } catch ( NullPointerException e ) { + response.setTargetError( true ); + } + return response; + } + + + @Override + public ComposeMessageResponse sendMessage( Administrator admin , MessageType type , String target , String title , + String contents , boolean simulate ) + { + int errCode = this.mboxDao.sendMessage( true , admin.getId( ) , type , target , title , contents , simulate ); + if ( errCode == 0 && !simulate ) { + return this.prepareBlankMessage( admin ); + } + + ComposeMessageResponse response = new ComposeMessageResponse( admin ); + return this.sendError( type , target , title , contents , errCode , response ); + } + + + @Override + public ComposeMessageResponse sendReply( Administrator admin , boolean inbox , long replyTo , MessageType type , + String target , String title , String contents , boolean simulate ) + { + int errCode = this.mboxDao.sendMessage( true , admin.getId( ) , type , target , title , contents , simulate ); + if ( errCode == 0 && !simulate ) { + return this.prepareBlankMessage( admin ); + } + + Message message = this.readMessage( admin , inbox , replyTo ); + ComposeMessageResponse response; + if ( message == null || message.getType( ) == MessageType.INTERNAL ) { + response = new ComposeMessageResponse( admin ); + } else { + response = new ComposeMessageResponse( admin , inbox , message ); + } + + return this.sendError( type , target , title , contents , errCode , response ); + } + + + private ComposeMessageResponse sendError( MessageType type , String target , String title , String contents , + int errCode , ComposeMessageResponse response ) + { + switch ( errCode ) { + case 1: + response.setTargetError( true ); + break; + case 2: + response.setTimingError( true ); + break; + } + + response.setMessageType( type ); + response.setTarget( target ); + response.setTitle( title ); + response.setContents( contents ); + + return response; + } + + + @Override + public ComposeMessageResponse prepareReply( Administrator admin , boolean inbox , long id ) + { + Message message = this.readMessage( admin , inbox , id ); + if ( message == null || message.getType( ) == MessageType.INTERNAL ) { + return this.prepareBlankMessage( admin ); + } + + ComposeMessageResponse response; + response = new ComposeMessageResponse( admin , inbox , message ); + + response.setMessageType( message.getType( ) ); + response.setTarget( message.getSender( ) ); + + String title = message.getTitle( ); + if ( !title.startsWith( "Re: " ) ) { + title = "Re: " + title; + if ( title.length( ) > 64 ) { + title = title.substring( 0 , 64 ); + } + } + response.setTitle( title ); + + response.setContents( "" ); + return response; + } + + + @Override + public void sendSpam( Administrator admin , String title , String body ) + { + this.mboxDao.sendSpam( admin.getId( ) , title , body ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/EmpireMessagesBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/EmpireMessagesBean.java new file mode 100644 index 0000000..7885bc5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/EmpireMessagesBean.java @@ -0,0 +1,449 @@ +package com.deepclone.lw.beans.msgs; + + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import com.deepclone.lw.cmd.admin.adata.AdministratorBasics; +import com.deepclone.lw.cmd.admin.naming.Name; +import com.deepclone.lw.cmd.admin.naming.NameType; +import com.deepclone.lw.cmd.msgdata.Message; +import com.deepclone.lw.cmd.msgdata.MessageListEntry; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.alliance.PublicAllianceInformation; +import com.deepclone.lw.cmd.player.msgs.ComposeMessageResponse; +import com.deepclone.lw.cmd.player.msgs.GetMessagesResponse; +import com.deepclone.lw.cmd.player.msgs.ListTargetsResponse; +import com.deepclone.lw.cmd.player.msgs.ReadMessageResponse; +import com.deepclone.lw.interfaces.acm.UsersDAO; +import com.deepclone.lw.interfaces.admin.AdminDAO; +import com.deepclone.lw.interfaces.game.AllianceDAO; +import com.deepclone.lw.interfaces.game.EmpireDAO; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.msg.MessageBoxDAO; +import com.deepclone.lw.interfaces.msg.MessageContentCache; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatRegistry; +import com.deepclone.lw.interfaces.msg.EmpireMessages; +import com.deepclone.lw.interfaces.naming.NamingDAO; +import com.deepclone.lw.sqld.admin.AdminRecord; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Transactional +public class EmpireMessagesBean + implements EmpireMessages +{ + + private EmpireManagement empireManager; + private MessageBoxDAO mboxDao; + private MessageContentCache contentCache; + private MessageFormatRegistry formats; + private EmpireDAO empireDao; + private AllianceDAO allianceDao; + private UsersDAO usersDao; + private AdminDAO adminDao; + private NamingDAO namingDao; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement empireManager ) + { + this.empireManager = empireManager; + } + + + @Autowired( required = true ) + public void setMboxDao( MessageBoxDAO mboxDao ) + { + this.mboxDao = mboxDao; + } + + + @Autowired( required = true ) + public void setContentCache( MessageContentCache contentCache ) + { + this.contentCache = contentCache; + } + + + @Autowired( required = true ) + public void setFormats( MessageFormatRegistry formats ) + { + this.formats = formats; + } + + + @Autowired( required = true ) + public void setEmpireDao( EmpireDAO empireDao ) + { + this.empireDao = empireDao; + } + + + @Autowired( required = true ) + public void setAllianceDao( AllianceDAO allianceDao ) + { + this.allianceDao = allianceDao; + } + + + @Autowired( required = true ) + public void setUsersDao( UsersDAO usersDao ) + { + this.usersDao = usersDao; + } + + + @Autowired( required = true ) + public void setAdminDao( AdminDAO adminDao ) + { + this.adminDao = adminDao; + } + + + @Autowired( required = true ) + public void setNamingDao( NamingDAO namingDao ) + { + this.namingDao = namingDao; + } + + + private Message readEmpireMessage( int empireId , boolean inbox , long id ) + { + int accountId = this.empireDao.getInformation( empireId ).getAccountId( ); + String lang = this.usersDao.getAccount( accountId ).getLanguage( ); + + // Get list of messages + List< InboxRecord > mbox = this.mboxDao.getList( false , empireId , inbox ); + Map< Long , MessageDataRecord > contents = this.contentCache.getContent( mbox ); + if ( !contents.containsKey( id ) ) { + return null; + } + + // Find next and previous messages + Long previous = null; + Long next = null; + InboxRecord record = null; + boolean found = false; + for ( InboxRecord message : mbox ) { + if ( !found ) { + if ( message.getId( ) == id ) { + found = true; + record = message; + } else { + previous = message.getId( ); + } + } else if ( next == null ) { + next = message.getId( ); + break; + } + } + + MessageDataRecord content = contents.get( record.getId( ) ); + MessageExtractor formatter = this.formats.getFormatter( content ).getExtractor( record , content , lang ); + + // Extract basic information + Message message = new Message( ); + message.setId( id ); + message.setNext( next ); + message.setPrevious( previous ); + message.setTime( record.getReceived( ) ); + message.setSender( inbox ? formatter.getSender( ) : record.getSenderName( ) ); + message.setReceiver( record.getReceiverName( ) ); + message.setTitle( formatter.getSubject( ) ); + message.setContents( formatter.getContents( ) ); + message.setUnread( !record.isRead( ) ); + message.setGameTime( content.getTick( ) ); + + // Handle message type + if ( record.isInternal( ) ) { + message.setType( MessageType.INTERNAL ); + } else { + String type = inbox ? record.getSenderType( ) : record.getReceiverType( ); + if ( "ALL".equals( record.getReceiverType( ) ) ) { + message.setType( MessageType.ALLIANCE ); + message.setReceiver( "[" + message.getReceiver( ) + "]" ); + } else if ( "EMP".equals( type ) ) { + message.setType( MessageType.EMPIRE ); + } else if ( "ADM".equals( type ) ) { + message.setType( MessageType.ADMINISTRATOR ); + } else { + throw new RuntimeException( "unknown message type " + type ); + } + } + + return message; + } + + + @Override + public GetMessagesResponse getMessages( int empireId , boolean inbox ) + { + int accountId = this.empireDao.getInformation( empireId ).getAccountId( ); + String lang = this.usersDao.getAccount( accountId ).getLanguage( ); + + // Get list of messages + List< InboxRecord > mbox = this.mboxDao.getList( false , empireId , inbox ); + Map< Long , MessageDataRecord > contents = this.contentCache.getContent( mbox ); + + // Format messages and create list of entries + List< MessageListEntry > results = new LinkedList< MessageListEntry >( ); + for ( InboxRecord mRecord : mbox ) { + MessageDataRecord content = contents.get( mRecord.getId( ) ); + MessageExtractor formatter = this.formats.getFormatter( content ).getExtractor( mRecord , content , lang ); + + MessageListEntry result = new MessageListEntry( ); + result.setId( mRecord.getId( ) ); + result.setTime( mRecord.getReceived( ) ); + result.setRead( mRecord.isRead( ) ); + result.setTitle( formatter.getSubject( ) ); + result.setSender( inbox ? formatter.getSender( ) : mRecord.getReceiverName( ) ); + if ( mRecord.isInternal( ) ) { + result.setType( MessageType.INTERNAL ); + } else { + String type = inbox ? mRecord.getSenderType( ) : mRecord.getReceiverType( ); + if ( "ADM".equals( type ) ) { + result.setType( MessageType.ADMINISTRATOR ); + } else if ( "ALL".equals( mRecord.getReceiverType( ) ) ) { + result.setType( MessageType.ALLIANCE ); + result.setSender( "[" + mRecord.getReceiverName( ) + "]" ); + } else if ( "EMP".equals( type ) ) { + result.setType( MessageType.EMPIRE ); + } else { + throw new RuntimeException( "unknown message type " + type ); + } + } + results.add( result ); + } + + return new GetMessagesResponse( this.empireManager.getGeneralInformation( empireId ) , results ); + } + + + @Override + public ReadMessageResponse getMessage( int empireId , boolean inbox , long id ) + { + // Get list of messages + Message message = this.readEmpireMessage( empireId , inbox , id ); + if ( message == null ) { + return new ReadMessageResponse( this.empireManager.getGeneralInformation( empireId ) , inbox ); + } + + // Mark message as read + if ( inbox && message.isUnread( ) ) { + this.mboxDao.markRead( false , empireId , new long[] { + id + } ); + } + + return new ReadMessageResponse( this.empireManager.getGeneralInformation( empireId ) , inbox , message ); + } + + + @Override + public void deleteMessages( int empireId , boolean inbox , long[] selection ) + { + if ( selection == null ) { + this.mboxDao.delete( false , empireId , inbox ); + } else { + this.mboxDao.delete( false , empireId , inbox , selection ); + } + } + + + @Override + public void markRead( int empireId , long[] selection ) + { + if ( selection == null ) { + this.mboxDao.markRead( false , empireId ); + } else { + this.mboxDao.markRead( false , empireId , selection ); + } + } + + + @Override + public void markUnread( int empireId , long[] selection ) + { + if ( selection == null ) { + this.mboxDao.markUnread( false , empireId ); + } else { + this.mboxDao.markUnread( false , empireId , selection ); + } + } + + + @Override + public ComposeMessageResponse prepareBlankMessage( int empireId ) + { + ComposeMessageResponse response = new ComposeMessageResponse( this.empireManager + .getGeneralInformation( empireId ) ); + response.setMessageType( MessageType.EMPIRE ); + response.setTarget( "" ); + response.setTitle( "" ); + response.setContents( "" ); + return response; + } + + + @Override + public ComposeMessageResponse prepareMessageTo( int empireId , MessageType type , int id ) + { + ComposeMessageResponse response = this.prepareBlankMessage( empireId ); + response.setMessageType( type ); + try { + switch ( type ) { + case EMPIRE: + response.setTarget( this.empireDao.getInformation( id ).getName( ) ); + break; + case ALLIANCE: + response.setTarget( this.allianceDao.getPublicInformation( id ).getTag( ) ); + break; + case ADMINISTRATOR: + response.setTarget( this.adminDao.getAdmin( id ).getName( ) ); + break; + default: + throw new RuntimeException( "unsupported target type " + type ); + } + } catch ( NullPointerException e ) { + response.setTargetError( true ); + } + return response; + } + + + @Override + public ComposeMessageResponse sendMessage( int empireId , MessageType type , String target , String title , + String contents , boolean simulate ) + { + int errCode = this.mboxDao.sendMessage( false , empireId , type , target , title , contents , simulate ); + if ( errCode == 0 && !simulate ) { + return this.prepareBlankMessage( empireId ); + } + + ComposeMessageResponse response = new ComposeMessageResponse( this.empireManager + .getGeneralInformation( empireId ) ); + return empireSendError( type , target , title , contents , errCode , response ); + } + + + @Override + public ComposeMessageResponse sendReply( int empireId , boolean inbox , long replyTo , MessageType type , + String target , String title , String contents , boolean simulate ) + { + int errCode = this.mboxDao.sendMessage( false , empireId , type , target , title , contents , simulate ); + if ( errCode == 0 && !simulate ) { + return this.prepareBlankMessage( empireId ); + } + + Message message = this.readEmpireMessage( empireId , inbox , replyTo ); + ComposeMessageResponse response; + if ( message == null || message.getType( ) == MessageType.INTERNAL ) { + response = new ComposeMessageResponse( this.empireManager.getGeneralInformation( empireId ) ); + } else { + response = new ComposeMessageResponse( this.empireManager.getGeneralInformation( empireId ) , inbox , + message ); + } + + return empireSendError( type , target , title , contents , errCode , response ); + } + + + private ComposeMessageResponse empireSendError( MessageType type , String target , String title , String contents , + int errCode , ComposeMessageResponse response ) + { + switch ( errCode ) { + case 1: + response.setTargetError( true ); + break; + case 2: + response.setTimingError( true ); + break; + } + + response.setMessageType( type ); + response.setTarget( target ); + response.setTitle( title ); + response.setContents( contents ); + + return response; + } + + + @Override + public ComposeMessageResponse prepareReply( int empireId , boolean inbox , long id ) + { + Message message = this.readEmpireMessage( empireId , inbox , id ); + if ( message == null || message.getType( ) == MessageType.INTERNAL ) { + return this.prepareBlankMessage( empireId ); + } + + ComposeMessageResponse response; + response = new ComposeMessageResponse( this.empireManager.getGeneralInformation( empireId ) , inbox , message ); + + response.setMessageType( message.getType( ) ); + if ( message.getType( ) == MessageType.ALLIANCE ) { + String allTag = message.getReceiver( ); + response.setTarget( allTag.substring( 1 , allTag.length( ) - 1 ) ); + } else { + response.setTarget( message.getSender( ) ); + } + + String title = message.getTitle( ); + if ( !title.startsWith( "Re: " ) ) { + title = "Re: " + title; + if ( title.length( ) > 64 ) { + title = title.substring( 0 , 64 ); + } + } + response.setTitle( title ); + + response.setContents( "" ); + return response; + } + + + @Override + public ListTargetsResponse getTargets( int empireId ) + { + // List all administrators + List< AdministratorBasics > admins = new LinkedList< AdministratorBasics >( ); + for ( AdminRecord record : this.adminDao.listAdministrators( ) ) { + if ( !record.isActive( ) ) { + continue; + } + AdministratorBasics admin = new AdministratorBasics( ); + admin.setId( record.getId( ) ); + admin.setName( record.getName( ) ); + admin.setPrivileges( record.getPrivileges( ) ); + admins.add( admin ); + } + + // List active empires + List< NameIdPair > empires = new LinkedList< NameIdPair >( ); + for ( Name n : this.namingDao.getNames( NameType.EMPIRE ) ) { + if ( n.getExtra( ) == null || n.getId( ) == empireId ) { + continue; + } + empires.add( new NameIdPair( n.getId( ) , n.getName( ) ) ); + } + + // List alliances + List< PublicAllianceInformation > alliances = new LinkedList< PublicAllianceInformation >( ); + for ( Name n : this.namingDao.getNames( NameType.ALLIANCE ) ) { + alliances.add( new PublicAllianceInformation( n.getId( ) , n.getName( ) , n.getExtra( ) , 0 , null , 0 ) ); + } + + return new ListTargetsResponse( this.empireManager.getGeneralInformation( empireId ) , empires , alliances , + admins ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MailTaskBase.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MailTaskBase.java new file mode 100644 index 0000000..c59099d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MailTaskBase.java @@ -0,0 +1,157 @@ +package com.deepclone.lw.beans.msgs; + + +import java.util.List; +import java.util.Map; + +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.msgdata.Message; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.interfaces.msg.MessageContentCache; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatRegistry; +import com.deepclone.lw.interfaces.msg.NotificationsDAO; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; +import com.deepclone.lw.sqld.msgs.NotificationsRecord; + + + +abstract class MailTaskBase + implements Runnable +{ + + protected static class MessageData + { + public List< InboxRecord > messages; + public Map< Long , MessageDataRecord > data; + } + + protected final SystemLogger logger; + protected final TransactionTemplate tTemplate; + protected final NotificationsDAO notificationsDao; + protected final MessageContentCache contents; + protected final MessageFormatRegistry formats; + protected final Translator translator; + protected final Mailer mailer; + protected final MessageCleanerBean cleaner; + protected final boolean mode; + + + public MailTaskBase( Logger logger , PlatformTransactionManager tManager , NotificationsDAO notificationsDao , + MessageContentCache contents , MessageFormatRegistry formats , Translator translator , Mailer mailer , + MessageCleanerBean cleaner , boolean mode ) + { + this.logger = logger.getSystemLogger( this.getClass( ).getSimpleName( ) ); + this.tTemplate = new TransactionTemplate( tManager ); + this.notificationsDao = notificationsDao; + this.contents = contents; + this.formats = formats; + this.translator = translator; + this.mailer = mailer; + this.cleaner = cleaner; + this.mode = mode; + } + + + @Override + public void run( ) + { + List< NotificationsRecord > notifications = this.getNotifications( ); + for ( NotificationsRecord notification : notifications ) { + this.notify( notification ); + } + } + + + private List< NotificationsRecord > getNotifications( ) + { + return this.tTemplate.execute( new TransactionCallback< List< NotificationsRecord > >( ) { + @Override + public List< NotificationsRecord > doInTransaction( TransactionStatus status ) + { + return notificationsDao.getNotificationRecords( mode ); + } + } ); + } + + + protected abstract void notify( NotificationsRecord notification ); + + + protected final MessageData getMessagesToSend( final int id , final long maxId , final boolean nPrivate , + final boolean nInternal , final boolean nAlliance , final boolean nAdmin ) + { + return this.tTemplate.execute( new TransactionCallback< MessageData >( ) { + @Override + public MessageData doInTransaction( TransactionStatus status ) + { + MessageData md = new MessageData( ); + md.messages = notificationsDao.listMessages( id , maxId , mode , nPrivate , nInternal , nAlliance , + nAdmin ); + if ( !md.messages.isEmpty( ) ) { + md.data = contents.getContent( md.messages ); + } + return md; + } + } ); + } + + + protected final String translate( String string , String lang ) + { + try { + return this.translator.translate( lang , string ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + } + + + protected final Message readMessage( int empireId , String lang , InboxRecord record , MessageDataRecord content , + boolean needBody ) + { + MessageExtractor formatter = this.formats.getFormatter( content ).getExtractor( record , content , lang ); + + // Extract basic information + Message message = new Message( ); + message.setTime( record.getReceived( ) ); + message.setSender( formatter.getSender( ) ); + message.setReceiver( record.getReceiverName( ) ); + message.setTitle( formatter.getSubject( ) ); + if ( needBody ) { + message.setContents( formatter.getContents( ) ); + } + message.setUnread( !record.isRead( ) ); + message.setGameTime( content.getTick( ) ); + + // Handle message type + if ( record.isInternal( ) ) { + message.setType( MessageType.INTERNAL ); + } else { + String type = record.getSenderType( ); + if ( "ALL".equals( record.getReceiverType( ) ) ) { + message.setType( MessageType.ALLIANCE ); + message.setReceiver( "[" + message.getReceiver( ) + "]" ); + } else if ( "EMP".equals( type ) ) { + message.setType( MessageType.EMPIRE ); + } else if ( "ADM".equals( type ) ) { + message.setType( MessageType.ADMINISTRATOR ); + } else { + throw new RuntimeException( "unknown message type " + type ); + } + } + + return message; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageBoxDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageBoxDAOBean.java new file mode 100644 index 0000000..3933d8d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageBoxDAOBean.java @@ -0,0 +1,420 @@ +package com.deepclone.lw.beans.msgs; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.player.msgs.MessageBoxAction; +import com.deepclone.lw.interfaces.msg.MessageBoxDAO; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.utils.StoredProc; + + + +public class MessageBoxDAOBean + implements MessageBoxDAO +{ + private static final int cacheTime = 6; + + private static class CacheKey + { + private final boolean admin; + private final int id; + private final boolean inbox; + + + public CacheKey( boolean admin , int id , boolean inbox ) + { + this.admin = admin; + this.id = id; + this.inbox = inbox; + } + + + @Override + public int hashCode( ) + { + final int prime = 31; + int result = 1; + result = prime * result + ( admin ? 1231 : 1237 ); + result = prime * result + id; + result = prime * result + ( inbox ? 1231 : 1237 ); + return result; + } + + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + return true; + if ( obj == null ) + return false; + if ( getClass( ) != obj.getClass( ) ) + return false; + CacheKey other = (CacheKey) obj; + if ( admin != other.admin ) + return false; + if ( id != other.id ) + return false; + if ( inbox != other.inbox ) + return false; + return true; + } + + } + + private static class CacheData + { + public int timeLeft = MessageBoxDAOBean.cacheTime; + public long maxId = Long.MIN_VALUE; + public List< InboxRecord > records = new LinkedList< InboxRecord >( ); + public Map< Long , MessageBoxAction > updates = new HashMap< Long , MessageBoxAction >( ); + } + + private final Map< CacheKey , CacheData > cache = new HashMap< CacheKey , CacheData >( ); + + private SimpleJdbcTemplate dTemplate; + private final RowMapper< InboxRecord > listMapper; + + private StoredProc fSendSpam; + private StoredProc fEmpireSend; + private StoredProc fEmpireMarkRead; + private StoredProc fEmpireMarkReadAll; + private StoredProc fEmpireDelete; + private StoredProc fEmpireDeleteAll; + private StoredProc fEmpireMarkUnread; + private StoredProc fEmpireMarkUnreadAll; + private StoredProc fAdminSend; + private StoredProc fAdminMarkRead; + private StoredProc fAdminMarkReadAll; + private StoredProc fAdminDelete; + private StoredProc fAdminDeleteAll; + private StoredProc fAdminMarkUnread; + private StoredProc fAdminMarkUnreadAll; + + + public MessageBoxDAOBean( ) + { + this.listMapper = new RowMapper< InboxRecord >( ) { + @Override + public InboxRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + InboxRecord iRec = new InboxRecord( ); + iRec.setId( rs.getLong( "id" ) ); + iRec.setRead( rs.getBoolean( "read" ) ); + iRec.setSenderType( rs.getString( "sender_type" ) ); + iRec.setSenderId( (Integer) rs.getObject( "sender_id" ) ); + iRec.setSenderName( rs.getString( "sender_name" ) ); + iRec.setReceiverType( rs.getString( "receiver_type" ) ); + iRec.setReceiverId( rs.getInt( "receiver_id" ) ); + iRec.setReceiverName( rs.getString( "receiver_name" ) ); + iRec.setInternal( rs.getBoolean( "internal_message" ) ); + iRec.setReceived( rs.getTimestamp( "r_time" ) ); + iRec.setContentId( rs.getLong( "content_id" ) ); + return iRec; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fSendSpam = new StoredProc( dataSource , "msgs" , "deliver_admin_spam" ); + this.fSendSpam.addParameter( "admin_id" , Types.INTEGER ); + this.fSendSpam.addParameter( "subject" , Types.VARCHAR ); + this.fSendSpam.addParameter( "contents" , "TEXT" ); + + this.fEmpireSend = new StoredProc( dataSource , "msgs" , "send_message" ); + this.fEmpireSend.addParameter( "empire_id" , Types.INTEGER ); + this.fEmpireSend.addParameter( "to_type" , "receiver_type" ); + this.fEmpireSend.addParameter( "target" , Types.VARCHAR ); + this.fEmpireSend.addParameter( "subject" , Types.VARCHAR ); + this.fEmpireSend.addParameter( "contents" , "TEXT" ); + this.fEmpireSend.addParameter( "really_send" , Types.BOOLEAN ); + this.fEmpireSend.addOutput( "err_code" , Types.INTEGER ); + + this.fEmpireMarkRead = new StoredProc( dataSource , "msgs" , "empire_mark_read" ); + this.fEmpireMarkRead.addParameter( "empire_id" , Types.INTEGER ); + this.fEmpireMarkRead.addParameter( "messages" , "BIGINT[]" ); + + this.fEmpireMarkReadAll = new StoredProc( dataSource , "msgs" , "empire_mark_read" ); + this.fEmpireMarkReadAll.addParameter( "empire_id" , Types.INTEGER ); + + this.fEmpireMarkUnread = new StoredProc( dataSource , "msgs" , "empire_mark_unread" ); + this.fEmpireMarkUnread.addParameter( "empire_id" , Types.INTEGER ); + this.fEmpireMarkUnread.addParameter( "messages" , "BIGINT[]" ); + + this.fEmpireMarkUnreadAll = new StoredProc( dataSource , "msgs" , "empire_mark_unread" ); + this.fEmpireMarkUnreadAll.addParameter( "empire_id" , Types.INTEGER ); + + this.fEmpireDelete = new StoredProc( dataSource , "msgs" , "empire_delete" ); + this.fEmpireDelete.addParameter( "empire_id" , Types.INTEGER ); + this.fEmpireDelete.addParameter( "in_inbox" , Types.BOOLEAN ); + this.fEmpireDelete.addParameter( "messages" , "BIGINT[]" ); + + this.fEmpireDeleteAll = new StoredProc( dataSource , "msgs" , "empire_delete" ); + this.fEmpireDeleteAll.addParameter( "empire_id" , Types.INTEGER ); + this.fEmpireDeleteAll.addParameter( "in_inbox" , Types.BOOLEAN ); + + this.fAdminSend = new StoredProc( dataSource , "msgs" , "send_admin_message" ); + this.fAdminSend.addParameter( "admin_id" , Types.INTEGER ); + this.fAdminSend.addParameter( "to_type" , "receiver_type" ); + this.fAdminSend.addParameter( "target" , Types.VARCHAR ); + this.fAdminSend.addParameter( "subject" , Types.VARCHAR ); + this.fAdminSend.addParameter( "contents" , "TEXT" ); + this.fAdminSend.addParameter( "really_send" , Types.BOOLEAN ); + this.fAdminSend.addOutput( "err_code" , Types.INTEGER ); + + this.fAdminMarkRead = new StoredProc( dataSource , "msgs" , "admin_mark_read" ); + this.fAdminMarkRead.addParameter( "admin_id" , Types.INTEGER ); + this.fAdminMarkRead.addParameter( "messages" , "BIGINT[]" ); + + this.fAdminMarkReadAll = new StoredProc( dataSource , "msgs" , "admin_mark_read" ); + this.fAdminMarkReadAll.addParameter( "admin_id" , Types.INTEGER ); + + this.fAdminMarkUnread = new StoredProc( dataSource , "msgs" , "admin_mark_unread" ); + this.fAdminMarkUnread.addParameter( "admin_id" , Types.INTEGER ); + this.fAdminMarkUnread.addParameter( "messages" , "BIGINT[]" ); + + this.fAdminMarkUnreadAll = new StoredProc( dataSource , "msgs" , "admin_mark_unread" ); + this.fAdminMarkUnreadAll.addParameter( "admin_id" , Types.INTEGER ); + + this.fAdminDelete = new StoredProc( dataSource , "msgs" , "admin_delete" ); + this.fAdminDelete.addParameter( "admin_id" , Types.INTEGER ); + this.fAdminDelete.addParameter( "in_inbox" , Types.BOOLEAN ); + this.fAdminDelete.addParameter( "messages" , "BIGINT[]" ); + + this.fAdminDeleteAll = new StoredProc( dataSource , "msgs" , "admin_delete" ); + this.fAdminDeleteAll.addParameter( "admin_id" , Types.INTEGER ); + this.fAdminDeleteAll.addParameter( "in_inbox" , Types.BOOLEAN ); + } + + + private String getIdArray( long[] ids ) + { + StringBuilder iArray = new StringBuilder( ).append( "{" ); + int i = 0; + int s = ids.length; + for ( Long id : ids ) { + iArray.append( id ); + if ( i != s - 1 ) { + iArray.append( "," ); + } + i++; + } + iArray.append( "}" ); + return iArray.toString( ); + } + + + @Override + public int sendMessage( boolean admin , int empireId , MessageType type , String target , String title , + String contents , boolean simulate ) + { + StoredProc send = admin ? this.fAdminSend : this.fEmpireSend; + Map< String , Object > result; + result = send.execute( empireId , type.toString( ).substring( 0 , 3 ) , target , title , contents , !simulate ); + return (Integer) result.get( "err_code" ); + } + + + @Override + public List< InboxRecord > getList( boolean admin , int id , boolean inbox ) + { + CacheKey key = new CacheKey( admin , id , inbox ); + CacheData data; + + synchronized ( this.cache ) { + data = this.cache.get( key ); + if ( data == null ) { + data = new CacheData( ); + this.cache.put( key , data ); + } else if ( !data.updates.isEmpty( ) ) { + this.applyUpdates( data ); + } + this.getNewRecords( admin , id , inbox , data ); + data.timeLeft = MessageBoxDAOBean.cacheTime; + } + + return data.records; + } + + + private void applyUpdates( CacheData data ) + { + Iterator< InboxRecord > iterator = data.records.iterator( ); + while ( iterator.hasNext( ) ) { + InboxRecord record = iterator.next( ); + MessageBoxAction update = data.updates.get( record.getId( ) ); + if ( update == null ) { + continue; + } + + switch ( update ) { + case DELETE: + iterator.remove( ); + break; + case MARK_READ: + record.setRead( true ); + break; + case MARK_UNREAD: + record.setRead( false ); + break; + } + } + data.updates.clear( ); + } + + + private void getNewRecords( boolean admin , int id , boolean inbox , CacheData data ) + { + String tString = ( admin ? "admin" : "empire" ); + String bString = ( inbox ? "in" : "out" ); + String sql = "SELECT * FROM msgs." + tString + "_" + bString + "box WHERE " + tString + "_id = ? AND id > ?"; + List< InboxRecord > newRecords = this.dTemplate.query( sql , this.listMapper , id , data.maxId ); + if ( newRecords.isEmpty( ) ) { + return; + } + + data.records.addAll( 0 , newRecords ); + data.maxId = newRecords.get( 0 ).getId( ); + } + + + @Override + public void markRead( boolean admin , int userId , long[] ids ) + { + synchronized ( this.cache ) { + CacheData data = this.cache.get( new CacheKey( admin , userId , true ) ); + if ( data != null ) { + for ( long id : ids ) { + if ( data.updates.containsKey( id ) ) { + continue; + } + data.updates.put( id , MessageBoxAction.MARK_READ ); + } + } + + StoredProc dbMark = admin ? this.fAdminMarkRead : this.fEmpireMarkRead; + dbMark.execute( userId , this.getIdArray( ids ) ); + } + } + + + @Override + public void markRead( boolean admin , int userId ) + { + synchronized ( this.cache ) { + this.cache.remove( new CacheKey( admin , userId , true ) ); + + StoredProc dbMark = admin ? this.fAdminMarkReadAll : this.fEmpireMarkReadAll; + dbMark.execute( userId ); + } + } + + + @Override + public void markUnread( boolean admin , int userId , long[] ids ) + { + synchronized ( this.cache ) { + CacheData data = this.cache.get( new CacheKey( admin , userId , true ) ); + if ( data != null ) { + for ( long id : ids ) { + if ( data.updates.containsKey( id ) ) { + continue; + } + data.updates.put( id , MessageBoxAction.MARK_UNREAD ); + } + } + + StoredProc dbMark = admin ? this.fAdminMarkUnread : this.fEmpireMarkUnread; + dbMark.execute( userId , this.getIdArray( ids ) ); + } + } + + + @Override + public void markUnread( boolean admin , int userId ) + { + synchronized ( this.cache ) { + this.cache.remove( new CacheKey( admin , userId , true ) ); + StoredProc dbMark = admin ? this.fAdminMarkUnreadAll : this.fEmpireMarkUnreadAll; + dbMark.execute( userId ); + } + } + + + @Override + public void delete( boolean admin , int userId , boolean inbox , long[] ids ) + { + synchronized ( this.cache ) { + CacheData data = this.cache.get( new CacheKey( admin , userId , inbox ) ); + if ( data != null ) { + for ( long id : ids ) { + data.updates.put( id , MessageBoxAction.DELETE ); + } + } + + StoredProc dbDelete = admin ? this.fAdminDelete : this.fEmpireDelete; + dbDelete.execute( userId , inbox , this.getIdArray( ids ) ); + } + } + + + @Override + public void delete( boolean admin , int userId , boolean inbox ) + { + synchronized ( this.cache ) { + this.cache.remove( new CacheKey( admin , userId , inbox ) ); + + StoredProc dbDelete = admin ? this.fAdminDeleteAll : this.fEmpireDeleteAll; + dbDelete.execute( userId , inbox ); + } + } + + + @Override + public void clearCache( ) + { + List< CacheKey > toRemove = new LinkedList< CacheKey >( ); + + synchronized ( this.cache ) { + for ( Map.Entry< CacheKey , CacheData > entry : this.cache.entrySet( ) ) { + CacheData data = entry.getValue( ); + data.timeLeft--; + if ( data.timeLeft == 0 ) { + toRemove.add( entry.getKey( ) ); + } + } + + for ( CacheKey key : toRemove ) { + this.cache.remove( key ); + } + } + } + + + @Override + public void sendSpam( int adminId , String title , String body ) + { + this.fSendSpam.execute( adminId , title , body ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageCleanerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageCleanerBean.java new file mode 100644 index 0000000..9fc4c5c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageCleanerBean.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.beans.msgs; + + +import java.util.regex.Pattern; + + + +public class MessageCleanerBean +{ + private final Pattern planet = Pattern.compile( "\\{\\{planet:\\d+ ([^\\}]+)\\}\\}" ); + private final Pattern empire = Pattern.compile( "\\{\\{empire:\\d+ ([^\\}]+)\\}\\}" ); + private final Pattern battle = Pattern.compile( "\\{\\{battle:\\d+ ([^\\}]+)\\}\\}" ); + private final Pattern bug = Pattern.compile( "\\{\\{bug:(\\d+)\\}\\}" ); + + + public String cleanMessage( String message ) + { + message = message.trim( ); + + StringBuilder repLine = new StringBuilder( ); + for ( Character c : message.toCharArray( ) ) { + int nVal = Character.codePointAt( new char[] { + c + } , 0 ); + if ( c != '\n' && Character.isISOControl( nVal ) ) { + continue; + } + repLine.append( c ); + } + message = repLine.toString( ); + return message; + } + + + public String removeInternals( String message ) + { + message = planet.matcher( message ).replaceAll( "$1" ); + message = empire.matcher( message ).replaceAll( "$1" ); + message = battle.matcher( message ).replaceAll( "$1" ); + message = bug.matcher( message ).replaceAll( "#$1" ); + return message; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageContentCacheBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageContentCacheBean.java new file mode 100644 index 0000000..26ad674 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageContentCacheBean.java @@ -0,0 +1,194 @@ +package com.deepclone.lw.beans.msgs; + + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.interfaces.msg.MessageContentCache; +import com.deepclone.lw.interfaces.msg.MessageRecordsDAO; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.EventTypeRecord; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +public class MessageContentCacheBean + implements MessageContentCache +{ + private static final int cacheTime = 24; + + private static class CacheKey + { + private final boolean internal; + private final long id; + + + public CacheKey( boolean internal , long id ) + { + this.internal = internal; + this.id = id; + } + + + @Override + public int hashCode( ) + { + final int prime = 31; + int result = 1; + result = prime * result + (int) ( id ^ ( id >>> 32 ) ); + result = prime * result + ( internal ? 1231 : 1237 ); + return result; + } + + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + return true; + if ( obj == null ) + return false; + if ( getClass( ) != obj.getClass( ) ) + return false; + CacheKey other = (CacheKey) obj; + if ( id != other.id ) + return false; + if ( internal != other.internal ) + return false; + return true; + } + + } + + private static class CacheData + { + public int timeLeft = MessageContentCacheBean.cacheTime; + public MessageDataRecord dataRecord; + } + + private final Map< CacheKey , CacheData > cache = new HashMap< CacheKey , CacheData >( ); + private MessageRecordsDAO recordsDao; + + + @Autowired( required = true ) + public void setRecordsDao( MessageRecordsDAO recordsDao ) + { + this.recordsDao = recordsDao; + } + + + @Override + public Map< Long , MessageDataRecord > getContent( List< InboxRecord > messages ) + { + // Creates cache keys for all records + Map< Long , CacheKey > mKeys = this.extractKeys( messages ); + + // Generate lists of uncached messages + List< Long > uncachedText = new LinkedList< Long >( ); + List< Long > uncachedEvents = new LinkedList< Long >( ); + synchronized ( this.cache ) { + this.getCachedRecords( mKeys , uncachedText , uncachedEvents ); + } + + // Fetch missing data + List< MessageDataRecord > nRecords = new LinkedList< MessageDataRecord >( ); + if ( !uncachedText.isEmpty( ) ) { + nRecords.addAll( this.recordsDao.getTextMessages( uncachedText ) ); + } + if ( !uncachedEvents.isEmpty( ) ) { + this.getMissingEvents( uncachedEvents , nRecords ); + } + + Map< Long , MessageDataRecord > result = new HashMap< Long , MessageDataRecord >( ); + synchronized ( this.cache ) { + // Add new records to the cache + for ( MessageDataRecord record : nRecords ) { + CacheKey key = new CacheKey( record.isInternal( ) , record.getId( ) ); + CacheData data = new CacheData( ); + data.dataRecord = record; + this.cache.put( key , data ); + } + + // Extract all required data + for ( Map.Entry< Long , CacheKey > entry : mKeys.entrySet( ) ) { + CacheKey key = entry.getValue( ); + result.put( entry.getKey( ) , this.cache.get( key ).dataRecord ); + } + } + + return result; + } + + + private Map< Long , CacheKey > extractKeys( List< InboxRecord > messages ) + { + Map< Long , CacheKey > mKeys = new HashMap< Long , CacheKey >( ); + for ( InboxRecord record : messages ) { + CacheKey key = new CacheKey( record.isInternal( ) , record.getContentId( ) ); + mKeys.put( record.getId( ) , key ); + } + return mKeys; + } + + + private void getCachedRecords( Map< Long , CacheKey > mKeys , List< Long > uncachedText , + List< Long > uncachedEvents ) + { + for ( Map.Entry< Long , CacheKey > entry : mKeys.entrySet( ) ) { + CacheKey key = entry.getValue( ); + CacheData data = this.cache.get( key ); + if ( data == null ) { + ( key.internal ? uncachedEvents : uncachedText ).add( key.id ); + } else { + data.timeLeft = MessageContentCacheBean.cacheTime; + } + } + } + + + private void getMissingEvents( List< Long > uncachedEvents , List< MessageDataRecord > nRecords ) + { + // Determine event types + Map< EventType , List< Long >> eventsByType = new HashMap< EventType , List< Long > >( ); + for ( EventTypeRecord eType : this.recordsDao.getEventTypes( uncachedEvents ) ) { + List< Long > typeIds = eventsByType.get( eType.getType( ) ); + if ( typeIds == null ) { + typeIds = new LinkedList< Long >( ); + eventsByType.put( eType.getType( ) , typeIds ); + } + typeIds.add( eType.getId( ) ); + } + + // Fetch data + for ( Map.Entry< EventType , List< Long > > entry : eventsByType.entrySet( ) ) { + nRecords.addAll( this.recordsDao.getEvents( entry.getKey( ) , entry.getValue( ) ) ); + } + } + + + @Override + public void clearCache( ) + { + synchronized ( this.cache ) { + List< CacheKey > toRemove = new LinkedList< CacheKey >( ); + for ( Map.Entry< CacheKey , CacheData > entry : this.cache.entrySet( ) ) { + CacheData data = entry.getValue( ); + data.timeLeft--; + if ( data.timeLeft < 0 ) { + toRemove.add( entry.getKey( ) ); + } + } + + for ( CacheKey key : toRemove ) { + this.cache.remove( key ); + } + } + + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageFormatRegistryBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageFormatRegistryBean.java new file mode 100644 index 0000000..1e0be12 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageFormatRegistryBean.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.beans.msgs; + + +import java.util.HashMap; +import java.util.Map; + +import com.deepclone.lw.interfaces.msg.MessageFormatRegistry; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EventRecord; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +public class MessageFormatRegistryBean + implements MessageFormatRegistry +{ + + private final Map< FormatType , MessageFormatter > formatters = new HashMap< FormatType , MessageFormatter >( ); + + + @Override + public void addFormatter( MessageFormatter formatter ) + { + for ( FormatType fmt : formatter.getFormats( ) ) { + if ( this.formatters.containsKey( fmt ) ) { + throw new IllegalArgumentException( "message formatter " + formatter.getClass( ) + " redefines format " + + fmt.toString( ) ); + } + this.formatters.put( fmt , formatter ); + } + } + + + @Override + public MessageFormatter getFormatter( MessageDataRecord contents ) + { + FormatType fmt; + if ( contents.isInternal( ) ) { + EventRecord evt = (EventRecord) contents; + fmt = new FormatType( evt.getType( ) , evt.getSubType( ) ); + } else { + fmt = new FormatType( ); + } + return this.formatters.get( fmt ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageFormatWiringBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageFormatWiringBean.java new file mode 100644 index 0000000..b2abdec --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageFormatWiringBean.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.beans.msgs; + + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import com.deepclone.lw.interfaces.msg.MessageFormatRegistry; +import com.deepclone.lw.interfaces.msg.MessageFormatter; + + + +public class MessageFormatWiringBean + implements BeanPostProcessor , ApplicationContextAware +{ + private final Logger logger = Logger.getLogger( MessageFormatWiringBean.class ); + private ApplicationContext context; + + + @Override + public void setApplicationContext( ApplicationContext applicationContext ) + throws BeansException + { + this.context = applicationContext; + } + + + @Override + public Object postProcessAfterInitialization( Object bean , String beanName ) + throws BeansException + { + if ( bean instanceof MessageFormatRegistry ) { + this.logger.debug( "Wiring message format registry" ); + this.autowire( (MessageFormatRegistry) bean ); + } + return bean; + } + + + @Override + public Object postProcessBeforeInitialization( Object bean , String beanName ) + throws BeansException + { + return bean; + } + + + private void autowire( MessageFormatRegistry bean ) + { + Collection< MessageFormatter > formatters; + formatters = this.context.getBeansOfType( MessageFormatter.class ).values( ); + + for ( MessageFormatter formatter : formatters ) { + this.logger.debug( "Adding formats " + formatter.getFormats( ) ); + bean.addFormatter( formatter ); + } + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageRecordsDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageRecordsDAOBean.java new file mode 100644 index 0000000..261d44a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageRecordsDAOBean.java @@ -0,0 +1,328 @@ +package com.deepclone.lw.beans.msgs; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.interfaces.msg.MessageRecordsDAO; +import com.deepclone.lw.sqld.msgs.*; + + + +public class MessageRecordsDAOBean + implements MessageRecordsDAO +{ + private static abstract class EventMapperBase< T extends EventRecord > + implements RowMapper< T > + { + protected void mapEvent( ResultSet rs , T event ) + throws SQLException + { + event.setId( rs.getLong( "id" ) ); + event.setType( EventType.valueOf( rs.getString( "evt_type" ) ) ); + event.setSubType( rs.getInt( "evt_subtype" ) ); + event.setTick( rs.getLong( "tick" ) ); + event.setTimestamp( rs.getTimestamp( "real_time" ) ); + } + } + + private static final String sGetTextMessages = "SELECT * FROM msgs.text_messages WHERE id = ANY( ? ::BIGINT[] )"; + private static final String sGetEventTypes = "SELECT event_id , evt_type FROM events.events WHERE event_id = ANY( ? ::BIGINT[] )"; + private static final String sGetEventParts[] = { + "SELECT * FROM events." , "_events_view WHERE id = ANY( ? ::BIGINT[] )" + }; + private static final String sGetQueueLocations = "SELECT * FROM events.queue_locations_view WHERE event_id = ANY( ? ::BIGINT[] )"; + private static final String sGetEventFleets = "SELECT * FROM events.fleet_lists WHERE event_id = ANY( ? ::BIGINT[] )"; + + private SimpleJdbcTemplate dTemplate; + + private final RowMapper< TextMessageRecord > mTextMessage; + private final RowMapper< EventTypeRecord > mEventTypes; + private final EventMapperBase< AdminEventRecord > mAdminEvent; + private final EventMapperBase< AllianceEventRecord > mAllianceEvent; + private final EventMapperBase< EmpireEventRecord > mEmpireEvent; + private final EventMapperBase< FleetEventRecord > mFleetEvent; + private final EventMapperBase< PlanetEventRecord > mPlanetEvent; + private final EventMapperBase< QueueEventRecord > mQueueEvent; + private final EventMapperBase< BugEventRecord > mBugEvent; + private final RowMapper< QueueEventLocation > mQueueLocation; + private final RowMapper< FleetEventFleet > mFleetList; + + + public MessageRecordsDAOBean( ) + { + this.mTextMessage = new RowMapper< TextMessageRecord >( ) { + @Override + public TextMessageRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + TextMessageRecord tmr = new TextMessageRecord( ); + tmr.setId( rs.getLong( "id" ) ); + tmr.setTimestamp( rs.getTimestamp( "t" ) ); + tmr.setTick( rs.getLong( "tick" ) ); + tmr.setSubject( rs.getString( "title" ) ); + tmr.setText( rs.getString( "contents" ) ); + return tmr; + } + }; + this.mEventTypes = new RowMapper< EventTypeRecord >( ) { + @Override + public EventTypeRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EventTypeRecord etr = new EventTypeRecord( ); + etr.setId( rs.getLong( "event_id" ) ); + etr.setType( EventType.valueOf( rs.getString( "evt_type" ) ) ); + return etr; + } + }; + this.mAdminEvent = new EventMapperBase< AdminEventRecord >( ) { + @Override + public AdminEventRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + AdminEventRecord event = new AdminEventRecord( ); + this.mapEvent( rs , event ); + event.setWarnings( (Integer) rs.getObject( "n_warnings" ) ); + event.setLocationId( (Integer) rs.getObject( "location_id" ) ); + event.setOldName( rs.getString( "old_name" ) ); + event.setNewName( rs.getString( "new_name" ) ); + return event; + } + }; + this.mAllianceEvent = new EventMapperBase< AllianceEventRecord >( ) { + @Override + public AllianceEventRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + AllianceEventRecord event = new AllianceEventRecord( ); + this.mapEvent( rs , event ); + event.setAllianceId( (Integer) rs.getObject( "alliance_id" ) ); + event.setAllianceTag( rs.getString( "alliance_tag" ) ); + event.setEmpireId( (Integer) rs.getObject( "empire_id" ) ); + event.setEmpireName( rs.getString( "empire_name" ) ); + event.setReqResult( (Boolean) rs.getObject( "req_result" ) ); + return event; + } + }; + this.mEmpireEvent = new EventMapperBase< EmpireEventRecord >( ) { + @Override + public EmpireEventRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EmpireEventRecord event = new EmpireEventRecord( ); + this.mapEvent( rs , event ); + event.setTech( rs.getString( "technology" ) ); + return event; + } + }; + this.mFleetEvent = new EventMapperBase< FleetEventRecord >( ) { + @Override + public FleetEventRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + FleetEventRecord event = new FleetEventRecord( ); + this.mapEvent( rs , event ); + event.setLocationId( rs.getInt( "location_id" ) ); + event.setLocationName( rs.getString( "location_name" ) ); + event.setX( rs.getInt( "x" ) ); + event.setY( rs.getInt( "y" ) ); + event.setOrbit( rs.getInt( "orbit" ) ); + return event; + } + }; + this.mPlanetEvent = new EventMapperBase< PlanetEventRecord >( ) { + @Override + public PlanetEventRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + PlanetEventRecord event = new PlanetEventRecord( ); + this.mapEvent( rs , event ); + event.setLocationId( rs.getInt( "location_id" ) ); + event.setLocationName( rs.getString( "location_name" ) ); + event.setX( rs.getInt( "x" ) ); + event.setY( rs.getInt( "y" ) ); + event.setOrbit( rs.getInt( "orbit" ) ); + event.setEmpireId( (Integer) rs.getObject( "empire_id" ) ); + event.setEmpireName( rs.getString( "empire_name" ) ); + event.setBattleId( (Long) rs.getObject( "battle_id" ) ); + return event; + } + }; + this.mQueueEvent = new EventMapperBase< QueueEventRecord >( ) { + @Override + public QueueEventRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + QueueEventRecord event = new QueueEventRecord( ); + this.mapEvent( rs , event ); + return event; + } + }; + this.mBugEvent = new EventMapperBase< BugEventRecord >( ) { + @Override + public BugEventRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BugEventRecord event = new BugEventRecord( ); + this.mapEvent( rs , event ); + event.setReportId( rs.getLong( "bug_id" ) ); + event.setAdmin( rs.getBoolean( "submitter_admin" ) ); + event.setSubmitter( rs.getString( "submitter_name" ) ); + return event; + } + }; + this.mQueueLocation = new RowMapper< QueueEventLocation >( ) { + @Override + public QueueEventLocation mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + QueueEventLocation loc = new QueueEventLocation( ); + loc.setEventId( rs.getLong( "event_id" ) ); + loc.setLocationId( rs.getInt( "location_id" ) ); + loc.setLocationName( rs.getString( "location_name" ) ); + loc.setX( rs.getInt( "x" ) ); + loc.setY( rs.getInt( "y" ) ); + loc.setOrbit( rs.getInt( "orbit" ) ); + return loc; + } + }; + this.mFleetList = new RowMapper< FleetEventFleet >( ) { + @Override + public FleetEventFleet mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + FleetEventFleet fleet = new FleetEventFleet( ); + fleet.setEventId( rs.getLong( "event_id" ) ); + fleet.setOwnerId( (Integer) rs.getObject( "owner_id" ) ); + fleet.setOwnerName( rs.getString( "owner_name" ) ); + fleet.setFleetName( rs.getString( "fleet_name" ) ); + fleet.setFleetPower( rs.getLong( "fleet_power" ) ); + fleet.setStatus( (Boolean) rs.getObject( "status" ) ); + fleet.setSourceId( (Integer) rs.getObject( "source_id" ) ); + fleet.setSourceName( rs.getString( "source_name" ) ); + return fleet; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + } + + + private String getIdArray( List< Long > ids ) + { + StringBuilder iArray = new StringBuilder( ).append( "{" ); + int i = 0; + int s = ids.size( ); + for ( Long id : ids ) { + iArray.append( id ); + if ( i != s - 1 ) { + iArray.append( "," ); + } + i++; + } + iArray.append( "}" ); + return iArray.toString( ); + } + + + @Override + public List< TextMessageRecord > getTextMessages( List< Long > ids ) + { + return this.dTemplate.query( sGetTextMessages , mTextMessage , this.getIdArray( ids ) ); + } + + + @Override + public List< EventTypeRecord > getEventTypes( List< Long > ids ) + { + return this.dTemplate.query( sGetEventTypes , mEventTypes , this.getIdArray( ids ) ); + } + + + @Override + @SuppressWarnings( "unchecked" ) + public List< EventRecord > getEvents( EventType type , List< Long > ids ) + { + String query = sGetEventParts[ 0 ] + type.toString( ).toLowerCase( ) + sGetEventParts[ 1 ]; + EventMapperBase< ? > mapper; + switch ( type ) { + case ADMIN: + mapper = this.mAdminEvent; + break; + case ALLIANCE: + mapper = this.mAllianceEvent; + break; + case EMPIRE: + mapper = this.mEmpireEvent; + break; + case FLEETS: + mapper = this.mFleetEvent; + break; + case PLANET: + mapper = this.mPlanetEvent; + break; + case QUEUE: + mapper = this.mQueueEvent; + break; + case BUGS: + mapper = this.mBugEvent; + break; + default: + throw new RuntimeException( "unsupported event type " + type ); + } + + String idArray = this.getIdArray( ids ); + List< EventRecord > result = (List< EventRecord >) this.dTemplate.query( query , mapper , idArray ); + + if ( type == EventType.FLEETS ) { + this.getFleetDetails( idArray , result ); + } else if ( type == EventType.QUEUE ) { + this.getQueueDetails( idArray , result ); + } + + return result; + } + + + private void getFleetDetails( String idArray , List< EventRecord > result ) + { + Map< Long , FleetEventRecord > records = new HashMap< Long , FleetEventRecord >( ); + for ( EventRecord e : result ) { + records.put( e.getId( ) , (FleetEventRecord) e ); + } + + List< FleetEventFleet > fleets = this.dTemplate.query( sGetEventFleets , mFleetList , idArray ); + for ( FleetEventFleet fleet : fleets ) { + records.get( fleet.getEventId( ) ).addFleet( fleet ); + } + } + + + private void getQueueDetails( String idArray , List< EventRecord > result ) + { + Map< Long , QueueEventRecord > records = new HashMap< Long , QueueEventRecord >( ); + for ( EventRecord e : result ) { + records.put( e.getId( ) , (QueueEventRecord) e ); + } + + List< QueueEventLocation > locations = this.dTemplate.query( sGetQueueLocations , mQueueLocation , idArray ); + for ( QueueEventLocation l : locations ) { + records.get( l.getEventId( ) ).addLocation( l ); + } + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageTasksBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageTasksBean.java new file mode 100644 index 0000000..5c07a2a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/MessageTasksBean.java @@ -0,0 +1,130 @@ +package com.deepclone.lw.beans.msgs; + + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; + +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.interfaces.msg.MessageBoxDAO; +import com.deepclone.lw.interfaces.msg.MessageContentCache; +import com.deepclone.lw.interfaces.msg.MessageFormatRegistry; +import com.deepclone.lw.interfaces.msg.NotificationsDAO; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class MessageTasksBean + implements InitializingBean , DisposableBean +{ + + private Ticker ticker; + private Logger logger; + private PlatformTransactionManager tManager; + private NotificationsDAO notificationsDao; + private MessageContentCache contents; + private MessageFormatRegistry formats; + private Translator translator; + private Mailer mailer; + private MessageCleanerBean cleaner; + private MessageBoxDAO mboxDao; + + private Runnable notificationsTask; + private Runnable recapsTask; + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger; + } + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager tManager ) + { + this.tManager = tManager; + } + + + @Autowired( required = true ) + public void setNotificationsDao( NotificationsDAO notificationsDao ) + { + this.notificationsDao = notificationsDao; + } + + + @Autowired( required = true ) + public void setContents( MessageContentCache contents ) + { + this.contents = contents; + } + + + @Autowired( required = true ) + public void setFormats( MessageFormatRegistry formats ) + { + this.formats = formats; + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Autowired( required = true ) + public void setMailer( Mailer mailer ) + { + this.mailer = mailer; + } + + + @Autowired( required = true ) + public void setCleaner( MessageCleanerBean cleaner ) + { + this.cleaner = cleaner; + } + + + @Autowired( required = true ) + public void setMboxDao( MessageBoxDAO mboxDao ) + { + this.mboxDao = mboxDao; + } + + + @Override + public void afterPropertiesSet( ) + { + this.notificationsTask = new NotificationsTask( this.logger , this.tManager , this.notificationsDao , + this.contents , this.formats , this.translator , this.mailer , this.cleaner ); + this.ticker.registerTask( Frequency.MEDIUM , "Instant notifications" , this.notificationsTask ); + + this.recapsTask = new RecapitulationTask( this.logger , this.tManager , this.notificationsDao , this.contents , + this.formats , this.translator , this.mailer , this.cleaner , this.mboxDao ); + this.ticker.registerTask( Frequency.LOW , "Message recaps/clean-up" , this.recapsTask ); + } + + + @Override + public void destroy( ) + { + this.notificationsTask = null; + this.recapsTask = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/NotificationsDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/NotificationsDAOBean.java new file mode 100644 index 0000000..9665362 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/NotificationsDAOBean.java @@ -0,0 +1,168 @@ +package com.deepclone.lw.beans.msgs; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.LinkedList; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; + +import com.deepclone.lw.interfaces.msg.NotificationsDAO; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.NotificationsRecord; +import com.deepclone.lw.utils.StoredProc; + + + +public class NotificationsDAOBean + implements NotificationsDAO +{ + private static final String sGetInstantNotifications = "SELECT * FROM msgs.get_mail_data() WHERE last_unmailed IS NOT NULL"; + private static final String sGetRecapNotifications = "SELECT * FROM msgs.get_mail_data() WHERE last_unrecaped IS NOT NULL"; + + private SimpleJdbcTemplate dTemplate; + + private final RowMapper< NotificationsRecord > mNotifications; + private RowMapper< InboxRecord > mList; + private StoredProc fMarkInstantMessages; + private StoredProc fMarkRecap; + + + public NotificationsDAOBean( ) + { + this.mNotifications = new RowMapper< NotificationsRecord >( ) { + @Override + public NotificationsRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + NotificationsRecord nr = new NotificationsRecord( ); + nr.setId( rs.getInt( "empire" ) ); + nr.setName( rs.getString( "empire_name" ) ); + nr.setLanguage( rs.getString( "language" ) ); + nr.setAddress( rs.getString( "address" ) ); + nr.setOnPrivate( rs.getString( "on_private" ) ); + nr.setOnInternal( rs.getString( "on_internal" ) ); + nr.setOnAlliance( rs.getString( "on_alliance" ) ); + nr.setOnAdmin( rs.getString( "on_admin" ) ); + nr.setLastUnmailed( (Long) rs.getObject( "last_unmailed" ) ); + nr.setLastUnrecaped( (Long) rs.getObject( "last_unrecaped" ) ); + nr.setCanNotify( rs.getBoolean( "can_notify" ) ); + return nr; + } + }; + this.mList = new RowMapper< InboxRecord >( ) { + @Override + public InboxRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + InboxRecord iRec = new InboxRecord( ); + iRec.setId( rs.getLong( "id" ) ); + iRec.setSenderType( rs.getString( "sender_type" ) ); + iRec.setSenderId( (Integer) rs.getObject( "sender_id" ) ); + iRec.setSenderName( rs.getString( "sender_name" ) ); + iRec.setReceiverType( rs.getString( "receiver_type" ) ); + iRec.setReceiverId( rs.getInt( "receiver_id" ) ); + iRec.setReceiverName( rs.getString( "receiver_name" ) ); + iRec.setInternal( rs.getBoolean( "internal_message" ) ); + iRec.setReceived( rs.getTimestamp( "r_time" ) ); + iRec.setContentId( rs.getLong( "content_id" ) ); + return iRec; + } + }; + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fMarkInstantMessages = new StoredProc( dataSource , "msgs" , "mark_instant_notifications" ); + this.fMarkInstantMessages.addParameter( "empire_id" , Types.INTEGER ); + this.fMarkInstantMessages.addParameter( "message_id" , Types.BIGINT ); + this.fMarkInstantMessages.addParameter( "sending" , Types.BOOLEAN ); + + this.fMarkRecap = new StoredProc( dataSource , "msgs" , "mark_recaps" ); + this.fMarkRecap.addParameter( "empire_id" , Types.INTEGER ); + this.fMarkRecap.addParameter( "message_id" , Types.BIGINT ); + } + + + @Override + public boolean isRecapTime( ) + { + String sql = "SELECT msgs.is_recap_time() AS recap"; + return (Boolean) this.dTemplate.queryForMap( sql ).get( "recap" ); + } + + + @Override + public List< NotificationsRecord > getNotificationRecords( boolean instant ) + { + String sql = instant ? sGetInstantNotifications : sGetRecapNotifications; + return this.dTemplate.query( sql , this.mNotifications ); + } + + + @Override + public List< InboxRecord > listMessages( int empireId , long maxId , boolean instant , boolean nPrivate , + boolean nInternal , boolean nAlliance , boolean nAdmin ) + { + List< InboxRecord > result; + if ( nPrivate || nInternal || nAlliance || nAdmin ) { + String sql = "SELECT * FROM msgs.empire_" + ( instant ? "instant" : "recap" ); + sql += " WHERE empire_id = ? AND id <= ?"; + + if ( ! ( nPrivate && nInternal && nAlliance && nAdmin ) ) { + sql += " AND ("; + if ( nPrivate ) { + sql += "( sender_type = 'EMP' AND receiver_type='EMP' )"; + } + if ( nInternal ) { + if ( nPrivate ) { + sql += " OR "; + } + sql += "sender_type = 'INT'"; + } + if ( nAlliance ) { + if ( nPrivate || nInternal ) { + sql += " OR "; + } + sql += "receiver_type = 'ALL'"; + } + if ( nAdmin ) { + if ( nPrivate || nInternal || nAlliance ) { + sql += " OR "; + } + sql += "sender_type = 'ADM'"; + } + sql += ")"; + } + + result = this.dTemplate.query( sql , this.mList , empireId , maxId ); + } else { + result = new LinkedList< InboxRecord >( ); + } + + if ( instant ) { + this.fMarkInstantMessages.execute( empireId , maxId , !result.isEmpty( ) ); + } else { + this.fMarkRecap.execute( empireId , maxId ); + } + + return result; + } + + + @Override + public void cleanupMessages( ) + { + this.dTemplate.getJdbcOperations( ).execute( "SELECT msgs.cleanup( )" ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/NotificationsTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/NotificationsTask.java new file mode 100644 index 0000000..59a75e6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/NotificationsTask.java @@ -0,0 +1,97 @@ +package com.deepclone.lw.beans.msgs; + + +import org.springframework.transaction.PlatformTransactionManager; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.msgdata.Message; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.mailer.MailData; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.interfaces.mailer.MailerException; +import com.deepclone.lw.interfaces.msg.MessageContentCache; +import com.deepclone.lw.interfaces.msg.MessageFormatRegistry; +import com.deepclone.lw.interfaces.msg.NotificationsDAO; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.NotificationsRecord; + + + +class NotificationsTask + extends MailTaskBase +{ + + public NotificationsTask( Logger logger , PlatformTransactionManager tManager , NotificationsDAO notificationsDao , + MessageContentCache contents , MessageFormatRegistry formats , Translator translator , Mailer mailer , + MessageCleanerBean cleaner ) + { + super( logger , tManager , notificationsDao , contents , formats , translator , mailer , cleaner , true ); + } + + + protected void notify( NotificationsRecord notification ) + { + boolean nPrivate = "INSTANT".equals( notification.getOnPrivate( ) ) && notification.isCanNotify( ); + boolean nInternal = "INSTANT".equals( notification.getOnInternal( ) ) && notification.isCanNotify( ); + boolean nAlliance = "INSTANT".equals( notification.getOnAlliance( ) ) && notification.isCanNotify( ); + boolean nAdmin = "INSTANT".equals( notification.getOnAdmin( ) ) && notification.isCanNotify( ); + + MessageData toSend = this.getMessagesToSend( notification.getId( ) , notification.getLastUnmailed( ) , + nPrivate , nInternal , nAlliance , nAdmin ); + if ( toSend.messages.isEmpty( ) ) { + return; + } + + this.logger.log( LogLevel.DEBUG , "Processing messages for empire " + notification.getName( ) ); + this.processMessages( notification , toSend ); + } + + + private void processMessages( NotificationsRecord notification , MessageData toSend ) + { + StringBuilder buffer = new StringBuilder( ); + String lang = notification.getLanguage( ); + + String template = this.translate( "instantNotification" , lang ); + int empireId = notification.getId( ); + for ( InboxRecord record : toSend.messages ) { + Message message = this.readMessage( empireId , lang , record , toSend.data.get( record.getId( ) ) , true ); + this.outputMessage( buffer , template , message ); + } + + MailData mailData; + try { + mailData = this.mailer.createMail( lang , "messageMail" , notification.getAddress( ) ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + + mailData.setData( "empire" , notification.getName( ) ); + mailData.setData( "messages" , buffer.toString( ) ); + + try { + mailData.queue( ); + } catch ( MailerException e ) { + throw new RuntimeException( e ); + } + } + + + private void outputMessage( StringBuilder buffer , String template , Message message ) + { + String data = template.replace( "${from}" , message.getSender( ) ); + data = data.replace( "${to}" , message.getReceiver( ) ); + if ( message.getType( ) == MessageType.INTERNAL ) { + data = data.replace( "${subject}" , message.getTitle( ) ); + data = data.replace( "${text}" , this.cleaner.removeInternals( message.getContents( ) ) ); + } else { + data = data.replace( "${subject}" , this.cleaner.cleanMessage( message.getTitle( ) ) ); + data = data.replace( "${text}" , this.cleaner.cleanMessage( message.getContents( ) ) ); + } + buffer.append( data ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/RecapitulationTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/RecapitulationTask.java new file mode 100644 index 0000000..fd25a92 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/RecapitulationTask.java @@ -0,0 +1,173 @@ +package com.deepclone.lw.beans.msgs; + + +import java.text.SimpleDateFormat; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.msgdata.Message; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.mailer.MailData; +import com.deepclone.lw.interfaces.mailer.Mailer; +import com.deepclone.lw.interfaces.mailer.MailerException; +import com.deepclone.lw.interfaces.msg.MessageBoxDAO; +import com.deepclone.lw.interfaces.msg.MessageContentCache; +import com.deepclone.lw.interfaces.msg.MessageFormatRegistry; +import com.deepclone.lw.interfaces.msg.NotificationsDAO; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.NotificationsRecord; + + + +class RecapitulationTask + extends MailTaskBase +{ + + private MessageBoxDAO mboxDao; + + + public RecapitulationTask( Logger logger , PlatformTransactionManager tManager , NotificationsDAO notificationsDao , + MessageContentCache contents , MessageFormatRegistry formats , Translator translator , Mailer mailer , + MessageCleanerBean cleaner , MessageBoxDAO mbox ) + { + super( logger , tManager , notificationsDao , contents , formats , translator , mailer , cleaner , false ); + this.mboxDao = mbox; + } + + + @Override + public void run( ) + { + if ( this.isTime( ) ) { + super.run( ); + } + + this.cleanup( ); + this.contents.clearCache( ); + this.mboxDao.clearCache( ); + } + + + private void cleanup( ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + notificationsDao.cleanupMessages( ); + } + } ); + } + + + private boolean isTime( ) + { + return this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + return notificationsDao.isRecapTime( ); + } + } ); + } + + + protected void notify( NotificationsRecord notification ) + { + boolean nPrivate = "DAILY_RECAP".equals( notification.getOnPrivate( ) ); + boolean nInternal = "DAILY_RECAP".equals( notification.getOnInternal( ) ); + boolean nAlliance = "DAILY_RECAP".equals( notification.getOnAlliance( ) ); + boolean nAdmin = "DAILY_RECAP".equals( notification.getOnAdmin( ) ); + + MessageData toSend = this.getMessagesToSend( notification.getId( ) , notification.getLastUnrecaped( ) , + nPrivate , nInternal , nAlliance , nAdmin ); + if ( toSend.messages.isEmpty( ) ) { + return; + } + + this.logger.log( LogLevel.DEBUG , "Processing messages for empire " + notification.getName( ) ); + this.processMessages( notification , toSend ); + } + + + private void processMessages( NotificationsRecord notification , MessageData toSend ) + { + String lang = notification.getLanguage( ); + + Map< MessageType , List< Message > > messages = new HashMap< MessageType , List< Message > >( ); + for ( MessageType type : MessageType.values( ) ) { + messages.put( type , new LinkedList< Message >( ) ); + } + + int empireId = notification.getId( ); + for ( InboxRecord record : toSend.messages ) { + Message message = this.readMessage( empireId , lang , record , toSend.data.get( record.getId( ) ) , false ); + messages.get( message.getType( ) ).add( message ); + } + + StringBuilder body = new StringBuilder( ); + String template = this.translate( "recapsMessage" , lang ); + for ( MessageType type : MessageType.values( ) ) { + List< Message > tMessages = messages.get( type ); + if ( tMessages.isEmpty( ) ) { + continue; + } + + StringBuilder typeList = new StringBuilder( ); + typeList.append( this.getTypeTitle( type , lang ) ).append( "\n\n" ); + for ( Message message : tMessages ) { + typeList.append( this.outputMessage( template , message ) ).append( "\n" ); + } + body.append( typeList ).append( "\n" ); + } + + MailData mailData; + try { + mailData = this.mailer.createMail( lang , "recapMail" , notification.getAddress( ) ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + + mailData.setData( "empire" , notification.getName( ) ); + mailData.setData( "messages" , body.toString( ) ); + + try { + mailData.queue( ); + } catch ( MailerException e ) { + throw new RuntimeException( e ); + } + } + + + private String getTypeTitle( MessageType type , String lang ) + { + String tString = type.toString( ); + return this.translate( "recaps" + tString.substring( 0 , 1 ) + tString.substring( 1 ).toLowerCase( ) , lang ); + } + + + private String outputMessage( String template , Message message ) + { + String data = template.replace( "${from}" , message.getSender( ) ); + if ( message.getType( ) == MessageType.INTERNAL ) { + data = data.replace( "${subject}" , message.getTitle( ) ); + } else { + data = data.replace( "${subject}" , this.cleaner.cleanMessage( message.getTitle( ) ) ); + } + SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss Z" ); + data = data.replace( "${time}" , dateFormat.format( message.getTime( ) ) ); + return data; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AbandonMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AbandonMessageFormatterBean.java new file mode 100644 index 0000000..0e074f9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AbandonMessageFormatterBean.java @@ -0,0 +1,100 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; +import com.deepclone.lw.sqld.msgs.PlanetEventRecord; + + + +@Component +public class AbandonMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class AbandonMessageExtractor + extends PlanetMessageExtractor + { + private String mTitle; + private String mBody; + private String mSource; + + + public AbandonMessageExtractor( PlanetEventRecord event , String mTitle , String mBody , String mSource ) + { + super(event); + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + return this.mBody.replace( "${location}" , this.getLocation( ) ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${location}" , this.event.getLocationName( ) ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.PLANET , 5 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + PlanetEventRecord event = (PlanetEventRecord) contents; + String mTitle , mBody , mSource; + try { + mTitle = this.translator.translate( language , "imtAbandonPlanet" ); + mBody = this.translator.translate( language , "imAbandonPlanet" ); + mSource = this.translator.translate( language , "imSenderEco" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new AbandonMessageExtractor( event , mTitle , mBody , mSource ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AdminMessageExtractor.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AdminMessageExtractor.java new file mode 100644 index 0000000..69b7bb6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AdminMessageExtractor.java @@ -0,0 +1,87 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.sqld.msgs.AdminEventRecord; + + + +public class AdminMessageExtractor + implements MessageExtractor +{ + + private Translator translator; + private String language; + private AdminEventRecord event; + private String eType; + + + private String translate( String what ) + { + try { + return this.translator.translate( this.language , what ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + } + + + public AdminMessageExtractor( AdminEventRecord event , Translator translator , String language ) + { + this.event = event; + this.translator = translator; + this.language = language; + switch ( this.event.getSubType( ) ) { + case 0: + this.eType = "Planet"; + break; + case 1: + this.eType = "Empire"; + break; + case 2: + this.eType = "Alliance"; + break; + default: + throw new RuntimeException( "unsupported event sub-type " + this.event.getSubType( ) ); + } + } + + + @Override + public String getSender( ) + { + return this.translate( "imSenderAdmin" ); + } + + + @Override + public String getSubject( ) + { + String s = this.translate( "imtAdmin" + this.eType ).replace( "${oldName}" , this.event.getOldName( ) ); + if ( this.event.getNewName( ) != null ) { + s = s.replace( "${newName}" , this.event.getNewName( ) ); + } + return s; + } + + + @Override + public String getContents( ) + { + String s = this.translate( "imAdmin" + this.eType ).replace( "${oldName}" , this.event.getOldName( ) ); + if ( this.event.getNewName( ) != null ) { + s = s.replace( "${newName}" , this.event.getNewName( ) ); + } + if ( this.event.getLocationId( ) != null ) { + s = s.replace( "${locationId}" , this.event.getLocationId( ).toString( ) ); + } + if ( this.event.getWarnings( ) != null ) { + s += "\n\n"; + s += this.translate( "imAdminWarning" ).replace( "${warnings}" , this.event.getWarnings( ).toString( ) ); + } + return s; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AdminMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AdminMessageFormatterBean.java new file mode 100644 index 0000000..a7be657 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AdminMessageFormatterBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.AdminEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class AdminMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.ADMIN , 0 ) ); + fmts.add( new FormatType( EventType.ADMIN , 1 ) ); + fmts.add( new FormatType( EventType.ADMIN , 2 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + return new AdminMessageExtractor( (AdminEventRecord) contents , this.translator , language ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AllianceDisbandedMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AllianceDisbandedMessageFormatterBean.java new file mode 100644 index 0000000..33df2ff --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AllianceDisbandedMessageFormatterBean.java @@ -0,0 +1,85 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.AllianceEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class AllianceDisbandedMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class AllianceDisbandedMessageExtractor + extends AllianceMessageExtractor + { + + public AllianceDisbandedMessageExtractor( AllianceEventRecord event , String mTitle , String mBody ) + { + super( event , mTitle , mBody ); + } + + + @Override + public String getSubject( ) + { + return this.mTitle; + } + + + @Override + public String getContents( ) + { + return this.mBody; + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.ALLIANCE , 5 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + AllianceEventRecord event = (AllianceEventRecord) contents; + String mTitle , mBody; + try { + mTitle = this.translator.translate( language , "imtAllianceDisbanded" ); + mBody = this.translator.translate( language , "imAllianceDisbanded" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new AllianceDisbandedMessageExtractor( event , mTitle , mBody ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AllianceMessageExtractor.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AllianceMessageExtractor.java new file mode 100644 index 0000000..e17369b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/AllianceMessageExtractor.java @@ -0,0 +1,32 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.sqld.msgs.AllianceEventRecord; + + + +abstract class AllianceMessageExtractor + implements MessageExtractor +{ + + protected AllianceEventRecord event; + protected String mTitle; + protected String mBody; + + + protected AllianceMessageExtractor( AllianceEventRecord event , String mTitle , String mBody ) + { + this.event = event; + this.mTitle = mTitle; + this.mBody = mBody; + } + + + @Override + public String getSender( ) + { + return "[" + event.getAllianceTag( ) + "]"; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/BattleMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/BattleMessageFormatterBean.java new file mode 100644 index 0000000..6d3ed2f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/BattleMessageFormatterBean.java @@ -0,0 +1,104 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; +import com.deepclone.lw.sqld.msgs.PlanetEventRecord; + + + +@Component +public class BattleMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class BattleMessageExtractor + extends PlanetMessageExtractor + { + private String mTitle; + private String mBody; + private String mSource; + + + public BattleMessageExtractor( PlanetEventRecord event , String mTitle , String mBody , String mSource ) + { + super( event ); + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + String locLink = this.getLocation( ); + return this.mBody.replace( "${battleId}" , this.event.getBattleId( ).toString( ) ).replace( "${location}" , + locLink ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${location}" , this.event.getLocationName( ) ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.PLANET , 0 ) ); + fmts.add( new FormatType( EventType.PLANET , 1 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + PlanetEventRecord event = (PlanetEventRecord) contents; + boolean isEnd = ( event.getSubType( ) == 1 ); + String mTitle , mBody , mSource; + try { + mTitle = this.translator.translate( language , "imtBattle" + ( isEnd ? "End" : "Start" ) ); + mBody = this.translator.translate( language , "imBattle" + ( isEnd ? "End" : "Start" ) ); + mSource = this.translator.translate( language , "imSenderWar" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new BattleMessageExtractor( event , mTitle , mBody , mSource ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/BugMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/BugMessageFormatterBean.java new file mode 100644 index 0000000..418241b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/BugMessageFormatterBean.java @@ -0,0 +1,103 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.BugEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class BugMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class BugMessageExtractor + implements MessageExtractor + { + private BugEventRecord event; + private String mTitle; + private String mBody; + private String mSource; + + + public BugMessageExtractor( BugEventRecord event , String mTitle , String mBody , String mSource ) + { + this.event = event; + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + String bug = "{{bug:" + this.event.getReportId( ) + "}}"; + return this.mBody.replace( "${bug}" , bug ).replace( "${submitter}" , this.event.getSubmitter( ) ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${id}" , ( (Long) this.event.getReportId( ) ).toString( ) ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.BUGS , 0 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + BugEventRecord event = (BugEventRecord) contents; + String suffix = event.isAdmin( ) ? "Admin" : "Empire"; + String mTitle , mBody , mSource; + try { + mTitle = this.translator.translate( language , "imtBugReportUpdate" ); + mBody = this.translator.translate( language , "imBugReportUpdate" + suffix ); + mSource = this.translator.translate( language , "imSenderBugtracker" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new BugMessageExtractor( event , mTitle , mBody , mSource ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/DebtMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/DebtMessageFormatterBean.java new file mode 100644 index 0000000..eba3f2e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/DebtMessageFormatterBean.java @@ -0,0 +1,101 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EmpireEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class DebtMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class DebtMessageExtractor + implements MessageExtractor + { + private String mTitle; + private String mBody; + private String mSource; + + + public DebtMessageExtractor( String mTitle , String mBody , String mSource ) + { + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + return this.mBody; + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle; + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.EMPIRE , 1 ) ); + fmts.add( new FormatType( EventType.EMPIRE , 2 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + EmpireEventRecord event = (EmpireEventRecord) contents; + String type = ( event.getSubType( ) == 1) ? "Start" : "End"; + String mTitle , mBody , mSource; + try { + mTitle = this.translator.translate( language , "imtDebt" + type ); + mBody = this.translator.translate( language , "imDebt" + type ); + mSource = this.translator.translate( language , "imSenderEco" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new DebtMessageExtractor( mTitle , mBody , mSource ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/ExternalMessageFormatBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/ExternalMessageFormatBean.java new file mode 100644 index 0000000..ffa9635 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/ExternalMessageFormatBean.java @@ -0,0 +1,75 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; +import com.deepclone.lw.sqld.msgs.TextMessageRecord; + + + +@Component +public class ExternalMessageFormatBean + implements MessageFormatter +{ + + static private class ExternalMessageExtractor + implements MessageExtractor + { + private InboxRecord inbox; + private TextMessageRecord message; + + + public ExternalMessageExtractor( InboxRecord inbox , TextMessageRecord message ) + { + this.inbox = inbox; + this.message = message; + } + + + @Override + public String getContents( ) + { + return message.getText( ); + } + + + @Override + public String getSender( ) + { + return inbox.getSenderName( ); + } + + + @Override + public String getSubject( ) + { + return message.getSubject( ); + } + + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + return new ExternalMessageExtractor( envelope , (TextMessageRecord) contents ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/FleetMessageExtractor.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/FleetMessageExtractor.java new file mode 100644 index 0000000..e4f2326 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/FleetMessageExtractor.java @@ -0,0 +1,190 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.sqld.msgs.FleetEventFleet; +import com.deepclone.lw.sqld.msgs.FleetEventRecord; + + + +public class FleetMessageExtractor + implements MessageExtractor +{ + private FleetEventRecord event; + private Translator translator; + private String language; + private String eType; + private int empireId; + + + private String translate( String what ) + { + try { + return this.translator.translate( this.language , what ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + } + + + public FleetMessageExtractor( int empireId , FleetEventRecord event , Translator translator , String language ) + { + this.empireId = empireId; + this.event = event; + this.translator = translator; + this.language = language; + switch ( this.event.getSubType( ) ) { + case 0: + this.eType = "Arrival"; + break; + case 1: + this.eType = "Departure"; + break; + case 2: + this.eType = "Switch"; + break; + case 3: + this.eType = "ELSwitch"; + break; + default: + throw new RuntimeException( "unsupported event sub-type " + this.event.getSubType( ) ); + } + } + + + @Override + public String getSender( ) + { + return this.translate( "imSenderWar" ); + } + + + @Override + public String getSubject( ) + { + return this.translate( "imtFleet" + this.eType ).replace( "${location}" , this.event.getLocationName( ) ); + } + + + @Override + public String getContents( ) + { + String body = this.translate( "imFleet" + this.eType ); + String fList; + if ( this.event.getSubType( ) == 2 ) { + fList = this.makeSwitchList( ); + } else if ( this.event.getSubType( ) == 0 ) { + fList = this.makeArrivalList( ); + } else { + fList = this.makeStandardList( ); + } + String locLink = "{{planet:" + this.event.getLocationId( ) + " " + this.event.getLocationName( ) + "}} ("; + locLink += this.event.getX( ) + "," + this.event.getY( ) + ";" + this.event.getOrbit( ) + ")"; + return body.replace( "${location}" , locLink ) + fList; + } + + + private String makeStandardList( ) + { + String namedOwn = this.translate( "imfOwnNamed" ); + String unnamedOwn = this.translate( "imfOwnUnnamed" ); + String namedFriendly = this.translate( "imfFriendlyNamed" ); + String unnamedFriendly = this.translate( "imfFriendlyUnnamed" ); + String namedHostile = this.translate( "imfHostileNamed" ); + String unnamedHostile = this.translate( "imfHostileUnnamed" ); + StringBuilder sBuilder = new StringBuilder( ); + + for ( FleetEventFleet fleet : this.event.getFleets( ) ) { + sBuilder.append( "\n* " ); + String named , unnamed; + if ( fleet.getOwnerId( ) != null && fleet.getOwnerId( ) == this.empireId ) { + named = namedOwn; + unnamed = unnamedOwn; + } else if ( fleet.getStatus( ) == true ) { + named = namedHostile; + unnamed = unnamedHostile; + } else { + named = namedFriendly; + unnamed = unnamedFriendly; + } + sBuilder.append( this.fleetLine( fleet , named , unnamed ) ); + } + + return sBuilder.toString( ); + } + + + private String makeArrivalList( ) + { + String namedOwn = this.translate( "imfOwnNamed" ); + String unnamedOwn = this.translate( "imfOwnUnnamed" ); + String namedFriendly = this.translate( "imfFriendlyNamed" ); + String unnamedFriendly = this.translate( "imfFriendlyUnnamed" ); + String namedHostile = this.translate( "imfHostileNamed" ); + String unnamedHostile = this.translate( "imfHostileUnnamed" ); + String arrival = this.translate( "imfSource" ); + StringBuilder sBuilder = new StringBuilder( ); + + for ( FleetEventFleet fleet : this.event.getFleets( ) ) { + sBuilder.append( "\n* " ); + String named , unnamed; + if ( fleet.getOwnerId( ) != null && fleet.getOwnerId( ) == this.empireId ) { + named = namedOwn; + unnamed = unnamedOwn; + } else if ( fleet.getStatus( ) == true ) { + named = namedHostile; + unnamed = unnamedHostile; + } else { + named = namedFriendly; + unnamed = unnamedFriendly; + } + sBuilder.append( this.fleetLine( fleet , named , unnamed ) ); + + String source = "{{planet:" + fleet.getSourceId( ) + " " + fleet.getSourceName( ) + "}}"; + sBuilder.append( arrival.replace( "${source}" , source ) ); + } + + return sBuilder.toString( ); + } + + + private String makeSwitchList( ) + { + String named = this.translate( "imfNamed" ); + String unnamed = this.translate( "imfUnnamed" ); + String toAttack = this.translate( "imfSwitchAttack" ); + String toDefence = this.translate( "imfSwitchDefence" ); + StringBuilder sBuilder = new StringBuilder( ); + + for ( FleetEventFleet fleet : this.event.getFleets( ) ) { + sBuilder.append( "\n* " ); + sBuilder.append( this.fleetLine( fleet , named , unnamed ) ); + sBuilder.append( fleet.getStatus( ) ? toAttack : toDefence ); + } + + return sBuilder.toString( ); + } + + + private String fleetLine( FleetEventFleet fleet , String named , String unnamed ) + { + String tmpl; + if ( fleet.getFleetName( ) == null ) { + tmpl = unnamed; + } else { + tmpl = named.replace( "${fleet}" , fleet.getFleetName( ) ); + } + tmpl = tmpl.replace( "${power}" , ( (Long) fleet.getFleetPower( ) ).toString( ) ); + + String empLink; + if ( fleet.getOwnerId( ) == null ) { + empLink = fleet.getOwnerName( ); + } else { + empLink = "{{empire:" + fleet.getOwnerId( ) + " " + fleet.getOwnerName( ) + "}}"; + } + return tmpl.replace( "${owner}" , empLink ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/FleetMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/FleetMessageFormatterBean.java new file mode 100644 index 0000000..ac3fe78 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/FleetMessageFormatterBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FleetEventRecord; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class FleetMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.FLEETS , 0 ) ); + fmts.add( new FormatType( EventType.FLEETS , 1 ) ); + fmts.add( new FormatType( EventType.FLEETS , 2 ) ); + fmts.add( new FormatType( EventType.FLEETS , 3 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + FleetEventRecord event = (FleetEventRecord) contents; + return new FleetMessageExtractor( envelope.getReceiverId( ) , event , this.translator , language ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/KickedMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/KickedMessageFormatterBean.java new file mode 100644 index 0000000..f0bd84a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/KickedMessageFormatterBean.java @@ -0,0 +1,93 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.AllianceEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class KickedMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class KickedMessageExtractor + extends AllianceMessageExtractor + { + + public KickedMessageExtractor( AllianceEventRecord event , String mTitle , String mBody ) + { + super( event , mTitle , mBody ); + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${empire}" , this.event.getEmpireName( ) ); + } + + + @Override + public String getContents( ) + { + String empLink; + if ( this.event.getEmpireId( ) == null ) { + empLink = this.event.getEmpireName( ); + } else { + empLink = "{{empire:" + this.event.getEmpireId( ) + " " + this.event.getEmpireName( ) + "}}"; + } + return this.mBody.replace( "${empire}" , empLink ).replace( "${alliance}" , + "[" + this.event.getAllianceTag( ) + "]" ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.ALLIANCE , 3 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + AllianceEventRecord event = (AllianceEventRecord) contents; + boolean self = ( event.getEmpireId( ) != null && event.getEmpireId( ) == envelope.getReceiverId( ) ); + String mTitle , mBody; + try { + mTitle = this.translator.translate( language , "imtKicked" + ( self ? "Self" : "" ) ); + mBody = this.translator.translate( language , "imKicked" + ( self ? "Self" : "" ) ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new KickedMessageExtractor( event , mTitle , mBody ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LeadershipMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LeadershipMessageFormatterBean.java new file mode 100644 index 0000000..8396b5e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LeadershipMessageFormatterBean.java @@ -0,0 +1,91 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.AllianceEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class LeadershipMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class LeadershipMessageExtractor + extends AllianceMessageExtractor + { + + public LeadershipMessageExtractor( AllianceEventRecord event , String mTitle , String mBody ) + { + super( event , mTitle , mBody ); + } + + + @Override + public String getSubject( ) + { + return this.mTitle; + } + + + @Override + public String getContents( ) + { + String empLink; + if ( this.event.getEmpireId( ) == null ) { + empLink = this.event.getEmpireName( ); + } else { + empLink = "{{empire:" + this.event.getEmpireId( ) + " " + this.event.getEmpireName( ) + "}}"; + } + return this.mBody.replace( "${prevLeader}" , empLink ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.ALLIANCE , 2 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + AllianceEventRecord event = (AllianceEventRecord) contents; + String mTitle , mBody; + try { + mTitle = this.translator.translate( language , "imtLeaderChange" ); + mBody = this.translator.translate( language , "imLeaderChange" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new LeadershipMessageExtractor( event , mTitle , mBody ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LeftAllianceMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LeftAllianceMessageFormatterBean.java new file mode 100644 index 0000000..ae861bf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LeftAllianceMessageFormatterBean.java @@ -0,0 +1,91 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.AllianceEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class LeftAllianceMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class LeftAllianceMessageExtractor + extends AllianceMessageExtractor + { + + public LeftAllianceMessageExtractor( AllianceEventRecord event , String mTitle , String mBody ) + { + super( event , mTitle , mBody ); + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${empire}" , this.event.getEmpireName( ) ); + } + + + @Override + public String getContents( ) + { + String empLink; + if ( this.event.getEmpireId( ) == null ) { + empLink = this.event.getEmpireName( ); + } else { + empLink = "{{empire:" + this.event.getEmpireId( ) + " " + this.event.getEmpireName( ) + "}}"; + } + return this.mBody.replace( "${empire}" , empLink ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.ALLIANCE , 4 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + AllianceEventRecord event = (AllianceEventRecord) contents; + String mTitle , mBody; + try { + mTitle = this.translator.translate( language , "imtLeftAlliance" ); + mBody = this.translator.translate( language , "imLeftAlliance" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new LeftAllianceMessageExtractor( event , mTitle , mBody ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LostPlanetMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LostPlanetMessageFormatterBean.java new file mode 100644 index 0000000..8e63601 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/LostPlanetMessageFormatterBean.java @@ -0,0 +1,107 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; +import com.deepclone.lw.sqld.msgs.PlanetEventRecord; + + + +@Component +public class LostPlanetMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class LostPlanetMessageExtractor + extends PlanetMessageExtractor + { + private String mTitle; + private String mBody; + private String mSource; + + + public LostPlanetMessageExtractor( PlanetEventRecord event , String mTitle , String mBody , String mSource ) + { + super( event ); + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + String locLink = this.getLocation( ); + String empLink; + if ( this.event.getEmpireId( ) == null ) { + empLink = this.event.getEmpireName( ); + } else { + empLink = "{{empire:" + this.event.getEmpireId( ) + " " + this.event.getEmpireName( ) + "}}"; + } + return this.mBody.replace( "${location}" , locLink ).replace( "${taker}" , empLink ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${location}" , this.event.getLocationName( ) ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.PLANET , 4 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + PlanetEventRecord event = (PlanetEventRecord) contents; + String mTitle , mBody , mSource; + try { + mTitle = this.translator.translate( language , "imtLostPlanet" ); + mBody = this.translator.translate( language , "imLostPlanet" ); + mSource = this.translator.translate( language , "imSenderWar" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new LostPlanetMessageExtractor( event , mTitle , mBody , mSource ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/PendingRequestMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/PendingRequestMessageFormatterBean.java new file mode 100644 index 0000000..4667d54 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/PendingRequestMessageFormatterBean.java @@ -0,0 +1,91 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.AllianceEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class PendingRequestMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class PendingRequestMessageExtractor + extends AllianceMessageExtractor + { + + public PendingRequestMessageExtractor( AllianceEventRecord event , String mTitle , String mBody ) + { + super( event , mTitle , mBody ); + } + + + @Override + public String getSubject( ) + { + return this.mTitle; + } + + + @Override + public String getContents( ) + { + String empLink; + if ( this.event.getEmpireId( ) == null ) { + empLink = this.event.getEmpireName( ); + } else { + empLink = "{{empire:" + this.event.getEmpireId( ) + " " + this.event.getEmpireName( ) + "}}"; + } + return this.mBody.replace( "${empire}" , empLink ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.ALLIANCE , 0 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + AllianceEventRecord event = (AllianceEventRecord) contents; + String mTitle , mBody; + try { + mTitle = this.translator.translate( language , "imtPendingRequest" ); + mBody = this.translator.translate( language , "imPendingRequest" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new PendingRequestMessageExtractor( event , mTitle , mBody ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/PlanetMessageExtractor.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/PlanetMessageExtractor.java new file mode 100644 index 0000000..eed22fc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/PlanetMessageExtractor.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.sqld.msgs.PlanetEventRecord; + + + +abstract class PlanetMessageExtractor + implements MessageExtractor +{ + + protected PlanetEventRecord event; + + + public PlanetMessageExtractor( PlanetEventRecord event ) + { + this.event = event; + } + + + protected String getLocation( ) + { + return "{{planet:" + this.event.getLocationId( ) + " " + this.event.getLocationName( ) + "}} (" + + this.event.getX( ) + "," + this.event.getY( ) + ";" + this.event.getOrbit( ) + ")"; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/QueueMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/QueueMessageFormatterBean.java new file mode 100644 index 0000000..2e7a165 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/QueueMessageFormatterBean.java @@ -0,0 +1,168 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; +import com.deepclone.lw.sqld.msgs.QueueEventLocation; +import com.deepclone.lw.sqld.msgs.QueueEventRecord; + + + +@Component +public class QueueMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static abstract class QMEBase + implements MessageExtractor + { + + public String formatLocation( QueueEventLocation location ) + { + return "{{planet:" + location.getLocationId( ) + " " + location.getLocationName( ) + "}} (" + + location.getX( ) + "," + location.getY( ) + ";" + location.getOrbit( ) + ")"; + } + } + + private static class QueuesMessageExtractor + extends QMEBase + { + private QueueEventRecord event; + private String mTitle; + private String mBody; + private String mSource; + + + public QueuesMessageExtractor( QueueEventRecord event , String mTitle , String mBody , String mSource ) + { + this.event = event; + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + StringBuilder sb = new StringBuilder( ).append( this.mBody ); + for ( QueueEventLocation location : this.event.getLocations( ) ) { + sb.append( "\n* " ).append( this.formatLocation( location ) ); + } + return sb.toString( ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle; + } + + } + + private static class QueueMessageExtractor + extends QMEBase + { + private QueueEventRecord event; + private String mTitle; + private String mBody; + private String mSource; + + + public QueueMessageExtractor( QueueEventRecord event , String mTitle , String mBody , String mSource ) + { + this.event = event; + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + QueueEventLocation location = this.event.getLocations( ).get( 0 ); + return this.mBody.replace( "${location}" , this.formatLocation( location ) ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + QueueEventLocation location = this.event.getLocations( ).get( 0 ); + return this.mTitle.replace( "${location}" , location.getLocationName( ) ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.QUEUE , 0 ) ); + fmts.add( new FormatType( EventType.QUEUE , 1 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + QueueEventRecord event = (QueueEventRecord) contents; + boolean isCiv = ( event.getSubType( ) == 0 ); + boolean multi = ( event.getLocations( ).size( ) > 1 ); + String mTitle , mBody , mSource; + try { + mTitle = this.translator.translate( language , "imtEmpty" + ( isCiv ? "Civ" : "Mil" ) + "Queue" + + ( multi ? "s" : "" ) ); + mBody = this.translator.translate( language , "imEmpty" + ( isCiv ? "Civ" : "Mil" ) + "Queue" + + ( multi ? "s" : "" ) ); + mSource = this.translator.translate( language , "imSender" + ( isCiv ? "Eco" : "War" ) ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + + if ( multi ) { + return new QueuesMessageExtractor( event , mTitle , mBody , mSource ); + } + return new QueueMessageExtractor( event , mTitle , mBody , mSource ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/RequestResultMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/RequestResultMessageFormatterBean.java new file mode 100644 index 0000000..960ae2e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/RequestResultMessageFormatterBean.java @@ -0,0 +1,86 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.AllianceEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class RequestResultMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class PendingRequestMessageExtractor + extends AllianceMessageExtractor + { + + public PendingRequestMessageExtractor( AllianceEventRecord event , String mTitle , String mBody ) + { + super( event , mTitle , mBody ); + } + + + @Override + public String getSubject( ) + { + return this.mTitle; + } + + + @Override + public String getContents( ) + { + return this.mBody.replace( "${alliance}" , "[" + this.event.getAllianceTag( ) + "]" ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.ALLIANCE , 1 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + AllianceEventRecord event = (AllianceEventRecord) contents; + String type = event.getReqResult( ) ? "Accepted" : "Rejected"; + String mTitle , mBody; + try { + mTitle = this.translator.translate( language , "imtRequest" + type ); + mBody = this.translator.translate( language , "imRequest" + type ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new PendingRequestMessageExtractor( event , mTitle , mBody ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/StrikeMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/StrikeMessageFormatterBean.java new file mode 100644 index 0000000..8b74e96 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/StrikeMessageFormatterBean.java @@ -0,0 +1,102 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; +import com.deepclone.lw.sqld.msgs.PlanetEventRecord; + + + +@Component +public class StrikeMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class StrikeMessageExtractor + extends PlanetMessageExtractor + { + private String mTitle; + private String mBody; + private String mSource; + + + public StrikeMessageExtractor( PlanetEventRecord event , String mTitle , String mBody , String mSource ) + { + super( event ); + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + return this.mBody.replace( "${location}" , this.getLocation( ) ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${location}" , this.event.getLocationName( ) ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.PLANET , 2 ) ); + fmts.add( new FormatType( EventType.PLANET , 3 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + PlanetEventRecord event = (PlanetEventRecord) contents; + boolean isEnd = ( event.getSubType( ) == 3 ); + String mTitle , mBody , mSource; + try { + mTitle = this.translator.translate( language , "imtStrike" + ( isEnd ? "End" : "Start" ) ); + mBody = this.translator.translate( language , "imStrike" + ( isEnd ? "End" : "Start" ) ); + mSource = this.translator.translate( language , "imSenderSec" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new StrikeMessageExtractor( event , mTitle , mBody , mSource ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/TakenPlanetMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/TakenPlanetMessageFormatterBean.java new file mode 100644 index 0000000..58c3845 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/TakenPlanetMessageFormatterBean.java @@ -0,0 +1,110 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; +import com.deepclone.lw.sqld.msgs.PlanetEventRecord; + + + +@Component +public class TakenPlanetMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class TakenPlanetMessageExtractor + extends PlanetMessageExtractor + { + private String mTitle; + private String mBody; + private String mSource; + + + public TakenPlanetMessageExtractor( PlanetEventRecord event , String mTitle , String mBody , String mSource ) + { + super( event ); + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + } + + + @Override + public String getContents( ) + { + String locLink = this.getLocation( ); + String empLink; + if ( this.event.getEmpireName( ) == null ) { + empLink = ""; + } else if ( this.event.getEmpireId( ) == null ) { + empLink = this.event.getEmpireName( ); + } else { + empLink = "{{empire:" + this.event.getEmpireId( ) + " " + this.event.getEmpireName( ) + "}}"; + } + return this.mBody.replace( "${location}" , locLink ).replace( "${owner}" , empLink ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${location}" , this.event.getLocationName( ) ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.PLANET , 6 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + PlanetEventRecord event = (PlanetEventRecord) contents; + boolean neutral = ( event.getEmpireName( ) == null ); + String mTitle , mBody , mSource; + try { + mTitle = this.translator.translate( language , "imtTakePlanet" ); + mBody = this.translator.translate( language , "imTakePlanet" + ( neutral ? "Neutral" : "" ) ); + mSource = this.translator.translate( language , "imSenderWar" ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new TakenPlanetMessageExtractor( event , mTitle , mBody , mSource ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/TechMessageFormatterBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/TechMessageFormatterBean.java new file mode 100644 index 0000000..d670026 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/msgs/fmt/TechMessageFormatterBean.java @@ -0,0 +1,103 @@ +package com.deepclone.lw.beans.msgs.fmt; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.msg.MessageExtractor; +import com.deepclone.lw.interfaces.msg.MessageFormatter; +import com.deepclone.lw.sqld.msgs.EmpireEventRecord; +import com.deepclone.lw.sqld.msgs.EventType; +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +@Component +public class TechMessageFormatterBean + implements MessageFormatter +{ + + private Translator translator; + + private static class TechMessageExtractor + implements MessageExtractor + { + private String mTitle; + private String mBody; + private String mSource; + private String techName; + + + public TechMessageExtractor( String mTitle , String mBody , String mSource , + String techName ) + { + this.mTitle = mTitle; + this.mBody = mBody; + this.mSource = mSource; + this.techName = techName; + } + + + @Override + public String getContents( ) + { + return this.mBody.replace( "${tech}" , this.techName ); + } + + + @Override + public String getSender( ) + { + return this.mSource; + } + + + @Override + public String getSubject( ) + { + return this.mTitle.replace( "${tech}" , this.techName ); + } + + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Set< FormatType > getFormats( ) + { + Set< FormatType > fmts = new HashSet< FormatType >( ); + fmts.add( new FormatType( EventType.EMPIRE , 0 ) ); + return fmts; + } + + + @Override + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ) + { + EmpireEventRecord event = (EmpireEventRecord) contents; + String mTitle , mBody , mSource , techName; + try { + mTitle = this.translator.translate( language , "imtTechAvailable" ); + mBody = this.translator.translate( language , "imTechAvailable" ); + mSource = this.translator.translate( language , "imSenderSci" ); + techName = this.translator.translate( language , event.getTech( ) ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return new TechMessageExtractor( mTitle , mBody , mSource , techName ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/updates/GameUpdateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/updates/GameUpdateBean.java new file mode 100644 index 0000000..3973457 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/updates/GameUpdateBean.java @@ -0,0 +1,138 @@ +package com.deepclone.lw.beans.updates; + + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.game.UpdatesDAO; +import com.deepclone.lw.interfaces.sys.MaintenanceStatusException; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.interfaces.sys.TickStatusException; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class GameUpdateBean + implements InitializingBean , Runnable +{ + private Ticker ticker; + private SystemStatus systemStatus; + private SystemLogger logger; + + private TransactionTemplate tTemplate; + private UpdatesDAO updatesDao; + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setSystemStatus( SystemStatus systemStatus ) + { + this.systemStatus = systemStatus; + } + + + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger.getSystemLogger( "GameUpdate" ); + } + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager transactionManager ) + { + this.tTemplate = new TransactionTemplate( transactionManager ); + } + + + @Autowired( required = true ) + public void setUpdatesDAO( UpdatesDAO updatesDao ) + { + this.updatesDao = updatesDao; + } + + + @Override + public void afterPropertiesSet( ) + { + try { + this.endPreviousTick( ); + } catch ( MaintenanceStatusException e ) { + // Do nothing + } + this.ticker.registerTask( Frequency.MINUTE , "Game update" , this ); + } + + + @Override + public void run( ) + { + // Attempt to end the previous tick, if e.g. maintenance mode was initiated while it was + // being processed + try { + this.endPreviousTick( ); + } catch ( MaintenanceStatusException e1 ) { + return; + } + + // Initiate next tick + long tickId; + try { + tickId = this.systemStatus.startTick( ); + } catch ( TickStatusException e ) { + throw new RuntimeException( "tick initiated while previous tick still being processed" , e ); + } catch ( MaintenanceStatusException e ) { + return; + } + + // Execute tick + this.logger.log( LogLevel.DEBUG , "Tick " + tickId + " started" ).flush( ); + this.executeTick( tickId ); + } + + + private void endPreviousTick( ) + throws MaintenanceStatusException + { + Long currentTick = this.systemStatus.checkStuckTick( ); + if ( currentTick == null ) { + return; + } + + this.logger.log( LogLevel.WARNING , "Tick " + currentTick + " restarted" ).flush( ); + this.executeTick( currentTick.longValue( ) ); + } + + + private void executeTick( final long tickId ) + { + boolean hasMore; + do { + hasMore = this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + return updatesDao.processUpdates( tickId ); + } + + } ); + } while ( hasMore ); + this.logger.log( LogLevel.TRACE , "Tick " + tickId + " completed" ).flush( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/updates/UpdatesDAOBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/updates/UpdatesDAOBean.java new file mode 100644 index 0000000..77a1bbd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/updates/UpdatesDAOBean.java @@ -0,0 +1,43 @@ +package com.deepclone.lw.beans.updates; + + +import java.sql.Types; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.SqlOutParameter; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.simple.SimpleJdbcCall; + +import com.deepclone.lw.interfaces.game.UpdatesDAO; + + + +public class UpdatesDAOBean + implements UpdatesDAO +{ + + private SimpleJdbcCall process; + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.process = new SimpleJdbcCall( dataSource ); + this.process.withCatalogName( "sys" ).withFunctionName( "process_updates" ); + this.process.withoutProcedureColumnMetaDataAccess( ); + this.process.addDeclaredParameter( new SqlParameter( "tick_id" , Types.BIGINT ) ); + this.process.addDeclaredParameter( new SqlOutParameter( "has_more" , Types.BOOLEAN ) ); + } + + + @Override + public boolean processUpdates( long tickId ) + { + Map< String , Object > m = this.process.execute( tickId ); + return (Boolean) m.get( "has_more" ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple-beans.xml new file mode 100644 index 0000000..ffd1068 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple-beans.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/alliance-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/alliance-dao-bean.xml new file mode 100644 index 0000000..3fbfa96 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/alliance-dao-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/alliance-management-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/alliance-management-bean.xml new file mode 100644 index 0000000..8e094be --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/alliance-management-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/battle-data-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/battle-data-beans.xml new file mode 100644 index 0000000..fcbb99c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/battle-data-beans.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/empire-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/empire-dao-bean.xml new file mode 100644 index 0000000..e3c77db --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/empire-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/empire-management-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/empire-management-bean.xml new file mode 100644 index 0000000..db80a8e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/empire-management-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/fleet-management-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/fleet-management-bean.xml new file mode 100644 index 0000000..6d821bf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/fleet-management-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/fleets-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/fleets-dao-bean.xml new file mode 100644 index 0000000..42dbbc8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/fleets-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/game-update-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/game-update-bean.xml new file mode 100644 index 0000000..54534ff --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/game-update-bean.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/map-viewer-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/map-viewer-bean.xml new file mode 100644 index 0000000..189fb3d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/map-viewer-bean.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/message-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/message-beans.xml new file mode 100644 index 0000000..7381a9a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/message-beans.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/planet-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/planet-dao-bean.xml new file mode 100644 index 0000000..c2054b8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/planet-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/planets-management-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/planets-management-bean.xml new file mode 100644 index 0000000..893f8fd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/planets-management-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/universe-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/universe-dao-bean.xml new file mode 100644 index 0000000..18928ba --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/universe-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/universe-generator-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/universe-generator-bean.xml new file mode 100644 index 0000000..759061f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/universe-generator-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/updates-dao-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/updates-dao-bean.xml new file mode 100644 index 0000000..eb24044 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-simple/src/main/resources/configuration/simple/updates-dao-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.project new file mode 100644 index 0000000..8351fb8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-system + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..35c2ee3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Tue Feb 23 12:51:19 CET 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..b7fd985 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Tue Feb 23 12:51:19 CET 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/pom.xml new file mode 100644 index 0000000..47dfd4f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-beans-system + 5.99.1 + Legacy Worlds system management + This module regroups system management beans such as the constants manager. + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsAdministrationImpl.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsAdministrationImpl.java new file mode 100644 index 0000000..0529a12 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsAdministrationImpl.java @@ -0,0 +1,106 @@ +package com.deepclone.lw.beans.sys; + + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import com.deepclone.lw.interfaces.sys.ConstantDefinition; +import com.deepclone.lw.interfaces.sys.ConstantsAdministration; +import com.deepclone.lw.interfaces.sys.InvalidConstantValue; +import com.deepclone.lw.interfaces.sys.UnknownConstantError; +import com.deepclone.lw.sqld.sys.Constant; + + + +/** + * The constants administration implementation mostly serves as a session-specific proxy for the + * share {@link ConstantsData} instance. + * + * @author tseeker + */ +class ConstantsAdministrationImpl + implements ConstantsAdministration +{ + /** Shared data storage instance */ + private ConstantsData data; + + private int admin; + + + /** + * Copies the required references. + * + * @param data + * shared data storage instance + * @param logger + * session-specific logger + */ + ConstantsAdministrationImpl( ConstantsData data , int admin ) + { + this.data = data; + this.admin = admin; + } + + + /* Documented in ConstantsAdministration interface */ + @Override + public Set< String > getCategories( ) + { + return this.data.getCategories( ); + } + + + /* Documented in ConstantsAdministration interface */ + @Override + public Collection< ConstantDefinition > getConstants( String category ) + { + List< Constant > constants = this.data.getCategory( category ); + List< ConstantDefinition > defs = new LinkedList< ConstantDefinition >( ); + if ( constants == null ) { + return defs; + } + + // Convert data to immutable records + for ( Constant constant : constants ) { + ConstantDefinition def; + if ( constant.getMaxValue( ) == null && constant.getMinValue( ) == null ) { + def = new ConstantDefinition( constant.getName( ) , category , constant.getDescription( ) , constant + .getValue( ) ); + } else if ( constant.getMaxValue( ) == null || constant.getMinValue( ) == null ) { + boolean isMin = ( constant.getMaxValue( ) == null ); + Double val = isMin ? constant.getMinValue( ) : constant.getMaxValue( ); + def = new ConstantDefinition( constant.getName( ) , category , constant.getDescription( ) , constant + .getValue( ) , val , isMin ); + } else { + if ( constant.getMaxValue( ) == null && constant.getMinValue( ) == null ) { + def = new ConstantDefinition( constant.getName( ) , category , constant.getDescription( ) , + constant.getValue( ) ); + } else if ( constant.getMaxValue( ) == null ) { + def = new ConstantDefinition( constant.getName( ) , category , constant.getDescription( ) , + constant.getValue( ) , constant.getMinValue( ) , true ); + } else if ( constant.getMinValue( ) == null ) { + def = new ConstantDefinition( constant.getName( ) , category , constant.getDescription( ) , + constant.getValue( ) , constant.getMaxValue( ) , false ); + } else { + def = new ConstantDefinition( constant.getName( ) , category , constant.getDescription( ) , constant + .getValue( ) , constant.getMinValue( ) , constant.getMaxValue( ) ); + } + } + defs.add( def ); + } + + return defs; + } + + + /* Documented in ConstantsAdministration interface */ + @Override + public void setConstant( String name , Double value ) + throws UnknownConstantError , InvalidConstantValue + { + this.data.setValue( name , value , this.admin ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsData.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsData.java new file mode 100644 index 0000000..4096acd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsData.java @@ -0,0 +1,630 @@ +package com.deepclone.lw.beans.sys; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.sql.DataSource; + +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.simple.SimpleJdbcCall; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.sys.ConstantDefinition; +import com.deepclone.lw.interfaces.sys.ConstantsUser; +import com.deepclone.lw.interfaces.sys.InvalidConstantValue; +import com.deepclone.lw.interfaces.sys.UnknownConstantError; +import com.deepclone.lw.sqld.sys.Constant; +import com.deepclone.lw.utils.StoredProc; + + + +/** + * This class defines the shared data structures used by both the constants manager bean and its + * administrative session instances. It also encapsulates all of the code used by both. + * + * @author tseeker + */ +class ConstantsData +{ + /** Database interface */ + private SimpleJdbcTemplate dTemplate; + + /** Transaction manager interface */ + private TransactionTemplate tTemplate; + + /** System logger instance for the ConstantsManager component */ + private SystemLogger sysLog; + + /** All registered constants, by name */ + private Map< String , Constant > registeredConstants; + + /** Constants users that have received their initial notification */ + private Set< ConstantsUser > notifiedUsers = new HashSet< ConstantsUser >( ); + + /** Constants needed by each user */ + private Map< ConstantsUser , Set< String >> userConstants = new HashMap< ConstantsUser , Set< String > >( ); + + /** Users listening to each constant */ + private Map< String , Set< ConstantsUser >> constantUsers = new HashMap< String , Set< ConstantsUser > >( ); + + /** Constants by category */ + private Map< String , List< Constant >> categories; + + private SimpleJdbcCall uocConstantNoBounds; + private SimpleJdbcCall uocConstantSingleBound; + private SimpleJdbcCall uocConstantTwoBounds; + private StoredProc fSetConstant; + + + /** + * Initialises the various references, creates the system logger used by the instance, then + * loads all existing constants. + * + * @param dataSource + * database interface + * @param tTemplate + * transaction manager interface + * @param logger + * logger bean interface + */ + ConstantsData( DataSource dataSource , TransactionTemplate tTemplate , Logger logger ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.uocConstantNoBounds = new SimpleJdbcCall( dataSource ); + this.uocConstantNoBounds.withCatalogName( "sys" ).withFunctionName( "uoc_constant" ); + this.uocConstantNoBounds.withoutProcedureColumnMetaDataAccess( ); + this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) ); + this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) ); + this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) ); + this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "value" , Types.REAL ) ); + + this.uocConstantSingleBound = new SimpleJdbcCall( dataSource ); + this.uocConstantSingleBound.withCatalogName( "sys" ).withFunctionName( "uoc_constant" ); + this.uocConstantSingleBound.withoutProcedureColumnMetaDataAccess( ); + this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) ); + this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) ); + this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) ); + this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "value" , Types.REAL ) ); + this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "boundary" , Types.REAL ) ); + this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "is_min" , Types.BOOLEAN ) ); + + this.uocConstantTwoBounds = new SimpleJdbcCall( dataSource ); + this.uocConstantTwoBounds.withCatalogName( "sys" ).withFunctionName( "uoc_constant" ); + this.uocConstantTwoBounds.withoutProcedureColumnMetaDataAccess( ); + this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) ); + this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) ); + this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) ); + this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "value" , Types.REAL ) ); + this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "min" , Types.REAL ) ); + this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "max" , Types.REAL ) ); + + this.fSetConstant = new StoredProc( dataSource , "sys" , "set_constant" ); + this.fSetConstant.addParameter( "cname" , Types.VARCHAR ); + this.fSetConstant.addParameter( "value" , Types.REAL ); + this.fSetConstant.addParameter( "admin" , Types.INTEGER ); + + this.tTemplate = tTemplate; + this.sysLog = logger.getSystemLogger( "ConstantsManager" ); + + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + loadConstants( ); + } + + } ); + } + + + private void loadConstants( ) + { + String sql = "SELECT category , name , description , value , min , max FROM sys.constants_view"; + RowMapper< Constant > mapper = new RowMapper< Constant >( ) { + + @Override + public Constant mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + Constant c = new Constant( ); + c.setCategory( rs.getString( "category" ) ); + c.setName( rs.getString( "name" ) ); + c.setDescription( rs.getString( "description" ) ); + c.setValue( rs.getDouble( "value" ) ); + c.setMinValue( (Float) rs.getObject( "min" ) ); + c.setMaxValue( (Float) rs.getObject( "max" ) ); + return c; + } + + }; + + this.registeredConstants = new HashMap< String , Constant >( ); + this.categories = new HashMap< String , List< Constant > >( ); + for ( Constant cnst : this.dTemplate.query( sql , mapper ) ) { + this.registeredConstants.put( cnst.getName( ) , cnst ); + + List< Constant > category = this.categories.get( cnst.getCategory( ) ); + if ( category == null ) { + category = new LinkedList< Constant >( ); + this.categories.put( cnst.getCategory( ) , category ); + } + category.add( cnst ); + } + } + + + private void updateConstants( List< ConstantDefinition > toUpdate ) + { + for ( ConstantDefinition cDef : toUpdate ) { + if ( cDef.maxValue == null && cDef.minValue == null ) { + this.uocConstantNoBounds.execute( cDef.name , cDef.description , cDef.category , cDef.defaultValue ); + } else if ( cDef.maxValue == null ) { + this.uocConstantSingleBound.execute( cDef.name , cDef.description , cDef.category , cDef.defaultValue , + cDef.minValue , true ); + } else if ( cDef.minValue == null ) { + this.uocConstantSingleBound.execute( cDef.name , cDef.description , cDef.category , cDef.defaultValue , + cDef.maxValue , false ); + } else { + this.uocConstantTwoBounds.execute( cDef.name , cDef.description , cDef.category , cDef.defaultValue , + cDef.minValue , cDef.maxValue ); + } + } + } + + + /** + * Checks that the descriptive parts of a constant data instance match the corresponding fields + * in a constant definition instance. + * + * @param constant + * the constant data instance + * @param def + * the definition + * @return true if the descriptive parts are a match + */ + private boolean compareConstantDescription( Constant constant , ConstantDefinition def ) + { + return constant.getCategory( ).equals( def.category ) && constant.getDescription( ).equals( def.description ); + } + + + /** + * Checks that the bounds defined in a constant data instance are identical to the bounds from a + * constant definition. + * + * @param constant + * the constant data instance + * @param def + * the definition + * @return true if the bounds match + */ + private boolean compareConstantBounds( Constant constant , ConstantDefinition def ) + { + return constant.getMinValue( ) == def.minValue && constant.getMaxValue( ) == def.maxValue; + } + + + /** + * Updates a constant's value after bounds changed. + * + * This method, called when a constant data instance's bounds have been changed, verifies that + * the constant's current value matches the new bounds and modifies it if that is required. + * + * @param constant + * the constant data instance + * @param def + * the definition + * @return true if the value was updated + */ + private boolean updateValue( Constant constant , ConstantDefinition def ) + { + if ( def.minValue != null && def.minValue > constant.getValue( ) ) { + constant.setValue( def.minValue ); + return true; + } else if ( def.maxValue != null && def.maxValue < constant.getValue( ) ) { + constant.setValue( def.maxValue ); + return true; + } + return false; + } + + + /** + * Notifies constant users that a specific constant value has been modified. + * + * @param changed + * the constant's name + * + * @see #notify(Set) + */ + private void notify( String changed ) + { + Set< String > temp = new HashSet< String >( ); + temp.add( changed ); + this.notify( temp ); + } + + + /** + * Notifies constant users that a set of constants has changed. + * + * Users of each specified constant are identified, and separated in two groups: users that have + * not received their initial notification and for which initial notification must be attempted, + * and already initialised users which will only receive updates on constants that actually + * changed. + * + * @param changed + * the names of the constants that have been changed. + * + * @see #notifyUpdate(ConstantsUser, Set) + * @see #attemptFirstNotification(ConstantsUser) + */ + private void notify( Set< String > changed ) + { + Map< ConstantsUser , Set< String >> notifyChange = new HashMap< ConstantsUser , Set< String > >( ); + Set< ConstantsUser > firstNotification = new HashSet< ConstantsUser >( ); + + // Build a map of users <-> notifications and a set of first notifications to attempt + for ( String ccn : changed ) { + Set< ConstantsUser > users = this.constantUsers.get( ccn ); + if ( users == null ) { + continue; + } + + for ( ConstantsUser user : users ) { + if ( this.notifiedUsers.contains( user ) ) { + Set< String > userChange = notifyChange.get( user ); + if ( userChange == null ) { + userChange = new HashSet< String >( ); + notifyChange.put( user , userChange ); + } + userChange.add( ccn ); + } else { + firstNotification.add( user ); + } + } + } + + // Attempt first notifications + for ( ConstantsUser user : firstNotification ) { + this.attemptFirstNotification( user ); + } + + // Send updates to the others + for ( ConstantsUser user : notifyChange.keySet( ) ) { + this.notifyUpdate( user , notifyChange.get( user ) ); + } + } + + + /** + * Notifies a constant user of changes. + * + * This method retrieves the values of the listed constants, then notifies the specified user + * that they have changed. If an exception occurs in the user's notification method, an error is + * written to the server's log. + * + * @param user + * the constants user instance. + * @param changed + * the names of the constants for which a notification is to be sent. + */ + private void notifyUpdate( ConstantsUser user , Set< String > changed ) + { + Map< String , Double > values = new HashMap< String , Double >( ); + + // Find updated values + for ( String cn : changed ) { + values.put( cn , this.registeredConstants.get( cn ).getValue( ) ); + } + + // Send notification + try { + user.setConstants( false , values ); + } catch ( Throwable t ) { + this.sysLog.log( LogLevel.ERROR , "updating constant values caused an exception" , t ).flush( ); + } + } + + + /** + * Attempts initial notification of constants values to a constants user. + * + * This method is called when constants registered to a not-yet-initialised constants user + * change. It attempts to retrieve the required values, returning directly if a constant is + * missing. If all values exist, the initial notification is sent. Should an exception occur, it + * is logged as an error and the method ends; otherwise the user is added to the set of + * initialised users. + * + * @param user + * the constants user to notify + */ + private void attemptFirstNotification( ConstantsUser user ) + { + Map< String , Double > values = new HashMap< String , Double >( ); + + // Try to find all required values + for ( String cn : this.userConstants.get( user ) ) { + Constant cst = this.registeredConstants.get( cn ); + if ( cst == null ) { + return; + } + values.put( cn , cst.getValue( ) ); + } + + // Send initial notification + try { + user.setConstants( true , values ); + } catch ( Throwable t ) { + this.sysLog.log( LogLevel.ERROR , "registering initial constant values caused an exception" , t ).flush( ); + return; + } + this.notifiedUsers.add( user ); + } + + + /** + * Updates the list of categories from the list of constants. + * + * This method updates the list of categories by going through all known constants, creating an + * entry in the categories map for each category and associating it with the list of constants + * it contains. + */ + private void updateCategories( ) + { + if ( this.categories != null ) { + return; + } + this.categories = new HashMap< String , List< Constant > >( ); + for ( Constant c : this.registeredConstants.values( ) ) { + String cat = c.getCategory( ); + List< Constant > cContents; + cContents = this.categories.get( cat ); + if ( cContents == null ) { + cContents = new LinkedList< Constant >( ); + this.categories.put( cat , cContents ); + } + cContents.add( c ); + } + } + + + /** + * Constants registration method. + * + * This method is responsible for updating the in-base constants data when new definitions are + * registered. It will add new constants or update existing one. Finally, if some of the updated + * constants are used by any constants user instance, it will send update notifications. + * + * @param definitions + * the constants to register + */ + synchronized void registerConstants( Collection< ConstantDefinition > definitions ) + { + Set< String > toNotify = new HashSet< String >( ); + final List< ConstantDefinition > toUpdate = new LinkedList< ConstantDefinition >( ); + + for ( ConstantDefinition def : definitions ) { + // Handle new definitions + Constant constant = this.registeredConstants.get( def.name ); + if ( constant == null ) { + toUpdate.add( def ); + toNotify.add( def.name ); + this.sysLog.log( LogLevel.DEBUG , "registering constant " + def.name ); + continue; + } + + boolean sameDescription = this.compareConstantDescription( constant , def ); + boolean sameBounds = this.compareConstantBounds( constant , def ); + if ( sameDescription && sameBounds ) { + continue; + } + + // Make sure the value is correct if the bounds have been changed + if ( !sameBounds && this.updateValue( constant , def ) ) { + toNotify.add( def.name ); + } + + toUpdate.add( def ); + this.sysLog.log( LogLevel.DEBUG , "updating definition of constant " + def.name ); + } + + // Apply updates and notify users + if ( !toUpdate.isEmpty( ) ) { + this.sysLog.flush( ); + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + updateConstants( toUpdate ); + loadConstants( ); + } + + } ); + + if ( !toNotify.isEmpty( ) ) { + this.notify( toNotify ); + } + } + } + + + /** + * Constants user registration + * + * This method registers (or re-registers) a constants user, indicating the constants used by + * the instance and for which update notifications should be sent. Once the user has been + * registered, an attempt at sending the initial notification is made. + * + * @param user + * the constants user to register + * @param constants + * the names of the constants for which notifications are required + */ + synchronized void registerUser( ConstantsUser user , Set< String > constants ) + { + // If this user was already registered, unregister it + if ( this.userConstants.containsKey( user ) ) { + this.unregisterUser( user ); + } + + // Add user <-> constant maps + this.userConstants.put( user , new HashSet< String >( constants ) ); + for ( String cn : constants ) { + Set< ConstantsUser > users; + users = this.constantUsers.get( cn ); + if ( users == null ) { + users = new HashSet< ConstantsUser >( ); + this.constantUsers.put( cn , users ); + } + users.add( user ); + } + + // Try sending the user its initial notification + this.attemptFirstNotification( user ); + } + + + /** + * Unregisters a constants user. + * + * This method removes a constants user from the manager, preventing further notifications to be + * sent. + * + * @param user + * the constants user to unregister + */ + synchronized void unregisterUser( ConstantsUser user ) + { + Set< String > constants = this.userConstants.get( user ); + if ( constants == null ) { + return; + } + + this.userConstants.remove( user ); + this.notifiedUsers.remove( user ); + for ( String constant : constants ) { + Set< ConstantsUser > users = this.constantUsers.get( constant ); + users.remove( user ); + if ( users.isEmpty( ) ) { + this.constantUsers.remove( constant ); + } + } + } + + + /** + * Gets the names of the constant categories. + * + * This method will make sure the constant categories map is up-to-date, then return a copy of + * its keys. + * + * @return the names of all constant categories + */ + synchronized Set< String > getCategories( ) + { + this.updateCategories( ); + return new HashSet< String >( this.categories.keySet( ) ); + } + + + /** + * Accesses the constant data instances from a category. + * + * This method will make sure the constant categories map is up-to-date, then return a copy of + * the list corresponding to the specified category. If the category is not present in the map, + * null will be returned. + * + * @param cat + * the category's name + * @return the list of constant data instances, or null if the category is + * undefined + */ + synchronized List< Constant > getCategory( String cat ) + { + this.updateCategories( ); + List< Constant > listCst = this.categories.get( cat ); + if ( listCst != null ) { + return new LinkedList< Constant >( listCst ); + } + return null; + } + + + /** + * Modifies the value of a single constant. + * + * This method is called by administrative sessions in order to modify a single constant. It + * checks that the constant exists and that its new value is valid, then updates the database + * entry. Once this is done, it notifies the constant's users and returns the previous value. + * + * @param name + * the name of the constant to modify + * @param value + * the constant's new value + * @return the constant's previous value + * @throws UnknownConstantError + * if the specified constant does not exist + * @throws InvalidConstantValue + * if the specified value is out of bounds + */ + synchronized Double setValue( final String name , final Double value , final int admin ) + throws UnknownConstantError , InvalidConstantValue + { + // Check name + Constant c = this.registeredConstants.get( name ); + if ( c == null ) { + throw new UnknownConstantError( name ); + } + + // Check value + if ( c.getMinValue( ) != null && value < c.getMinValue( ) || c.getMaxValue( ) != null + && value > c.getMaxValue( ) ) { + throw new InvalidConstantValue( ); + } + + // Store constant + try { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + fSetConstant.execute( name , value.floatValue( ) , admin ); + } + + } ); + } catch ( RuntimeException t ) { + this.sysLog.log( LogLevel.ERROR , "could not update constant " + c.getName( ) , t ).flush( ); + throw t; + } + + // Update in-memory copy + Double old = c.getValue( ); + c.setValue( value ); + + // Notify constant users + this.notify( c.getName( ) ); + + return old; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsManagerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsManagerBean.java new file mode 100644 index 0000000..04064d3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsManagerBean.java @@ -0,0 +1,115 @@ +package com.deepclone.lw.beans.sys; + + +import java.util.Collection; +import java.util.Set; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.sys.ConstantDefinition; +import com.deepclone.lw.interfaces.sys.ConstantsAdministration; +import com.deepclone.lw.interfaces.sys.ConstantsManager; +import com.deepclone.lw.interfaces.sys.ConstantsUser; + + + +/** + * The constants manager bean initialises a {@link ConstantsData} instance, to which it delegates + * all operations. + * + * @author tseeker + */ +public class ConstantsManagerBean + implements ConstantsManager , InitializingBean +{ + + /** Transaction manager interface */ + private TransactionTemplate tTemplate; + + /** Logger bean */ + private Logger logger; + + /** Shared constants data instance */ + private ConstantsData data; + + private DataSource dataSource; + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dataSource = dataSource; + } + + + /** + * Sets the transaction manager interface (DI) + * + * @param transactionManager + * the transaction manager + */ + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager transactionManager ) + { + this.tTemplate = new TransactionTemplate( transactionManager ); + } + + + /** + * Sets the logger bean interface (DI) + * + * @param logger + * the logger bean + */ + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger; + } + + + /** Creates the data storage and manipulation instance once the bean is ready */ + @Override + public void afterPropertiesSet( ) + { + this.data = new ConstantsData( this.dataSource , this.tTemplate , this.logger ); + } + + + /* Documented in ConstantsManager interface */ + @Override + public void registerConstants( Collection< ConstantDefinition > definitions ) + { + this.data.registerConstants( definitions ); + } + + + /* Documented in ConstantsManager interface */ + @Override + public void registerUser( ConstantsUser user , Set< String > constants ) + { + this.data.registerUser( user , constants ); + } + + + /* Documented in ConstantsManager interface */ + @Override + public void unregisterUser( ConstantsUser user ) + { + this.data.unregisterUser( user ); + } + + + /* Documented in ConstantsManager interface */ + @Override + public ConstantsAdministration getAdminSession( int admin ) + { + return new ConstantsAdministrationImpl( this.data , admin ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsRegistrarBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsRegistrarBean.java new file mode 100644 index 0000000..59743d9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ConstantsRegistrarBean.java @@ -0,0 +1,202 @@ +package com.deepclone.lw.beans.sys; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.interfaces.sys.ConstantDefinition; +import com.deepclone.lw.interfaces.sys.ConstantsManager; + + + +public class ConstantsRegistrarBean +{ + + @Autowired( required = true ) + public void setConstantsManager( ConstantsManager cm ) + { + List< ConstantDefinition > defs = new LinkedList< ConstantDefinition >( ); + String cDesc; + + // Default maximal age for log entries = 1 week + double oneWeek = 60 * 60 * 24 * 7; + + // Initial values + cDesc = "Initial cash for new empires."; + defs.add( new ConstantDefinition( "game.initialCash" , "Initial values" , cDesc , 2000.0 , 0.0 , true ) ); + cDesc = "Initial credits for new accounts."; + defs.add( new ConstantDefinition( "game.initialCredits" , "Initial values" , cDesc , 0.0 , 0.0 , true ) ); + + // Misc. game-related values + cDesc = "Game updates - batch size."; + defs.add( new ConstantDefinition( "game.batchSize" , "Game (misc)" , cDesc , 20.0 , 1.0 , true ) ); + cDesc = "Population growth factor."; + defs.add( new ConstantDefinition( "game.growthFactor" , "Game (misc)" , cDesc , 50.0 , 1.0 , true ) ); + cDesc = "Increase to the population growth factor caused by reanimation centres."; + defs.add( new ConstantDefinition( "game.growthFactor.rCentre" , "Game (misc)" , cDesc , 10.0 , 1.0 , true ) ); + cDesc = "Time to abandon a planet (in ticks)."; + defs.add( new ConstantDefinition( "game.timeToAbandon" , "Game (misc)" , cDesc , 1440.0 , 1.0 , true ) ); + cDesc = "Fleet damage ratio per day when debt and upkeep are equal."; + defs.add( new ConstantDefinition( "game.debt.fleet" , "Game (misc)" , cDesc , 0.3 , 0.001 , 0.999 ) ); + cDesc = "Buildings damage ratio per day when debt and upkeep are equal."; + defs.add( new ConstantDefinition( "game.debt.buildings" , "Game (misc)" , cDesc , 0.1 , 0.001 , 0.999 ) ); + + // Universe + cDesc = "Ratio of free planets below which universe expansion is triggered."; + defs.add( new ConstantDefinition( "game.universe.minFreeRatio" , "Universe" , cDesc , 0.1 , 0.02 , 0.98 ) ); + cDesc = "Amount of pictures available to generate planets."; + defs.add( new ConstantDefinition( "game.universe.pictures" , "Universe" , cDesc , 200.0 , 1.0 , true ) ); + cDesc = "Initial population on first-generation planets."; + defs.add( new ConstantDefinition( "game.universe.initialPopulation" , "Universe" , cDesc , 2000.0 , 1000.0 , + true ) ); + cDesc = "Initial universe size (offset relative to the centre)."; + defs.add( new ConstantDefinition( "game.universe.initialSize" , "Universe" , cDesc , 1.0 , 1.0 , true ) ); + + // Happiness + String[] hcNames = { + "noEmployment" , "employmentLimit" , "noDefence" , "defenceLimit" , "popPerDefencePoint" , + "idealEmpireSize" , "smallEmpire" , "eSizeLimit" , "strike" , "relativeChange" , "maxAbsoluteChange" + }; + for ( int i = 0 ; i < hcNames.length ; i++ ) { + hcNames[ i ] = "game.happiness." + hcNames[ i ]; + } + String cat = "Happiness"; + cDesc = "Employment happiness level when there is no employment."; + defs.add( new ConstantDefinition( hcNames[ 0 ] , cat , cDesc , 0.7 , 0.05 , 0.99 ) ); + cDesc = "Employment ratio beyond which things get tough."; + defs.add( new ConstantDefinition( hcNames[ 1 ] , cat , cDesc , 2.0 , 1.1 , true ) ); + cDesc = "Defence happiness level when there is no defence."; + defs.add( new ConstantDefinition( hcNames[ 2 ] , cat , cDesc , 0.5 , 0.05 , 0.99 ) ); + cDesc = "Defence ratio beyond which things get tough."; + defs.add( new ConstantDefinition( hcNames[ 3 ] , cat , cDesc , 4.0 , 1.1 , true ) ); + cDesc = "Population covered by a single defence power point."; + defs.add( new ConstantDefinition( hcNames[ 4 ] , cat , cDesc , 5.0 , 1.0 , true ) ); + cDesc = "Ideal empire size."; + defs.add( new ConstantDefinition( hcNames[ 5 ] , cat , cDesc , 10.0 , 2.0 , true ) ); + cDesc = "Happiness level for 1-planet empires."; + defs.add( new ConstantDefinition( hcNames[ 6 ] , cat , cDesc , 0.9 , 0.5 , true ) ); + cDesc = "Empire size limit (relative to the ideal size) beyond which things get tough."; + defs.add( new ConstantDefinition( hcNames[ 7 ] , cat , cDesc , 2.0 , 1.1 , true ) ); + cDesc = "Happiness level below which strikes begin."; + defs.add( new ConstantDefinition( hcNames[ 8 ] , cat , cDesc , 0.25 , 0.0 , 1.0 ) ); + cDesc = "Happiness change at each update, relative to the size of the population."; + defs.add( new ConstantDefinition( hcNames[ 9 ] , cat , cDesc , 0.001 , 0.00001 , 0.99999 ) ); + cDesc = "Maximal population units for which happiness will change."; + defs.add( new ConstantDefinition( hcNames[ 10 ] , cat , cDesc , 1000.0 , 1.0 , true ) ); + + // Work and income + String[] wcNames = { + "population" , "factory" , "strikeEffect" , "wuPerPopUnit" , "destructionRecovery" , "destructionWork" , + "rpPerPopUnit" , "cancelRecovery" + }; + for ( int i = 0 ; i < wcNames.length ; i++ ) { + wcNames[ i ] = "game.work." + wcNames[ i ]; + } + cat = "Work & income"; + cDesc = "Daily income per population unit."; + defs.add( new ConstantDefinition( wcNames[ 0 ] , cat , cDesc , 0.2 , 0.01 , true ) ); + cDesc = "Daily income per factory production unit."; + defs.add( new ConstantDefinition( wcNames[ 1 ] , cat , cDesc , 250.0 , 0.01 , true ) ); + cDesc = "Proportion of the base income that disappears if the whole population is on strike."; + defs.add( new ConstantDefinition( wcNames[ 2 ] , cat , cDesc , 1.0 , 0.0 , 1.0 ) ); + cDesc = "Work units generated by each population unit."; + defs.add( new ConstantDefinition( wcNames[ 3 ] , cat , cDesc , 0.01 , 0.001 , true ) ); + cDesc = "Proportion of a building's cost that is recovered when it is destroyed."; + defs.add( new ConstantDefinition( wcNames[ 4 ] , cat , cDesc , 0.1 , 0.01 , 0.99 ) ); + cDesc = "Proportion of a building's construction work units required to destroy it"; + defs.add( new ConstantDefinition( wcNames[ 5 ] , cat , cDesc , 0.25 , 0.01 , 1.0 ) ); + cDesc = "Research points per population unit."; + defs.add( new ConstantDefinition( wcNames[ 6 ] , cat , cDesc , 0.50 , 0.01 , true ) ); + cDesc = "Proportion of queue investments that is recovered when flushing the queue."; + defs.add( new ConstantDefinition( wcNames[ 7 ] , cat , cDesc , 0.1 , 0.01 , 1.0 ) ); + + // Vacation mode + cDesc = "Initial vacation credits."; + defs.add( new ConstantDefinition( "vacation.initial" , "Vacation mode" , cDesc , 4320.0 , 0.0 , true ) ); + cDesc = "Delay before vacation mode is activated (seconds)."; + defs.add( new ConstantDefinition( "vacation.delay" , "Vacation mode" , cDesc , 21600.0 , 3600.0 , true ) ); + cDesc = "Maximal vacation credits."; + defs.add( new ConstantDefinition( "vacation.max" , "Vacation mode" , cDesc , 259200.0 , 10000.0 , true ) ); + cDesc = "Vacation cost (credits / minute)."; + defs.add( new ConstantDefinition( "vacation.cost" , "Vacation mode" , cDesc , 3.0 , 2.0 , 20.0 ) ); + cDesc = "Income/upkeep divider used when vacation mode is active."; + defs.add( new ConstantDefinition( "vacation.cashDivider" , "Vacation mode" , cDesc , 3.0 , 1.1 , 10.0 ) ); + cDesc = "Research points divider used when vacation mode is active."; + defs.add( new ConstantDefinition( "vacation.researchDivider" , "Vacation mode" , cDesc , 10.0 , 1.1 , 50.0 ) ); + + // Map names + cDesc = "Minimal delay between map object renaming."; + defs.add( new ConstantDefinition( "map.names.minDelay" , "Map names" , cDesc , 15.0 , 1.0 , true ) ); + cDesc = "Units for the minimal delay between map object renaming (seconds)."; + defs.add( new ConstantDefinition( "map.names.minDelay.units" , "Map names" , cDesc , 86400.0 , 1.0 , true ) ); + + // Log clean-up + cDesc = "Maximal age of administration log entries, in seconds."; + defs.add( new ConstantDefinition( "log.maxAge.admin" , "Logs" , cDesc , oneWeek , 1.0 , true ) ); + cDesc = "Maximal age of account log entries, in seconds."; + defs.add( new ConstantDefinition( "log.maxAge.users" , "Logs" , cDesc , oneWeek , 1.0 , true ) ); + cDesc = "Maximal age of system log entries, in seconds."; + defs.add( new ConstantDefinition( "log.maxAge.sys" , "Logs" , cDesc , oneWeek , 1.0 , true ) ); + + // Battles + cDesc = "Amount of ticks before a battle reaches full intensity."; + defs.add( new ConstantDefinition( "game.battle.timeToFullIntensity" , "Battles" , cDesc , 30.0 , 0.0 , true ) ); + cDesc = "Initial intensity of a battle."; + defs.add( new ConstantDefinition( "game.battle.initialIntensity" , "Battles" , cDesc , 0.25 , 0.0 , 1.0 ) ); + cDesc = "Defence bonus."; + defs.add( new ConstantDefinition( "game.battle.defenceBonus" , "Battles" , cDesc , 0.1 , 0.0 , true ) ); + cDesc = "Damage / power unit / minute"; + defs.add( new ConstantDefinition( "game.battle.damage" , "Battles" , cDesc , 0.01 , 0.001 , true ) ); + cDesc = "Proportion of random damage variation."; + defs.add( new ConstantDefinition( "game.battle.randomDamage" , "Battles" , cDesc , 0.05 , 0.0 , 0.9 ) ); + + // Ticker + cDesc = "Interval between ticks with the highest frequency, in milliseconds."; + defs.add( new ConstantDefinition( "ticker.interval" , "Ticker" , cDesc , 5000.0 , 1000.0 , true ) ); + + // Accounts + cDesc = "Minimal interval between address change requests (seconds)"; + defs.add( new ConstantDefinition( "accounts.acrDelay" , "Accounts" , cDesc , 14400.0 , 1.0 , true ) ); + cDesc = "Minimal interval between password recovery requests (seconds)"; + defs.add( new ConstantDefinition( "accounts.prrDelay" , "Accounts" , cDesc , 8800.0 , 1.0 , true ) ); + cDesc = "Time before a new or reactivated account is deleted / disabled (seconds)"; + defs.add( new ConstantDefinition( "accounts.cacDelay" , "Accounts" , cDesc , 86400.0 , 3600.0 , true ) ); + cDesc = "Delay between clicking the 'Quit' button and account de-activation (seconds)"; + defs.add( new ConstantDefinition( "accounts.quitDelay" , "Accounts" , cDesc , 86400.0 , 3600.0 , true ) ); + cDesc = "Delay between a ban and the deletion of the player's empire (seconds)"; + defs.add( new ConstantDefinition( "accounts.banDelay" , "Accounts" , cDesc , 178000.0 , 3600.0 , true ) ); + cDesc = "Delay before a ban request expires (seconds)"; + defs.add( new ConstantDefinition( "accounts.banExpiration" , "Accounts" , cDesc , oneWeek , 3600.0 , true ) ); + + // Accounts - warnings + cDesc = "Amount of warnings that triggers an automatic ban request."; + defs.add( new ConstantDefinition( "accounts.warnings.autoBan" , "Accounts - Warnings" , cDesc , 3.0 , 1.0 , true ) ); + cDesc = "Period after a warning is received during which additional warnings will be ignored (seconds)."; + defs.add( new ConstantDefinition( "accounts.warnings.grace" , "Accounts - Warnings" , cDesc , 7200.0 , 60.0 , true ) ); + cDesc = "Time after which warnings are decreased (expressed in units as defined by a.w.expiration.units)."; + defs.add( new ConstantDefinition( "accounts.warnings.expiration" , "Accounts - Warnings" , cDesc , 60.0 , 1.0 , true ) ); + cDesc = "Units used to express warning expiration time (seconds)."; + defs.add( new ConstantDefinition( "accounts.warnings.expiration.units" , "Accounts - Warnings" , cDesc , 86400.0 , 1.0 , true ) ); + + // Account inactivity + cDesc = "Time units (seconds)"; + defs.add( new ConstantDefinition( "accounts.inactivity.units" , "Accounts - Inactivity" , cDesc , oneWeek , 3600.0 , true ) ); + cDesc = "Time after which the inactivity warning e-mail is to be sent, expressed using units defined by a.i.units."; + defs.add( new ConstantDefinition( "accounts.inactivity.warningMail" , "Accounts - Inactivity" , cDesc , 3.0 , 1.0 , true ) ); + cDesc = "Time between the inactivity warning e-mail and actual account deletion, expressed using units defined by a.i.units."; + defs.add( new ConstantDefinition( "accounts.inactivity.deletion" , "Accounts - Inactivity" , cDesc , 1.0 , 1.0 , true ) ); + + // Bug reports + cDesc = "Amount of credits granted for low priority bug reports."; + defs.add( new ConstantDefinition( "bugtracker.lowCredits" , "Bug tracking system" , cDesc , 1.0 , 1.0 , true ) ); + cDesc = "Amount of credits granted for normal bug reports."; + defs.add( new ConstantDefinition( "bugtracker.mediumCredits" , "Bug tracking system" , cDesc , 2.0 , 1.0 , true ) ); + cDesc = "Amount of credits granted for critical bug reports."; + defs.add( new ConstantDefinition( "bugtracker.highCredits" , "Bug tracking system" , cDesc , 3.0 , 1.0 , true ) ); + + cm.registerConstants( defs ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ServerSessionData.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ServerSessionData.java new file mode 100644 index 0000000..22765fe --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/ServerSessionData.java @@ -0,0 +1,251 @@ +package com.deepclone.lw.beans.sys; + + +import java.net.InetAddress; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.session.SessionTypeDefiner; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionCommandException; +import com.deepclone.lw.session.SessionIdentifierException; +import com.deepclone.lw.session.SessionReference; +import com.deepclone.lw.session.SessionStateException; +import com.deepclone.lw.utils.RandomStringGenerator; + + + +/** + * Session data. + * + * @author tseeker + */ +class ServerSessionData + implements ServerSession +{ + + /** Data store */ + private Map< String , Object > storage = new HashMap< String , Object >( ); + + /** Session identifier */ + private String identifier; + + /** Definer for the session's type */ + private SessionTypeDefiner definer; + + /** Authentication challenge generator */ + private RandomStringGenerator challengeGenerator; + + /** Last authentication challenge */ + private String lastChallenge; + + /** Session expiration date */ + private Date expire; + + /** Termination reason */ + SessionTerminationType termination = null; + + /** IPv4 address of the client */ + private InetAddress address; + + /** Client type identifier */ + private String client; + + + /** + * Initialises a new session. + * + * @param generator + * authentication challenge generator + * @param definer + * session type definer + * @param client + * type of the client interface initiating the session + * @param address + * IP address the session is being initiated from + */ + public ServerSessionData( RandomStringGenerator generator , SessionTypeDefiner definer , String client , + InetAddress address ) + { + this.challengeGenerator = generator; + this.definer = definer; + this.expire = new Date( new Date( ).getTime( ) + 5000L ); + this.definer.initialise( this ); + this.client = client; + this.address = address; + } + + + /** + * Sets the session's identifier + * + * @param id + * the session's identifier + */ + public void setIdentifier( String id ) + { + this.identifier = id; + } + + + /* Documented in ServerSession interface */ + @Override + public String getIdentifier( ) + { + return this.identifier; + } + + + /* Documented in ServerSession interface */ + @Override + public String getClient( ) + { + return this.client; + } + + + /* Documented in ServerSession interface */ + @Override + public InetAddress getAddress( ) + { + return this.address; + } + + + /* Documented in ServerSession interface */ + @Override + public String getChallenge( ) + { + return this.lastChallenge; + } + + + /* Documented in ServerSession interface */ + @Override + public void setExpirationDate( Date date ) + { + this.expire = date; + } + + + /** @return the session's expiration date */ + public Date getExpirationDate( ) + { + return this.expire; + } + + + /** + * Sets the termination type and handles termination + * + * @param termination + * type of session termination + */ + synchronized public void handleTermination( SessionTerminationType termination ) + { + if ( this.termination == null ) { + this.termination = termination; + this.definer.terminate( this , termination ); + } + } + + + /* Documented in ServerSession interface */ + @Override + public SessionTerminationType getTerminationType( ) + { + return this.termination; + } + + + /* Documented in ServerSession interface */ + @Override + public void terminate( ) + { + this.handleTermination( SessionTerminationType.MANUAL ); + } + + + @Override + public void terminate( SessionTerminationType reason ) + { + this.handleTermination( reason ); + } + + + /* Documented in ServerSession interface */ + @Override + public void put( String key , Object value ) + { + if ( value == null ) { + this.storage.remove( key ); + } else { + this.storage.put( key , value ); + } + } + + + /* Documented in ServerSession interface */ + @Override + public < T > T get( String key , Class< T > type ) + { + Object obj = this.storage.get( key ); + try { + return ( obj == null ) ? null : type.cast( obj ); + } catch ( ClassCastException e ) { + return null; + } + } + + + /** + * Generates a {@link SessionReference} from the session's current state. + * + * @return the new session reference + */ + synchronized public SessionReference toSessionReference( ) + { + if ( this.termination != null ) { + return null; + } + + boolean auth = this.definer.isAuthenticated( this ); + String extra; + if ( auth ) { + extra = this.definer.getState( this ); + } else { + extra = this.challengeGenerator.generate( ); + this.lastChallenge = extra; + } + + return new SessionReference( this.identifier , this.definer.getName( ) , auth , extra ); + } + + + /** Attempts to authenticate the session */ + synchronized public void authenticate( String identifier , String sha1Hash , String md5Hash ) + throws SessionStateException , SessionIdentifierException + { + if ( this.termination != null ) { + throw new SessionIdentifierException( this.identifier ); + } + this.definer.authenticate( this , identifier , sha1Hash , md5Hash ); + } + + + /** + * Attempts to execute a command on the session + */ + synchronized public CommandResponse execute( Command command ) + throws SessionStateException , SessionCommandException , SessionIdentifierException + { + if ( this.termination != null ) { + throw new SessionIdentifierException( this.identifier ); + } + return this.definer.execute( this , command ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/SessionManagerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/SessionManagerBean.java new file mode 100644 index 0000000..dc0295a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/SessionManagerBean.java @@ -0,0 +1,396 @@ +package com.deepclone.lw.beans.sys; + + +import java.lang.ref.WeakReference; +import java.net.InetAddress; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.session.*; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.session.*; +import com.deepclone.lw.utils.RandomStringGenerator; + + + +/** + * Session management bean implementation. + * + *

+ * This class is the implementation of the session management bean. It is responsible for creating + * sessions, using its collection of type definers, for accessing the sessions, and for making them + * expire as required. + * + * @author tseeker + */ +public class SessionManagerBean + implements SessionManager , DisposableBean +{ + + /** Session type definers, by name */ + private final Map< String , WeakReference< SessionTypeDefiner > > types = new HashMap< String , WeakReference< SessionTypeDefiner > >( ); + + /** Sessions, by identifier */ + private final Map< String , ServerSessionData > sessions = new HashMap< String , ServerSessionData >( ); + + /** Random string generator for session identifiers */ + private RandomStringGenerator sessionIDGenerator; + + /** Random string generator for authentication challenges */ + private RandomStringGenerator challengeGenerator; + + /** Session clean-up task, registered to the {@link Ticker} */ + private Runnable cleanupTask; + + /** System logger for the session manager */ + private SystemLogger logger; + + + /** + * Sets the generator for session identifiers (DI) + * + * @param rsg + * reference to the random string generator to use for session identifiers + */ + @Autowired( required = true ) + @Qualifier( "sessionIdentifiers" ) + public void setSessionIDGenerator( RandomStringGenerator rsg ) + { + this.sessionIDGenerator = rsg; + } + + + /** + * Sets the generator for authentication challenges (DI) + * + * @param rsg + * reference to the random string generator to use for authentication challenges + */ + @Autowired( required = true ) + @Qualifier( "authChallenges" ) + public void setChallangeGenerator( RandomStringGenerator rsg ) + { + this.challengeGenerator = rsg; + } + + + /** + * Initialises the session clean-up task (DI) + * + * @param ticker + * reference to the ticker bean + */ + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.cleanupTask = new Runnable( ) { + + @Override + public void run( ) + { + purgeSessions( ); + } + + }; + ticker.registerTask( Ticker.Frequency.HIGH , "Sessions clean-up" , this.cleanupTask ); + } + + + /** + * Initialises the system logger (DI) + * + * @param logger + * reference to the logger bean + */ + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger.getSystemLogger( "SessionManager" ); + } + + + /** + * Removes the reference to the clean-up task. + */ + @Override + public void destroy( ) + { + this.cleanupTask = null; + synchronized ( this.sessions ) { + for ( ServerSessionData data : this.sessions.values( ) ) { + try { + this.logger.log( LogLevel.DEBUG , "expiring '" + data.getIdentifier( ) + "'" ).flush( ); + data.handleTermination( SessionTerminationType.EXPIRED ); + } catch ( RuntimeException e ) { + this.logger.log( LogLevel.ERROR , "error while terminating '" + data.getIdentifier( ) + "'" , e ) + .flush( ); + } + } + } + } + + + /** + * Finds the session type definer corresponding to a type name. + * + * @param type + * the name of the session type + * @return the session type definer, or null if it doesn't exist + */ + private SessionTypeDefiner getTypeDefiner( String type ) + { + SessionTypeDefiner definer = null; + + synchronized ( this.types ) { + WeakReference< SessionTypeDefiner > ref = this.types.get( type ); + if ( ref != null ) { + definer = ref.get( ); + if ( definer == null ) { + this.types.remove( type ); + } + } + } + + return definer; + } + + + /** + * Allocates a session identifier. + * + *

+ * This method generates an unique session identifier for the specified session, setting the + * session's identifier and storing it in the {@link #sessions} map. + * + * @param data + * the session that needs to be initialised + */ + private void allocateSessionIdentifier( ServerSessionData data ) + { + synchronized ( this.sessions ) { + String id; + do { + id = this.sessionIDGenerator.generate( ); + } while ( this.sessions.containsKey( id ) ); + data.setIdentifier( id ); + this.sessions.put( id , data ); + } + } + + + /** + * Retrieves a session from an identifier. + * + *

+ * This method attempts to retrieve a session from the {@link #sessions} map. If the session + * exists but is expired, it will be removed and the method will behave as if it didn't exist. + * + * @param id + * the session's identifier + * @return the session's data + * @throws SessionIdentifierException + * if the session doesn't exist or has expired. + */ + private ServerSessionData getSession( String id ) + throws SessionIdentifierException + { + ServerSessionData data; + synchronized ( this.sessions ) { + data = this.sessions.get( id ); + if ( data == null ) { + this.logger.log( LogLevel.INFO , "session '" + id + "' not found" ).flush( ); + throw new SessionIdentifierException( id ); + } + if ( data.getExpirationDate( ).before( new Date( ) ) ) { + this.logger.log( LogLevel.INFO , "session '" + id + "' found but expired" ).flush( ); + ServerSessionData session = this.sessions.remove( id ); + session.handleTermination( SessionTerminationType.EXPIRED ); + throw new SessionIdentifierException( id ); + } + } + return data; + } + + + /** + * Removes expired sessions. + * + *

+ * This method goes through all registered sessions, removing them from the {@link #sessions} + * map if they have expired. + */ + private void purgeSessions( ) + { + Date now = new Date( ); + List< ServerSessionData > toRemove = new LinkedList< ServerSessionData >( ); + synchronized ( this.sessions ) { + for ( ServerSessionData session : this.sessions.values( ) ) { + if ( session.getExpirationDate( ).before( now ) ) { + toRemove.add( session ); + } + } + + for ( ServerSessionData session : toRemove ) { + this.sessions.remove( session.getIdentifier( ) ); + } + } + + for ( ServerSessionData session : toRemove ) { + this.handleTermination( session , SessionTerminationType.EXPIRED ); + } + + if ( !toRemove.isEmpty( ) ) { + this.logger.log( LogLevel.TRACE , toRemove.size( ) + " session(s) removed" ).flush( ); + } + } + + + private void handleTermination( ServerSessionData session , SessionTerminationType reason ) + { + try { + session.handleTermination( reason ); + } catch ( RuntimeException e ) { + this.logger.log( LogLevel.ERROR , "error while terminating '" + session.getIdentifier( ) + "'" , e ) + .flush( ); + } + } + + + /* Documented in SessionManager interface */ + @Override + public void registerSessionType( SessionTypeDefiner definer ) + { + synchronized ( this.types ) { + this.types.put( definer.getName( ) , new WeakReference< SessionTypeDefiner >( definer ) ); + } + this.logger.log( LogLevel.INFO , "registered session type definer '" + definer.getName( ) + "'" ).flush( ); + } + + + /* Documented in SessionAccessor interface */ + @Override + public SessionReference create( String type , String client , InetAddress address ) + throws SessionInternalException + { + SessionTypeDefiner definer = this.getTypeDefiner( type ); + if ( definer == null ) { + this.logger.log( LogLevel.WARNING , "no such session type '" + type + "'" ).flush( ); + return null; + } + + ServerSessionData data; + try { + data = new ServerSessionData( this.challengeGenerator , definer , client , address ); + } catch ( RuntimeException e ) { + this.logger.log( LogLevel.ERROR , "error while creating session with type '" + type + "'" , e ).flush( ); + throw new SessionInternalException( false , e ); + } + + this.allocateSessionIdentifier( data ); + this.logger.log( LogLevel.INFO , "session " + data.getIdentifier( ) + " created (type " + type + ")" ).flush( ); + + return data.toSessionReference( ); + } + + + /* Documented in SessionAccessor interface */ + @Override + public SessionReference authenticate( String session , String identifier , String sha1Hash , String md5Hash ) + throws SessionIdentifierException , SessionStateException , SessionInternalException + { + ServerSessionData data = this.getSession( session ); + this.logger.log( LogLevel.TRACE , "attempting to authenticate session '" + session + "'" ).flush( ); + + try { + data.authenticate( identifier , sha1Hash , md5Hash ); + } catch ( SessionIdentifierException e ) { + synchronized ( this.sessions ) { + this.sessions.remove( session ); + } + throw e; + } catch ( RuntimeException e ) { + this.logger.log( LogLevel.ERROR , "error while authenticating session '" + session + "'" , e ).flush( ); + throw new SessionInternalException( false , e ); + } + + if ( data.getTerminationType( ) != null ) { + synchronized ( this.sessions ) { + this.logger.log( LogLevel.INFO , "terminated '" + session + "' during authentication" ).flush( ); + this.sessions.remove( session ); + } + } + + return data.toSessionReference( ); + } + + + /* Documented in SessionAccessor interface */ + @Override + public SessionResponse executeCommand( String session , Command command ) + throws SessionIdentifierException , SessionStateException , SessionCommandException , + SessionInternalException + { + ServerSessionData data = this.getSession( session ); + this.logger.log( LogLevel.DEBUG , "executing command " + command.getClass( ) + " on '" + session + "'" ) + .flush( ); + + CommandResponse response; + try { + response = data.execute( command ); + } catch ( SessionIdentifierException e ) { + synchronized ( this.sessions ) { + this.sessions.remove( session ); + } + throw e; + } catch ( RuntimeException e ) { + this.logger.log( LogLevel.ERROR , "error while executing command on '" + session + "'" , e ).flush( ); + throw new SessionInternalException( false , e ); + } + + if ( data.getTerminationType( ) != null ) { + this.logger.log( LogLevel.INFO , "terminated '" + session + "' during command execution" ).flush( ); + synchronized ( this.sessions ) { + this.sessions.remove( session ); + } + } + + return new SessionResponse( data.toSessionReference( ) , response ); + } + + + /* Documented in SessionAccessor interface */ + @Override + public void terminate( String session ) + throws SessionIdentifierException , SessionInternalException + { + ServerSessionData data; + synchronized ( this.sessions ) { + data = this.sessions.remove( session ); + } + if ( data == null ) { + throw new SessionIdentifierException( session ); + } else if ( data.getExpirationDate( ).before( new Date( ) ) ) { + data.handleTermination( SessionTerminationType.EXPIRED ); + throw new SessionIdentifierException( session ); + } + + try { + data.handleTermination( SessionTerminationType.MANUAL ); + this.logger.log( LogLevel.INFO , "terminated '" + session + "'" ).flush( ); + } catch ( RuntimeException e ) { + this.logger.log( LogLevel.ERROR , "error while terminating '" + session + "'" , e ).flush( ); + throw new SessionInternalException( false , e ); + } + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/SystemStatusBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/SystemStatusBean.java new file mode 100644 index 0000000..18db00f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/SystemStatusBean.java @@ -0,0 +1,302 @@ +package com.deepclone.lw.beans.sys; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.SqlOutParameter; +import org.springframework.jdbc.core.simple.SimpleJdbcCall; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.interfaces.sys.MaintenanceData; +import com.deepclone.lw.interfaces.sys.MaintenanceStatusException; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.interfaces.sys.TickStatusException; +import com.deepclone.lw.sqld.sys.Status; +import com.deepclone.lw.utils.StoredProc; + + + +public class SystemStatusBean + implements SystemStatus +{ + + /** Database interface */ + private SimpleJdbcTemplate dTemplate; + + /** Transaction template */ + private TransactionTemplate tTemplate; + + /** System status record */ + private Status status = null; + + /** Current maintenance mode record */ + private MaintenanceData maintenance = null; + + private SimpleJdbcCall doStartTick; + private SimpleJdbcCall doCheckTick; + + private StoredProc fEnterMaintenanceMode; + private StoredProc fExtendMaintenanceMode; + private StoredProc fExitMaintenanceMode; + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fEnterMaintenanceMode = new StoredProc( dataSource , "sys" , "enter_maintenance_mode" ); + this.fEnterMaintenanceMode.addParameter( "admin_id" , Types.INTEGER ); + this.fEnterMaintenanceMode.addParameter( "reason" , Types.VARCHAR ); + this.fEnterMaintenanceMode.addParameter( "duration" , Types.INTEGER ); + this.fEnterMaintenanceMode.addOutput( "success" , Types.BOOLEAN ); + + this.fExtendMaintenanceMode = new StoredProc( dataSource , "sys" , "extend_maintenance_mode" ); + this.fExtendMaintenanceMode.addParameter( "admin_id" , Types.INTEGER ); + this.fExtendMaintenanceMode.addParameter( "duration" , Types.INTEGER ); + this.fExtendMaintenanceMode.addOutput( "success" , Types.BOOLEAN ); + + this.fExitMaintenanceMode = new StoredProc( dataSource , "sys" , "exit_maintenance_mode" ); + this.fExitMaintenanceMode.addParameter( "admin_id" , Types.INTEGER ); + this.fExitMaintenanceMode.addOutput( "success" , Types.BOOLEAN ); + + this.doStartTick = new SimpleJdbcCall( dataSource ); + this.doStartTick.withCatalogName( "sys" ).withFunctionName( "start_tick" ); + this.doStartTick.withoutProcedureColumnMetaDataAccess( ); + this.doStartTick.addDeclaredParameter( new SqlOutParameter( "tick_id" , Types.BIGINT ) ); + + this.doCheckTick = new SimpleJdbcCall( dataSource ); + this.doCheckTick.withCatalogName( "sys" ).withFunctionName( "check_stuck_tick" ); + this.doCheckTick.withoutProcedureColumnMetaDataAccess( ); + this.doCheckTick.addDeclaredParameter( new SqlOutParameter( "tick_id" , Types.BIGINT ) ); + + } + + + /** + * Sets the transaction manager interface (DI) + * + * @param transactionManager + * the transaction manager + */ + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager transactionManager ) + { + this.tTemplate = new TransactionTemplate( transactionManager ); + } + + + private void loadStatus( ) + { + String sql = "SELECT * FROM sys.status"; + RowMapper< Status > mapper = new RowMapper< Status >( ) { + + @Override + public Status mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + Status s = new Status( ); + s.setNextTickIdentifier( rs.getLong( "next_tick" ) ); + s.setCurrentTick( rs.getLong( "current_tick" ) ); + s.setLastMsgRecap( rs.getTimestamp( "last_msg_recap" ) ); + s.setLastAdminRecap( rs.getTimestamp( "last_admin_recap" ) ); + s.setLastErrorCheck( rs.getTimestamp( "last_error_recap" ) ); + s.setMaintenanceStart( rs.getTimestamp( "maintenance_start" ) ); + s.setMaintenanceEnd( rs.getTimestamp( "maintenance_end" ) ); + s.setMaintenanceReason( rs.getString( "maintenance_text" ) ); + return s; + } + + }; + + this.status = this.dTemplate.queryForObject( sql , mapper ); + + // Update maintenance status + if ( this.status.getMaintenanceReason( ) != null ) { + this.maintenance = new MaintenanceData( this.status.getMaintenanceStart( ) , this.status + .getMaintenanceEnd( ) , this.status.getMaintenanceReason( ) ); + } else { + this.maintenance = null; + } + } + + + /** + * Initialises the system's status. + * + *

+ * This method attempts to read the system's previous status from the database. If the entry + * doesn't exist, it is created. Some of the record's data is then stored locally and the bean + * is marked as initialised. + */ + private void initialise( ) + { + if ( this.status != null ) { + return; + } + + // Load status + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + loadStatus( ); + } + + } ); + } + + + /* Documented in interface */ + @Override + synchronized public MaintenanceData checkMaintenance( ) + { + this.initialise( ); + return this.maintenance; + } + + + /* Documented in interface */ + @Override + synchronized public void startMaintenance( final int adminId , final String reason , final int duration ) + throws MaintenanceStatusException + { + if ( duration <= 0 || reason == null ) { + throw new IllegalArgumentException( ); + } + + boolean s = this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + Map< String , Object > m = fEnterMaintenanceMode.execute( adminId , reason , duration ); + loadStatus( ); + return (Boolean) m.get( "success" ); + } + + } ); + + if ( !s ) { + throw new MaintenanceStatusException( this.maintenance ); + } + } + + + /* Documented in interface */ + @Override + synchronized public void updateMaintenance( final int adminId , final int durationFromNow ) + throws MaintenanceStatusException + { + if ( durationFromNow <= 0 ) { + throw new IllegalArgumentException( ); + } + + boolean s = this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + Map< String , Object > m = fExtendMaintenanceMode.execute( adminId , durationFromNow ); + loadStatus( ); + return (Boolean) m.get( "success" ); + } + + } ); + + if ( !s ) { + throw new MaintenanceStatusException( ); + } + } + + + /* Documented in interface */ + @Override + synchronized public void endMaintenance( final int adminId ) + throws MaintenanceStatusException + { + boolean s = this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + Map< String , Object > m = fExitMaintenanceMode.execute( adminId ); + loadStatus( ); + return (Boolean) m.get( "success" ); + } + + } ); + + if ( !s ) { + throw new MaintenanceStatusException( ); + } + } + + + /* Documented in interface */ + @Override + synchronized public long startTick( ) + throws TickStatusException , MaintenanceStatusException + { + Long tid = this.tTemplate.execute( new TransactionCallback< Long >( ) { + + @Override + public Long doInTransaction( TransactionStatus status ) + { + Map< String , Object > m = doStartTick.execute( ); + loadStatus( ); + return (Long) m.get( "tick_id" ); + } + + } ); + + if ( tid == null ) { + if ( this.maintenance != null ) { + throw new MaintenanceStatusException( this.maintenance ); + } else { + throw new TickStatusException( this.status.getCurrentTick( ) ); + } + } + + return tid; + } + + + /* Documented in interface */ + @Override + public Long checkStuckTick( ) + throws MaintenanceStatusException + { + Long tid = this.tTemplate.execute( new TransactionCallback< Long >( ) { + + @Override + public Long doInTransaction( TransactionStatus status ) + { + Map< String , Object > m = doCheckTick.execute( ); + loadStatus( ); + return (Long) m.get( "tick_id" ); + } + + } ); + + if ( tid == null && this.maintenance != null ) { + throw new MaintenanceStatusException( this.maintenance ); + } + + return tid; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerBean.java new file mode 100644 index 0000000..b39d795 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerBean.java @@ -0,0 +1,160 @@ +package com.deepclone.lw.beans.sys; + + +import java.util.HashSet; +import java.util.Set; + +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.interfaces.eventlog.Logger; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.sys.ConstantsManager; +import com.deepclone.lw.interfaces.sys.Ticker; + + + +/** + * Task scheduler bean. + * + *

+ * This class implements Legacy Worlds' task scheduler, used for most repetitive actions such as + * updating the game's state, cleaning logs or de-activating accounts. + * + *

+ * + *

+ * ticker.interval defaults to 5 seconds. + * + * @author tseeker + */ +public class TickerBean + implements Ticker , InitializingBean , DisposableBean +{ + + /** System logger for the bean */ + private SystemLogger logger; + + /** Constants manager bean */ + private ConstantsManager constantsManager; + + /** Main thread for ticker control */ + private TickerThread mainThread; + + private TickerTaskStatusHandler tickerManager; + + + /** + * Sets the system logger (DI) + * + * @param logger + * reference to the logger bean + */ + @Autowired( required = true ) + public void setLogger( Logger logger ) + { + this.logger = logger.getSystemLogger( "Ticker" ); + } + + + /** + * Sets the constants manager (DI) + * + * @param manager + * reference to the constants manager bean + */ + @Autowired( required = true ) + public void setConstantsManager( ConstantsManager manager ) + { + this.constantsManager = manager; + } + + + @Autowired( required = true ) + public void setManager( TickerTaskStatusHandler manager ) + { + this.tickerManager = manager; + } + + + /** + * Initialises the bean. + * + *

+ * When all dependencies have been set, the bean will register the ticker.interval + * system constant. The main control thread will then be created and registered as an user of + * the constant (which causes the control thread to schedule itself using the timer). + */ + @Override + public void afterPropertiesSet( ) + { + this.logger.log( LogLevel.INFO , "Initialisation" ).flush( ); + + // Create thread + this.mainThread = new TickerThread( this.logger , this.tickerManager ); + + // Register thread as a constants user + Set< String > use = new HashSet< String >( ); + use.add( "ticker.interval" ); + this.constantsManager.registerUser( this.mainThread , use ); + } + + + /** + * Destroys the bean. + * + * This method will abort the main control thread's execution, and unregister it from the + * constants manager. + */ + @Override + public void destroy( ) + { + this.logger.log( LogLevel.INFO , "Destruction" ).flush( ); + this.mainThread.terminate( ); + this.constantsManager.unregisterUser( this.mainThread ); + this.constantsManager = null; + } + + + /* Documented in Ticker interface */ + @Override + public void registerTask( Ticker.Frequency frequency , String name , Runnable task ) + { + this.logger.log( LogLevel.DEBUG , "Registering task " + name + " at frequency " + frequency ).flush( ); + int id = this.tickerManager.registerTask( name ); + this.mainThread.registerTask( id , frequency , name , task ); + } + + + /* Documented in Ticker interface */ + @Override + public void pause( ) + throws IllegalStateException + { + this.mainThread.pause( ); + } + + + /* Documented in Ticker interface */ + @Override + public void unpause( ) + throws IllegalStateException + { + this.mainThread.unpause( ); + } + + + /* Documented in Ticker interface */ + @Override + public boolean isActive( ) + { + return this.mainThread.isActive( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerManagerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerManagerBean.java new file mode 100644 index 0000000..87a93ca --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerManagerBean.java @@ -0,0 +1,269 @@ +package com.deepclone.lw.beans.sys; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.sql.Types; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.tick.TickerTaskInfo; +import com.deepclone.lw.cmd.admin.tick.TickerTaskStatus; +import com.deepclone.lw.interfaces.sys.TickerManager; +import com.deepclone.lw.sqld.sys.TickerTaskRecord; +import com.deepclone.lw.utils.StoredProc; + + + +public class TickerManagerBean + implements TickerManager , TickerTaskStatusHandler , InitializingBean +{ + + private final Map< Integer , TickerTaskRecord > tasks = new HashMap< Integer , TickerTaskRecord >( ); + private final Map< String , Integer > taskIds = new HashMap< String , Integer >( ); + private final Set< Integer > registered = new HashSet< Integer >( ); + + private TransactionTemplate tTemplate; + private SimpleJdbcTemplate dTemplate; + + private final RowMapper< TickerTaskRecord > mTask; + + private StoredProc fRegisterTask; + private StoredProc fSetTaskStarted; + private StoredProc fSetTaskRunning; + private StoredProc fScheduleTask; + + + public TickerManagerBean( ) + { + this.mTask = new RowMapper< TickerTaskRecord >( ) { + @Override + public TickerTaskRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + TickerTaskRecord task = new TickerTaskRecord( ); + task.setId( rs.getInt( "id" ) ); + task.setName( rs.getString( "task_name" ) ); + task.setStatus( rs.getString( "status" ) ); + task.setTimestamp( rs.getTimestamp( "auto_start" ) ); + return task; + } + }; + } + + + @Autowired( required = true ) + public void setTransactionManager( PlatformTransactionManager manager ) + { + this.tTemplate = new TransactionTemplate( manager ); + } + + + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new SimpleJdbcTemplate( dataSource ); + + this.fRegisterTask = new StoredProc( dataSource , "sys" , "register_ticker_task" ); + this.fRegisterTask.addParameter( "task_name" , Types.VARCHAR ); + this.fRegisterTask.addOutput( "id" , Types.INTEGER ); + + this.fSetTaskStarted = new StoredProc( dataSource , "sys" , "set_task_started" ); + this.fSetTaskStarted.addParameter( "id" , Types.INTEGER ); + + this.fSetTaskRunning = new StoredProc( dataSource , "sys" , "set_task_running" ); + this.fSetTaskRunning.addParameter( "admin_id" , Types.INTEGER ); + this.fSetTaskRunning.addParameter( "task_id" , Types.INTEGER ); + this.fSetTaskRunning.addParameter( "running" , Types.BOOLEAN ); + + this.fScheduleTask = new StoredProc( dataSource , "sys" , "schedule_task" ); + this.fScheduleTask.addParameter( "admin_id" , Types.INTEGER ); + this.fScheduleTask.addParameter( "task_id" , Types.INTEGER ); + this.fScheduleTask.addParameter( "time_to_start" , Types.BIGINT ); + this.fScheduleTask.addOutput( "start_at" , Types.TIMESTAMP ); + } + + + private List< TickerTaskRecord > getDBTasks( ) + { + return this.tTemplate.execute( new TransactionCallback< List< TickerTaskRecord > >( ) { + @Override + public List< TickerTaskRecord > doInTransaction( TransactionStatus status ) + { + return dTemplate.query( "SELECT * FROM sys.ticker" , mTask ); + } + } ); + } + + + private void checkAutoStart( final TickerTaskRecord record ) + { + if ( record.getStatus( ).equals( "AUTO" ) ) { + Timestamp start = record.getTimestamp( ); + if ( start.before( new Date( ) ) ) { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + fSetTaskStarted.execute( record.getId( ) ); + } + } ); + record.setStatus( "RUNNING" ); + record.setTimestamp( null ); + } + } + } + + + private void setTaskRunning( final int administrator , final TickerTaskRecord record , final boolean running ) + { + this.tTemplate.execute( new TransactionCallbackWithoutResult( ) { + @Override + protected void doInTransactionWithoutResult( TransactionStatus status ) + { + fSetTaskRunning.execute( administrator , record.getId( ) , running ); + } + } ); + record.setStatus( running ? "RUNNING" : "STOPPED" ); + record.setTimestamp( null ); + } + + + @Override + public void afterPropertiesSet( ) + { + List< TickerTaskRecord > rTasks = this.getDBTasks( ); + for ( TickerTaskRecord task : rTasks ) { + this.tasks.put( task.getId( ) , task ); + this.taskIds.put( task.getName( ) , task.getId( ) ); + } + } + + + @Override + synchronized public List< TickerTaskInfo > getTasks( ) + { + List< TickerTaskInfo > result = new LinkedList< TickerTaskInfo >( ); + long now = new Date( ).getTime( ); + for ( Integer id : this.registered ) { + TickerTaskRecord record = this.tasks.get( id ); + this.checkAutoStart( record ); + + TickerTaskInfo info = new TickerTaskInfo( ); + info.setId( record.getId( ) ); + info.setName( record.getName( ) ); + info.setStatus( TickerTaskStatus.valueOf( record.getStatus( ) ) ); + if ( info.getStatus( ) == TickerTaskStatus.AUTO ) { + info.setStart( record.getTimestamp( ) ); + info.setTimeToStart( ( record.getTimestamp( ).getTime( ) - now ) / 1000 ); + } + result.add( info ); + } + return result; + } + + + @Override + synchronized public void startTask( int administrator , int id ) + { + TickerTaskRecord record = this.tasks.get( id ); + if ( record == null || record.getStatus( ).equals( "RUNNING" ) ) { + return; + } + this.setTaskRunning( administrator , record , true ); + } + + + @Override + synchronized public void stopTask( int administrator , int id ) + { + TickerTaskRecord record = this.tasks.get( id ); + if ( record == null || record.getStatus( ).equals( "STOPPED" ) ) { + return; + } + this.setTaskRunning( administrator , record , false ); + } + + + @Override + synchronized public void setTaskStart( final int administrator , final int id , final long time ) + { + if ( time <= 0 ) { + this.startTask( administrator , id ); + return; + } + + TickerTaskRecord record = this.tasks.get( id ); + if ( record == null ) { + return; + } + + Timestamp startAt = this.tTemplate.execute( new TransactionCallback< Timestamp >( ) { + @Override + public Timestamp doInTransaction( TransactionStatus status ) + { + return (Timestamp) fScheduleTask.execute( administrator , id , time ).get( "start_at" ); + } + } ); + record.setStatus( "AUTO" ); + record.setTimestamp( startAt ); + } + + + @Override + synchronized public int registerTask( final String name ) + { + Integer eId = this.taskIds.get( name ); + if ( eId != null ) { + this.registered.add( eId ); + return eId; + } + + // Register new task + eId = this.tTemplate.execute( new TransactionCallback< Integer >( ) { + @Override + public Integer doInTransaction( TransactionStatus status ) + { + return (Integer) fRegisterTask.execute( name ).get( "id" ); + } + } ); + + TickerTaskRecord record = new TickerTaskRecord( ); + record.setId( eId ); + record.setName( name ); + record.setStatus( "RUNNING" ); + record.setTimestamp( null ); + this.tasks.put( eId , record ); + this.taskIds.put( name , eId ); + + return eId; + } + + + @Override + synchronized public boolean isTaskRunning( int id ) + { + TickerTaskRecord record = this.tasks.get( id ); + this.checkAutoStart( record ); + return ( record.getStatus( ).equals( "RUNNING" ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerTask.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerTask.java new file mode 100644 index 0000000..2e33c6e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerTask.java @@ -0,0 +1,312 @@ +package com.deepclone.lw.beans.sys; + + +import java.lang.ref.WeakReference; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.interfaces.eventlog.SystemLogger; + + + +/** + * Ticker task execution class. + * + *

+ * This class is responsible for both the execution and the control of ticker tasks. + * + * @author tseeker + */ +class TickerTask + extends Thread +{ + /** Possible states of a task execution thread. */ + private static enum State { + + /** The task thread is being initialised. */ + STARTING , + + /** The task thread is waiting for instructions */ + WAITING , + + /** The task is currently being executed */ + RUNNING , + + /** The task thread is exiting. */ + EXITING , + + /** The task thread is finished. */ + FINISHED + } + + /** Reference to the system logger */ + private final SystemLogger logger; + + /** Name of the task */ + private final String name; + + /** Weak reference to the task's code */ + private final WeakReference< Runnable > task; + + /** Lock used to protect the task thread's state */ + private final Lock lock = new ReentrantLock( ); + + /** Condition triggered whenever the thread's state changes */ + private final Condition stateChanged = this.lock.newCondition( ); + + /** The thread's current state */ + private State state = State.STARTING; + + + /** + * @param name + * the task's name + * @param task + * reference to the task's code + * @param logger + * system logger instance + */ + TickerTask( String name , Runnable task , SystemLogger logger ) + { + super( "Ticker thread for '" + name + "'" ); + this.name = name; + this.task = new WeakReference< Runnable >( task ); + this.logger = logger; + } + + + /** + * Starts the task execution thread. + * + *

+ * Starts the thread itself, then waits for the thread's state to change from its default + * {@link State#STARTING} value. + */ + @Override + public void start( ) + { + super.start( ); + this.lock.lock( ); + try { + State state = this.getTaskState( ); + while ( state == State.STARTING ) { + state = this.waitTaskState( ); + } + } finally { + this.lock.unlock( ); + } + } + + + /** + * Retrieves the task execution thread's state. + * + *

+ * This method retrieves the task execution thread's state, locking {@link #lock} to prevent + * concurrent access. + * + * @return the task execution thread's current state. + */ + private State getTaskState( ) + { + this.lock.lock( ); + try { + return this.state; + } finally { + this.lock.unlock( ); + } + } + + + /** + * Changes the task execution thread's state. + * + *

+ * This method modifies the thread's state, locking {@link #lock} to prevent concurrent access + * and triggering {@link #stateChanged} once it's done. + * + * @param newState + * the thread's new state. + */ + private void setTaskState( State newState ) + { + this.lock.lock( ); + try { + this.state = newState; + this.stateChanged.signal( ); + } finally { + this.lock.unlock( ); + } + } + + + /** + * Waits for a change of state. + * + *

+ * This method waits for the task's state to change using {@link #stateChanged}, then returns + * the new state. + * + * @return the task execution thread's new state. + */ + private State waitTaskState( ) + { + this.lock.lock( ); + try { + this.stateChanged.await( ); + return this.state; + } catch ( InterruptedException e ) { + return this.state; + } finally { + this.lock.unlock( ); + } + } + + + /** + * Task execution loop. + * + *

+ * This method makes sure that the task is executed every time the state is set to + * {@link State#RUNNING}, setting it to {@link State#WAITING} when it is inactive. + * + *

+ * If the thread's state is set to {@link State#EXITING}, or if the task code is no longer + * referenced, the method will exit, setting the state to {@link State#FINISHED}. + */ + @Override + public void run( ) + { + while ( true ) { + State state; + + this.lock.lock( ); + try { + if ( this.getTaskState( ) == State.EXITING ) { + break; + } + this.setTaskState( State.WAITING ); + state = this.waitTaskState( ); + } finally { + this.lock.unlock( ); + } + + if ( state == State.EXITING || !this.runTask( ) ) { + break; + } + } + this.setTaskState( State.FINISHED ); + } + + + /** + * Runs the task's code. + * + *

+ * This method runs the task's code, if it is still referenced. All exceptions will be caught + * and logged, but they will not affect the main loop. + * + * @return true if the task was still referenced, false if it wasn't. + */ + private boolean runTask( ) + { + Runnable task = this.task.get( ); + if ( task == null ) { + this.logger.log( LogLevel.INFO , "task '" + this.name + "' is no longer referenced, exiting" ) + .flush( ); + return false; + } + + try { + this.logger.log( LogLevel.TRACE , "task '" + this.name + "' started" ).flush( ); + task.run( ); + this.logger.log( LogLevel.TRACE , "task '" + this.name + "' ended" ).flush( ); + } catch ( Throwable t ) { + this.logger.log( LogLevel.ERROR , "task '" + this.name + "' failed due to exception" , t ).flush( ); + } + + return true; + } + + + /** + * Triggers the task's execution. + * + *

+ * This method attempts to trigger the task's execution. It will not do anything if the task + * thread is exiting or finished, but if the task is still running, a warning will be added to + * the log. + */ + void startTask( ) + { + this.lock.lock( ); + try { + State state = this.getTaskState( ); + if ( state == State.EXITING || state == State.FINISHED ) { + return; + } else if ( state == State.RUNNING ) { + this.logger.log( LogLevel.WARNING , "task '" + this.name + "' didn't manage to run in time" ) + .flush( ); + return; + } + this.setTaskState( State.RUNNING ); + } finally { + this.lock.unlock( ); + } + } + + + /** + * Terminates the task execution thread. + * + *

+ * This method shuts down the task execution thread, waiting until it has completed to return. + */ + void terminate( ) + { + this.lock.lock( ); + try { + State state = this.getTaskState( ); + while ( state != State.FINISHED ) { + this.setTaskState( State.EXITING ); + state = this.waitTaskState( ); + } + } finally { + this.lock.unlock( ); + } + this.logger.log( LogLevel.DEBUG , "task '" + this.name + "' terminated" ).flush( ); + } + + + /** + * Waits until the task is done running. + * + *

+ * This method waits until the task is no longer running. If the task is not running when the + * method is called, it will return immediately. + */ + void waitForTask( ) + { + this.lock.lock( ); + try { + State state = this.getTaskState( ); + while ( state == State.RUNNING ) { + state = this.waitTaskState( ); + } + } finally { + this.lock.unlock( ); + } + } + + + /** + * @return true if the task execution thread is no longer running, + * false otherwise. + */ + boolean isFinished( ) + { + return ( this.getTaskState( ) == State.FINISHED ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerTaskStatusHandler.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerTaskStatusHandler.java new file mode 100644 index 0000000..19774e4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerTaskStatusHandler.java @@ -0,0 +1,12 @@ +package com.deepclone.lw.beans.sys; + + +public interface TickerTaskStatusHandler +{ + + public int registerTask( String name ); + + + public boolean isTaskRunning( int id ); + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerThread.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerThread.java new file mode 100644 index 0000000..db5d273 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/java/com/deepclone/lw/beans/sys/TickerThread.java @@ -0,0 +1,251 @@ +package com.deepclone.lw.beans.sys; + + +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +import com.deepclone.lw.interfaces.eventlog.SystemLogger; +import com.deepclone.lw.interfaces.sys.ConstantsUser; +import com.deepclone.lw.interfaces.sys.Ticker; + + + +/** + * Main ticker control thread. + * + *

+ * This class implements the ticker bean's main control thread, executed through a Java + * {@link Timer} instance. It supports changing the timer's period when the ticker.interval + * constant is modified, and includes the code that pauses or reactivates the ticker. + * + * @author tseeker + */ +class TickerThread + implements ConstantsUser +{ + private static class TaskStat + { + public final int id; + public final TickerTask task; + public final int modulo; + public int counter = 0; + + + public TaskStat( int id , TickerTask task , int modulo ) + { + this.id = id; + this.task = task; + this.task.start( ); + this.modulo = modulo; + } + + } + + private Timer timer; + + private long interval = 0; + + private boolean paused = false; + + private int taskIndex = 0; + + private int nTasks = 0; + + private TaskStat[] tasks; + + private TickerTaskStatusHandler handler; + + private SystemLogger logger; + + + TickerThread( SystemLogger logger , TickerTaskStatusHandler handler ) + { + this.timer = null; + this.tasks = new TaskStat[ 5 ]; + this.handler = handler; + this.logger = logger; + } + + + synchronized private void runTasks( ) + { + if ( this.paused ) { + return; + } + this.taskIndex = ( this.taskIndex + 1 ) % this.tasks.length; + + TaskStat toExecute = this.tasks[ this.taskIndex ]; + if ( toExecute == null || !this.handler.isTaskRunning( toExecute.id ) ) { + return; + } + + toExecute.counter = ( toExecute.counter + 1 ) % toExecute.modulo; + if ( toExecute.counter != 0 ) { + return; + } + + if ( toExecute.task.isFinished( ) ) { + this.tasks[ this.taskIndex ] = null; + this.nTasks--; + return; + } + + toExecute.task.startTask( ); + } + + + /** + * Updates the ticker's frequency. + * + *

+ * When the ticker.interval constant is changed, this method will cancel the current + * scheduling and re-start it using the new interval. + */ + @Override + synchronized public void setConstants( boolean initial , Map< String , Double > values ) + { + this.interval = Math.round( values.get( "ticker.interval" ) ); + this.reschedule( ); + } + + + private void reschedule( ) + { + if ( this.interval == 0 ) { + return; + } + + if ( this.timer != null ) { + this.timer.cancel( ); + } + + TimerTask task = new TimerTask( ) { + @Override + public void run( ) + { + runTasks( ); + } + }; + + this.timer = new Timer( "Main ticker thread" ); + this.timer.scheduleAtFixedRate( task , 1 , this.interval / this.tasks.length ); + } + + + synchronized void registerTask( int id , Ticker.Frequency frequency , String name , Runnable task ) + { + if ( this.nTasks == this.tasks.length ) { + TaskStat[] nState = new TaskStat[ this.tasks.length * 2 ]; + for ( int i = 0 ; i < this.tasks.length ; i++ ) { + nState[ i * 2 ] = this.tasks[ i ]; + } + this.taskIndex *= 2; + this.tasks = nState; + this.reschedule( ); + } + + int modulo; + switch ( frequency ) { + case HIGH: + modulo = 1; + break; + case LOW: + modulo = 30; + break; + case MEDIUM: + modulo = 6; + break; + case MINUTE: + modulo = 12; + break; + default: + throw new RuntimeException( "Invalid timer frequency " + frequency ); + } + + for ( int i = 0 ; i < this.tasks.length ; i++ ) { + if ( this.tasks[ i ] == null ) { + this.tasks[ i ] = new TaskStat( id , new TickerTask( name , task , this.logger ) , modulo ); + break; + } + } + this.nTasks ++; + } + + + /** + * Pauses the ticker. + * + *

+ * This method implements the bean's pause method. If the ticker is not already paused, it will + * set the {@link #paused} flag, then wait for all running tasks to complete. + * + * @throws IllegalStateException + * if the ticker is already paused. + */ + synchronized void pause( ) + throws IllegalStateException + { + if ( this.paused ) { + throw new IllegalStateException( "already paused" ); + } + this.paused = true; + for ( int i = 0 ; i < this.tasks.length ; i++ ) { + TaskStat ts = this.tasks[ i ]; + if ( ts == null ) { + continue; + } + if ( ts.task.isFinished( ) ) { + this.tasks[ i ] = null; + this.nTasks--; + continue; + } + ts.task.waitForTask( ); + } + } + + + /** + * Restarts the ticker after it's been paused. + * + * @throws IllegalStateException + * if the ticker was not paused. + */ + synchronized void unpause( ) + throws IllegalStateException + { + if ( !this.paused ) { + throw new IllegalStateException( "not paused" ); + } + this.paused = false; + } + + + /** + * Terminates all tasks in all task sets, then stops the timer. + */ + synchronized void terminate( ) + { + for ( TaskStat ts : this.tasks ) { + if ( ts == null ) { + continue; + } + ts.task.terminate( ); + } + this.nTasks = 0; + this.tasks = new TaskStat[ 5 ]; + if ( this.timer != null ) { + this.timer.cancel( ); + } + } + + + /** + * @return true the ticker is currently running or false if it has + * been paused. + */ + synchronized boolean isActive( ) + { + return !this.paused; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system-beans.xml new file mode 100644 index 0000000..7d0a16e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system-beans.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/constants-manager-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/constants-manager-bean.xml new file mode 100644 index 0000000..3603ae6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/constants-manager-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/constants-registrar-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/constants-registrar-bean.xml new file mode 100644 index 0000000..3fa577d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/constants-registrar-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/session-manager-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/session-manager-bean.xml new file mode 100644 index 0000000..dcddd03 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/session-manager-bean.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/system-status-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/system-status-bean.xml new file mode 100644 index 0000000..f8b97f4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/system-status-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/ticker-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/ticker-bean.xml new file mode 100644 index 0000000..894c846 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-system/src/main/resources/configuration/system/ticker-bean.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.classpath b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.project b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.project new file mode 100644 index 0000000..b2adbb1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-beans-user + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..ce751ed --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Wed Apr 14 12:43:45 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..6b7d8f9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Wed Apr 14 12:43:44 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/pom.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/pom.xml new file mode 100644 index 0000000..0de863a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/pom.xml @@ -0,0 +1,15 @@ + + 4.0.0 + + legacyworlds-server-beans + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-beans-user + 5.99.1 + Legacy Worlds server - user actions + This module defines beans and classes that handle user actions. + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ObjectNameValidatorBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ObjectNameValidatorBean.java new file mode 100644 index 0000000..cd3bcff --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ObjectNameValidatorBean.java @@ -0,0 +1,77 @@ +package com.deepclone.lw.beans.user; + + +import java.util.regex.Pattern; + +import com.deepclone.lw.cmd.ObjectNameError; + + + +public class ObjectNameValidatorBean +{ + + private int minLength = 2; + private int maxLength = 20; + + private static Pattern fail[] = { + Pattern.compile( "\\s\\s+" ) , + Pattern.compile( "[^A-Za-z0-9 _\\'\\!\\:\\,\\-\\.\\*@\\[\\]\\{\\}]" ) + }; + + private static Pattern needed[] = { + Pattern.compile( "[A-Za-z]" ) + }; + + + public void setMinLength( Integer v ) + { + this.minLength = v; + } + + + public void setMaxLength( Integer v ) + { + this.maxLength = v; + } + + + public ObjectNameError validate( String name ) + { + return this.customValidate( name , this.minLength , this.maxLength ); + } + + + public ObjectNameError customValidate( String name , int minLength , int maxLength ) + { + if ( "".equals( name.trim( ) ) ) { + return ObjectNameError.EMPTY; + } + + // No leading or trailing spaces + if ( !name.equals( name.trim( ) ) ) { + return ObjectNameError.INVALID; + } + + // Check length + int length = name.length( ); + if ( length < minLength || length > maxLength ) { + return ObjectNameError.INVALID; + } + + // Check bad patterns + for ( Pattern p : ObjectNameValidatorBean.fail ) { + if ( p.matcher( name ).find( ) ) { + return ObjectNameError.INVALID; + } + } + + // Check good patterns + for ( Pattern p : ObjectNameValidatorBean.needed ) { + if ( !p.matcher( name ).find( ) ) { + return ObjectNameError.INVALID; + } + } + + return null; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/AutowiredCommandDelegate.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/AutowiredCommandDelegate.java new file mode 100644 index 0000000..f412cb9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/AutowiredCommandDelegate.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.beans.user.abst; + + +public interface AutowiredCommandDelegate + extends SessionCommandDelegate +{ + + public Class< ? extends SessionCommandHandler > getCommandHandler( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/AutowiredSubTypeDelegate.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/AutowiredSubTypeDelegate.java new file mode 100644 index 0000000..fdb4455 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/AutowiredSubTypeDelegate.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.beans.user.abst; + + +public interface AutowiredSubTypeDelegate + extends SessionSubTypeDelegate +{ + + public Class< ? extends StatefulSessionTypeDefiner > getSessionType( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandDelegate.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandDelegate.java new file mode 100644 index 0000000..67f4e40 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandDelegate.java @@ -0,0 +1,18 @@ +package com.deepclone.lw.beans.user.abst; + + +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public interface SessionCommandDelegate +{ + + public Class< ? extends Command > getType( ); + + + public CommandResponse execute( ServerSession session , Command command ); + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandHandler.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandHandler.java new file mode 100644 index 0000000..7be021d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandHandler.java @@ -0,0 +1,40 @@ +package com.deepclone.lw.beans.user.abst; + + +import java.util.HashMap; +import java.util.Map; + +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionCommandException; + + + +public abstract class SessionCommandHandler +{ + + private Map< Class< ? extends Command > , SessionCommandDelegate > commands = new HashMap< Class< ? extends Command > , SessionCommandDelegate >( ); + + + public final void registerCommandDelegate( SessionCommandDelegate delegate ) + { + synchronized ( this.commands ) { + this.commands.put( delegate.getType( ) , delegate ); + } + } + + + protected final CommandResponse executeDelegate( ServerSession session , Command command ) + throws SessionCommandException + { + SessionCommandDelegate delegate; + synchronized ( this.commands ) { + delegate = this.commands.get( command.getClass( ) ); + } + if ( delegate == null ) { + throw new SessionCommandException( command.getClass( ).getCanonicalName( ) ); + } + return delegate.execute( session , command ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandWiringBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandWiringBean.java new file mode 100644 index 0000000..2d4013e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionCommandWiringBean.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.beans.user.abst; + + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + + + +public class SessionCommandWiringBean + implements BeanPostProcessor , ApplicationContextAware +{ + private final Logger logger = Logger.getLogger( SessionCommandWiringBean.class ); + private ApplicationContext context; + + + @Override + public void setApplicationContext( ApplicationContext applicationContext ) + throws BeansException + { + this.context = applicationContext; + } + + + @Override + public Object postProcessAfterInitialization( Object bean , String beanName ) + throws BeansException + { + return bean; + } + + + @Override + public Object postProcessBeforeInitialization( Object bean , String beanName ) + throws BeansException + { + if ( bean instanceof SessionCommandHandler ) { + this.logger.debug( "Wiring command handler " + beanName ); + this.autowire( (SessionCommandHandler) bean ); + } + return bean; + } + + + private void autowire( SessionCommandHandler bean ) + { + Class< ? extends SessionCommandHandler > beanType = bean.getClass( ); + + Collection< AutowiredCommandDelegate > delegates; + delegates = this.context.getBeansOfType( AutowiredCommandDelegate.class ).values( ); + + for ( AutowiredCommandDelegate delegate : delegates ) { + if ( delegate.getCommandHandler( ) != beanType ) { + continue; + } + this.logger.debug( "Adding delegate from " + delegate.getClass( ) ); + bean.registerCommandDelegate( delegate ); + } + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionSubTypeDelegate.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionSubTypeDelegate.java new file mode 100644 index 0000000..2d62372 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionSubTypeDelegate.java @@ -0,0 +1,20 @@ +package com.deepclone.lw.beans.user.abst; + + +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionCommandException; + + + +public interface SessionSubTypeDelegate +{ + + public String getName( ); + + + public CommandResponse execute( ServerSession session , Command command ) + throws SessionCommandException; + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionSubTypeWiringBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionSubTypeWiringBean.java new file mode 100644 index 0000000..d4b88e2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/SessionSubTypeWiringBean.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.beans.user.abst; + + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + + + +public class SessionSubTypeWiringBean + implements BeanPostProcessor , ApplicationContextAware +{ + private final Logger logger = Logger.getLogger( SessionSubTypeWiringBean.class ); + private ApplicationContext context; + + + @Override + public void setApplicationContext( ApplicationContext applicationContext ) + throws BeansException + { + this.context = applicationContext; + } + + + @Override + public Object postProcessAfterInitialization( Object bean , String beanName ) + throws BeansException + { + return bean; + } + + + @Override + public Object postProcessBeforeInitialization( Object bean , String beanName ) + throws BeansException + { + if ( bean instanceof StatefulSessionTypeDefiner ) { + this.logger.debug( "Wiring session type definer " + beanName ); + this.autowire( (StatefulSessionTypeDefiner) bean ); + } + return bean; + } + + + private void autowire( StatefulSessionTypeDefiner bean ) + { + Class< ? extends StatefulSessionTypeDefiner > beanType = bean.getClass( ); + + Collection< AutowiredSubTypeDelegate > delegates; + delegates = this.context.getBeansOfType( AutowiredSubTypeDelegate.class ).values( ); + + for ( AutowiredSubTypeDelegate delegate : delegates ) { + if ( delegate.getSessionType( ) != beanType ) { + continue; + } + this.logger.debug( "Adding delegate from " + delegate.getClass( ) ); + bean.registerSubType( delegate ); + } + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/StatefulSessionTypeDefiner.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/StatefulSessionTypeDefiner.java new file mode 100644 index 0000000..f544884 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/abst/StatefulSessionTypeDefiner.java @@ -0,0 +1,129 @@ +package com.deepclone.lw.beans.user.abst; + + +import java.util.HashMap; +import java.util.Map; + +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.session.SessionTypeDefiner; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionCommandException; +import com.deepclone.lw.session.SessionStateException; + + + +public abstract class StatefulSessionTypeDefiner + implements SessionTypeDefiner +{ + + private SessionSubTypeDelegate commonDelegate = null; + + private Map< String , SessionSubTypeDelegate > subTypes = new HashMap< String , SessionSubTypeDelegate >( ); + + + protected abstract String initAuthToken( ServerSession session , String identifier , String sha1Hash , + String md5Hash ); + + + protected abstract String getSessionType( ServerSession session ); + + + protected final String getAuthToken( ServerSession session ) + { + return session.get( "authenticationToken" , String.class ); + } + + + public final void registerSubType( SessionSubTypeDelegate delegate ) + { + String name = delegate.getName( ); + synchronized ( this.subTypes ) { + if ( name == null ) { + this.commonDelegate = delegate; + } else { + this.subTypes.put( delegate.getName( ) , delegate ); + } + } + } + + + private String updateSessionType( ServerSession session ) + { + String type = this.getSessionType( session ); + session.put( "sessionState" , type ); + return type; + } + + + @Override + public final String getState( ServerSession session ) + { + return session.get( "sessionState" , String.class ); + } + + + @Override + public final void authenticate( ServerSession session , String identifier , String sha1Hash , String md5Hash ) + throws SessionStateException + { + if ( this.isAuthenticated( session ) ) { + throw new SessionStateException( ); + } + + String token = this.initAuthToken( session , identifier , sha1Hash , md5Hash ); + if ( token == null ) { + return; + } + session.put( "authenticationToken" , token ); + this.updateSessionType( session ); + } + + + @Override + public final boolean isAuthenticated( ServerSession session ) + { + return ( this.getAuthToken( session ) != null ); + } + + + @Override + public final CommandResponse execute( ServerSession session , Command command ) + throws SessionStateException , SessionCommandException + { + if ( !this.isAuthenticated( session ) ) { + throw new SessionStateException( ); + } + + String type = this.updateSessionType( session ); + SessionSubTypeDelegate delegate; + SessionSubTypeDelegate fallback; + synchronized ( this.subTypes ) { + delegate = this.subTypes.get( type ); + fallback = this.commonDelegate; + } + if ( delegate == null ) { + if ( fallback == null ) { + throw new SessionStateException( ); + } else { + delegate = fallback; + fallback = null; + } + } + + CommandResponse response; + try { + response = delegate.execute( session , command ); + } catch ( SessionCommandException e ) { + if ( fallback != null ) { + response = fallback.execute( session , command ); + } else { + throw e; + } + } + + this.updateSessionType( session ); + return response; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/AdminSessionDefinerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/AdminSessionDefinerBean.java new file mode 100644 index 0000000..ee3df68 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/AdminSessionDefinerBean.java @@ -0,0 +1,98 @@ +package com.deepclone.lw.beans.user.admin; + + +import java.util.Date; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.StatefulSessionTypeDefiner; +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.session.SessionManager; +import com.deepclone.lw.sqld.admin.AdminRecord; +import com.deepclone.lw.utils.EmailAddress; + + + +public class AdminSessionDefinerBean + extends StatefulSessionTypeDefiner +{ + private Administration administration; + + + @Autowired( required = true ) + public void setSessionManager( SessionManager manager ) + { + manager.registerSessionType( this ); + } + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public String getName( ) + { + return "admin"; + } + + + @Override + public void initialise( ServerSession session ) + { + // EMPTY + } + + + @Override + protected String initAuthToken( ServerSession session , String identifier , String sha1Hash , String md5Hash ) + { + EmailAddress address = new EmailAddress( identifier ); + if ( !address.isValid( ) ) { + return null; + } + + AdminRecord admin = this.administration.login( address , session.getChallenge( ) , sha1Hash , md5Hash , session + .getAddress( ) ); + if ( admin == null ) { + return null; + } + + session.setExpirationDate( new Date( new Date( ).getTime( ) + 600000L ) ); + return ( (Integer) admin.getId( ) ).toString( ); + } + + + @Override + protected String getSessionType( ServerSession session ) + { + int adminId = Integer.parseInt( session.get( "authenticationToken" , String.class ) ); + AdminRecord admin = this.administration.getAdmin( adminId ); + session.put( "admin" , admin ); + + // Administrator has been disabled + if ( !admin.isActive( ) ) { + session.terminate( SessionTerminationType.GONE ); + return null; + } + + return ( admin.getPassChangeRequired( ) ? "pass" : "main" ); + } + + + @Override + public void terminate( ServerSession session , SessionTerminationType reason ) + { + String authToken = session.get( "authenticationToken" , String.class ); + if ( authToken != null ) { + int adminId = Integer.parseInt( session.get( "authenticationToken" , String.class ) ); + this.administration.logout( adminId ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/AdminSessionSubType.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/AdminSessionSubType.java new file mode 100644 index 0000000..95f9a7f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/AdminSessionSubType.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.beans.user.admin; + + +import java.util.Date; + +import com.deepclone.lw.beans.user.abst.AutowiredSubTypeDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.abst.StatefulSessionTypeDefiner; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionCommandException; + + + +public abstract class AdminSessionSubType + extends SessionCommandHandler + implements AutowiredSubTypeDelegate +{ + + @Override + public Class< ? extends StatefulSessionTypeDefiner > getSessionType( ) + { + return AdminSessionDefinerBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + throws SessionCommandException + { + session.setExpirationDate( new Date( new Date( ).getTime( ) + 1800000L ) ); + return this.executeDelegate( session , command ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/AdminOperation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/AdminOperation.java new file mode 100644 index 0000000..75f3790 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/AdminOperation.java @@ -0,0 +1,29 @@ +package com.deepclone.lw.beans.user.admin.common; + + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.sqld.admin.AdminRecord; + + + +public abstract class AdminOperation +{ + + protected Administrator getAdministrator( ServerSession session ) + { + return this.convertAdministrator( session.get( "admin" , AdminRecord.class ) ); + } + + + protected Administrator convertAdministrator( AdminRecord record ) + { + Administrator admin = new Administrator( ); + admin.setId( record.getId( ) ); + admin.setAddress( record.getAddress( ) ); + admin.setName( record.getName( ) ); + admin.setPrivileges( record.getPrivileges( ) ); + admin.setPasswordChange( record.getPassChangeRequired( ) ); + return admin; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/CommonCommandsBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/CommonCommandsBean.java new file mode 100644 index 0000000..834735e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/CommonCommandsBean.java @@ -0,0 +1,18 @@ +package com.deepclone.lw.beans.user.admin.common; + + +import com.deepclone.lw.beans.user.admin.AdminSessionSubType; + + + +public class CommonCommandsBean + extends AdminSessionSubType +{ + + @Override + public String getName( ) + { + return null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/CreateAuthChallengeCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/CreateAuthChallengeCommandDelegateBean.java new file mode 100644 index 0000000..4141e01 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/CreateAuthChallengeCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.admin.common; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.CreateAuthChallengeCommand; +import com.deepclone.lw.cmd.CreateAuthChallengeResponse; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.RandomStringGenerator; + + + +public class CreateAuthChallengeCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private RandomStringGenerator challengeGenerator; + + + @Autowired( required = true ) + @Qualifier( "authChallenges" ) + public void setChallangeGenerator( RandomStringGenerator rsg ) + { + this.challengeGenerator = rsg; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return CommonCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return CreateAuthChallengeCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + String challenge = this.challengeGenerator.generate( ); + session.put( "tempChallenge" , challenge ); + return new CreateAuthChallengeResponse( challenge ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/NoOperationCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/NoOperationCommandDelegateBean.java new file mode 100644 index 0000000..200f846 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/NoOperationCommandDelegateBean.java @@ -0,0 +1,51 @@ +package com.deepclone.lw.beans.user.admin.common; + + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.NoOperationCommand; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class NoOperationCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return CommonCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return NoOperationCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + NoOperationCommand command = (NoOperationCommand) cParam; + Administrator admin = this.getAdministrator( session ); + + Privileges priv = command.getRequirePrivilege( ); + AdminResponse response; + if ( priv == null ) { + response = new AdminResponse( admin ); + } else { + response = new AdminResponse( admin , admin.hasPrivilege( priv ) ); + } + + return response; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/SetPasswordCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/SetPasswordCommandDelegateBean.java new file mode 100644 index 0000000..d85a0a1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/common/SetPasswordCommandDelegateBean.java @@ -0,0 +1,96 @@ +package com.deepclone.lw.beans.user.admin.common; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.admin.SetPasswordCommand; +import com.deepclone.lw.cmd.admin.SetPasswordResponse; +import com.deepclone.lw.cmd.admin.SetPasswordResponse.PasswordChangeStatus; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.interfaces.acm.PasswordProhibitedException; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.Password; + + + +public class SetPasswordCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private Administration administration; + private int minPasswordStrength = 20; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + public void setMinPasswordStrength( int strength ) + { + this.minPasswordStrength = strength; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return CommonCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetPasswordCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + SetPasswordCommand command = (SetPasswordCommand) cParam; + + String challenge = session.get( "tempChallenge" , String.class ); + session.put( "tempChallenge" , null ); + + PasswordChangeStatus status = PasswordChangeStatus.OK; + Password pwd = null; + if ( "".equals( command.getPassword( ) ) ) { + status = PasswordChangeStatus.EMPTY; + } else if ( !command.getPassword( ).equals( command.getPasswordConfirm( ) ) ) { + status = PasswordChangeStatus.MISMATCH; + } else { + pwd = new Password( command.getPassword( ) ); + if ( pwd.getStrength( ) < this.minPasswordStrength ) { + status = PasswordChangeStatus.TOO_WEAK; + } + } + + boolean authError; + if ( status == PasswordChangeStatus.OK ) { + try { + authError = !this.administration.setPassword( admin.getId( ) , challenge , command.getSha1Auth( ) , + command.getMd5Auth( ) , pwd ); + } catch ( PasswordProhibitedException e ) { + authError = false; + status = PasswordChangeStatus.PROHIBITED; + } + } else { + authError = false; + } + + if ( !authError && status == PasswordChangeStatus.OK ) { + return new SetPasswordResponse( ); + } + return new SetPasswordResponse( admin , authError , status ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/AdminCommandsBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/AdminCommandsBean.java new file mode 100644 index 0000000..ea3eaff --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/AdminCommandsBean.java @@ -0,0 +1,18 @@ +package com.deepclone.lw.beans.user.admin.main; + + +import com.deepclone.lw.beans.user.admin.AdminSessionSubType; + + + +public class AdminCommandsBean + extends AdminSessionSubType +{ + + @Override + public String getName( ) + { + return "main"; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/AdminOverviewCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/AdminOverviewCommandDelegateBean.java new file mode 100644 index 0000000..098b55a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/AdminOverviewCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.admin.main; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.cmd.admin.AdminOverviewCommand; +import com.deepclone.lw.cmd.admin.AdminOverviewResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class AdminOverviewCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return AdminOverviewCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + AdminOverviewResponse response = this.administration.getOverview( admin ); + return response; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/BansSummaryCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/BansSummaryCommandDelegateBean.java new file mode 100644 index 0000000..481f45b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/BansSummaryCommandDelegateBean.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.beans.user.admin.main.bans; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.BansSummaryCommand; +import com.deepclone.lw.cmd.admin.bans.BansSummaryResponse; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class BansSummaryCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return BansSummaryCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BANH ) ) { + return new BansSummaryResponse( admin ); + } + return this.administration.getBansSummary( admin ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/ConfirmBanCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/ConfirmBanCommandDelegateBean.java new file mode 100644 index 0000000..541ad4e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/ConfirmBanCommandDelegateBean.java @@ -0,0 +1,63 @@ +package com.deepclone.lw.beans.user.admin.main.bans; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.ConfirmBanCommand; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class ConfirmBanCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ConfirmBanCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BANH ) ) { + return new NullResponse( ); + } + + this.administration.confirmBan( admin , ( (ConfirmBanCommand) command ).getId( ) ); + + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/LiftBanCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/LiftBanCommandDelegateBean.java new file mode 100644 index 0000000..dff587b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/LiftBanCommandDelegateBean.java @@ -0,0 +1,63 @@ +package com.deepclone.lw.beans.user.admin.main.bans; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.LiftBanCommand; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class LiftBanCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return LiftBanCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BANH ) ) { + return new NullResponse( ); + } + + this.administration.liftBan( admin , ( (LiftBanCommand) command ).getId( ) ); + + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/ListBansCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/ListBansCommandDelegateBean.java new file mode 100644 index 0000000..a326981 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/ListBansCommandDelegateBean.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.beans.user.admin.main.bans; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.ListBansCommand; +import com.deepclone.lw.cmd.admin.bans.ListBansResponse; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListBansCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListBansCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BANH ) ) { + return new ListBansResponse( admin ); + } + return this.administration.getBans( admin , ( (ListBansCommand) command ).getType( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/RejectBanCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/RejectBanCommandDelegateBean.java new file mode 100644 index 0000000..6048211 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/RejectBanCommandDelegateBean.java @@ -0,0 +1,70 @@ +package com.deepclone.lw.beans.user.admin.main.bans; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.RejectBanCommand; +import com.deepclone.lw.cmd.admin.bans.RejectBanResponse; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class RejectBanCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return RejectBanCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BANH ) ) { + return new RejectBanResponse( admin , true ); + } + + RejectBanCommand command = (RejectBanCommand) cParam; + int id = command.getId( ); + String reason = command.getReason( ).trim( ); + + if ( "".equals( reason ) ) { + return new RejectBanResponse( admin , id ); + } + + this.administration.rejectBan( admin , id , reason ); + return new RejectBanResponse( admin , false ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/RequestBanCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/RequestBanCommandDelegateBean.java new file mode 100644 index 0000000..0b6c1a5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bans/RequestBanCommandDelegateBean.java @@ -0,0 +1,72 @@ +package com.deepclone.lw.beans.user.admin.main.bans; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.RequestBanCommand; +import com.deepclone.lw.cmd.admin.bans.RequestBanResponse; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class RequestBanCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return RequestBanCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BANH ) ) { + return new RequestBanResponse( admin , true ); + } + + RequestBanCommand command = (RequestBanCommand) cParam; + String user = command.getUser( ).trim( ); + boolean empire = command.isEmpire( ); + String reason = command.getReason( ).trim( ); + + if ( "".equals( reason ) ) { + return new RequestBanResponse( admin , RequestBanResponse.Error.NO_REASON , user , empire , reason ); + } else if ( "".equals( user ) ) { + return new RequestBanResponse( admin , RequestBanResponse.Error.NOT_FOUND , user , empire , reason ); + } + + return this.administration.requestBan( admin , user , empire , reason ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/BugsSummaryCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/BugsSummaryCommandDelegateBean.java new file mode 100644 index 0000000..3549c80 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/BugsSummaryCommandDelegateBean.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.BugsSummaryCommand; +import com.deepclone.lw.cmd.admin.bt.BugsSummaryResponse; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class BugsSummaryCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return BugsSummaryCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BUGT ) ) { + return new BugsSummaryResponse( admin ); + } + return this.bugs.getSummary( admin ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/GetSnapshotCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/GetSnapshotCommandDelegateBean.java new file mode 100644 index 0000000..cc8eb91 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/GetSnapshotCommandDelegateBean.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.GetSnapshotCommand; +import com.deepclone.lw.cmd.admin.bt.GetSnapshotResponse; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetSnapshotCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetSnapshotCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BUGT ) ) { + return new GetSnapshotResponse( admin , true ); + } + long id = ( (GetSnapshotCommand) cParam ).getBugId( ); + return this.bugs.getSnapshot( admin , id ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ListBugsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ListBugsCommandDelegateBean.java new file mode 100644 index 0000000..4afcb43 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ListBugsCommandDelegateBean.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.ListBugsResponse; +import com.deepclone.lw.cmd.bt.ListBugsCommand; +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListBugsCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListBugsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BUGT ) ) { + return new ListBugsResponse( admin ); + } + + ListBugsCommand command = (ListBugsCommand) cParam; + long first = command.getFirst( ); + int count = command.getCount( ); + BugStatus status = command.getStatus( ); + boolean own = command.isOwnOnly( ); + + return this.bugs.getBugs( admin , status , own , first , count ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/MergeReportsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/MergeReportsCommandDelegateBean.java new file mode 100644 index 0000000..a81ccbc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/MergeReportsCommandDelegateBean.java @@ -0,0 +1,63 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.MergeReportsCommand; +import com.deepclone.lw.cmd.admin.bt.MergeReportsResponse; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class MergeReportsCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return MergeReportsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BUGT ) ) { + return new MergeReportsResponse( admin , true ); + } + + long id = ( (MergeReportsCommand) command ).getId1( ); + long mergeId = ( (MergeReportsCommand) command ).getId2( ); + + return this.bugs.mergeReports( admin , id , mergeId ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ModerateCommentCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ModerateCommentCommandDelegateBean.java new file mode 100644 index 0000000..21abb94 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ModerateCommentCommandDelegateBean.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.ModerateCommentCommand; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class ModerateCommentCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ModerateCommentCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( admin.hasPrivilege( Privileges.BUGT ) ) { + ModerateCommentCommand mc = (ModerateCommentCommand) command; + this.bugs.moderateComment( admin , mc.getId( ) , mc.isValidation( ) ); + } + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/PostCommentCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/PostCommentCommandDelegateBean.java new file mode 100644 index 0000000..e58f6ea --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/PostCommentCommandDelegateBean.java @@ -0,0 +1,85 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.bt.PostCommentCommand; +import com.deepclone.lw.cmd.admin.bt.PostCommentResponse; +import com.deepclone.lw.cmd.admin.bt.ViewBugResponse; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class PostCommentCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return PostCommentCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BUGT ) ) { + return new PostCommentResponse( admin , true ); + } + + long id = ( (PostCommentCommand) command ).getId( ); + String comment = ( (PostCommentCommand) command ).getComment( ).trim( ); + boolean pComment = ( (PostCommentCommand) command ).isPublicComment( ); + + ObjectNameError error; + if ( "".equals( comment ) ) { + error = ObjectNameError.EMPTY; + } else if ( comment.length( ) < 30 ) { + error = ObjectNameError.INVALID; + } else { + error = null; + } + + if ( error != null ) { + ViewBugResponse response = this.bugs.getReport( admin , id ); + if ( response.getReport( ) == null ) { + return new PostCommentResponse( admin , false ); + } + return new PostCommentResponse( admin , response.getReport( ) , response.getEvents( ) , error , comment , + pComment ); + } + + PostCommentResponse response = this.bugs.postComment( admin , id , comment , pComment ); + return response; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportBugCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportBugCommandDelegateBean.java new file mode 100644 index 0000000..af6a0be --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportBugCommandDelegateBean.java @@ -0,0 +1,87 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.ReportBugResponse; +import com.deepclone.lw.cmd.bt.ReportBugCommand; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ReportBugCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ReportBugCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BUGT ) ) { + return new ReportBugResponse( admin ); + } + + ReportBugCommand command = (ReportBugCommand) cParam; + String title = command.getTitle( ).trim( ); + String desc = command.getDescription( ).trim( ); + boolean isPublic = command.isPublicReport( ); + + ObjectNameError titleError; + if ( "".equals( title ) ) { + titleError = ObjectNameError.EMPTY; + } else if ( title.length( ) < 10 || title.length( ) > 127 ) { + titleError = ObjectNameError.INVALID; + } else { + titleError = null; + } + + ObjectNameError descError; + if ( "".equals( desc ) ) { + descError = ObjectNameError.EMPTY; + } else if ( desc.length( ) < 30 ) { + descError = ObjectNameError.INVALID; + } else { + descError = null; + } + + if ( descError != null || titleError != null ) { + return new ReportBugResponse( admin , titleError , title , descError , desc , isPublic ); + } + + return this.bugs.postReport( admin , title , desc , isPublic ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportStatusCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportStatusCommandDelegateBean.java new file mode 100644 index 0000000..c543668 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportStatusCommandDelegateBean.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.ReportStatusCommand; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class ReportStatusCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ReportStatusCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( admin.hasPrivilege( Privileges.BUGT ) ) { + ReportStatusCommand rs = (ReportStatusCommand) command; + this.bugs.setStatus( admin , rs.getId( ) , rs.getStatus( ) ); + } + return new NullResponse( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportVisibilityCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportVisibilityCommandDelegateBean.java new file mode 100644 index 0000000..b3c191a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ReportVisibilityCommandDelegateBean.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.ReportVisibilityCommand; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class ReportVisibilityCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ReportVisibilityCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( admin.hasPrivilege( Privileges.BUGT ) ) { + ReportVisibilityCommand rs = (ReportVisibilityCommand) command; + this.bugs.toggleVisibility( admin , rs.getId( ) ); + } + return new NullResponse( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ValidateReportCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ValidateReportCommandDelegateBean.java new file mode 100644 index 0000000..13c646b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ValidateReportCommandDelegateBean.java @@ -0,0 +1,67 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.ValidateReportCommand; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class ValidateReportCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ValidateReportCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( admin.hasPrivilege( Privileges.BUGT ) ) { + ValidateReportCommand vr = (ValidateReportCommand) command; + int creds = vr.getGrantCredits( ); + if ( creds < 0 ) { + creds = 0; + } else if ( creds > 3 ) { + creds = 3; + } + this.bugs.validateReport( admin , vr.getId( ) , vr.getStatus( ) , vr.isPublicReport( ) , creds , vr + .isSnapshot( ) ); + } + return new NullResponse( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ViewBugCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ViewBugCommandDelegateBean.java new file mode 100644 index 0000000..ee536dd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/bt/ViewBugCommandDelegateBean.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.beans.user.admin.main.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.ViewBugResponse; +import com.deepclone.lw.cmd.bt.ViewBugCommand; +import com.deepclone.lw.interfaces.bt.AdminBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ViewBugCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminBugs bugs; + + + @Autowired( required = true ) + public void setBugs( AdminBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewBugCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.BUGT ) ) { + return new ViewBugResponse( admin , true ); + } + + long id = ( (ViewBugCommand) command ).getId( ); + return this.bugs.getReport( admin , id ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/cnst/GetConstantsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/cnst/GetConstantsCommandDelegateBean.java new file mode 100644 index 0000000..a210352 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/cnst/GetConstantsCommandDelegateBean.java @@ -0,0 +1,84 @@ +package com.deepclone.lw.beans.user.admin.main.cnst; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.constants.Category; +import com.deepclone.lw.cmd.admin.constants.Definition; +import com.deepclone.lw.cmd.admin.constants.GetConstantsCommand; +import com.deepclone.lw.cmd.admin.constants.GetConstantsResponse; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.ConstantDefinition; +import com.deepclone.lw.interfaces.sys.ConstantsAdministration; +import com.deepclone.lw.interfaces.sys.ConstantsManager; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetConstantsCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private ConstantsManager constants; + + + @Autowired( required = true ) + public void setConstants( ConstantsManager constants ) + { + this.constants = constants; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetConstantsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.CNST ) ) { + return new GetConstantsResponse( admin ); + } + + ConstantsAdministration cAdmin = this.constants.getAdminSession( admin.getId( ) ); + List< Category > cats = new LinkedList< Category >( ); + for ( String cName : cAdmin.getCategories( ) ) { + List< Definition > defs = new LinkedList< Definition >( ); + for ( ConstantDefinition cnst : cAdmin.getConstants( cName ) ) { + Definition def = new Definition( ); + def.setName( cnst.name ); + def.setDescription( cnst.description ); + def.setValue( cnst.defaultValue ); + def.setMinValue( cnst.minValue ); + def.setMaxValue( cnst.maxValue ); + defs.add( def ); + } + + cats.add( new Category( cName , defs ) ); + } + + return new GetConstantsResponse( admin , cats ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/cnst/SetConstantCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/cnst/SetConstantCommandDelegateBean.java new file mode 100644 index 0000000..e5f27fd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/cnst/SetConstantCommandDelegateBean.java @@ -0,0 +1,96 @@ +package com.deepclone.lw.beans.user.admin.main.cnst; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.constants.Category; +import com.deepclone.lw.cmd.admin.constants.Definition; +import com.deepclone.lw.cmd.admin.constants.SetConstantCommand; +import com.deepclone.lw.cmd.admin.constants.SetConstantResponse; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.ConstantDefinition; +import com.deepclone.lw.interfaces.sys.ConstantsAdministration; +import com.deepclone.lw.interfaces.sys.ConstantsManager; +import com.deepclone.lw.interfaces.sys.InvalidConstantValue; +import com.deepclone.lw.interfaces.sys.UnknownConstantError; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class SetConstantCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private ConstantsManager constants; + + + @Autowired( required = true ) + public void setConstants( ConstantsManager constants ) + { + this.constants = constants; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetConstantCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.CNST ) ) { + return new SetConstantResponse( admin , true ); + } + + ConstantsAdministration cAdmin = this.constants.getAdminSession( admin.getId( ) ); + SetConstantCommand command = (SetConstantCommand) cParam; + try { + cAdmin.setConstant( command.getName( ) , command.getValue( ) ); + return new SetConstantResponse( admin , false ); + } catch ( UnknownConstantError e ) { + return new SetConstantResponse( admin , false ); + } catch ( InvalidConstantValue e ) { + // EMPTY + } + + List< Category > cats = new LinkedList< Category >( ); + for ( String cName : cAdmin.getCategories( ) ) { + List< Definition > defs = new LinkedList< Definition >( ); + for ( ConstantDefinition cnst : cAdmin.getConstants( cName ) ) { + Definition def = new Definition( ); + def.setName( cnst.name ); + def.setDescription( cnst.description ); + def.setValue( cnst.defaultValue ); + def.setMinValue( cnst.minValue ); + def.setMaxValue( cnst.maxValue ); + defs.add( def ); + } + + cats.add( new Category( cName , defs ) ); + } + + return new SetConstantResponse( admin , cats , command.getName( ) , command.getValue( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/ChangeLanguageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/ChangeLanguageCommandDelegateBean.java new file mode 100644 index 0000000..16bf25d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/ChangeLanguageCommandDelegateBean.java @@ -0,0 +1,96 @@ +package com.deepclone.lw.beans.user.admin.main.i18n; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.i18n.ChangeLanguageCommand; +import com.deepclone.lw.cmd.admin.i18n.ChangeLanguageResponse; +import com.deepclone.lw.cmd.admin.i18n.I18NString; +import com.deepclone.lw.cmd.admin.i18n.Language; +import com.deepclone.lw.interfaces.i18n.I18NAdministration; +import com.deepclone.lw.interfaces.i18n.I18NManager; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ChangeLanguageCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private I18NManager i18n; + + + @Autowired( required = true ) + public void setI18n( I18NManager i18n ) + { + this.i18n = i18n; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ChangeLanguageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.I18N ) ) { + return new ChangeLanguageResponse( admin ); + } + + ChangeLanguageCommand command = (ChangeLanguageCommand) cParam; + String lId = command.getId( ); + String newName = command.getName( ).trim( ); + + I18NAdministration i18n = this.i18n.getAdminSession( admin.getId( ) ); + if ( !i18n.getLanguages( ).contains( lId ) ) { + return new ChangeLanguageResponse( admin , null ); + } + + Language language = new Language( ); + List< I18NString > strings = new LinkedList< I18NString >( ); + boolean error = ( newName.length( ) < 2 || newName.length( ) > 48 ); + language.setId( lId ); + language.setName( newName ); + try { + if ( error ) { + for ( String sId : i18n.getStrings( ) ) { + strings.add( new I18NString( sId , i18n.getTranslation( lId , sId ) ) ); + } + } else { + i18n.setLanguageName( lId , newName ); + } + language.setCompletion( (int) Math.floor( i18n.getLanguageSupport( lId ) * 100 ) ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + + return error ? new ChangeLanguageResponse( admin , language , strings ) : new ChangeLanguageResponse( admin , + language ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/GetLanguageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/GetLanguageCommandDelegateBean.java new file mode 100644 index 0000000..886a5a8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/GetLanguageCommandDelegateBean.java @@ -0,0 +1,86 @@ +package com.deepclone.lw.beans.user.admin.main.i18n; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.i18n.GetLanguageCommand; +import com.deepclone.lw.cmd.admin.i18n.GetLanguageResponse; +import com.deepclone.lw.cmd.admin.i18n.I18NString; +import com.deepclone.lw.cmd.admin.i18n.Language; +import com.deepclone.lw.interfaces.i18n.I18NAdministration; +import com.deepclone.lw.interfaces.i18n.I18NManager; +import com.deepclone.lw.interfaces.i18n.UnknownLanguageException; +import com.deepclone.lw.interfaces.i18n.UnknownStringException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetLanguageCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private I18NManager i18n; + + + @Autowired( required = true ) + public void setI18n( I18NManager i18n ) + { + this.i18n = i18n; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetLanguageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.I18N ) ) { + return new GetLanguageResponse( admin ); + } + + String lId = ( (GetLanguageCommand) cParam ).getLanguage( ); + I18NAdministration i18n = this.i18n.getAdminSession( admin.getId( ) ); + + Language language = new Language( ); + List< I18NString > strings = new LinkedList< I18NString >( ); + language.setId( lId ); + try { + language.setName( i18n.getLanguageName( lId ) ); + language.setCompletion( (int) Math.floor( i18n.getLanguageSupport( lId ) * 100 ) ); + for ( String sId : i18n.getStrings( ) ) { + strings.add( new I18NString( sId , i18n.getTranslation( lId , sId ) ) ); + } + } catch ( UnknownLanguageException e ) { + return new GetLanguageResponse( admin , null , null ); + } catch ( UnknownStringException e ) { + throw new RuntimeException( e ); + } + + return new GetLanguageResponse( admin , language , strings ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/SetStringCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/SetStringCommandDelegateBean.java new file mode 100644 index 0000000..83920b5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/SetStringCommandDelegateBean.java @@ -0,0 +1,110 @@ +package com.deepclone.lw.beans.user.admin.main.i18n; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.i18n.ChangeLanguageResponse; +import com.deepclone.lw.cmd.admin.i18n.I18NString; +import com.deepclone.lw.cmd.admin.i18n.Language; +import com.deepclone.lw.cmd.admin.i18n.SetStringCommand; +import com.deepclone.lw.cmd.admin.i18n.SetStringResponse; +import com.deepclone.lw.interfaces.i18n.I18NAdministration; +import com.deepclone.lw.interfaces.i18n.I18NManager; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.UnknownLanguageException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class SetStringCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private I18NManager i18n; + + + @Autowired( required = true ) + public void setI18n( I18NManager i18n ) + { + this.i18n = i18n; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetStringCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.I18N ) ) { + return new ChangeLanguageResponse( admin ); + } + + SetStringCommand command = (SetStringCommand) cParam; + String lId = command.getLanguage( ); + String sId = command.getId( ); + String text = command.getText( ).trim( ); + + I18NAdministration i18n = this.i18n.getAdminSession( admin.getId( ) ); + if ( !i18n.getLanguages( ).contains( lId ) ) { + return new SetStringResponse( admin , null ); + } + + Language language = new Language( ); + language.setId( lId ); + + if ( !i18n.getStrings( ).contains( sId ) ) { + try { + language.setName( i18n.getLanguageName( lId ) ); + language.setCompletion( (int) Math.floor( i18n.getLanguageSupport( lId ) * 100 ) ); + } catch ( UnknownLanguageException e ) { + throw new RuntimeException( e ); + } + return new SetStringResponse( admin , language ); + } + + boolean error = "".equals( text ); + List< I18NString > strings = new LinkedList< I18NString >( ); + try { + if ( error ) { + for ( String s : i18n.getStrings( ) ) { + strings.add( new I18NString( s , i18n.getTranslation( lId , s ) ) ); + } + } else { + i18n.updateTranslation( lId , sId , text ); + } + language.setName( i18n.getLanguageName( lId ) ); + language.setCompletion( (int) Math.floor( i18n.getLanguageSupport( lId ) * 100 ) ); + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + + return error ? new SetStringResponse( admin , language , strings , sId ) : new SetStringResponse( admin , + language ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/ViewLanguagesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/ViewLanguagesCommandDelegateBean.java new file mode 100644 index 0000000..f6cfbae --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/i18n/ViewLanguagesCommandDelegateBean.java @@ -0,0 +1,81 @@ +package com.deepclone.lw.beans.user.admin.main.i18n; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.i18n.Language; +import com.deepclone.lw.cmd.admin.i18n.ViewLanguagesCommand; +import com.deepclone.lw.cmd.admin.i18n.ViewLanguagesResponse; +import com.deepclone.lw.interfaces.i18n.I18NAdministration; +import com.deepclone.lw.interfaces.i18n.I18NManager; +import com.deepclone.lw.interfaces.i18n.UnknownLanguageException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ViewLanguagesCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private I18NManager i18n; + + + @Autowired( required = true ) + public void setI18n( I18NManager i18n ) + { + this.i18n = i18n; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewLanguagesCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.I18N ) ) { + return new ViewLanguagesResponse( admin ); + } + + I18NAdministration i18n = this.i18n.getAdminSession( admin.getId( ) ); + List< Language > languages = new LinkedList< Language >( ); + for ( String lang : i18n.getLanguages( ) ) { + Language language = new Language( ); + language.setId( lang ); + try { + language.setName( i18n.getLanguageName( lang ) ); + language.setCompletion( (int) Math.floor( i18n.getLanguageSupport( lang ) * 100 ) ); + } catch ( UnknownLanguageException e ) { + throw new RuntimeException( e ); + } + languages.add( language ); + } + + return new ViewLanguagesResponse( admin , languages ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/logs/GetEntryCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/logs/GetEntryCommandDelegateBean.java new file mode 100644 index 0000000..a424309 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/logs/GetEntryCommandDelegateBean.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.beans.user.admin.main.logs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.logs.GetEntryCommand; +import com.deepclone.lw.cmd.admin.logs.GetEntryResponse; +import com.deepclone.lw.interfaces.eventlog.LogReader; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetEntryCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private LogReader logReader; + + + @Autowired( required = true ) + public void setLogReader( LogReader logReader ) + { + this.logReader = logReader; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetEntryCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.LOGS ) ) { + return new GetEntryResponse( admin , true ); + } + GetEntryCommand command = (GetEntryCommand) cParam; + return this.logReader.getEntry( admin , command.getId( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/logs/ViewLogsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/logs/ViewLogsCommandDelegateBean.java new file mode 100644 index 0000000..3bd464d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/logs/ViewLogsCommandDelegateBean.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.beans.user.admin.main.logs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.logs.ViewLogCommand; +import com.deepclone.lw.cmd.admin.logs.ViewLogResponse; +import com.deepclone.lw.interfaces.eventlog.LogReader; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ViewLogsCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private LogReader logReader; + + + @Autowired( required = true ) + public void setLogReader( LogReader logReader ) + { + this.logReader = logReader; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewLogCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.LOGS ) ) { + return new ViewLogResponse( admin ); + } + ViewLogCommand command = (ViewLogCommand) cParam; + return this.logReader.getLog( admin , command.getType( ) , command.getFirstEntry( ) , command.getCount( ) , + command.getMinLogLevel( ) , command.getComponent( ) , command.isExceptionOnly( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/EnableMaintenanceCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/EnableMaintenanceCommandDelegateBean.java new file mode 100644 index 0000000..8e06851 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/EnableMaintenanceCommandDelegateBean.java @@ -0,0 +1,88 @@ +package com.deepclone.lw.beans.user.admin.main.mntm; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.mntm.EnableMaintenanceCommand; +import com.deepclone.lw.cmd.admin.mntm.MaintenanceChangeResponse; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.MaintenanceData; +import com.deepclone.lw.interfaces.sys.MaintenanceStatusException; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class EnableMaintenanceCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private SystemStatus systemStatus; + + + @Autowired( required = true ) + public void setSystemStatus( SystemStatus systemStatus ) + { + this.systemStatus = systemStatus; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return EnableMaintenanceCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.MNTM ) ) { + return new MaintenanceChangeResponse( admin , true ); + } + + String reason = ( (EnableMaintenanceCommand) command ).getReason( ); + ObjectNameError one; + if ( "".equals( reason ) ) { + one = ObjectNameError.EMPTY; + } else if ( reason.length( ) < 10 ) { + one = ObjectNameError.INVALID; + } else { + one = null; + } + + int duration = ( (EnableMaintenanceCommand) command ).getDuration( ); + if ( duration < 1 || one != null ) { + MaintenanceData data = this.systemStatus.checkMaintenance( ); + if ( data == null ) { + data = new MaintenanceData( null , null , null ); + } + return new MaintenanceChangeResponse( admin , data.reason , data.start , data.end , reason , one , duration ); + } + + try { + this.systemStatus.startMaintenance( admin.getId( ) , reason , duration ); + } catch ( MaintenanceStatusException e ) { + // Do nothing + } + return new MaintenanceChangeResponse( admin , false ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/EndMaintenanceCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/EndMaintenanceCommandDelegateBean.java new file mode 100644 index 0000000..98ea752 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/EndMaintenanceCommandDelegateBean.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.beans.user.admin.main.mntm; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.mntm.EndMaintenanceCommand; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.MaintenanceStatusException; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class EndMaintenanceCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private SystemStatus systemStatus; + + + @Autowired( required = true ) + public void setSystemStatus( SystemStatus systemStatus ) + { + this.systemStatus = systemStatus; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return EndMaintenanceCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( admin.hasPrivilege( Privileges.MNTM ) ) { + try { + this.systemStatus.endMaintenance( admin.getId( ) ); + } catch ( MaintenanceStatusException e ) { + // Do nothing + } + } + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/ExtendMaintenanceCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/ExtendMaintenanceCommandDelegateBean.java new file mode 100644 index 0000000..2f720ed --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/ExtendMaintenanceCommandDelegateBean.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.beans.user.admin.main.mntm; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.mntm.ExtendMaintenanceCommand; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.MaintenanceStatusException; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class ExtendMaintenanceCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private SystemStatus systemStatus; + + + @Autowired( required = true ) + public void setSystemStatus( SystemStatus systemStatus ) + { + this.systemStatus = systemStatus; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ExtendMaintenanceCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + int duration = ( (ExtendMaintenanceCommand) command ).getDuration( ); + if ( duration >= 1 ) { + try { + this.systemStatus.updateMaintenance( admin.getId( ) , duration ); + } catch ( MaintenanceStatusException e ) { + // Do nothing + } + } + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/MaintenanceStatusCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/MaintenanceStatusCommandDelegateBean.java new file mode 100644 index 0000000..df78d15 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/mntm/MaintenanceStatusCommandDelegateBean.java @@ -0,0 +1,66 @@ +package com.deepclone.lw.beans.user.admin.main.mntm; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.mntm.MaintenanceStatusCommand; +import com.deepclone.lw.cmd.admin.mntm.MaintenanceStatusResponse; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.MaintenanceData; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class MaintenanceStatusCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private SystemStatus systemStatus; + + + @Autowired( required = true ) + public void setSystemStatus( SystemStatus systemStatus ) + { + this.systemStatus = systemStatus; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return MaintenanceStatusCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.MNTM ) ) { + return new MaintenanceStatusResponse( admin , true ); + } + + MaintenanceData m = this.systemStatus.checkMaintenance( ); + if ( m == null ) { + return new MaintenanceStatusResponse( admin , false ); + } + return new MaintenanceStatusResponse( admin , m.reason , m.start , m.end ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/ComposeMessageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/ComposeMessageCommandDelegateBean.java new file mode 100644 index 0000000..8805113 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/ComposeMessageCommandDelegateBean.java @@ -0,0 +1,79 @@ +package com.deepclone.lw.beans.user.admin.main.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.msg.ComposeMessageCommand; +import com.deepclone.lw.cmd.admin.msg.ComposeMessageResponse; +import com.deepclone.lw.interfaces.msg.AdminMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ComposeMessageCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AdminMessages messages; + + + @Autowired( required = true ) + public void setMessages( AdminMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ComposeMessageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + ComposeMessageCommand command = (ComposeMessageCommand) cParam; + + MessageType type = command.getType( ); + if ( type == MessageType.INTERNAL ) { + type = MessageType.EMPIRE; + } + String target = command.getTarget( ); + String title = command.getSubject( ).trim( ); + String contents = command.getContents( ).trim( ); + + boolean titleError = ( title.length( ) < 2 || title.length( ) > 64 ); + boolean contentsError = ( contents.length( ) < 2 ); + + ComposeMessageResponse response; + if ( command.getReplyTo( ) != null && command.getInbox( ) != null ) { + response = this.messages.sendReply( admin , command.getInbox( ) , command.getReplyTo( ) , type , target , + title , contents , titleError || contentsError ); + } else { + response = this.messages.sendMessage( admin , type , target , title , contents , titleError + || contentsError ); + } + response.setTitleError( titleError ); + response.setContentsError( contentsError ); + + return response; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/GetMessagesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/GetMessagesCommandDelegateBean.java new file mode 100644 index 0000000..bcac6a4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/GetMessagesCommandDelegateBean.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.beans.user.admin.main.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.msg.GetMessagesCommand; +import com.deepclone.lw.interfaces.msg.AdminMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetMessagesCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AdminMessages messages; + + + @Autowired( required = true ) + public void setMessages( AdminMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetMessagesCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + GetMessagesCommand command = (GetMessagesCommand) cParam; + return this.messages.getMessages( this.getAdministrator( session ) , command.isInbox( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/MessageBoxCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/MessageBoxCommandDelegateBean.java new file mode 100644 index 0000000..16963b9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/MessageBoxCommandDelegateBean.java @@ -0,0 +1,74 @@ +package com.deepclone.lw.beans.user.admin.main.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.msg.MessageBoxCommand; +import com.deepclone.lw.interfaces.msg.AdminMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class MessageBoxCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AdminMessages messages; + + + @Autowired( required = true ) + public void setMessages( AdminMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return MessageBoxCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + MessageBoxCommand command = (MessageBoxCommand) cParam; + Administrator admin = this.getAdministrator( session ); + + long[] selection = command.getSelection( ); + if ( selection != null && selection.length == 0 ) { + return new NullResponse( ); + } + + switch ( command.getAction( ) ) { + case DELETE: + this.messages.deleteMessages( admin , command.isInbox( ) , selection ); + break; + case MARK_READ: + this.messages.markRead( admin , selection ); + break; + case MARK_UNREAD: + this.messages.markUnread( admin , selection ); + break; + } + + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/PrepareMessageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/PrepareMessageCommandDelegateBean.java new file mode 100644 index 0000000..0324a60 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/PrepareMessageCommandDelegateBean.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.beans.user.admin.main.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.admin.msg.PrepareMessageCommand; +import com.deepclone.lw.interfaces.msg.AdminMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class PrepareMessageCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AdminMessages messages; + + + @Autowired( required = true ) + public void setMessages( AdminMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return PrepareMessageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + PrepareMessageCommand command = (PrepareMessageCommand) cParam; + Administrator admin = this.getAdministrator( session ); + MessageType type = command.getType( ); + + if ( type == null ) { + return this.messages.prepareBlankMessage( admin ); + } else if ( type == MessageType.INTERNAL ) { + return this.messages.prepareReply( admin , command.getInbox( ) , command.getId( ) ); + } + return this.messages.prepareMessageTo( admin , type , command.getId( ).intValue( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/ReadMessageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/ReadMessageCommandDelegateBean.java new file mode 100644 index 0000000..37dc669 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/ReadMessageCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.admin.main.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.msg.ReadMessageCommand; +import com.deepclone.lw.interfaces.msg.AdminMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ReadMessageCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AdminMessages messages; + + + @Autowired( required = true ) + public void setMessages( AdminMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ReadMessageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ReadMessageCommand command = (ReadMessageCommand) cParam; + Administrator admin = this.getAdministrator( session ); + return this.messages.getMessage( admin , command.isInbox( ) , command.getId( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/SendSpamCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/SendSpamCommandDelegateBean.java new file mode 100644 index 0000000..b91b7dc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/msgs/SendSpamCommandDelegateBean.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.beans.user.admin.main.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.msg.SendSpamCommand; +import com.deepclone.lw.interfaces.msg.AdminMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class SendSpamCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AdminMessages messages; + + + @Autowired( required = true ) + public void setMessages( AdminMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SendSpamCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.SPAM ) ) { + return new AdminResponse( admin , false ); + } + + SendSpamCommand command = (SendSpamCommand) cParam; + this.messages.sendSpam( admin , command.getTitle( ) , command.getBody( ) ); + return new AdminResponse( admin ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/GetNamesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/GetNamesCommandDelegateBean.java new file mode 100644 index 0000000..7afefb9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/GetNamesCommandDelegateBean.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.beans.user.admin.main.names; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.naming.GetNamesCommand; +import com.deepclone.lw.cmd.admin.naming.GetNamesResponse; +import com.deepclone.lw.interfaces.naming.NamesManager; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetNamesCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private NamesManager namesManager; + + + @Autowired( required = true ) + public void setNamesManager( NamesManager namesManager ) + { + this.namesManager = namesManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetNamesCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.NAME ) ) { + return new GetNamesResponse( admin ); + } + return this.namesManager.getNames( admin , ( (GetNamesCommand) command ).getType( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/NamesActionCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/NamesActionCommandDelegateBean.java new file mode 100644 index 0000000..d28758a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/NamesActionCommandDelegateBean.java @@ -0,0 +1,92 @@ +package com.deepclone.lw.beans.user.admin.main.names; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.naming.NameAction; +import com.deepclone.lw.cmd.admin.naming.NameType; +import com.deepclone.lw.cmd.admin.naming.NamesActionCommand; +import com.deepclone.lw.interfaces.naming.NamesManager; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class NamesActionCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private NamesManager namesManager; + + + @Autowired( required = true ) + public void setNamesManager( NamesManager namesManager ) + { + this.namesManager = namesManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return NamesActionCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.NAME ) ) { + return new NullResponse( ); + } + + NamesActionCommand command = (NamesActionCommand) cParam; + NameType type = command.getType( ); + NameAction action = command.getAction( ); + int[] ids = command.getIdentifiers( ); + if ( ids.length == 0 ) { + return new NullResponse( ); + } + + switch ( action ) { + case VALIDATE: + if ( type != NameType.ALLIANCE && type != NameType.EMPIRE ) { + this.namesManager.validateMapNames( admin , ids ); + } + break; + case REJECT: + case REJECT_BAN: + if ( type != NameType.ALLIANCE && type != NameType.EMPIRE ) { + this.namesManager.rejectMapNames( admin , ids , action == NameAction.REJECT_BAN ); + } else if ( type == NameType.ALLIANCE ) { + this.namesManager.rejectAllianceNames( admin , ids ); + } else if ( type == NameType.EMPIRE ) { + this.namesManager.rejectEmpireNames( admin , ids , action == NameAction.REJECT_BAN ); + } + break; + case RESET: + if ( type == NameType.MAP_CHANGED || type == NameType.MAP_VALIDATED ) { + this.namesManager.allowMapNameChanges( admin , ids ); + } + break; + } + + return new NullResponse( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/NamesSummaryCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/NamesSummaryCommandDelegateBean.java new file mode 100644 index 0000000..b0109d1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/names/NamesSummaryCommandDelegateBean.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.beans.user.admin.main.names; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.naming.NamesSummaryCommand; +import com.deepclone.lw.cmd.admin.naming.NamesSummaryResponse; +import com.deepclone.lw.interfaces.naming.NamesManager; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class NamesSummaryCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private NamesManager namesManager; + + + @Autowired( required = true ) + public void setNamesManager( NamesManager namesManager ) + { + this.namesManager = namesManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return NamesSummaryCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.NAME ) ) { + return new NamesSummaryResponse( admin ); + } + return this.namesManager.getSummary( admin ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/prefs/GetPrefDefaultsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/prefs/GetPrefDefaultsCommandDelegateBean.java new file mode 100644 index 0000000..55c0fed --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/prefs/GetPrefDefaultsCommandDelegateBean.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.user.admin.main.prefs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.prefs.GetPrefDefaultsCommand; +import com.deepclone.lw.cmd.admin.prefs.PrefDefaultsResponse; +import com.deepclone.lw.interfaces.prefs.PreferenceDefinitions; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetPrefDefaultsCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private PreferenceDefinitions preferences; + + + @Autowired( required = true ) + public void setPreferences( PreferenceDefinitions preferences ) + { + this.preferences = preferences; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetPrefDefaultsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.PREF ) ) { + return new PrefDefaultsResponse( admin ); + } + + return new PrefDefaultsResponse( admin , this.preferences.getDefaults( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/prefs/SetPrefDefaultCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/prefs/SetPrefDefaultCommandDelegateBean.java new file mode 100644 index 0000000..c1b7f99 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/prefs/SetPrefDefaultCommandDelegateBean.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.beans.user.admin.main.prefs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.prefs.SetPrefDefaultCommand; +import com.deepclone.lw.interfaces.prefs.PreferenceDefinitions; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class SetPrefDefaultCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private PreferenceDefinitions preferences; + + + @Autowired( required = true ) + public void setPreferences( PreferenceDefinitions preferences ) + { + this.preferences = preferences; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetPrefDefaultCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( admin.hasPrivilege( Privileges.PREF ) ) { + SetPrefDefaultCommand command = (SetPrefDefaultCommand) cParam; + this.preferences.setDefault( admin , command.getPreference( ) , command.getValue( ) ); + } + return new NullResponse( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/AddAdministratorCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/AddAdministratorCommandDelegateBean.java new file mode 100644 index 0000000..8be8246 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/AddAdministratorCommandDelegateBean.java @@ -0,0 +1,100 @@ +package com.deepclone.lw.beans.user.admin.main.su; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.ObjectNameValidatorBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.su.AddAdministratorCommand; +import com.deepclone.lw.cmd.admin.su.AddAdministratorResponse; +import com.deepclone.lw.cmd.admin.su.AddAdministratorResponse.AddressError; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class AddAdministratorCommandDelegateBean + extends SuperUserOperation +{ + + private Administration administration; + private ObjectNameValidatorBean validator; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Autowired( required = true ) + public void setValidator( ObjectNameValidatorBean validator ) + { + this.validator = validator; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return AddAdministratorCommand.class; + } + + + @Override + protected CommandResponse handleCommand( Administrator admin , Command cParam ) + { + AddAdministratorCommand command = (AddAdministratorCommand) cParam; + + // Check name + String name = command.getAppearAs( ); + ObjectNameError nameError; + if ( "".equals( name ) ) { + nameError = ObjectNameError.EMPTY; + } else { + nameError = this.validator.customValidate( name , 2 , 64 ); + } + + // Check address + String aStr = command.getAddress( ); + AddressError addrError; + if ( "".equals( aStr ) ) { + addrError = AddressError.EMPTY; + } else { + EmailAddress address = new EmailAddress( aStr ); + if ( address.isValid( ) ) { + addrError = null; + } else { + addrError = AddressError.INVALID; + } + aStr = address.getAddress( ); + } + + // Check privileges + int privileges = 0; + for ( Privileges priv : command.getPrivileges( )) { + privileges = priv.grant( privileges ); + } + boolean privError = ( privileges == 0 ); + + // If we already have errors, return + if ( addrError != null || nameError != null || privError ) { + return new AddAdministratorResponse( admin , addrError , aStr , nameError , name , privError , privileges ); + } + + return this.administration.createAdmin( admin , aStr , name , privileges ); + } + + + @Override + protected CommandResponse insufficientPrivileges( Administrator admin ) + { + return new AddAdministratorResponse( admin , true ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ListAdministratorsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ListAdministratorsCommandDelegateBean.java new file mode 100644 index 0000000..7f868b0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ListAdministratorsCommandDelegateBean.java @@ -0,0 +1,57 @@ +package com.deepclone.lw.beans.user.admin.main.su; + + +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.su.ListAdministratorsCommand; +import com.deepclone.lw.cmd.admin.su.ListAdministratorsResponse; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.sqld.admin.AdminRecord; + + + +public class ListAdministratorsCommandDelegateBean + extends SuperUserOperation +{ + + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListAdministratorsCommand.class; + } + + + @Override + protected CommandResponse handleCommand( Administrator admin , Command command ) + { + List< Administrator > result = new LinkedList< Administrator >( ); + for ( AdminRecord record : this.administration.listAdministrators( ) ) { + result.add( this.convertAdministrator( record ) ); + } + return new ListAdministratorsResponse( admin , result ); + } + + + @Override + protected CommandResponse insufficientPrivileges( Administrator admin ) + { + return new ListAdministratorsResponse( admin ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ResetAdminPasswordCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ResetAdminPasswordCommandDelegateBean.java new file mode 100644 index 0000000..6f468e8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ResetAdminPasswordCommandDelegateBean.java @@ -0,0 +1,51 @@ +package com.deepclone.lw.beans.user.admin.main.su; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.su.ResetAdminPasswordCommand; +import com.deepclone.lw.cmd.admin.su.ViewAdministratorResponse; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.sqld.admin.AdminRecord; + + + +public class ResetAdminPasswordCommandDelegateBean + extends SUExistingOperation +{ + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ResetAdminPasswordCommand.class; + } + + + @Override + protected CommandResponse handleCommand( Administrator admin , Command cParam ) + { + ResetAdminPasswordCommand command = (ResetAdminPasswordCommand) cParam; + if ( admin.getId( ) == command.getIdentifier( ) ) { + return new ViewAdministratorResponse( admin , admin ); + } + + AdminRecord record = this.administration.resetPassword( admin , command.getIdentifier( ) ); + if ( record == null ) { + return this.adminNotFound( admin ); + } + return new ViewAdministratorResponse( admin , this.convertAdministrator( record ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SUExistingOperation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SUExistingOperation.java new file mode 100644 index 0000000..8fd2238 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SUExistingOperation.java @@ -0,0 +1,25 @@ +package com.deepclone.lw.beans.user.admin.main.su; + + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.su.ViewAdministratorResponse; +import com.deepclone.lw.session.CommandResponse; + + + +abstract class SUExistingOperation + extends SuperUserOperation +{ + + protected final CommandResponse adminNotFound( Administrator admin ) + { + return new ViewAdministratorResponse( admin , false ); + } + + + @Override + protected CommandResponse insufficientPrivileges( Administrator admin ) + { + return new ViewAdministratorResponse( admin , true ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SetPrivilegesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SetPrivilegesCommandDelegateBean.java new file mode 100644 index 0000000..aae2e2d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SetPrivilegesCommandDelegateBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.user.admin.main.su; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.su.SetPrivilegesCommand; +import com.deepclone.lw.cmd.admin.su.ViewAdministratorResponse; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.sqld.admin.AdminRecord; + + + +public class SetPrivilegesCommandDelegateBean + extends SUExistingOperation +{ + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetPrivilegesCommand.class; + } + + + @Override + protected CommandResponse handleCommand( Administrator admin , Command cParam ) + { + SetPrivilegesCommand command = (SetPrivilegesCommand) cParam; + if ( command.getIdentifier( ) == admin.getId( ) ) { + return new ViewAdministratorResponse( admin , admin ); + } + + AdminRecord record = this.administration.setPrivileges( admin , command.getIdentifier( ) , command + .getPrivileges( ) ); + if ( record == null ) { + return this.adminNotFound( admin ); + } + return new ViewAdministratorResponse( admin , this.convertAdministrator( record ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SuperUserOperation.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SuperUserOperation.java new file mode 100644 index 0000000..4bf74d5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/SuperUserOperation.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.beans.user.admin.main.su; + + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +abstract class SuperUserOperation + extends AdminOperation + implements AutowiredCommandDelegate +{ + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.SUPER ) ) { + return this.insufficientPrivileges( admin ); + } + return this.handleCommand( admin , command ); + } + + + protected abstract CommandResponse handleCommand( Administrator admin , Command command ); + + + protected abstract CommandResponse insufficientPrivileges( Administrator admin ); + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ViewAdministratorCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ViewAdministratorCommandDelegateBean.java new file mode 100644 index 0000000..c593a66 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/su/ViewAdministratorCommandDelegateBean.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.beans.user.admin.main.su; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.su.ViewAdministratorCommand; +import com.deepclone.lw.cmd.admin.su.ViewAdministratorResponse; +import com.deepclone.lw.interfaces.admin.Administration; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.sqld.admin.AdminRecord; + + + +public class ViewAdministratorCommandDelegateBean + extends SUExistingOperation +{ + private Administration administration; + + + @Autowired( required = true ) + public void setAdministration( Administration administration ) + { + this.administration = administration; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewAdministratorCommand.class; + } + + + @Override + protected CommandResponse handleCommand( Administrator admin , Command cParam ) + { + ViewAdministratorCommand command = (ViewAdministratorCommand) cParam; + AdminRecord record = this.administration.getAdmin( command.getIdentifier( ) ); + if ( record == null ) { + return this.adminNotFound( admin ); + } + return new ViewAdministratorResponse( admin , this.convertAdministrator( record ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/SetTaskStatusCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/SetTaskStatusCommandDelegateBean.java new file mode 100644 index 0000000..b687457 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/SetTaskStatusCommandDelegateBean.java @@ -0,0 +1,73 @@ +package com.deepclone.lw.beans.user.admin.main.tick; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.tick.SetTaskStatusCommand; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.TickerManager; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class SetTaskStatusCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private TickerManager manager; + + + @Autowired( required = true ) + public void setManager( TickerManager manager ) + { + this.manager = manager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetTaskStatusCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.TICK ) ) { + return new NullResponse( ); + } + + SetTaskStatusCommand command = (SetTaskStatusCommand) cParam; + switch ( command.getNewStatus( ) ) { + case RUNNING: + this.manager.startTask( admin.getId( ) , command.getTask( ) ); + break; + case STOPPED: + this.manager.stopTask( admin.getId( ) , command.getTask( ) ); + break; + case AUTO: + this.manager.setTaskStart( admin.getId( ) , command.getTask( ) , command.getDelay( ) ); + break; + } + + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/TickerStatusCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/TickerStatusCommandDelegateBean.java new file mode 100644 index 0000000..07c370d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/TickerStatusCommandDelegateBean.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.beans.user.admin.main.tick; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.tick.TickerStatusCommand; +import com.deepclone.lw.cmd.admin.tick.TickerStatusResponse; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.TickerManager; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class TickerStatusCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private Ticker ticker; + private TickerManager manager; + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Autowired( required = true ) + public void setManager( TickerManager manager ) + { + this.manager = manager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return TickerStatusCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.TICK ) ) { + return new TickerStatusResponse( admin ); + } + return new TickerStatusResponse( admin , !this.ticker.isActive( ) , this.manager.getTasks( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/ToggleTickerCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/ToggleTickerCommandDelegateBean.java new file mode 100644 index 0000000..7a6bd7e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/tick/ToggleTickerCommandDelegateBean.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.user.admin.main.tick; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.tick.ToggleTickerCommand; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class ToggleTickerCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private Ticker ticker; + + + @Autowired( required = true ) + public void setTicker( Ticker ticker ) + { + this.ticker = ticker; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ToggleTickerCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + if ( this.getAdministrator( session ).hasPrivilege( Privileges.TICK ) ) { + if ( this.ticker.isActive( ) ) { + this.ticker.pause( ); + } else { + this.ticker.unpause( ); + } + } + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/GiveCreditsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/GiveCreditsCommandDelegateBean.java new file mode 100644 index 0000000..b430461 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/GiveCreditsCommandDelegateBean.java @@ -0,0 +1,66 @@ +package com.deepclone.lw.beans.user.admin.main.users; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.users.GiveCreditsCommand; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class GiveCreditsCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AccountManagement accounts; + + + @Autowired( required = true ) + public void setAccounts( AccountManagement accounts ) + { + this.accounts = accounts; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GiveCreditsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.USER ) ) { + return new NullResponse( ); + } + + int credits = ( (GiveCreditsCommand) command ).getCredits( ); + if ( credits > 0 ) { + int id = ( (GiveCreditsCommand) command ).getId( ); + this.accounts.giveCredits( admin , id , credits ); + } + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ListAccountsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ListAccountsCommandDelegateBean.java new file mode 100644 index 0000000..e8491f3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ListAccountsCommandDelegateBean.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.beans.user.admin.main.users; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.users.AccountStatus; +import com.deepclone.lw.cmd.admin.users.ListAccountsCommand; +import com.deepclone.lw.cmd.admin.users.ListAccountsResponse; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListAccountsCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AccountManagement accounts; + + + @Autowired( required = true ) + public void setAccounts( AccountManagement accounts ) + { + this.accounts = accounts; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListAccountsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.USER ) ) { + return new ListAccountsResponse( admin ); + } + + AccountStatus status = ( (ListAccountsCommand) cParam ).getStatus( ); + boolean online = ( (ListAccountsCommand) cParam ).isOnline( ); + return new ListAccountsResponse( admin , status , online , this.accounts.listAccounts( status , online ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ListSessionsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ListSessionsCommandDelegateBean.java new file mode 100644 index 0000000..fc47fcd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ListSessionsCommandDelegateBean.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.user.admin.main.users; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.users.ListSessionsCommand; +import com.deepclone.lw.cmd.admin.users.ListSessionsResponse; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListSessionsCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + private AccountManagement accounts; + + + @Autowired( required = true ) + public void setAccounts( AccountManagement accounts ) + { + this.accounts = accounts; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListSessionsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.USER ) ) { + return new ListSessionsResponse( admin ); + } + + return new ListSessionsResponse( admin , this.accounts + .viewSessions( ( (ListSessionsCommand) command ).getId( ) ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ViewAccountCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ViewAccountCommandDelegateBean.java new file mode 100644 index 0000000..e56883e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/admin/main/users/ViewAccountCommandDelegateBean.java @@ -0,0 +1,63 @@ +package com.deepclone.lw.beans.user.admin.main.users; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.admin.common.AdminOperation; +import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.users.AccountViewEntry; +import com.deepclone.lw.cmd.admin.users.ViewAccountCommand; +import com.deepclone.lw.cmd.admin.users.ViewAccountResponse; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ViewAccountCommandDelegateBean + extends AdminOperation + implements AutowiredCommandDelegate +{ + + private AccountManagement accounts; + + + @Autowired( required = true ) + public void setAccounts( AccountManagement accounts ) + { + this.accounts = accounts; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return AdminCommandsBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewAccountCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + Administrator admin = this.getAdministrator( session ); + if ( !admin.hasPrivilege( Privileges.USER ) ) { + return new ViewAccountResponse( admin ); + } + + AccountViewEntry account = this.accounts.getAccountView( ( (ViewAccountCommand) command ).getId( ) ); + return new ViewAccountResponse( admin , account ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/AccountCreationCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/AccountCreationCommandDelegateBean.java new file mode 100644 index 0000000..e13c5d7 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/AccountCreationCommandDelegateBean.java @@ -0,0 +1,142 @@ +package com.deepclone.lw.beans.user.ext; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.MailError; +import com.deepclone.lw.cmd.PasswordError; +import com.deepclone.lw.cmd.ext.CreateAccountCommand; +import com.deepclone.lw.cmd.ext.CreateAccountResponse; +import com.deepclone.lw.interfaces.acm.AccountMailException; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.mailer.MailerException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; + + + +public class AccountCreationCommandDelegateBean + extends LanguageListRequired + implements AutowiredCommandDelegate +{ + private int minPasswordStrength = 10; + private AccountManagement accountManagement; + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Autowired( required = true ) + public void setAccountManagement( AccountManagement accountManagement ) + { + this.accountManagement = accountManagement; + } + + + public void setMinPasswordStrength( int strength ) + { + this.minPasswordStrength = strength; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return ExternalSessionDefinerBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return CreateAccountCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + CreateAccountCommand command = (CreateAccountCommand) cParam; + String temp , tempConf; + + // Check mail addresses + EmailAddress address = null; + MailError mailError = null; + temp = command.getMail( ); + tempConf = command.getMailConfirm( ); + if ( temp == null || temp.trim( ).equals( "" ) ) { + mailError = MailError.EMPTY; + } else if ( !temp.equals( tempConf ) ) { + mailError = MailError.MISMATCH; + } else { + address = new EmailAddress( temp ); + if ( !address.isValid( ) ) { + mailError = MailError.INVALID; + } + } + + // Check passwords + Password password = null; + PasswordError passError = null; + temp = command.getPassword( ); + tempConf = command.getPasswordConfirm( ); + if ( temp == null || temp.trim( ).equals( "" ) ) { + passError = PasswordError.EMPTY; + } else if ( !temp.equals( tempConf ) ) { + passError = PasswordError.MISMATCH; + } else { + password = new Password( temp ); + if ( password.getStrength( ) < this.minPasswordStrength ) { + passError = PasswordError.TOO_WEAK; + } + } + + // Return error response if necessary at this point + if ( passError != null || mailError != null ) { + return this.accountValidationError( command , passError , mailError ); + } + + return this.createAccount( address , password , command.getLanguage( ) ); + } + + + private CreateAccountResponse createAccount( EmailAddress address , Password password , String language ) + { + try { + this.accountManagement.createAccount( address , password , language ); + } catch ( TranslationException e ) { + return this.accountCreationError( address.getAddress( ) , null , null ); + } catch ( AccountMailException e ) { + return this.accountCreationError( address.getAddress( ) , MailError.IN_USE , language ); + } catch ( MailerException e ) { + return this.accountCreationError( address.getAddress( ) , MailError.SEND_FAIL , language ); + } + return new CreateAccountResponse( address.getAddress( ) , language ); + } + + + private CreateAccountResponse accountValidationError( CreateAccountCommand command , PasswordError pError , + MailError mError ) + { + return new CreateAccountResponse( command.getMail( ) , command.getMailConfirm( ) , pError , mError , command + .getLanguage( ) , this.getSupportedLanguages( ) ); + } + + + private CreateAccountResponse accountCreationError( String address , MailError mError , String language ) + { + return new CreateAccountResponse( address , address , null , mError , language , this.getSupportedLanguages( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ConfPwdRecoveryCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ConfPwdRecoveryCommandDelegateBean.java new file mode 100644 index 0000000..ca87956 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ConfPwdRecoveryCommandDelegateBean.java @@ -0,0 +1,94 @@ +package com.deepclone.lw.beans.user.ext; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.ext.ConfirmPasswordRecoveryCommand; +import com.deepclone.lw.cmd.ext.ConfirmPasswordRecoveryResponse; +import com.deepclone.lw.cmd.ext.RequestPasswordRecoveryResponse; +import com.deepclone.lw.cmd.ext.ConfirmPasswordRecoveryResponse.PasswordRecoveryStatus; +import com.deepclone.lw.cmd.ext.RequestPasswordRecoveryResponse.PasswordRecoveryRequestStatus; +import com.deepclone.lw.interfaces.acm.AccountMailException; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.acm.PasswordProhibitedException; +import com.deepclone.lw.interfaces.acm.PasswordRecoveryException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; + + + +public class ConfPwdRecoveryCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManagement; + private int minPasswordStrength = 10; + + + @Autowired( required = true ) + public void setAccountManagement( AccountManagement accountManagement ) + { + this.accountManagement = accountManagement; + } + + + public void setMinPasswordStrength( int strength ) + { + this.minPasswordStrength = strength; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return ExternalSessionDefinerBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ConfirmPasswordRecoveryCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ConfirmPasswordRecoveryCommand command = (ConfirmPasswordRecoveryCommand) cParam; + EmailAddress address = new EmailAddress( command.getMailAddress( ) ); + if ( !address.isValid( ) ) { + return new ConfirmPasswordRecoveryResponse( PasswordRecoveryStatus.INVALID_MAIL ); + } + if ( !command.getPassword( ).equals( command.getPasswordConfirm( ) ) ) { + return new ConfirmPasswordRecoveryResponse( PasswordRecoveryStatus.MISMATCH_PASSWORD ); + } + + Password pwd = new Password( command.getPassword( ) ); + if ( pwd.getStrength( ) < this.minPasswordStrength ) { + return new ConfirmPasswordRecoveryResponse( PasswordRecoveryStatus.WEAK_PASSWORD ); + } + + String token = command.getToken( ); + try { + this.accountManagement.recoverPassword( address , token , pwd ); + } catch ( AccountMailException e ) { + return new ConfirmPasswordRecoveryResponse( PasswordRecoveryStatus.NOT_FOUND ); + } catch ( PasswordRecoveryException e ) { + if ( e.statusProblem ) { + return new RequestPasswordRecoveryResponse( PasswordRecoveryRequestStatus.ACCOUNT_STATUS ); + } + return new ConfirmPasswordRecoveryResponse( PasswordRecoveryStatus.NOT_FOUND ); + } catch ( PasswordProhibitedException e ) { + return new ConfirmPasswordRecoveryResponse( PasswordRecoveryStatus.PROHIBITED ); + } + + return new ConfirmPasswordRecoveryResponse( PasswordRecoveryStatus.OK ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ExternalSessionDefinerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ExternalSessionDefinerBean.java new file mode 100644 index 0000000..9deade5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ExternalSessionDefinerBean.java @@ -0,0 +1,103 @@ +package com.deepclone.lw.beans.user.ext; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.MaintenanceResponse; +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.session.SessionManager; +import com.deepclone.lw.interfaces.session.SessionTypeDefiner; +import com.deepclone.lw.interfaces.sys.MaintenanceData; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionCommandException; +import com.deepclone.lw.session.SessionStateException; + + + +public class ExternalSessionDefinerBean + extends SessionCommandHandler + implements SessionTypeDefiner +{ + + private SystemStatus systemStatus; + + + @Autowired( required = true ) + public void setSessionManager( SessionManager manager ) + { + manager.registerSessionType( this ); + } + + + @Autowired( required = true ) + public void setSystemStatus( SystemStatus systemStatus ) + { + this.systemStatus = systemStatus; + } + + + @Override + public String getName( ) + { + return "ext"; + } + + + @Override + public boolean isAuthenticated( ServerSession session ) + { + return true; + } + + + @Override + public String getState( ServerSession session ) + { + return null; + } + + + @Override + public void initialise( ServerSession session ) + { + // EMPTY + } + + + @Override + public void authenticate( ServerSession session , String identifier , String sha1Hash , String md5Hash ) + throws SessionStateException + { + throw new SessionStateException( ); + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + throws SessionStateException , SessionCommandException + { + try { + // Check maintenance + MaintenanceData mData = this.systemStatus.checkMaintenance( ); + if ( mData != null ) { + return new MaintenanceResponse( mData.start , mData.end , mData.reason ); + } + + return this.executeDelegate( session , command ); + } finally { + session.terminate( ); + } + } + + + @Override + public void terminate( ServerSession session , SessionTerminationType reason ) + { + // EMPTY + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/LanguageListRequired.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/LanguageListRequired.java new file mode 100644 index 0000000..b60f11d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/LanguageListRequired.java @@ -0,0 +1,30 @@ +package com.deepclone.lw.beans.user.ext; + + +import java.util.HashMap; +import java.util.Map; + +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.i18n.UnknownLanguageException; + + + +abstract class LanguageListRequired +{ + protected Translator translator; + + + protected Map< String , String > getSupportedLanguages( ) + { + Map< String , String > result = new HashMap< String , String >( ); + for ( String lId : this.translator.getSupportedLanguages( ) ) { + try { + result.put( lId , this.translator.getLanguageName( lId ) ); + } catch ( UnknownLanguageException e ) { + // EMPTY + } + } + return result; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ListLanguagesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ListLanguagesCommandDelegateBean.java new file mode 100644 index 0000000..256fae2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ListLanguagesCommandDelegateBean.java @@ -0,0 +1,49 @@ +package com.deepclone.lw.beans.user.ext; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.ext.ListLanguagesCommand; +import com.deepclone.lw.cmd.ext.ListLanguagesResponse; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListLanguagesCommandDelegateBean + extends LanguageListRequired + implements AutowiredCommandDelegate +{ + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return ExternalSessionDefinerBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListLanguagesCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + return new ListLanguagesResponse( this.getSupportedLanguages( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ReqPwdRecoveryCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ReqPwdRecoveryCommandDelegateBean.java new file mode 100644 index 0000000..bcd48dd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/ext/ReqPwdRecoveryCommandDelegateBean.java @@ -0,0 +1,74 @@ +package com.deepclone.lw.beans.user.ext; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.ext.RequestPasswordRecoveryCommand; +import com.deepclone.lw.cmd.ext.RequestPasswordRecoveryResponse; +import com.deepclone.lw.cmd.ext.RequestPasswordRecoveryResponse.PasswordRecoveryRequestStatus; +import com.deepclone.lw.interfaces.acm.AccountMailException; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.acm.PasswordRecoveryException; +import com.deepclone.lw.interfaces.mailer.MailerException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class ReqPwdRecoveryCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManagement; + + + @Autowired( required = true ) + public void setAccountManagement( AccountManagement accountManagement ) + { + this.accountManagement = accountManagement; + } + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return ExternalSessionDefinerBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return RequestPasswordRecoveryCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + RequestPasswordRecoveryCommand command = (RequestPasswordRecoveryCommand) cParam; + EmailAddress address = new EmailAddress( command.getMailAddress( ) ); + if ( !address.isValid( ) ) { + return new RequestPasswordRecoveryResponse( PasswordRecoveryRequestStatus.INVALID_INPUT ); + } + + try { + this.accountManagement.requestPasswordRecovery( address ); + } catch ( AccountMailException e ) { + return new RequestPasswordRecoveryResponse( PasswordRecoveryRequestStatus.ACCOUNT_NOT_FOUND ); + } catch ( MailerException e ) { + return new RequestPasswordRecoveryResponse( PasswordRecoveryRequestStatus.MAIL_ERROR ); + } catch ( PasswordRecoveryException e ) { + if ( e.statusProblem ) { + return new RequestPasswordRecoveryResponse( PasswordRecoveryRequestStatus.ACCOUNT_STATUS ); + } + return new RequestPasswordRecoveryResponse( PasswordRecoveryRequestStatus.RECOVERY_IN_PROGRESS ); + } + + return new RequestPasswordRecoveryResponse( PasswordRecoveryRequestStatus.OK ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/BanDetailsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/BanDetailsCommandDelegateBean.java new file mode 100644 index 0000000..40fecce --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/BanDetailsCommandDelegateBean.java @@ -0,0 +1,51 @@ +package com.deepclone.lw.beans.user.player; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.player.account.BanDetailsCommand; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class BanDetailsCommandDelegateBean + implements AutowiredCommandDelegate +{ + private AccountManagement manager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement manager ) + { + this.manager = manager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return BannedSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return BanDetailsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + return this.manager.getBanDetails( address ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/BannedSubTypeBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/BannedSubTypeBean.java new file mode 100644 index 0000000..65e4a57 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/BannedSubTypeBean.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.beans.user.player; + + +public class BannedSubTypeBean + extends PlayerSessionSubType +{ + + @Override + public String getName( ) + { + return "banned"; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/DisabledSubTypeBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/DisabledSubTypeBean.java new file mode 100644 index 0000000..3d4c243 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/DisabledSubTypeBean.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.beans.user.player; + + +public class DisabledSubTypeBean + extends PlayerSessionSubType +{ + + @Override + public String getName( ) + { + return "disabled"; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/GameSubTypeBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/GameSubTypeBean.java new file mode 100644 index 0000000..45a031a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/GameSubTypeBean.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.beans.user.player; + + +public class GameSubTypeBean + extends PlayerSessionSubType +{ + + @Override + public String getName( ) + { + return "game"; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/GetLanguageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/GetLanguageCommandDelegateBean.java new file mode 100644 index 0000000..8e7cb38 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/GetLanguageCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.player.account.GetLanguageCommand; +import com.deepclone.lw.cmd.player.account.GetLanguageResponse; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.utils.EmailAddress; + + + +public class GetLanguageCommandDelegateBean + implements AutowiredCommandDelegate + +{ + private AccountManagement manager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement manager ) + { + this.manager = manager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetLanguageCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return PlayerCommonCommandsBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + EmailAddress addr = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + Account accnt = this.manager.getAccount( addr ); + return new GetLanguageResponse( accnt.getLanguage( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerCommonCommandsBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerCommonCommandsBean.java new file mode 100644 index 0000000..8efb566 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerCommonCommandsBean.java @@ -0,0 +1,15 @@ +package com.deepclone.lw.beans.user.player; + + +public class PlayerCommonCommandsBean + extends PlayerSessionSubType + +{ + + @Override + public String getName( ) + { + return null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerSessionDefinerBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerSessionDefinerBean.java new file mode 100644 index 0000000..d392014 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerSessionDefinerBean.java @@ -0,0 +1,167 @@ +package com.deepclone.lw.beans.user.player; + + +import java.util.Date; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.StatefulSessionTypeDefiner; +import com.deepclone.lw.cmd.admin.users.AccountStatus; +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.acm.AccountSession; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.session.SessionManager; +import com.deepclone.lw.interfaces.sys.MaintenanceData; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.utils.EmailAddress; + + + +public class PlayerSessionDefinerBean + extends StatefulSessionTypeDefiner +{ + private SystemStatus systemStatus; + private AccountManagement accountManagement; + private EmpireManagement empireManagement; + + + @Autowired( required = true ) + public void setSystemStatus( SystemStatus systemStatus ) + { + this.systemStatus = systemStatus; + } + + + @Autowired( required = true ) + public void setAccountManagement( AccountManagement accountManagement ) + { + this.accountManagement = accountManagement; + } + + + @Autowired( required = true ) + public void setEmpireManagement( EmpireManagement empireManagement ) + { + this.empireManagement = empireManagement; + } + + + @Autowired( required = true ) + public void setSessionManager( SessionManager manager ) + { + manager.registerSessionType( this ); + } + + + @Override + public String getName( ) + { + return "player"; + } + + + @Override + public void initialise( ServerSession session ) + { + // EMPTY + } + + + @Override + protected String getSessionType( ServerSession session ) + { + // If the system is under maintenance, do not check + MaintenanceData mData = this.systemStatus.checkMaintenance( ); + if ( mData != null ) { + return this.getState( session ); + } + + // Get account status + Account account = this.accountManagement.restoreSession( session.get( "sessionId" , Long.class ) ); + if ( account == null ) { + session.terminate( SessionTerminationType.GONE ); + return null; + } + AccountStatus status = account.getStatus( ); + + switch ( status ) { + case ACTIVE: + case QUITTING: + case START_VACATION: + case VACATION: + session.put( "vacation" , (Boolean) ( status == AccountStatus.VACATION ) ); + this.updateEmpireId( session ); + return "game"; + } + + session.put( "empireId" , null ); + switch ( status ) { + case UNCONFIRMED: + case REACTIVATING: + return "validation"; + case BANNED: + return "banned"; + case DISABLED: + return "disabled"; + } + + return null; + } + + + private void updateEmpireId( ServerSession session ) + { + if ( session.get( "empireId" , Integer.class ) != null ) { + return; + } + session.put( "empireId" , this.empireManagement.getEmpireId( this.getPlayer( session ) ) ); + } + + + @Override + protected String initAuthToken( ServerSession session , String identifier , String sha1Hash , String md5Hash ) + { + // If the system is under maintenance, do not check + MaintenanceData mData = this.systemStatus.checkMaintenance( ); + if ( mData != null ) { + return null; + } + + EmailAddress address = new EmailAddress( identifier ); + if ( !address.isValid( ) ) { + return null; + } + + AccountSession lResult; + lResult = this.accountManagement.login( address , session.getChallenge( ) , sha1Hash , md5Hash , session + .getAddress( ) , session.getClient( ) , session.getIdentifier( ) ); + if ( lResult == null ) { + return null; + } + + // FIXME: that should not be hardcoded + session.setExpirationDate( new Date( new Date( ).getTime( ) + 1800000L ) ); + session.put( "sessionId" , (Long) lResult.session ); + return address.getAddress( ); + } + + + @Override + public void terminate( ServerSession session , SessionTerminationType reason ) + { + if ( !this.isAuthenticated( session ) ) { + return; + } + + this.accountManagement.logout( session.get( "sessionId" , Long.class ) , reason ); + } + + + private EmailAddress getPlayer( ServerSession session ) + { + return new EmailAddress( this.getAuthToken( session ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerSessionSubType.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerSessionSubType.java new file mode 100644 index 0000000..f2adad6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/PlayerSessionSubType.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.beans.user.player; + + +import java.util.Date; + +import com.deepclone.lw.beans.user.abst.AutowiredSubTypeDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.abst.StatefulSessionTypeDefiner; +import com.deepclone.lw.cmd.MaintenanceResponse; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.interfaces.sys.MaintenanceData; +import com.deepclone.lw.interfaces.sys.SystemStatus; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionCommandException; + + + +abstract class PlayerSessionSubType + extends SessionCommandHandler + implements AutowiredSubTypeDelegate +{ + + private SystemStatus systemStatus; + + + public void setSystemStatus( SystemStatus systemStatus ) + { + this.systemStatus = systemStatus; + } + + + @Override + public final Class< ? extends StatefulSessionTypeDefiner > getSessionType( ) + { + return PlayerSessionDefinerBean.class; + } + + + @Override + public final CommandResponse execute( ServerSession session , Command command ) + throws SessionCommandException + { + MaintenanceData mData = this.systemStatus.checkMaintenance( ); + if ( mData != null ) { + return new MaintenanceResponse( mData.start , mData.end , mData.reason ); + } + //FIXME: that should not be hardcoded + session.setExpirationDate( new Date( new Date( ).getTime( ) + 1800000L ) ); + return this.executeDelegate( session , command ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ReactivateCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ReactivateCommandDelegateBean.java new file mode 100644 index 0000000..cba702e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ReactivateCommandDelegateBean.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.beans.user.player; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.player.account.AccountReactivationCommand; +import com.deepclone.lw.cmd.player.account.AccountReactivationResponse; +import com.deepclone.lw.interfaces.acm.AccountMailException; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.mailer.MailerException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class ReactivateCommandDelegateBean + implements AutowiredCommandDelegate + +{ + private AccountManagement manager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement manager ) + { + this.manager = manager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return AccountReactivationCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return DisabledSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + String address = session.get( "authenticationToken" , String.class ); + boolean rv; + try { + this.manager.reactivateAccount( new EmailAddress( address ) ); + rv = true; + } catch ( AccountMailException e ) { + rv = false; + } catch ( MailerException e ) { + rv = false; + } + return new AccountReactivationResponse( address , rv ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ValidationCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ValidationCommandDelegateBean.java new file mode 100644 index 0000000..6633bb8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ValidationCommandDelegateBean.java @@ -0,0 +1,132 @@ +package com.deepclone.lw.beans.user.player; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.ObjectNameValidatorBean; +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.account.AccountValidationCommand; +import com.deepclone.lw.cmd.player.account.AccountValidationResponse; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.sqld.accounts.ValidationResult; +import com.deepclone.lw.utils.EmailAddress; + + + +public class ValidationCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement manager; + private ObjectNameValidatorBean validator; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement manager ) + { + this.manager = manager; + } + + + @Autowired( required = true ) + public void setObjectNameValidator( ObjectNameValidatorBean validator ) + { + this.validator = validator; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return ValidationSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return AccountValidationCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + AccountValidationCommand command = (AccountValidationCommand) cParam; + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + + if ( command.isInitialisation( ) ) { + return new AccountValidationResponse( this.manager.getEmpireNames( address ) ); + } + + AccountValidationResponse vResponse; + + // Validate empire / planet names + vResponse = this.validateNames( command , address ); + if ( vResponse != null ) { + return vResponse; + } + + // Actual validation / game registration + ValidationResult result; + result = this.manager.validateAccount( address , command.getToken( ) , command.getEmpire( ) , command + .getPlanet( ) ); + + if ( result.isError( ) ) { + return this.makeError( command , address , result ); + } + + return new AccountValidationResponse( ); + } + + + private AccountValidationResponse validateNames( AccountValidationCommand command , EmailAddress address ) + { + ObjectNameError eOne = this.validator.validate( command.getEmpire( ) ); + ObjectNameError pOne = this.validator.validate( command.getPlanet( ) ); + if ( eOne == null && pOne == null ) { + return null; + } + return this.makeError( command , address , false , eOne , pOne ); + } + + + private CommandResponse makeError( AccountValidationCommand command , EmailAddress address , ValidationResult result ) + { + ObjectNameError eOne = null , pOne = null; + + switch ( result.getEmpireError( ) ) { + case 1: + eOne = ObjectNameError.BANNED; + break; + case 2: + eOne = ObjectNameError.UNAVAILABLE; + break; + } + + switch ( result.getPlanetError( ) ) { + case 1: + pOne = ObjectNameError.BANNED; + break; + case 2: + pOne = ObjectNameError.UNAVAILABLE; + break; + } + + return this.makeError( command , address , ( result.getAccountError( ) != 0 ) , eOne , pOne ); + } + + + private AccountValidationResponse makeError( AccountValidationCommand command , EmailAddress address , + boolean wrongToken , ObjectNameError empireError , ObjectNameError planetError ) + { + return new AccountValidationResponse( this.manager.getEmpireNames( address ) , command.getToken( ) , command + .getEmpire( ) , command.getPlanet( ) , wrongToken , empireError , planetError ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ValidationSubTypeBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ValidationSubTypeBean.java new file mode 100644 index 0000000..65d0ae0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/ValidationSubTypeBean.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.beans.user.player; + + +public class ValidationSubTypeBean + extends PlayerSessionSubType +{ + + @Override + public String getName( ) + { + return "validation"; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/CancelQuitCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/CancelQuitCommandDelegateBean.java new file mode 100644 index 0000000..c1d40aa --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/CancelQuitCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.CancelQuitCommand; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class CancelQuitCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return CancelQuitCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + this.accountManager.cancelQuit( address ); + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/CreateAuthChallengeCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/CreateAuthChallengeCommandDelegateBean.java new file mode 100644 index 0000000..46f6559 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/CreateAuthChallengeCommandDelegateBean.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.CreateAuthChallengeCommand; +import com.deepclone.lw.cmd.CreateAuthChallengeResponse; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.RandomStringGenerator; + + + +public class CreateAuthChallengeCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private RandomStringGenerator challengeGenerator; + + + @Autowired( required = true ) + @Qualifier( "authChallenges" ) + public void setChallangeGenerator( RandomStringGenerator rsg ) + { + this.challengeGenerator = rsg; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return CreateAuthChallengeCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + String challenge = this.challengeGenerator.generate( ); + session.put( "tempChallenge" , challenge ); + return new CreateAuthChallengeResponse( challenge ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/GetAccountCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/GetAccountCommandDelegateBean.java new file mode 100644 index 0000000..f08ebbb --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/GetAccountCommandDelegateBean.java @@ -0,0 +1,67 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.GetAccountCommand; +import com.deepclone.lw.cmd.player.account.GetAccountResponse; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class GetAccountCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManager; + private EmpireManagement empireManager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement empireManager ) + { + this.empireManager = empireManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetAccountCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + EmailAddress addr = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + AccountData accnt = this.accountManager.getAccountPage( addr ); + GamePageData gPage = this.empireManager.getGeneralInformation( session.get( "empireId" , Integer.class ) ); + return new GetAccountResponse( gPage , accnt ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/QuitGameCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/QuitGameCommandDelegateBean.java new file mode 100644 index 0000000..969da2a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/QuitGameCommandDelegateBean.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.QuitGameCommand; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class QuitGameCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return QuitGameCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + QuitGameCommand command = (QuitGameCommand) cParam; + this.accountManager.setQuit( address , command.getReason( ) ); + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetAddressCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetAddressCommandDelegateBean.java new file mode 100644 index 0000000..8964d65 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetAddressCommandDelegateBean.java @@ -0,0 +1,104 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.SetAddressCommand; +import com.deepclone.lw.cmd.player.account.SetAddressResponse; +import com.deepclone.lw.cmd.player.account.SetAddressResponse.AddressChangeStatus; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; +import com.deepclone.lw.interfaces.acm.AccountMailException; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.mailer.MailerException; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class SetAddressCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManager; + private EmpireManagement empireManager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement empireManager ) + { + this.empireManager = empireManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetAddressCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + SetAddressCommand command = (SetAddressCommand) cParam; + String challenge = session.get( "tempChallenge" , String.class ); + session.put( "tempChallenge" , null ); + + EmailAddress nAddress = null; + AddressChangeStatus mailStatus = AddressChangeStatus.OK; + String temp = command.getMail( ); + String tempConf = command.getMailConfirm( ); + if ( temp == null || temp.trim( ).equals( "" ) ) { + mailStatus = AddressChangeStatus.EMPTY; + } else if ( !temp.equals( tempConf ) ) { + mailStatus = AddressChangeStatus.MISMATCH; + } else { + nAddress = new EmailAddress( temp ); + if ( !address.isValid( ) ) { + mailStatus = AddressChangeStatus.INVALID; + } + } + + boolean authError = false; + if ( mailStatus == AddressChangeStatus.OK ) { + try { + authError = !this.accountManager.setAddress( address , challenge , command.getSha1Auth( ) , command + .getMd5Auth( ) , nAddress ); + } catch ( AccountMailException e ) { + mailStatus = AddressChangeStatus.IN_USE; + } catch ( MailerException e ) { + mailStatus = AddressChangeStatus.SEND_FAIL; + } + } + + if ( !authError && mailStatus == AddressChangeStatus.OK ) { + return new SetAddressResponse( ); + } + + AccountData accnt = this.accountManager.getAccountPage( address ); + GamePageData gPage = this.empireManager.getGeneralInformation( session.get( "empireId" , Integer.class ) ); + return new SetAddressResponse( gPage , accnt , authError , mailStatus , command.getMail( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetLanguageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetLanguageCommandDelegateBean.java new file mode 100644 index 0000000..f1b4e60 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetLanguageCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.SetLanguageCommand; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class SetLanguageCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetLanguageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + SetLanguageCommand command = (SetLanguageCommand) cParam; + EmailAddress addr = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + this.accountManager.setLanguage( addr , command.getLanguage( ) ); + return null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetPasswordCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetPasswordCommandDelegateBean.java new file mode 100644 index 0000000..8ba8abc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetPasswordCommandDelegateBean.java @@ -0,0 +1,110 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.SetPasswordCommand; +import com.deepclone.lw.cmd.player.account.SetPasswordResponse; +import com.deepclone.lw.cmd.player.account.SetPasswordResponse.PasswordChangeStatus; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.acm.PasswordProhibitedException; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; + + + +public class SetPasswordCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManager; + private EmpireManagement empireManager; + private int minPasswordStrength = 10; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement empireManager ) + { + this.empireManager = empireManager; + } + + + public void setMinPasswordStrength( int strength ) + { + this.minPasswordStrength = strength; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetPasswordCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + SetPasswordCommand command = (SetPasswordCommand) cParam; + String challenge = session.get( "tempChallenge" , String.class ); + session.put( "tempChallenge" , null ); + + PasswordChangeStatus status = PasswordChangeStatus.OK; + Password pwd = null; + if ( "".equals( command.getPassword( ) ) ) { + status = PasswordChangeStatus.EMPTY; + } else if ( !command.getPassword( ).equals( command.getPasswordConfirm( ) ) ) { + status = PasswordChangeStatus.MISMATCH; + } else { + pwd = new Password( command.getPassword( ) ); + if ( pwd.getStrength( ) < this.minPasswordStrength ) { + status = PasswordChangeStatus.TOO_WEAK; + } + } + + boolean authError; + if ( status == PasswordChangeStatus.OK ) { + try { + authError = !this.accountManager.setPassword( address , challenge , command.getSha1Auth( ) , command + .getMd5Auth( ) , pwd ); + } catch ( PasswordProhibitedException e ) { + authError = false; + status = PasswordChangeStatus.PROHIBITED; + } + } else { + authError = false; + } + + if ( !authError && status == PasswordChangeStatus.OK ) { + return new SetPasswordResponse( ); + } + + AccountData accnt = this.accountManager.getAccountPage( address ); + GamePageData gPage = this.empireManager.getGeneralInformation( session.get( "empireId" , Integer.class ) ); + return new SetPasswordResponse( gPage , accnt , authError , status ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetPreferencesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetPreferencesCommandDelegateBean.java new file mode 100644 index 0000000..7c8e9fa --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/SetPreferencesCommandDelegateBean.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.SetPreferencesCommand; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class SetPreferencesCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private AccountManagement accountManager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetPreferencesCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + SetPreferencesCommand command = (SetPreferencesCommand) cParam; + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + + if ( command.isReset( ) ) { + this.accountManager.resetPreferences( address ); + } else { + this.accountManager.setPreferences( address , command.getValues( ) ); + } + + return new NullResponse( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/ToggleVacationCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/ToggleVacationCommandDelegateBean.java new file mode 100644 index 0000000..c97768d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/ToggleVacationCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.ToggleVacationCommand; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class ToggleVacationCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ToggleVacationCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + this.accountManager.toggleVacation( address ); + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/ValidateSetAddressCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/ValidateSetAddressCommandDelegateBean.java new file mode 100644 index 0000000..9dbf8e8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/account/ValidateSetAddressCommandDelegateBean.java @@ -0,0 +1,79 @@ +package com.deepclone.lw.beans.user.player.account; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.account.ValidateSetAddressCommand; +import com.deepclone.lw.cmd.player.account.ValidateSetAddressResponse; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class ValidateSetAddressCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AccountManagement accountManager; + private EmpireManagement empireManager; + + + @Autowired( required = true ) + public void setAccountManager( AccountManagement accountManager ) + { + this.accountManager = accountManager; + } + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement empireManager ) + { + this.empireManager = empireManager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ValidateSetAddressCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ValidateSetAddressCommand command = (ValidateSetAddressCommand) cParam; + EmailAddress cAddress = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + + if ( command.isCancel( ) ) { + this.accountManager.cancelAddressChange( cAddress ); + } else { + String code = command.getCode( ); + AccountData data = this.accountManager.confirmAddressChange( cAddress , code ); + if ( data.getAddress( ).equals( cAddress.getAddress( ) ) ) { + GamePageData gPage = this.empireManager + .getGeneralInformation( session.get( "empireId" , Integer.class ) ); + return new ValidateSetAddressResponse( gPage , data , code ); + } + session.put( "authenticationToken" , data.getAddress( ) ); + } + + return new ValidateSetAddressResponse( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ListBugsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ListBugsCommandDelegateBean.java new file mode 100644 index 0000000..a1c6b8a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ListBugsCommandDelegateBean.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.beans.user.player.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.bt.ListBugsCommand; +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.interfaces.bt.PlayerBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListBugsCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private PlayerBugs bugs; + + + @Autowired( required = true ) + public void setBugs( PlayerBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListBugsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + int empireId = session.get( "empireId" , Integer.class ); + + ListBugsCommand command = (ListBugsCommand) cParam; + long first = command.getFirst( ); + int count = command.getCount( ); + BugStatus status = command.getStatus( ); + boolean own = command.isOwnOnly( ); + + return this.bugs.getBugs( empireId , status , own , first , count ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/PostCommentCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/PostCommentCommandDelegateBean.java new file mode 100644 index 0000000..361e3c8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/PostCommentCommandDelegateBean.java @@ -0,0 +1,76 @@ +package com.deepclone.lw.beans.user.player.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.bt.PostCommentCommand; +import com.deepclone.lw.cmd.player.bt.PostCommentResponse; +import com.deepclone.lw.cmd.player.bt.ViewBugResponse; +import com.deepclone.lw.interfaces.bt.PlayerBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class PostCommentCommandDelegateBean + implements AutowiredCommandDelegate +{ + private PlayerBugs bugs; + + + @Autowired( required = true ) + public void setBugs( PlayerBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return PostCommentCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + int empireId = session.get( "empireId" , Integer.class ); + long id = ( (PostCommentCommand) command ).getId( ); + String comment = ( (PostCommentCommand) command ).getComment( ).trim( ); + + ObjectNameError error; + if ( "".equals( comment ) ) { + error = ObjectNameError.EMPTY; + } else if ( comment.length( ) < 30 ) { + error = ObjectNameError.INVALID; + } else { + error = null; + } + + if ( error != null ) { + ViewBugResponse response = this.bugs.getReport( empireId , id ); + if ( response.getReport( ) == null ) { + return new PostCommentResponse( response.getPage( ) , false ); + } + return new PostCommentResponse( response.getPage( ) , response.getReport( ) , response.getEvents( ) , + error , comment ); + } + + PostCommentResponse response = this.bugs.postComment( empireId , id , comment ); + return response; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ReportBugCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ReportBugCommandDelegateBean.java new file mode 100644 index 0000000..e0eaa21 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ReportBugCommandDelegateBean.java @@ -0,0 +1,89 @@ +package com.deepclone.lw.beans.user.player.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.bt.ReportBugCommand; +import com.deepclone.lw.cmd.player.bt.ReportBugResponse; +import com.deepclone.lw.interfaces.bt.PlayerBugs; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ReportBugCommandDelegateBean + implements AutowiredCommandDelegate +{ + private PlayerBugs bugs; + private EmpireManagement empires; + + + @Autowired( required = true ) + public void setBugs( PlayerBugs bugs ) + { + this.bugs = bugs; + } + + + @Autowired( required = true ) + public void setEmpires( EmpireManagement empires ) + { + this.empires = empires; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ReportBugCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + int empireId = session.get( "empireId" , Integer.class ); + + ReportBugCommand command = (ReportBugCommand) cParam; + String title = command.getTitle( ).trim( ); + String desc = command.getDescription( ).trim( ); + + ObjectNameError titleError; + if ( "".equals( title ) ) { + titleError = ObjectNameError.EMPTY; + } else if ( title.length( ) < 10 || title.length( ) > 127 ) { + titleError = ObjectNameError.INVALID; + } else { + titleError = null; + } + + ObjectNameError descError; + if ( "".equals( desc ) ) { + descError = ObjectNameError.EMPTY; + } else if ( desc.length( ) < 30 ) { + descError = ObjectNameError.INVALID; + } else { + descError = null; + } + + if ( descError != null || titleError != null ) { + return new ReportBugResponse( this.empires.getGeneralInformation( empireId ) , titleError , title , + descError , desc ); + } + + return this.bugs.postReport( empireId , title , desc ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ViewBugCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ViewBugCommandDelegateBean.java new file mode 100644 index 0000000..67f9bb6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/bt/ViewBugCommandDelegateBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.user.player.bt; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.bt.ViewBugCommand; +import com.deepclone.lw.interfaces.bt.PlayerBugs; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ViewBugCommandDelegateBean + implements AutowiredCommandDelegate +{ + private PlayerBugs bugs; + + + @Autowired( required = true ) + public void setBugs( PlayerBugs bugs ) + { + this.bugs = bugs; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewBugCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + int empireId = session.get( "empireId" , Integer.class ); + long id = ( (ViewBugCommand) command ).getId( ); + return this.bugs.getReport( empireId , id ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/GetBattleCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/GetBattleCommandDelegateBean.java new file mode 100644 index 0000000..4b63387 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/GetBattleCommandDelegateBean.java @@ -0,0 +1,58 @@ +package com.deepclone.lw.beans.user.player.game; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.battles.GetBattleCommand; +import com.deepclone.lw.interfaces.game.BattleViewer; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetBattleCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private BattleViewer battleViewer; + + + @Autowired( required = true ) + public void setBattleViewer( BattleViewer battleViewer ) + { + this.battleViewer = battleViewer; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetBattleCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + GetBattleCommand command = (GetBattleCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + long battle = command.getBattle( ); + Long tick = command.getTick( ); + if ( tick == null ) { + return this.battleViewer.getBattle( empireId , battle ); + } + return this.battleViewer.getBattle( empireId , battle , tick ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/GetNewPlanetCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/GetNewPlanetCommandDelegateBean.java new file mode 100644 index 0000000..e59bb96 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/GetNewPlanetCommandDelegateBean.java @@ -0,0 +1,74 @@ +package com.deepclone.lw.beans.user.player.game; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.ObjectNameValidatorBean; +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.GetNewPlanetCommand; +import com.deepclone.lw.cmd.player.GetNewPlanetResponse; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetNewPlanetCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private EmpireManagement empireManagement; + private ObjectNameValidatorBean validator; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Autowired( required = true ) + public void setObjectNameValidator( ObjectNameValidatorBean validator ) + { + this.validator = validator; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetNewPlanetCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + GetNewPlanetCommand command = (GetNewPlanetCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return new GetNewPlanetResponse( this.empireManagement.getGeneralInformation( empireId ) , null , null ); + } + + String name = command.getName( ); + ObjectNameError one = this.validator.validate( name ); + if ( one != null ) { + return new GetNewPlanetResponse( this.empireManagement.getGeneralInformation( empireId ) , name , one ); + } + + return this.empireManagement.getNewPlanet( empireId , name ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ImplementTechCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ImplementTechCommandDelegateBean.java new file mode 100644 index 0000000..d6d7165 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ImplementTechCommandDelegateBean.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.beans.user.player.game; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.ImplementTechCommand; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ImplementTechCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private EmpireManagement empireManagement; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ImplementTechCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ImplementTechCommand command = (ImplementTechCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.empireManagement.getOverview( empireId ); + } + return this.empireManagement.implementTechnology( empireId , command.getTech( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ListBattlesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ListBattlesCommandDelegateBean.java new file mode 100644 index 0000000..92fbe08 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ListBattlesCommandDelegateBean.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.beans.user.player.game; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.battles.ListBattlesCommand; +import com.deepclone.lw.interfaces.game.BattleViewer; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListBattlesCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private BattleViewer battleViewer; + + + @Autowired( required = true ) + public void setBattleViewer( BattleViewer battleViewer ) + { + this.battleViewer = battleViewer; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListBattlesCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ListBattlesCommand command = (ListBattlesCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + return this.battleViewer.getBattles( empireId , command.getPage( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ListPlanetsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ListPlanetsCommandDelegateBean.java new file mode 100644 index 0000000..00978f8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ListPlanetsCommandDelegateBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.user.player.game; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.ListPlanetsCommand; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListPlanetsCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private EmpireManagement empireManagement; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListPlanetsCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + int empireId = session.get( "empireId" , Integer.class ); + return this.empireManagement.getPlanetList( empireId ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/OverviewCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/OverviewCommandDelegateBean.java new file mode 100644 index 0000000..7deb80c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/OverviewCommandDelegateBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.user.player.game; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.OverviewCommand; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class OverviewCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private EmpireManagement empireManagement; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return OverviewCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + int empireId = session.get( "empireId" , Integer.class ); + return this.empireManagement.getOverview( empireId ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ViewMapCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ViewMapCommandDelegateBean.java new file mode 100644 index 0000000..6a569f5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/ViewMapCommandDelegateBean.java @@ -0,0 +1,125 @@ +package com.deepclone.lw.beans.user.player.game; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.ViewMapCommand; +import com.deepclone.lw.cmd.player.ViewMapResponse; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.MapSize; +import com.deepclone.lw.cmd.player.gdata.map.MapSystemData; +import com.deepclone.lw.interfaces.acm.AccountManagement; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.game.MapViewParameters; +import com.deepclone.lw.interfaces.game.MapViewer; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.i18n.Translator; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.utils.EmailAddress; + + + +public class ViewMapCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private AccountManagement accountManagement; + private EmpireManagement empireManagement; + private MapViewer mapViewer; + private Translator translator; + + + @Autowired( required = true ) + public void setAccountManagement( AccountManagement accountManagement ) + { + this.accountManagement = accountManagement; + } + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Autowired( required = true ) + public void setMapViewer( MapViewer mapViewer ) + { + this.mapViewer = mapViewer; + } + + + @Autowired( required = true ) + public void setTranslator( Translator translator ) + { + this.translator = translator; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewMapCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ViewMapCommand command = (ViewMapCommand) cParam; + EmailAddress address = new EmailAddress( session.get( "authenticationToken" , String.class ) ); + int empireId = session.get( "empireId" , Integer.class ); + + boolean useDefaults = command.isDefaults( ); + if ( !useDefaults ) { + useDefaults = ( command.getX( ) == null || command.getY( ) == null || command.getSize( ) == null ); + } + + MapViewParameters params; + if ( useDefaults ) { + params = this.mapViewer.getDefaults( address ); + } else { + params = new MapViewParameters( command.getX( ) , command.getY( ) , command.getSize( ) ); + } + + GamePageData page = this.empireManagement.getGeneralInformation( empireId ); + List< String > sizeText = this.getSizeText( address ); + MapSystemData[][] systems = this.mapViewer.getMapView( empireId , params ); + return new ViewMapResponse( page , params.x , params.y , params.size , sizeText , systems ); + } + + + private List< String > getSizeText( EmailAddress address ) + { + String language = this.accountManagement.getAccount( address ).getLanguage( ); + Map< MapSize , String > sizes = MapSize.getValues( ); + + List< String > rv = new ArrayList< String >( sizes.size( ) ); + try { + for ( MapSize sz : MapSize.values( ) ) { + rv.add( sz.ordinal( ) , this.translator.translate( language , sizes.get( sz ) ) ); + } + } catch ( TranslationException e ) { + throw new RuntimeException( e ); + } + return rv; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/AllianceStatusCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/AllianceStatusCommandDelegateBean.java new file mode 100644 index 0000000..778be01 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/AllianceStatusCommandDelegateBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.alliances.AllianceStatusCommand; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class AllianceStatusCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return AllianceStatusCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + int empireId = session.get( "empireId" , Integer.class ); + return this.allianceManagement.getView( empireId ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/CancelJoinCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/CancelJoinCommandDelegateBean.java new file mode 100644 index 0000000..90130ef --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/CancelJoinCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.alliances.CancelJoinCommand; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class CancelJoinCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return CancelJoinCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.allianceManagement.getView( empireId ); + } + return this.allianceManagement.cancelJoin( empireId ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/CreateAllianceCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/CreateAllianceCommandDelegateBean.java new file mode 100644 index 0000000..607054a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/CreateAllianceCommandDelegateBean.java @@ -0,0 +1,82 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.ObjectNameValidatorBean; +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.alliances.AllianceStatusResponse; +import com.deepclone.lw.cmd.player.alliances.CreateAllianceCommand; +import com.deepclone.lw.cmd.player.alliances.CreateAllianceResponse; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceCreationStatus; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class CreateAllianceCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + private ObjectNameValidatorBean validator; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Autowired( required = true ) + public void setObjectNameValidator( ObjectNameValidatorBean validator ) + { + this.validator = validator; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return CreateAllianceCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + CreateAllianceCommand command = (CreateAllianceCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.allianceManagement.getView( empireId ); + } + + String tag = command.getTag( ); + ObjectNameError tagError = this.validator.customValidate( tag , 2 , 5 ); + + String name = command.getName( ); + ObjectNameError nameError = this.validator.customValidate( name , 5 , 64 ); + + if ( tagError != null || nameError != null ) { + AllianceStatusResponse r = this.allianceManagement.getView( empireId ); + AllianceCreationStatus status = new AllianceCreationStatus( tag , tagError , name , nameError ); + return new CreateAllianceResponse( r.getPage( ) , r.getAlliance( ) , status ); + } + + return this.allianceManagement.create( empireId , tag , name ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/JoinAllianceCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/JoinAllianceCommandDelegateBean.java new file mode 100644 index 0000000..8799897 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/JoinAllianceCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.alliances.JoinAllianceCommand; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class JoinAllianceCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return JoinAllianceCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + JoinAllianceCommand command = (JoinAllianceCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.allianceManagement.getView( empireId ); + } + return this.allianceManagement.requestJoin( empireId , command.getTag( ).trim( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/KickMembersCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/KickMembersCommandDelegateBean.java new file mode 100644 index 0000000..e1643f5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/KickMembersCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.alliances.KickMembersCommand; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class KickMembersCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return KickMembersCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + KickMembersCommand command = (KickMembersCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.allianceManagement.getView( empireId ); + } + return this.allianceManagement.kick( empireId , command.getMembers( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/LeaveAllianceCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/LeaveAllianceCommandDelegateBean.java new file mode 100644 index 0000000..2f8d6f2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/LeaveAllianceCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.alliances.LeaveAllianceCommand; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class LeaveAllianceCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return LeaveAllianceCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.allianceManagement.getView( empireId ); + } + return this.allianceManagement.leave( empireId ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/ManageRequestsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/ManageRequestsCommandDelegateBean.java new file mode 100644 index 0000000..a5c5b23 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/ManageRequestsCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.alliances.ManageRequestsCommand; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ManageRequestsCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ManageRequestsCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ManageRequestsCommand command = (ManageRequestsCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.allianceManagement.getView( empireId ); + } + return this.allianceManagement.manageRequests( empireId , command.isAccept( ) , command.getMembers( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/TransferLeadershipCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/TransferLeadershipCommandDelegateBean.java new file mode 100644 index 0000000..6b3221b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/TransferLeadershipCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.alliances.TransferLeadershipCommand; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class TransferLeadershipCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return TransferLeadershipCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + TransferLeadershipCommand command = (TransferLeadershipCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.allianceManagement.getView( empireId ); + } + return this.allianceManagement.transferLeadership( empireId , command.getToMember( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/ViewAllianceCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/ViewAllianceCommandDelegateBean.java new file mode 100644 index 0000000..bfa0de1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/alliances/ViewAllianceCommandDelegateBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.user.player.game.alliances; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.alliances.ViewAllianceCommand; +import com.deepclone.lw.interfaces.game.AllianceManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ViewAllianceCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private AllianceManagement allianceManagement; + + + @Autowired( required = true ) + public void setAllianceManagement( AllianceManagement allianceManagement ) + { + this.allianceManagement = allianceManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewAllianceCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ViewAllianceCommand command = (ViewAllianceCommand) cParam; + Integer empireId = session.get( "empireId" , Integer.class ); + return this.allianceManagement.getInformation( empireId , command.getTag( ).trim( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/AddEnemyCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/AddEnemyCommandDelegateBean.java new file mode 100644 index 0000000..a1aa300 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/AddEnemyCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.game.elist; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.elist.AddEnemyCommand; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class AddEnemyCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private EmpireManagement empireManagement; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return AddEnemyCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + AddEnemyCommand command = (AddEnemyCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.empireManagement.getEnemyLists( empireId ); + } + return this.empireManagement.addEnemy( empireId , command.isAlliance( ) , command.getName( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/EnemyListCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/EnemyListCommandDelegateBean.java new file mode 100644 index 0000000..0960e16 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/EnemyListCommandDelegateBean.java @@ -0,0 +1,50 @@ +package com.deepclone.lw.beans.user.player.game.elist; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.elist.EnemyListCommand; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class EnemyListCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private EmpireManagement empireManagement; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return EnemyListCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + return this.empireManagement.getEnemyLists( session.get( "empireId" , Integer.class ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/RemoveEnemiesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/RemoveEnemiesCommandDelegateBean.java new file mode 100644 index 0000000..c940d42 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/elist/RemoveEnemiesCommandDelegateBean.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.beans.user.player.game.elist; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.elist.RemoveEnemiesCommand; +import com.deepclone.lw.interfaces.game.EmpireManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class RemoveEnemiesCommandDelegateBean + implements AutowiredCommandDelegate +{ + + private EmpireManagement empireManagement; + + + @Autowired( required = true ) + public void setEmpireManager( EmpireManagement manager ) + { + this.empireManagement = manager; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return RemoveEnemiesCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + RemoveEnemiesCommand command = (RemoveEnemiesCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.empireManagement.getEnemyLists( empireId ); + } + return this.empireManagement.removeEnemies( empireId , command.isAlliance( ) , command.getIdentifiers( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/DisbandFleetsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/DisbandFleetsCommandDelegateBean.java new file mode 100644 index 0000000..535ffc0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/DisbandFleetsCommandDelegateBean.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.beans.user.player.game.fleets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.fleets.DisbandFleetsCommand; +import com.deepclone.lw.interfaces.game.FleetManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class DisbandFleetsCommandDelegateBean + implements AutowiredCommandDelegate +{ + private FleetManagement fleetManager; + + + @Autowired( required = true ) + public void setFleetManager( FleetManagement fleetManager ) + { + this.fleetManager = fleetManager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return DisbandFleetsCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + DisbandFleetsCommand command = (DisbandFleetsCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.fleetManager.disband( empireId , new long[] { } , false ); + } + return this.fleetManager.disband( empireId , command.getFleets( ) , command.isConfirm( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/MergeFleetsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/MergeFleetsCommandDelegateBean.java new file mode 100644 index 0000000..c4769a5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/MergeFleetsCommandDelegateBean.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.beans.user.player.game.fleets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.fleets.MergeFleetsCommand; +import com.deepclone.lw.interfaces.game.FleetManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class MergeFleetsCommandDelegateBean + implements AutowiredCommandDelegate +{ + private FleetManagement fleetManager; + + + @Autowired( required = true ) + public void setFleetManager( FleetManagement fleetManager ) + { + this.fleetManager = fleetManager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return MergeFleetsCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + MergeFleetsCommand command = (MergeFleetsCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.fleetManager.disband( empireId , new long[] { } , false ); + } + return this.fleetManager.merge( empireId , command.getFleets( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/MoveFleetsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/MoveFleetsCommandDelegateBean.java new file mode 100644 index 0000000..e40f64a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/MoveFleetsCommandDelegateBean.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.beans.user.player.game.fleets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.fleets.MoveFleetsCommand; +import com.deepclone.lw.interfaces.game.FleetManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class MoveFleetsCommandDelegateBean + implements AutowiredCommandDelegate +{ + private FleetManagement fleetManager; + + + @Autowired( required = true ) + public void setFleetManager( FleetManagement fleetManager ) + { + this.fleetManager = fleetManager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return MoveFleetsCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + MoveFleetsCommand command = (MoveFleetsCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.fleetManager.disband( empireId , new long[] { } , false ); + } + + String destination = command.getDestination( ); + if ( destination != null ) { + destination = destination.trim( ); + if ( "".equals( destination ) ) { + destination = null; + } + } + boolean attack = ( destination == null ) ? false : command.getMode( ); + + return this.fleetManager.move( empireId , command.getFleets( ) , destination , attack ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/RenameFleetsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/RenameFleetsCommandDelegateBean.java new file mode 100644 index 0000000..240c345 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/RenameFleetsCommandDelegateBean.java @@ -0,0 +1,88 @@ +package com.deepclone.lw.beans.user.player.game.fleets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.ObjectNameValidatorBean; +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.fleets.RenameFleetsCommand; +import com.deepclone.lw.cmd.player.fleets.RenameFleetsResponse; +import com.deepclone.lw.interfaces.game.FleetManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class RenameFleetsCommandDelegateBean + implements AutowiredCommandDelegate +{ + private FleetManagement fleetManager; + private ObjectNameValidatorBean validator; + + + @Autowired( required = true ) + public void setFleetManager( FleetManagement fleetManager ) + { + this.fleetManager = fleetManager; + } + + + @Autowired( required = true ) + public void setObjectNameValidator( ObjectNameValidatorBean validator ) + { + this.validator = validator; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return RenameFleetsCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + RenameFleetsCommand command = (RenameFleetsCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.fleetManager.disband( empireId , new long[] { } , false ); + } + + String name; + boolean error; + if ( command.isRename( ) ) { + name = command.getName( ).trim( ); + if ( !"".equals( name ) && this.validator.customValidate( name , 1 , 40 ) != null ) { + error = true; + name = null; + } else { + error = false; + } + } else { + name = null; + error = false; + } + + RenameFleetsResponse response; + response = (RenameFleetsResponse) this.fleetManager.rename( empireId , command.getFleets( ) , name ); + + response.setError( error ); + if ( error ) { + response.setName( command.getName( ).trim( ) ); + } + + return response; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/SetFleetsModeCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/SetFleetsModeCommandDelegateBean.java new file mode 100644 index 0000000..18c2281 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/SetFleetsModeCommandDelegateBean.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.beans.user.player.game.fleets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.fleets.SetFleetsModeCommand; +import com.deepclone.lw.interfaces.game.FleetManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class SetFleetsModeCommandDelegateBean + implements AutowiredCommandDelegate +{ + private FleetManagement fleetManager; + + + @Autowired( required = true ) + public void setFleetManager( FleetManagement fleetManager ) + { + this.fleetManager = fleetManager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SetFleetsModeCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + SetFleetsModeCommand command = (SetFleetsModeCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.fleetManager.disband( empireId , new long[] { } , false ); + } + return this.fleetManager.setMode( empireId , command.getFleets( ) , command.isAttack( ) , command.isConfirm( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/SplitFleetCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/SplitFleetCommandDelegateBean.java new file mode 100644 index 0000000..3d77684 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/SplitFleetCommandDelegateBean.java @@ -0,0 +1,88 @@ +package com.deepclone.lw.beans.user.player.game.fleets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.ObjectNameValidatorBean; +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.fleets.SplitFleetCommand; +import com.deepclone.lw.cmd.player.fleets.SplitFleetResponse; +import com.deepclone.lw.interfaces.game.FleetManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class SplitFleetCommandDelegateBean + implements AutowiredCommandDelegate +{ + private FleetManagement fleetManager; + private ObjectNameValidatorBean validator; + + + @Autowired( required = true ) + public void setFleetManager( FleetManagement fleetManager ) + { + this.fleetManager = fleetManager; + } + + + @Autowired( required = true ) + public void setObjectNameValidator( ObjectNameValidatorBean validator ) + { + this.validator = validator; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return SplitFleetCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + SplitFleetCommand command = (SplitFleetCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.fleetManager.split( empireId , -1 , null , 0 , null , false ); + } + + String name = command.getName( ); + boolean error; + if ( name != null ) { + name = command.getName( ).trim( ); + if ( !"".equals( name ) && this.validator.customValidate( name , 1 , 40 ) != null ) { + error = true; + name = ""; + } else { + error = false; + } + } else { + error = false; + } + + int nFleets = ( command.getnFleets( ) == null ) ? 0 : command.getnFleets( ).intValue( ); + SplitFleetResponse response = this.fleetManager.split( empireId , command.getFleet( ) , command.getShips( ) , + nFleets , name , error ); + + response.setNameError( error ); + if ( error ) { + response.setName( command.getName( ).trim( ) ); + } + + return response; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/ViewFleetsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/ViewFleetsCommandDelegateBean.java new file mode 100644 index 0000000..96f6dde --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/fleets/ViewFleetsCommandDelegateBean.java @@ -0,0 +1,51 @@ +package com.deepclone.lw.beans.user.player.game.fleets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.fleets.ViewFleetsCommand; +import com.deepclone.lw.interfaces.game.FleetManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ViewFleetsCommandDelegateBean + implements AutowiredCommandDelegate + +{ + private FleetManagement fleetManager; + + + @Autowired( required = true ) + public void setFleetManager( FleetManagement fleetManager ) + { + this.fleetManager = fleetManager; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewFleetsCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + int empireId = session.get( "empireId" , Integer.class ); + return this.fleetManager.getFleets( empireId ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/AbandonPlanetCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/AbandonPlanetCommandDelegateBean.java new file mode 100644 index 0000000..ba7155c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/AbandonPlanetCommandDelegateBean.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.user.player.game.planets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.planets.AbandonPlanetCommand; +import com.deepclone.lw.interfaces.game.PlanetsManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class AbandonPlanetCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private PlanetsManagement planetsManagement; + + + @Autowired( required = true ) + public void setPlanetsManagement( PlanetsManagement planetsManagement ) + { + this.planetsManagement = planetsManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return AbandonPlanetCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + AbandonPlanetCommand command = (AbandonPlanetCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + int planetId = command.getId( ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.planetsManagement.viewPlanet( empireId , planetId ); + } + + if ( command.isCancel( ) ) { + return this.planetsManagement.cancelAbandon( empireId , planetId ); + } + return this.planetsManagement.abandon( empireId , planetId ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/BuildingActionCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/BuildingActionCommandDelegateBean.java new file mode 100644 index 0000000..25050a3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/BuildingActionCommandDelegateBean.java @@ -0,0 +1,58 @@ +package com.deepclone.lw.beans.user.player.game.planets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.planets.BuildingActionCommand; +import com.deepclone.lw.interfaces.game.PlanetsManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class BuildingActionCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private PlanetsManagement planetsManagement; + + + @Autowired( required = true ) + public void setPlanetsManagement( PlanetsManagement planetsManagement ) + { + this.planetsManagement = planetsManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return BuildingActionCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + BuildingActionCommand command = (BuildingActionCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + int planetId = command.getId( ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.planetsManagement.viewPlanet( empireId , planetId ); + } + return this.planetsManagement.addToCivilianQueue( empireId , planetId , command.getbType( ) , command + .isDestroy( ) , command.getAmount( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/FlushQueueCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/FlushQueueCommandDelegateBean.java new file mode 100644 index 0000000..c43095e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/FlushQueueCommandDelegateBean.java @@ -0,0 +1,57 @@ +package com.deepclone.lw.beans.user.player.game.planets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.planets.FlushQueueCommand; +import com.deepclone.lw.interfaces.game.PlanetsManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class FlushQueueCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private PlanetsManagement planetsManagement; + + + @Autowired( required = true ) + public void setPlanetsManagement( PlanetsManagement planetsManagement ) + { + this.planetsManagement = planetsManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return FlushQueueCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + FlushQueueCommand command = (FlushQueueCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + int planetId = command.getId( ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.planetsManagement.viewPlanet( empireId , planetId ); + } + return this.planetsManagement.flushQueue( empireId , planetId , command.isMilitary( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/RenamePlanetCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/RenamePlanetCommandDelegateBean.java new file mode 100644 index 0000000..f006bee --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/RenamePlanetCommandDelegateBean.java @@ -0,0 +1,78 @@ +package com.deepclone.lw.beans.user.player.game.planets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.ObjectNameValidatorBean; +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.planets.RenamePlanetCommand; +import com.deepclone.lw.cmd.player.planets.RenamePlanetResponse; +import com.deepclone.lw.cmd.player.planets.ViewPlanetResponse; +import com.deepclone.lw.interfaces.game.PlanetsManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class RenamePlanetCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private PlanetsManagement planetsManagement; + private ObjectNameValidatorBean validator; + + + @Autowired( required = true ) + public void setPlanetsManagement( PlanetsManagement planetsManagement ) + { + this.planetsManagement = planetsManagement; + } + + + @Autowired( required = true ) + public void setObjectNameValidator( ObjectNameValidatorBean validator ) + { + this.validator = validator; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return RenamePlanetCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + RenamePlanetCommand command = (RenamePlanetCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + int planetId = command.getId( ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.planetsManagement.viewPlanet( empireId , planetId ); + } + + String name = command.getName( ); + ObjectNameError one = this.validator.validate( name ); + if ( one != null ) { + ViewPlanetResponse r = this.planetsManagement.viewPlanet( empireId , planetId ); + return new RenamePlanetResponse( planetId , r.getPage( ) , r.getBasic( ) , r.getOrbit( ) , r.getOwn( ) , + name , one.toString( ) ); + } + + return this.planetsManagement.renamePlanet( empireId , planetId , name ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/ShipBuildingCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/ShipBuildingCommandDelegateBean.java new file mode 100644 index 0000000..07fa618 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/ShipBuildingCommandDelegateBean.java @@ -0,0 +1,58 @@ +package com.deepclone.lw.beans.user.player.game.planets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.planets.BuildShipsCommand; +import com.deepclone.lw.interfaces.game.PlanetsManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ShipBuildingCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private PlanetsManagement planetsManagement; + + + @Autowired( required = true ) + public void setPlanetsManagement( PlanetsManagement planetsManagement ) + { + this.planetsManagement = planetsManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return BuildShipsCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + BuildShipsCommand command = (BuildShipsCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + int planetId = command.getId( ); + if ( session.get( "vacation" , Boolean.class ) ) { + return this.planetsManagement.viewPlanet( empireId , planetId ); + } + return this.planetsManagement.addToMilitaryQueue( empireId , planetId , command.getsType( ) , command + .getAmount( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/ViewPlanetCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/ViewPlanetCommandDelegateBean.java new file mode 100644 index 0000000..d3668f3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/game/planets/ViewPlanetCommandDelegateBean.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.beans.user.player.game.planets; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.planets.ViewPlanetCommand; +import com.deepclone.lw.interfaces.game.PlanetsManagement; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ViewPlanetCommandDelegateBean + implements AutowiredCommandDelegate + +{ + + private PlanetsManagement planetsManagement; + + + @Autowired( required = true ) + public void setPlanetsManagement( PlanetsManagement planetsManagement ) + { + this.planetsManagement = planetsManagement; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ViewPlanetCommand.class; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ViewPlanetCommand command = (ViewPlanetCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + int planetId = command.getId( ); + return this.planetsManagement.viewPlanet( empireId , planetId ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ComposeMessageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ComposeMessageCommandDelegateBean.java new file mode 100644 index 0000000..4fa1eb5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ComposeMessageCommandDelegateBean.java @@ -0,0 +1,76 @@ +package com.deepclone.lw.beans.user.player.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.player.msgs.ComposeMessageCommand; +import com.deepclone.lw.cmd.player.msgs.ComposeMessageResponse; +import com.deepclone.lw.interfaces.msg.EmpireMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ComposeMessageCommandDelegateBean + implements AutowiredCommandDelegate +{ + private EmpireMessages messages; + + + @Autowired( required = true ) + public void setMessages( EmpireMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ComposeMessageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ComposeMessageCommand command = (ComposeMessageCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + + MessageType type = command.getType( ); + if ( type == MessageType.INTERNAL ) { + type = MessageType.EMPIRE; + } + String target = command.getTarget( ); + String title = command.getSubject( ).trim( ); + String contents = command.getContents( ).trim( ); + + boolean titleError = ( title.length( ) < 2 || title.length( ) > 64 ); + boolean contentsError = ( contents.length( ) < 2 ); + + ComposeMessageResponse response; + if ( command.getReplyTo( ) != null && command.getInbox( ) != null ) { + response = this.messages.sendReply( empireId , command.getInbox( ) , command.getReplyTo( ) , type , + target , title , contents , titleError || contentsError ); + } else { + response = this.messages.sendMessage( empireId , type , target , title , contents , titleError + || contentsError ); + } + response.setTitleError( titleError ); + response.setContentsError( contentsError ); + + return response; + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/GetMessagesCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/GetMessagesCommandDelegateBean.java new file mode 100644 index 0000000..87bd199 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/GetMessagesCommandDelegateBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.user.player.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.msgs.GetMessagesCommand; +import com.deepclone.lw.interfaces.msg.EmpireMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class GetMessagesCommandDelegateBean + implements AutowiredCommandDelegate +{ + private EmpireMessages messages; + + + @Autowired( required = true ) + public void setMessages( EmpireMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return GetMessagesCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + GetMessagesCommand command = (GetMessagesCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + return this.messages.getMessages( empireId , command.isInbox( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ListTargetsCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ListTargetsCommandDelegateBean.java new file mode 100644 index 0000000..66ff2a1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ListTargetsCommandDelegateBean.java @@ -0,0 +1,51 @@ +package com.deepclone.lw.beans.user.player.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.msgs.ListTargetsCommand; +import com.deepclone.lw.interfaces.msg.EmpireMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ListTargetsCommandDelegateBean + implements AutowiredCommandDelegate +{ + private EmpireMessages messages; + + + @Autowired( required = true ) + public void setMessages( EmpireMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ListTargetsCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command command ) + { + int empireId = session.get( "empireId" , Integer.class ); + return this.messages.getTargets( empireId ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/MessageBoxCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/MessageBoxCommandDelegateBean.java new file mode 100644 index 0000000..245f149 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/MessageBoxCommandDelegateBean.java @@ -0,0 +1,71 @@ +package com.deepclone.lw.beans.user.player.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.msgs.MessageBoxCommand; +import com.deepclone.lw.interfaces.msg.EmpireMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.NullResponse; + + + +public class MessageBoxCommandDelegateBean + implements AutowiredCommandDelegate +{ + private EmpireMessages messages; + + + @Autowired( required = true ) + public void setMessages( EmpireMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return MessageBoxCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + MessageBoxCommand command = (MessageBoxCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + + long[] selection = command.getSelection( ); + if ( selection != null && selection.length == 0 ) { + return new NullResponse( ); + } + + switch ( command.getAction( ) ) { + case DELETE: + this.messages.deleteMessages( empireId , command.isInbox( ) , selection ); + break; + case MARK_READ: + this.messages.markRead( empireId , selection ); + break; + case MARK_UNREAD: + this.messages.markUnread( empireId , selection ); + break; + } + + return new NullResponse( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/PrepareMessageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/PrepareMessageCommandDelegateBean.java new file mode 100644 index 0000000..f0e08de --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/PrepareMessageCommandDelegateBean.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.beans.user.player.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.player.msgs.PrepareMessageCommand; +import com.deepclone.lw.interfaces.msg.EmpireMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class PrepareMessageCommandDelegateBean + implements AutowiredCommandDelegate +{ + private EmpireMessages messages; + + + @Autowired( required = true ) + public void setMessages( EmpireMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return PrepareMessageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + PrepareMessageCommand command = (PrepareMessageCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + MessageType type = command.getType( ); + + if ( type == null ) { + return this.messages.prepareBlankMessage( empireId ); + } else if ( type == MessageType.INTERNAL ) { + return this.messages.prepareReply( empireId , command.getInbox( ) , command.getId( ) ); + } + return this.messages.prepareMessageTo( empireId , type , command.getId( ).intValue( ) ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ReadMessageCommandDelegateBean.java b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ReadMessageCommandDelegateBean.java new file mode 100644 index 0000000..64183dd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/java/com/deepclone/lw/beans/user/player/msgs/ReadMessageCommandDelegateBean.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.beans.user.player.msgs; + + +import org.springframework.beans.factory.annotation.Autowired; + +import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; +import com.deepclone.lw.beans.user.abst.SessionCommandHandler; +import com.deepclone.lw.beans.user.player.GameSubTypeBean; +import com.deepclone.lw.cmd.player.msgs.ReadMessageCommand; +import com.deepclone.lw.interfaces.msg.EmpireMessages; +import com.deepclone.lw.interfaces.session.ServerSession; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; + + + +public class ReadMessageCommandDelegateBean + implements AutowiredCommandDelegate +{ + private EmpireMessages messages; + + + @Autowired( required = true ) + public void setMessages( EmpireMessages messages ) + { + this.messages = messages; + } + + + @Override + public Class< ? extends SessionCommandHandler > getCommandHandler( ) + { + return GameSubTypeBean.class; + } + + + @Override + public Class< ? extends Command > getType( ) + { + return ReadMessageCommand.class; + } + + + @Override + public CommandResponse execute( ServerSession session , Command cParam ) + { + ReadMessageCommand command = (ReadMessageCommand) cParam; + int empireId = session.get( "empireId" , Integer.class ); + return this.messages.getMessage( empireId , command.isInbox( ) , command.getId( ) ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user-beans.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user-beans.xml new file mode 100644 index 0000000..3c1c824 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user-beans.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/admin-session-definer-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/admin-session-definer-bean.xml new file mode 100644 index 0000000..deab9c8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/admin-session-definer-bean.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/external-session-definer-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/external-session-definer-bean.xml new file mode 100644 index 0000000..e0ffd6f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/external-session-definer-bean.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/object-name-validator-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/object-name-validator-bean.xml new file mode 100644 index 0000000..7d06f66 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/object-name-validator-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/player-session-definer-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/player-session-definer-bean.xml new file mode 100644 index 0000000..37a91ea --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/player-session-definer-bean.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/session-command-wiring-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/session-command-wiring-bean.xml new file mode 100644 index 0000000..da9ba6d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/session-command-wiring-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/session-subtype-wiring-bean.xml b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/session-subtype-wiring-bean.xml new file mode 100644 index 0000000..5713773 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/legacyworlds-server-beans-user/src/main/resources/configuration/user/session-subtype-wiring-bean.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-beans/pom.xml b/legacyworlds-server/legacyworlds-server-beans/pom.xml new file mode 100644 index 0000000..9d74460 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-beans/pom.xml @@ -0,0 +1,36 @@ + + 4.0.0 + + legacyworlds-server + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-beans + Legacy Worlds server beans + 5.99.1 + pom + This metapackage regroups all packages which define beans for the Legacy Worlds server. + + + + com.deepclone.lw + legacyworlds-server-interfaces + ${project.version} + + + + + legacyworlds-server-beans-i18n + legacyworlds-server-beans-eventlog + legacyworlds-server-beans-accounts + legacyworlds-server-beans-mailer + legacyworlds-server-beans-system + legacyworlds-server-beans-naming + legacyworlds-server-beans-bt + legacyworlds-server-beans-user + legacyworlds-server-beans-simple + + diff --git a/legacyworlds-server/legacyworlds-server-data/.classpath b/legacyworlds-server/legacyworlds-server-data/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-data/.project b/legacyworlds-server/legacyworlds-server-data/.project new file mode 100644 index 0000000..e0c56e5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-data + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-data/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-data/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..b66e1f0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 09 10:19:59 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/database.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/database.sql new file mode 100644 index 0000000..675eeb6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/database.sql @@ -0,0 +1,54 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Main database script +-- +-- Initialises the various roles and the database itself, +-- then processes scripts from the "parts" directory. +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- Read configuration from file +\set pgadmin `grep ^admin= db-config.txt | sed -e s/.*=//` +\set dbname `grep ^db= db-config.txt | sed -e s/.*=//` +\set dbuser `grep ^user= db-config.txt | sed -e s/.*=//` +\set dbupass ''''`grep ^password= db-config.txt | sed -e s/.*=// -e "s/'/''/g"`'''' + + +-- Connect to the main system database +\c postgres :pgadmin + +-- Drop the database and users if they exist +DROP DATABASE IF EXISTS :dbname; +DROP ROLE IF EXISTS :dbuser; + +-- Create the LW users +CREATE ROLE :dbuser WITH LOGIN ENCRYPTED PASSWORD :dbupass; + +-- Create the database +CREATE DATABASE :dbname ENCODING='UTF8' TEMPLATE=template0; +GRANT CONNECT ON DATABASE :dbname TO :dbuser; + + +-- Connect to the LW database with the PostgreSQL admin user +\c :dbname :pgadmin + +-- Register PL/PgSQL +CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql; + +BEGIN; + +-- Create database schemas +\i parts/000-schemas.sql + +-- Process structure definition scripts +\i parts/010-data.sql + +-- Process functions and views definition scripts +\i parts/020-functions.sql + +-- Process game update functions +\i parts/030-updates.sql + +COMMIT; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/db-config.txt b/legacyworlds-server/legacyworlds-server-data/db-structure/db-config.txt new file mode 100644 index 0000000..c8cc851 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/db-config.txt @@ -0,0 +1,4 @@ +admin=tseeker +db=lwb6 +user=lwb6 +password=test diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/000-schemas.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/000-schemas.sql new file mode 100644 index 0000000..20284d2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/000-schemas.sql @@ -0,0 +1,46 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Creates schemas +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +CREATE SCHEMA admin; +GRANT USAGE ON SCHEMA admin TO :dbuser; + +CREATE SCHEMA battles; +GRANT USAGE ON SCHEMA battles TO :dbuser; + +CREATE SCHEMA bugs; +GRANT USAGE ON SCHEMA bugs TO :dbuser; + +CREATE SCHEMA defs; +GRANT USAGE ON SCHEMA defs TO :dbuser; + +CREATE SCHEMA events; +GRANT USAGE ON SCHEMA events TO :dbuser; + +CREATE SCHEMA emp; +GRANT USAGE ON SCHEMA emp TO :dbuser; + +CREATE SCHEMA fleets; +GRANT USAGE ON SCHEMA fleets TO :dbuser; + +CREATE SCHEMA msgs; +GRANT USAGE ON SCHEMA msgs TO :dbuser; + +CREATE SCHEMA naming; +GRANT USAGE ON SCHEMA naming TO :dbuser; + +CREATE SCHEMA sys; +GRANT USAGE ON SCHEMA sys TO :dbuser; + +CREATE SCHEMA tech; +GRANT USAGE ON SCHEMA tech TO :dbuser; + +CREATE SCHEMA users; +GRANT USAGE ON SCHEMA users TO :dbuser; + +CREATE SCHEMA verse; +GRANT USAGE ON SCHEMA verse TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/010-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/010-data.sql new file mode 100644 index 0000000..add939b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/010-data.sql @@ -0,0 +1,29 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Structures creation +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +\i parts/data/000-typedefs.sql +\i parts/data/010-i18n-data.sql +\i parts/data/020-prefs-data.sql +\i parts/data/030-users-data.sql +\i parts/data/035-session-data.sql +\i parts/data/040-admin-data.sql +\i parts/data/050-accounts-data.sql +\i parts/data/055-bugs-data.sql +\i parts/data/060-naming-data.sql +\i parts/data/070-constants-data.sql +\i parts/data/080-techs-data.sql +\i parts/data/090-buildables-data.sql +\i parts/data/100-universe-data.sql +\i parts/data/110-empires-data.sql +\i parts/data/120-construction-data.sql +\i parts/data/130-fleets-data.sql +\i parts/data/140-status-data.sql +\i parts/data/150-logs-data.sql +\i parts/data/160-battle-data.sql +\i parts/data/170-events-data.sql +\i parts/data/180-messages-data.sql \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/020-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/020-functions.sql new file mode 100644 index 0000000..5a55389 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/020-functions.sql @@ -0,0 +1,36 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Functions and views +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +\i parts/functions/000-defs-functions.sql +\i parts/functions/002-sys-functions.sql +\i parts/functions/005-logs-functions.sql +\i parts/functions/010-constants-functions.sql +\i parts/functions/020-naming-functions.sql +\i parts/functions/030-tech-functions.sql +\i parts/functions/035-users-view.sql +\i parts/functions/040-empire-functions.sql +\i parts/functions/050-computation-functions.sql +\i parts/functions/060-universe-functions.sql +\i parts/functions/070-users-functions.sql +\i parts/functions/075-session-functions.sql +\i parts/functions/080-buildings-functions.sql +\i parts/functions/100-status-functions.sql +\i parts/functions/110-prefs-functions.sql +\i parts/functions/120-map-functions.sql +\i parts/functions/140-planets-functions.sql +\i parts/functions/150-battle-functions.sql +\i parts/functions/160-battle-views.sql +\i parts/functions/163-alliance-functions.sql +\i parts/functions/165-fleets-functions.sql +\i parts/functions/167-planet-list.sql +\i parts/functions/170-event-functions.sql +\i parts/functions/180-messages-functions.sql +\i parts/functions/190-admin-functions.sql +\i parts/functions/200-bugs-functions.sql +\i parts/functions/210-admin-overview.sql + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/030-updates.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/030-updates.sql new file mode 100644 index 0000000..47862f5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/030-updates.sql @@ -0,0 +1,22 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +\i parts/updates/000-updates-ctrl.sql +\i parts/updates/010-empire-money.sql +\i parts/updates/020-empire-research.sql +\i parts/updates/025-empire-debt.sql +\i parts/updates/030-fleet-arrivals.sql +\i parts/updates/040-fleet-movements.sql +\i parts/updates/050-fleet-status.sql +\i parts/updates/060-planet-battle.sql +\i parts/updates/070-planet-abandon.sql +\i parts/updates/080-planet-construction.sql +\i parts/updates/090-planet-military.sql +\i parts/updates/100-planet-population.sql +\i parts/updates/110-planet-money.sql diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/000-typedefs.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/000-typedefs.sql new file mode 100644 index 0000000..4ba3baa --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/000-typedefs.sql @@ -0,0 +1,53 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Type definitions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- Processing status +CREATE TYPE processing_status + AS ENUM ( 'FUTURE', 'PROCESSING', 'PROCESSED' ); + +-- Building output types +CREATE TYPE building_output_type + AS ENUM ( 'CASH', 'POP', 'DEF', 'WORK' ); + +-- Fleet status +CREATE TYPE fleet_status + AS ENUM ( 'AVAILABLE', 'DEPLOYING' , 'REDEPLOYING' , 'REDIRECTING' ); + +-- Log levels +CREATE TYPE log_level + AS ENUM ( 'TRACE' , 'DEBUG' , 'INFO' , 'WARNING' , 'ERROR' ); + +-- Log types +CREATE TYPE log_type + AS ENUM ( 'SYS' , 'USERS' , 'ADMIN' ); + +-- Update types +CREATE TYPE update_type AS ENUM ( + 'EMPIRE_MONEY' , + 'EMPIRE_RESEARCH' , + 'EMPIRE_DEBT' , + 'PLANET_FLEET_ARRIVALS' , + 'PLANET_FLEET_MOVEMENTS' , + 'PLANET_FLEET_STATUS' , + 'PLANET_BATTLE_START' , + 'PLANET_BATTLE_MAIN' , + 'PLANET_BATTLE_END' , + 'PLANET_ABANDON' , + 'PLANET_CONSTRUCTION' , + 'PLANET_MILITARY' , + 'PLANET_POPULATION' , + 'PLANET_MONEY' +); + +-- Types of recapitulative e-mail messages +CREATE TYPE recap_type + AS ENUM ( 'ADMIN' , 'MSG', 'ERROR' ); + +-- Empire relations +CREATE TYPE empire_relation_type + AS ENUM ('OWN' , 'ALLIED' , 'ENEMY'); diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/010-i18n-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/010-i18n-data.sql new file mode 100644 index 0000000..15ba3d3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/010-i18n-data.sql @@ -0,0 +1,53 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Translations +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- Languages +-- +CREATE TABLE defs.languages( + id SERIAL PRIMARY KEY , + language VARCHAR(5) NOT NULL , + name VARCHAR(48) NOT NULL +); + +CREATE UNIQUE INDEX idx_languages_lid + ON defs.languages (language); + + + +-- +-- Internationalised strings +-- +CREATE TABLE defs.strings( + id SERIAL PRIMARY KEY , + name VARCHAR(64) NOT NULL +); + +CREATE UNIQUE INDEX idx_strings_id + ON defs.strings (name); + + + +-- +-- Translations +-- +CREATE TABLE defs.translations( + lang_id INT NOT NULL , + string_id INT NOT NULL , + translated_string TEXT NOT NULL , + PRIMARY KEY (lang_id, string_id) +); + +CREATE INDEX idx_translations_string + ON defs.translations (string_id); + +ALTER TABLE defs.translations + ADD CONSTRAINT fk_translation_language + FOREIGN KEY (lang_id) REFERENCES defs.languages , + ADD CONSTRAINT fk_translation_string + FOREIGN KEY (string_id) REFERENCES defs.strings; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/020-prefs-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/020-prefs-data.sql new file mode 100644 index 0000000..ab2e7c3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/020-prefs-data.sql @@ -0,0 +1,57 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Preference definitions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Preference groups +-- +CREATE TABLE defs.preference_groups( + id SERIAL PRIMARY KEY , + name VARCHAR(32) NOT NULL , + display_id INT NOT NULL +); + +CREATE UNIQUE INDEX idx_prefgroups_name + ON defs.preference_groups (name); +CREATE INDEX idx_prefgroups_dispname + ON defs.preference_groups (display_id); + +ALTER TABLE defs.preference_groups + ADD CONSTRAINT fk_prefgroups_display + FOREIGN KEY (display_id) REFERENCES defs.strings; + + +-- +-- Preference definitions +-- +CREATE TABLE defs.preference_definitions( + id SERIAL PRIMARY KEY , + group_id INT NOT NULL , + name VARCHAR(32) NOT NULL , + disp_name_id INT NOT NULL , + disp_desc_id INT NOT NULL , + java_type VARCHAR( 255 ) NOT NULL , + default_value TEXT NOT NULL +); + +CREATE INDEX idx_prefdefs_group + ON defs.preference_definitions (group_id); +CREATE UNIQUE INDEX idx_prefdefs_name + ON defs.preference_definitions (name); +CREATE INDEX idx_prefdefs_dispname + ON defs.preference_definitions (disp_name_id); +CREATE INDEX idx_prefdefs_dispdesc + ON defs.preference_definitions (disp_desc_id); + +ALTER TABLE defs.preference_definitions + ADD CONSTRAINT fk_prefdefs_group + FOREIGN KEY (group_id) REFERENCES defs.preference_groups , + ADD CONSTRAINT fk_prefdefs_dispname + FOREIGN KEY (disp_name_id) REFERENCES defs.strings , + ADD CONSTRAINT fk_prefdefs_dispdesc + FOREIGN KEY (disp_desc_id) REFERENCES defs.strings; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/030-users-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/030-users-data.sql new file mode 100644 index 0000000..97f0988 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/030-users-data.sql @@ -0,0 +1,111 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- User management tables +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- Identifiers sequence for users +-- +CREATE SEQUENCE users.identifiers_seq; + + +-- +-- E-mail addresses +-- +CREATE TABLE users.addresses( + id INT DEFAULT nextval('users.identifiers_seq') NOT NULL PRIMARY KEY , + address VARCHAR(255) NOT NULL +); + +CREATE UNIQUE INDEX idx_addresses_address + ON users.addresses (lower(address)); + + +-- +-- User credentials +-- +CREATE TABLE users.credentials( + address_id INT NOT NULL PRIMARY KEY, + pass_md5 CHAR(32) NOT NULL , + pass_sha1 CHAR(40) NOT NULL , + credits INT NOT NULL CHECK (credits >= 0) , + language_id INT NOT NULL +); + +ALTER TABLE users.credentials + ADD CONSTRAINT fk_credentials_id + FOREIGN KEY (address_id) REFERENCES users.addresses + ON DELETE CASCADE , + ADD CONSTRAINT fk_credentials_language + FOREIGN KEY (language_id) REFERENCES defs.languages; + + +-- +-- Validation keys +-- +CREATE TABLE users.validation_keys( + credentials_id INT NOT NULL PRIMARY KEY , + token CHAR( 64 ) NOT NULL , + created TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT NOW() +); + +CREATE INDEX idx_validationkeys_created + ON users.validation_keys (created); + +ALTER TABLE users.validation_keys + ADD CONSTRAINT fk_validationkeys_id + FOREIGN KEY (credentials_id) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Password recovery +-- +CREATE TABLE users.pwd_recovery_requests( + credentials_id INT NOT NULL PRIMARY KEY , + token CHAR( 64 ) NOT NULL , + used BOOLEAN NOT NULL + DEFAULT FALSE , + created TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT NOW() +); + +CREATE INDEX idx_pwdrecovery_created + ON users.pwd_recovery_requests (created); + +ALTER TABLE users.pwd_recovery_requests + ADD CONSTRAINT fk_pwdrecovery_id + FOREIGN KEY (credentials_id) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Mail address change requests +-- +CREATE TABLE users.address_change_requests( + credentials_id INT NOT NULL PRIMARY KEY , + address_id INT NOT NULL , + token CHAR( 64 ) NOT NULL , + used BOOLEAN NOT NULL + DEFAULT FALSE , + created TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT NOW() +); + +CREATE UNIQUE INDEX idx_addrchangereq_address + ON users.address_change_requests (address_id); +CREATE INDEX idx_addrchangereq_created + ON users.address_change_requests (created); + +ALTER TABLE users.address_change_requests + ADD CONSTRAINT fk_addrchangereq_id + FOREIGN KEY (credentials_id) REFERENCES users.credentials ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT fk_addrchangereq_address + FOREIGN KEY (address_id) REFERENCES users.addresses ON DELETE CASCADE; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/035-session-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/035-session-data.sql new file mode 100644 index 0000000..7d88e09 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/035-session-data.sql @@ -0,0 +1,92 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- User sessions tables +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Session client type definitions +-- + +CREATE TABLE defs.session_clients( + id SERIAL PRIMARY KEY , + name VARCHAR( 16 ) NOT NULL UNIQUE , + exclusive BOOLEAN NOT NULL +); + +-- +-- Default session client types +-- + +INSERT INTO defs.session_clients ( name , exclusive ) + VALUES( 'web' , TRUE ); +INSERT INTO defs.session_clients ( name , exclusive ) + VALUES( 'vac_end' , FALSE ); + + + +-- +-- Types of session termination +-- + +CREATE TYPE session_termination_type + AS ENUM( 'MANUAL' , 'GONE' , 'EXPIRED' , 'EXCLUSIVE' , 'SERVER' ); + + + +-- +-- User sessions start +-- + +CREATE TABLE users.session_starts( + id BIGSERIAL PRIMARY KEY , + credentials_id INT NOT NULL , + client_id INT NOT NULL , + session VARCHAR( 64 ) NOT NULL , + started TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) , + from_address VARCHAR( 64 ) NOT NULL +); + +CREATE INDEX idx_sessstart_credentials + ON users.session_starts ( credentials_id ); + +CREATE INDEX idx_sessstart_client + ON users.session_starts ( client_id ); + +CREATE INDEX idx_sessstart_started + ON users.session_starts ( started ); + +ALTER TABLE users.session_starts + ADD CONSTRAINT fk_sessstart_credentials + FOREIGN KEY ( credentials_id ) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE , + ADD CONSTRAINT fk_sessstart_client + FOREIGN KEY ( client_id ) REFERENCES defs.session_clients; + + + +-- +-- User sessions end +-- + +CREATE TABLE users.session_ends( + id BIGINT NOT NULL PRIMARY KEY , + ended TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) , + end_type session_termination_type NOT NULL +); + +CREATE INDEX idx_sessend_ended + ON users.session_ends ( ended ); + +ALTER TABLE users.session_ends + ADD CONSTRAINT fk_sessend_id + FOREIGN KEY ( id ) REFERENCES users.session_starts + ON DELETE CASCADE; + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/040-admin-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/040-admin-data.sql new file mode 100644 index 0000000..928ae81 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/040-admin-data.sql @@ -0,0 +1,169 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Administrative tables +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- Administrators +-- +CREATE TABLE admin.administrators( + id SERIAL NOT NULL PRIMARY KEY , + appear_as VARCHAR( 48 ) NOT NULL , + pass_md5 CHAR(32) NOT NULL , + pass_sha1 CHAR(40) NOT NULL , + privileges INT NOT NULL +); + +CREATE UNIQUE INDEX idx_administrators_appearas + ON admin.administrators( lower(appear_as) ); + + +-- +-- Administrators <-> credentials +-- +CREATE TABLE admin.admin_credentials( + administrator_id INT NOT NULL , + credentials_id INT NOT NULL , + PRIMARY KEY(administrator_id) +); + +CREATE UNIQUE INDEX idx_admincreds_creds + ON admin.admin_credentials( credentials_id ); + +ALTER TABLE admin.admin_credentials + ADD CONSTRAINT fk_admincreds_admin + FOREIGN KEY (administrator_id) REFERENCES admin.administrators , + ADD CONSTRAINT fk_admincreds_creds + FOREIGN KEY (credentials_id) REFERENCES users.credentials + ON UPDATE CASCADE; + + +-- +-- Ban requests +-- +CREATE TABLE admin.ban_requests( + id SERIAL NOT NULL PRIMARY KEY , + requested_by INT NOT NULL , + reason TEXT NOT NULL , + requested TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now() +); + +CREATE INDEX idx_banrequests_requestedby + ON admin.ban_requests( requested_by ); + +ALTER TABLE admin.ban_requests + ADD CONSTRAINT fk_banrequests_requestedby + FOREIGN KEY (requested_by) REFERENCES admin.administrators; + + +-- +-- Active ban requests +-- +CREATE TABLE admin.active_ban_requests( + request_id INT NOT NULL PRIMARY KEY , + credentials_id INT NOT NULL , + validated BOOLEAN NOT NULL + DEFAULT FALSE +); + +CREATE UNIQUE INDEX idx_activebanrequests_creds + ON admin.active_ban_requests (credentials_id); + +ALTER TABLE admin.active_ban_requests + ADD CONSTRAINT fk_activebanrequests_request + FOREIGN KEY (request_id) REFERENCES admin.ban_requests , + ADD CONSTRAINT fk_activebanrequests_creds + FOREIGN KEY (credentials_id) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Archived ban requests +-- +CREATE TABLE admin.archived_ban_requests( + request_id INT NOT NULL PRIMARY KEY , + credentials_id INT NOT NULL , + updated TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now() +); + +CREATE INDEX idx_archivedbanrequests_creds + ON admin.archived_ban_requests (credentials_id); + +ALTER TABLE admin.archived_ban_requests + ADD CONSTRAINT fk_archivedbanrequests_request + FOREIGN KEY (request_id) REFERENCES admin.ban_requests , + ADD CONSTRAINT fk_archivedbanrequests_creds + FOREIGN KEY (credentials_id) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Rejected ban requests +-- +CREATE TABLE admin.rejected_ban_requests( + request_id INT NOT NULL PRIMARY KEY , + rejected_by INT NOT NULL , + reason TEXT NOT NULL +); + +CREATE INDEX idx_rejectedbanrequests_rejected + ON admin.rejected_ban_requests (rejected_by); + +ALTER TABLE admin.rejected_ban_requests + ADD CONSTRAINT fk_rejectedbanrequests_request + FOREIGN KEY (request_id) REFERENCES admin.ban_requests , + ADD CONSTRAINT fk_rejectedbanrequests_rejected + FOREIGN KEY (rejected_by) REFERENCES admin.administrators; + + +-- +-- Validated ban requests +-- +CREATE TABLE admin.validated_ban_requests( + request_id INT NOT NULL PRIMARY KEY , + validated_by INT NOT NULL , + validated TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) +); + +CREATE INDEX idx_validatedbanrequests_validated + ON admin.validated_ban_requests (validated_by); + +ALTER TABLE admin.validated_ban_requests + ADD CONSTRAINT fk_validatedbanrequests_request + FOREIGN KEY (request_id) REFERENCES admin.ban_requests , + ADD CONSTRAINT fk_validatedbanrequests_rejected + FOREIGN KEY (validated_by) REFERENCES admin.administrators; + + + +-- +-- Warnings to users +-- + +CREATE TABLE admin.warnings ( + credentials_id INT NOT NULL PRIMARY KEY , + warnings INT NOT NULL + DEFAULT 1 + CHECK( warnings >= 0 ) , + last_received TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) +); + +CREATE INDEX idx_warnings_received + ON admin.warnings( last_received ) + WHERE warnings > 0; + +ALTER TABLE admin.warnings + ADD CONSTRAINT fk_warnings_credentials + FOREIGN KEY ( credentials_id ) REFERENCES users.credentials + ON UPDATE CASCADE ON DELETE CASCADE; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/050-accounts-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/050-accounts-data.sql new file mode 100644 index 0000000..2ffee8b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/050-accounts-data.sql @@ -0,0 +1,137 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Account tables +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- Active account +-- +CREATE TABLE users.active_accounts( + credentials_id INT NOT NULL PRIMARY KEY , + vacation_credits INT NOT NULL CHECK( vacation_credits >= 0 ) +); + +ALTER TABLE users.active_accounts + ADD CONSTRAINT fk_activeaccounts_creds + FOREIGN KEY (credentials_id) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Vacation credits +-- +CREATE TABLE users.vacations( + account_id INT NOT NULL PRIMARY KEY , + since TIMESTAMP WITHOUT TIME ZONE + NOT NULL , + status processing_status NOT NULL +); + +CREATE INDEX idx_vacations_status + ON users.vacations (since, status); + +ALTER TABLE users.vacations + ADD CONSTRAINT fk_vacations_accounts + FOREIGN KEY (account_id) REFERENCES users.active_accounts + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Preferences +-- + +CREATE TABLE users.preferences( + account_id INT NOT NULL , + definition_id INT NOT NULL , + pref_value TEXT NOT NULL , + PRIMARY KEY (account_id,definition_id) +); + +CREATE INDEX idx_preferences_definition + ON users.preferences( definition_id ); + +ALTER TABLE users.preferences + ADD CONSTRAINT fk_preferences_accounts + FOREIGN KEY (account_id) REFERENCES users.active_accounts + ON DELETE CASCADE ON UPDATE CASCADE , + ADD CONSTRAINT fk_preferences_definition + FOREIGN KEY (definition_id) REFERENCES defs.preference_definitions + ON DELETE CASCADE; + + +-- +-- Inactive accounts +-- + +CREATE TABLE users.inactive_accounts( + credentials_id INT NOT NULL PRIMARY KEY , + since TIMESTAMP WITHOUT TIME ZONE + NOT NULL , + status processing_status NOT NULL +); + +CREATE INDEX idx_inactiveaccounts_status + ON users.vacations (since, status); + +ALTER TABLE users.inactive_accounts + ADD CONSTRAINT fk_inactiveaccounts_creds + FOREIGN KEY (credentials_id) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Account de-activation reasons +-- +CREATE TABLE users.reasons( + account_id INT NOT NULL PRIMARY KEY , + reason TEXT NOT NULL +); + +ALTER TABLE users.reasons + ADD CONSTRAINT fk_reasons_account + FOREIGN KEY (account_id) REFERENCES users.inactive_accounts + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Bans +-- +CREATE TABLE users.bans( + account_id INT NOT NULL PRIMARY KEY , + ban_id INT NOT NULL +); + +CREATE UNIQUE INDEX idx_bans_banrequest + ON users.bans (ban_id); + +ALTER TABLE users.bans + ADD CONSTRAINT fk_bans_account + FOREIGN KEY (account_id) REFERENCES users.inactive_accounts + ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT fk_bans_ban + FOREIGN KEY (ban_id) REFERENCES admin.validated_ban_requests; + + + +-- +-- Table that stores inactivity warning e-mail status +-- + +CREATE TABLE users.inactivity_emails( + account_id INT NOT NULL PRIMARY KEY , + mail_sent TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) +); + +CREATE INDEX idx_inactivitymails_sent + ON users.inactivity_emails ( mail_sent ); + +ALTER TABLE users.inactivity_emails + ADD CONSTRAINT fk_inactivitymails_account + FOREIGN KEY ( account_id ) REFERENCES users.active_accounts + ON DELETE CASCADE ON UPDATE CASCADE; + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/055-bugs-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/055-bugs-data.sql new file mode 100644 index 0000000..721c9e9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/055-bugs-data.sql @@ -0,0 +1,273 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Tables that support the bug tracking system +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Bug event types +-- + +CREATE TYPE bug_event_type + AS ENUM( 'INIT' , 'MERGE' , 'STATUS' , 'COMMENT' , 'VISIBILITY' ); + + + +-- +-- Bug statuses +-- + +CREATE TYPE bug_status_type + AS ENUM( 'OPEN' , 'NOT_A_BUG' , 'WONT_FIX' , 'RESOLVED' ); + + + +-- +-- Bug submitters +-- + +CREATE TABLE bugs.submitters ( + submitter_id BIGSERIAL PRIMARY KEY , + is_admin BOOLEAN NOT NULL , + name VARCHAR( 64 ) NOT NULL +); + +CREATE INDEX idx_submitters_isadmin + ON bugs.submitters ( is_admin ); + + + +-- +-- Bug submitters - administrators +-- + +CREATE TABLE bugs.admin_submitters( + submitter_id BIGINT PRIMARY KEY , + admin_id INT NOT NULL UNIQUE +); + +ALTER TABLE bugs.admin_submitters + ADD CONSTRAINT fk_adminsubs_submitter + FOREIGN KEY ( submitter_id ) REFERENCES bugs.submitters , + ADD CONSTRAINT fk_adminsubs_admin + FOREIGN KEY ( admin_id ) REFERENCES admin.administrators + ON DELETE CASCADE; + + + +-- +-- Bug submitters - users +-- + +CREATE TABLE bugs.user_submitters( + submitter_id BIGINT PRIMARY KEY , + account_id INT NOT NULL UNIQUE +); + +ALTER TABLE bugs.user_submitters + ADD CONSTRAINT fk_usersubs_submitter + FOREIGN KEY ( submitter_id ) REFERENCES bugs.submitters , + ADD CONSTRAINT fk_usersubs_account + FOREIGN KEY ( account_id ) REFERENCES users.active_accounts + ON DELETE CASCADE ON UPDATE CASCADE; + + + +-- +-- Report groups +-- + +CREATE TABLE bugs.groups( + group_id BIGSERIAL PRIMARY KEY +); + + + +-- +-- Report events - main table +-- + +CREATE TABLE bugs.events( + event_id BIGSERIAL PRIMARY KEY , + group_id BIGINT NOT NULL , + submitter_id BIGINT NOT NULL , + e_type bug_event_type NOT NULL , + t TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) +); + +CREATE INDEX idx_events_group + ON bugs.events( group_id ); + +CREATE INDEX idx_events_submitter + ON bugs.events( submitter_id ); + +CREATE INDEX idx_events_time + ON bugs.events( t ); + +ALTER TABLE bugs.events + ADD CONSTRAINT fk_events_group + FOREIGN KEY ( group_id ) REFERENCES bugs.groups , + ADD CONSTRAINT fk_events_submitter + FOREIGN KEY ( submitter_id ) REFERENCES bugs.submitters; + +GRANT SELECT ON bugs.events TO :dbuser; + + + +-- +-- Report events - initial reports +-- + +CREATE TABLE bugs.initial_report_events( + event_id BIGINT PRIMARY KEY , + title VARCHAR( 128 ) NOT NULL , + description TEXT NOT NULL +); + +ALTER TABLE bugs.initial_report_events + ADD CONSTRAINT fk_initialreports_event + FOREIGN KEY ( event_id ) REFERENCES bugs.events; + + + +-- +-- Report events - mergers +-- + +CREATE TABLE bugs.merge_events( + event_id BIGINT PRIMARY KEY , + initial_post_id BIGINT NOT NULL +); + +CREATE INDEX idx_mergers_initialpost + ON bugs.merge_events( initial_post_id ); + +ALTER TABLE bugs.merge_events + ADD CONSTRAINT fk_mergers_event + FOREIGN KEY ( event_id ) REFERENCES bugs.events , + ADD CONSTRAINT fk_mergers_initial + FOREIGN KEY ( initial_post_id ) REFERENCES bugs.initial_report_events; + + + +-- +-- Report events - status change +-- + +CREATE TABLE bugs.status_change_events( + event_id BIGINT PRIMARY KEY , + status bug_status_type NOT NULL +); + +ALTER TABLE bugs.status_change_events + ADD CONSTRAINT fk_statuschanges_event + FOREIGN KEY ( event_id ) REFERENCES bugs.events; + + + +-- +-- Report events - comments +-- + +CREATE TABLE bugs.comment_events( + event_id BIGINT PRIMARY KEY , + comment TEXT NOT NULL , + visible BOOLEAN NOT NULL +); + +ALTER TABLE bugs.comment_events + ADD CONSTRAINT fk_comments_event + FOREIGN KEY ( event_id ) REFERENCES bugs.events; + + + +-- +-- Report events - visibility changes +-- + +CREATE TABLE bugs.visibility_events( + event_id BIGINT PRIMARY KEY , + visible BOOLEAN NOT NULL +); + + +ALTER TABLE bugs.visibility_events + ADD CONSTRAINT fk_visibility_event + FOREIGN KEY ( event_id ) REFERENCES bugs.events; + + + +-- +-- Account status information submitted along with bug reports by players +-- + +CREATE TABLE bugs.account_status_data( + event_id BIGINT PRIMARY KEY , + account_status TEXT +); + +ALTER TABLE bugs.account_status_data + ADD CONSTRAINT fk_accountstatus_event + FOREIGN KEY ( event_id ) REFERENCES bugs.initial_report_events; + +GRANT SELECT ON bugs.account_status_data TO :dbuser; + + + +-- +-- View status - administrators +-- + +CREATE TABLE bugs.admin_view_status( + group_id BIGINT NOT NULL , + admin_id INT NOT NULL , + last_view TIMESTAMP WITHOUT TIME ZONE + NOT NULL DEFAULT now( ) , + PRIMARY KEY( group_id , admin_id ) +); + +CREATE INDEX idx_adminview_admin + ON bugs.admin_view_status ( admin_id ); + +CREATE INDEX idx_adminview_lastview + ON bugs.admin_view_status ( last_view ); + +ALTER TABLE bugs.admin_view_status + ADD CONSTRAINT fk_adminview_group + FOREIGN KEY ( group_id ) REFERENCES bugs.groups + ON DELETE CASCADE , + ADD CONSTRAINT fk_adminview_admin + FOREIGN KEY ( admin_id ) REFERENCES admin.administrators; + + + +-- +-- View status - players +-- + +CREATE TABLE bugs.user_view_status( + group_id BIGINT NOT NULL , + user_id INT NOT NULL , + last_view TIMESTAMP WITHOUT TIME ZONE + NOT NULL DEFAULT now( ) , + PRIMARY KEY( group_id , user_id ) +); + +CREATE INDEX idx_userview_user + ON bugs.user_view_status ( user_id ); + +CREATE INDEX idx_userview_lastview + ON bugs.user_view_status ( last_view ); + +ALTER TABLE bugs.user_view_status + ADD CONSTRAINT fk_userview_group + FOREIGN KEY ( group_id ) REFERENCES bugs.groups + ON DELETE CASCADE , + ADD CONSTRAINT fk_userview_user + FOREIGN KEY ( user_id ) REFERENCES users.active_accounts + ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/060-naming-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/060-naming-data.sql new file mode 100644 index 0000000..b9e0115 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/060-naming-data.sql @@ -0,0 +1,109 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Empire/map object names +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Banned names +-- + +CREATE TABLE naming.banned_names( + name VARCHAR(20) NOT NULL , + added_by INT NOT NULL +); + +CREATE UNIQUE INDEX idx_bannednames_name + ON naming.banned_names( lower(name) ); +CREATE INDEX idx_bannednames_addedby + ON naming.banned_names (added_by); + +ALTER TABLE naming.banned_names + ADD CONSTRAINT fk_bannednames_addedby + FOREIGN KEY (added_by) REFERENCES admin.administrators; + + +-- +-- Empire names +-- + +CREATE TABLE naming.empire_names ( + id SERIAL NOT NULL PRIMARY KEY , + owner_id INT NOT NULL , + name VARCHAR(20) NOT NULL +); + +CREATE UNIQUE INDEX idx_empirenames_name + ON naming.empire_names( lower(name) ); +CREATE INDEX idx_empirenames_owner + ON naming.empire_names( owner_id ); + +ALTER TABLE naming.empire_names + ADD CONSTRAINT fk_empirenames_owner + FOREIGN KEY (owner_id) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + +GRANT SELECT ON naming.empire_names TO :dbuser; + + + +-- +-- Map names +-- +CREATE TABLE naming.map_names( + id SERIAL NOT NULL PRIMARY KEY , + name VARCHAR(20) NOT NULL +); + +CREATE UNIQUE INDEX idx_mapnames_name + ON naming.map_names( lower(name) ); + + +-- +-- Changed map names +-- + +CREATE TABLE naming.changed_map_names( + name_id INT NOT NULL PRIMARY KEY , + named_by INT NOT NULL , + named_at TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now() +); + +CREATE INDEX idx_changedmapnames_namedby + ON naming.changed_map_names (named_by); + +ALTER TABLE naming.changed_map_names + ADD CONSTRAINT fk_changedmapnames_name + FOREIGN KEY (name_id) REFERENCES naming.map_names , + ADD CONSTRAINT fk_changedmapnames_namedby + FOREIGN KEY (named_by) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + + +-- +-- Validated map names +-- + +CREATE TABLE naming.validated_map_names( + name_id INT NOT NULL PRIMARY KEY , + validated_by INT NOT NULL , + validated_at TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now() +); + +CREATE INDEX idx_validatedmapnames_namedby + ON naming.validated_map_names (validated_by); + + +ALTER TABLE naming.validated_map_names + ADD CONSTRAINT fk_validatedmapnames_name + FOREIGN KEY (name_id) REFERENCES naming.changed_map_names + ON DELETE CASCADE , + ADD CONSTRAINT fk_validatedmapnames_validatedby + FOREIGN KEY (validated_by) REFERENCES admin.administrators; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/070-constants-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/070-constants-data.sql new file mode 100644 index 0000000..82bca01 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/070-constants-data.sql @@ -0,0 +1,44 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- System "constants" +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- Constant categories +-- +CREATE TABLE sys.constant_categories( + id SERIAL NOT NULL PRIMARY KEY , + name VARCHAR(64) NOT NULL +); + +CREATE UNIQUE INDEX idx_constantcategories_name + ON sys.constant_categories (name); + + +-- +-- Constant definitions and values +-- +CREATE TABLE sys.constant_definitions( + name VARCHAR(64) NOT NULL PRIMARY KEY, + category_id INT NOT NULL , + description TEXT NOT NULL , + min_value REAL , + max_value REAL , + c_value REAL NOT NULL , + CHECK( + ( min_value IS NULL OR ( + min_value IS NOT NULL AND c_value >= min_value ) ) + AND ( max_value IS NULL OR ( + max_value IS NOT NULL AND max_value >= c_value ) ) + ) +); + +CREATE INDEX idx_constantdefinitions_category + ON sys.constant_definitions (category_id); + +ALTER TABLE sys.constant_definitions + ADD CONSTRAINT fk_constraintdefinitions_category + FOREIGN KEY (category_id) REFERENCES sys.constant_categories; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/080-techs-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/080-techs-data.sql new file mode 100644 index 0000000..c539ac2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/080-techs-data.sql @@ -0,0 +1,56 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Technology definitions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Technology lines +-- + +CREATE TABLE tech.lines( + name_id INT NOT NULL PRIMARY KEY , + description_id INT NOT NULL +); + +CREATE INDEX idx_lines_description + ON tech.lines (description_id); + +ALTER TABLE tech.lines + ADD CONSTRAINT fk_lines_name + FOREIGN KEY (name_id) REFERENCES defs.strings , + ADD CONSTRAINT fk_lines_description + FOREIGN KEY (description_id) REFERENCES defs.strings; + + +-- +-- Technology levels +-- + +CREATE TABLE tech.levels( + id SERIAL NOT NULL PRIMARY KEY , + line_id INT NOT NULL , + level INT NOT NULL CHECK( level > 0 ) , + name_id INT NOT NULL , + description_id INT NOT NULL , + points INT NOT NULL CHECK( points > 0 ) , + cost INT NOT NULL CHECK( cost > 0 ) +); + +CREATE UNIQUE INDEX idx_levels_linelevel + ON tech.levels (line_id, level); +CREATE INDEX idx_levels_name + ON tech.levels (name_id); +CREATE INDEX idx_levels_description + ON tech.levels (description_id); + +ALTER TABLE tech.levels + ADD CONSTRAINT fk_levels_line + FOREIGN KEY (line_id) REFERENCES tech.lines , + ADD CONSTRAINT fk_levels_name + FOREIGN KEY (name_id) REFERENCES defs.strings , + ADD CONSTRAINT fk_levels_description + FOREIGN KEY (description_id) REFERENCES defs.strings; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/090-buildables-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/090-buildables-data.sql new file mode 100644 index 0000000..3a80b4d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/090-buildables-data.sql @@ -0,0 +1,75 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Buildings/ships definitions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- "Buildables" +-- +CREATE TABLE tech.buildables( + name_id INT NOT NULL PRIMARY KEY , + description_id INT NOT NULL , + cost INT NOT NULL CHECK( cost > 0 ) , + work INT NOT NULL CHECK( work > 0 ) , + upkeep INT NOT NULL CHECK( upkeep >= 0 ) +); + +CREATE INDEX idx_buildables_description + ON tech.buildables (description_id); + +ALTER TABLE tech.buildables + ADD CONSTRAINT fk_buildables_name + FOREIGN KEY (name_id) REFERENCES defs.strings , + ADD CONSTRAINT fk_buildables_description + FOREIGN KEY (description_id) REFERENCES defs.strings; + + +-- +-- Requirements +-- +CREATE TABLE tech.buildable_requirements( + buildable_id INT NOT NULL , + level_id INT NOT NULL , + PRIMARY KEY( buildable_id , level_id ) +); + +CREATE INDEX idx_buildablereqs_level + ON tech.buildable_requirements( level_id ); + +ALTER TABLE tech.buildable_requirements + ADD CONSTRAINT fk_buildablereqs_buildable + FOREIGN KEY (buildable_id) REFERENCES tech.buildables , + ADD CONSTRAINT fk_buildablereqs_level + FOREIGN KEY (level_id) REFERENCES tech.levels; + + +-- +-- Buildings +-- +CREATE TABLE tech.buildings( + buildable_id INT NOT NULL PRIMARY KEY , + workers INT NOT NULL CHECK( workers >= 0 ) , + output_type building_output_type , + output INT NOT NULL CHECK( output > 0 ) +); + +ALTER TABLE tech.buildings + ADD CONSTRAINT fk_buildings_buildable + FOREIGN KEY (buildable_id) REFERENCES tech.buildables; + +-- +-- Ships +-- +CREATE TABLE tech.ships( + buildable_id INT NOT NULL PRIMARY KEY , + flight_time INT NOT NULL CHECK( flight_time > 0 ) , + power INT NOT NULL CHECK( power > 0 ) +); + + +ALTER TABLE tech.ships + ADD CONSTRAINT fk_buildings_buildable + FOREIGN KEY (buildable_id) REFERENCES tech.buildables; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/100-universe-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/100-universe-data.sql new file mode 100644 index 0000000..fb8f379 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/100-universe-data.sql @@ -0,0 +1,95 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Stellar systems and planets +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Stellar systems +-- +CREATE TABLE verse.systems( + id SERIAL NOT NULL PRIMARY KEY , + x INT NOT NULL , + y INT NOT NULL +); + +CREATE UNIQUE INDEX idx_systems_coordinates + ON verse.systems( x , y ); + +-- +-- Planets +-- +CREATE TABLE verse.planets( + name_id INT NOT NULL PRIMARY KEY , + system_id INT NOT NULL , + orbit INT NOT NULL + CHECK( orbit BETWEEN 1 AND 5 ) , + picture INT NOT NULL , + population REAL NOT NULL + CHECK( population >= 0 ) +); + +CREATE UNIQUE INDEX idx_planets_coordinates + ON verse.planets( system_id , orbit ); + +ALTER TABLE verse.planets + ADD CONSTRAINT fk_planets_name + FOREIGN KEY (name_id) REFERENCES naming.map_names , + ADD CONSTRAINT fk_planets_system + FOREIGN KEY (system_id) REFERENCES verse.systems; + + +-- +-- Happiness +-- +CREATE TABLE verse.planet_happiness( + planet_id INT NOT NULL PRIMARY KEY , + target REAL NOT NULL + CHECK( target BETWEEN 0.0 AND 1.0 ) , + current REAL NOT NULL + CHECK( current > 0 ) +); + +ALTER TABLE verse.planet_happiness + ADD CONSTRAINT fk_planethappiness_planet + FOREIGN KEY (planet_id) REFERENCES verse.planets; + + +-- +-- Money +-- +CREATE TABLE verse.planet_money( + planet_id INT NOT NULL PRIMARY KEY , + income REAL NOT NULL + CHECK( income >= 0 ) , + upkeep REAL NOT NULL + CHECK( upkeep >= 0 ) +); + +ALTER TABLE verse.planet_money + ADD CONSTRAINT fk_planetmoney_planet + FOREIGN KEY (planet_id) REFERENCES verse.planets; + + +-- +-- Buildings +-- +CREATE TABLE verse.planet_buildings( + planet_id INT NOT NULL , + building_id INT NOT NULL , + amount INT NOT NULL CHECK( amount >= 0 ) , + damage REAL NOT NULL CHECK( damage >= 0 ) , + PRIMARY KEY( planet_id , building_id ) +); + +CREATE INDEX idx_planetbuildings_building + ON verse.planet_buildings (building_id); + +ALTER TABLE verse.planet_buildings + ADD CONSTRAINT fk_planetbuildings_planet + FOREIGN KEY (planet_id) REFERENCES verse.planets , + ADD CONSTRAINT fk_planetbuildings_building + FOREIGN KEY (building_id) REFERENCES tech.buildings; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/110-empires-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/110-empires-data.sql new file mode 100644 index 0000000..5a3d00a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/110-empires-data.sql @@ -0,0 +1,176 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Empires and alliances +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Empires +-- + +CREATE TABLE emp.empires( + name_id INT NOT NULL PRIMARY KEY , + cash REAL NOT NULL + CHECK( cash >= 0 ), + debt REAL NOT NULL DEFAULT 0 + CHECK( debt >= 0) +); + +ALTER TABLE emp.empires + ADD CONSTRAINT fk_empires_name + FOREIGN KEY (name_id) REFERENCES naming.empire_names; + + +-- +-- Empire technologies +-- + +CREATE TABLE emp.technologies( + empire_id INT NOT NULL , + line_id INT NOT NULL , + level INT NOT NULL DEFAULT 1 + CHECK( level > 0 ) , + accumulated REAL NOT NULL DEFAULT 0 + CHECK( accumulated >= 0 ), + PRIMARY KEY( empire_id , line_id ) +); + +CREATE INDEX idx_technologies_line + ON emp.technologies (line_id); + +ALTER TABLE emp.technologies + ADD CONSTRAINT fk_technologies_empire + FOREIGN KEY (empire_id) REFERENCES emp.empires + ON DELETE CASCADE , + ADD CONSTRAINT fk_technologies_line + FOREIGN KEY (line_id) REFERENCES tech.lines; + + +-- +-- Empire planets +-- + +CREATE TABLE emp.planets( + planet_id INT NOT NULL PRIMARY KEY , + empire_id INT NOT NULL +); + +CREATE INDEX idx_planets_empire + ON emp.planets (empire_id); + +ALTER TABLE emp.planets + ADD CONSTRAINT fk_eplanets_planet + FOREIGN KEY (planet_id) REFERENCES verse.planets , + ADD CONSTRAINT fk_eplanets_empire + FOREIGN KEY (empire_id) REFERENCES emp.empires + ON DELETE CASCADE; + + +-- +-- Planets being abandonned +-- + +CREATE TABLE emp.abandon( + planet_id INT NOT NULL PRIMARY KEY , + time_left INT NOT NULL CHECK ( time_left > 0 ) +); + +CREATE INDEX idx_abandon_ready + ON emp.abandon ( ( time_left = 1 ) ); + +ALTER TABLE emp.abandon + ADD CONSTRAINT fk_abandon_planet + FOREIGN KEY (planet_id) REFERENCES emp.planets + ON DELETE CASCADE; + + +-- +-- Alliances +-- + +CREATE TABLE emp.alliances( + id SERIAL NOT NULL PRIMARY KEY , + tag VARCHAR(5) NOT NULL , + name VARCHAR(128) NOT NULL , + leader_id INT NOT NULL +); + +CREATE UNIQUE INDEX idx_alliances_tag + ON emp.alliances ( lower(tag) ); +CREATE UNIQUE INDEX idx_alliances_leader + ON emp.alliances (leader_id); + +ALTER TABLE emp.alliances + ADD CONSTRAINT fk_alliances_leader + FOREIGN KEY (leader_id) REFERENCES emp.empires + ON DELETE CASCADE; + + +-- +-- Alliance membership +-- + +CREATE TABLE emp.alliance_members( + empire_id INT NOT NULL PRIMARY KEY , + alliance_id INT NOT NULL , + is_pending BOOLEAN NOT NULL + DEFAULT TRUE +); + +CREATE INDEX idx_alliancemembers_alliance + ON emp.alliance_members( alliance_id ); + +ALTER TABLE emp.alliance_members + ADD CONSTRAINT fk_alliancemembers_empire + FOREIGN KEY (empire_id) REFERENCES emp.empires + ON DELETE CASCADE , + ADD CONSTRAINT fk_alliancemembers_alliance + FOREIGN KEY (alliance_id) REFERENCES emp.alliances + ON DELETE CASCADE; + + +-- +-- Enemy lists, alliances +-- + +CREATE TABLE emp.enemy_alliances( + empire_id INT NOT NULL , + alliance_id INT NOT NULL , + PRIMARY KEY (empire_id,alliance_id) +); + +CREATE INDEX idx_enemyalliances_alliance + ON emp.enemy_alliances (alliance_id); + +ALTER TABLE emp.enemy_alliances + ADD CONSTRAINT fk_enemyalliances_empire + FOREIGN KEY (empire_id) REFERENCES emp.empires + ON DELETE CASCADE , + ADD CONSTRAINT fk_enemyalliances_alliance + FOREIGN KEY (alliance_id) REFERENCES emp.alliances + ON DELETE CASCADE; + + +-- +-- Enemy lists, empires +-- + +CREATE TABLE emp.enemy_empires( + empire_id INT NOT NULL , + enemy_id INT NOT NULL , + PRIMARY KEY (empire_id,enemy_id) +); + +CREATE INDEX idx_enemyempires_enemy + ON emp.enemy_empires (enemy_id); + +ALTER TABLE emp.enemy_empires + ADD CONSTRAINT fk_enemyempires_empire + FOREIGN KEY (empire_id) REFERENCES emp.empires + ON DELETE CASCADE , + ADD CONSTRAINT fk_enemyempires_enemy + FOREIGN KEY (enemy_id) REFERENCES emp.empires + ON DELETE CASCADE; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/120-construction-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/120-construction-data.sql new file mode 100644 index 0000000..9ae9fcd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/120-construction-data.sql @@ -0,0 +1,82 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Construction queues +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Buildings queues +-- + +CREATE TABLE verse.bld_queues( + planet_id INT NOT NULL PRIMARY KEY , + money REAL NOT NULL CHECK( money >= 0 ), + work REAL NOT NULL CHECK( work >= 0 ) +); + +ALTER TABLE verse.bld_queues + ADD CONSTRAINT fk_bldqueues_planet + FOREIGN KEY (planet_id) REFERENCES verse.planets; + + +-- +-- Buildings queue items +-- + +CREATE TABLE verse.bld_items( + queue_id INT NOT NULL , + queue_order INT NOT NULL CHECK( queue_order >= 0 ) , + building_id INT NOT NULL , + destroy BOOLEAN NOT NULL , + amount INT NOT NULL CHECK( amount > 0 ) , + PRIMARY KEY( queue_id , queue_order ) +); + +CREATE INDEX idx_blditems_building + ON verse.bld_items (building_id); + +ALTER TABLE verse.bld_items + ADD CONSTRAINT fk_blditems_queue + FOREIGN KEY (queue_id) REFERENCES verse.bld_queues , + ADD CONSTRAINT fk_blditems_building + FOREIGN KEY (building_id) REFERENCES tech.buildings; + + +-- +-- Military queues +-- + +CREATE TABLE verse.mil_queues( + planet_id INT NOT NULL PRIMARY KEY , + money REAL NOT NULL CHECK( money >= 0 ), + work REAL NOT NULL CHECK( work >= 0 ) +); + +ALTER TABLE verse.mil_queues + ADD CONSTRAINT fk_milqueues_planet + FOREIGN KEY (planet_id) REFERENCES verse.planets; + + +-- +-- Military queue items +-- + +CREATE TABLE verse.mil_items( + queue_id INT NOT NULL , + queue_order INT NOT NULL CHECK( queue_order >= 0 ) , + ship_id INT NOT NULL , + amount INT NOT NULL CHECK( amount > 0 ) , + PRIMARY KEY( queue_id , queue_order ) +); + +CREATE INDEX idx_militems_ship + ON verse.mil_items (ship_id); + +ALTER TABLE verse.mil_items + ADD CONSTRAINT fk_militems_queue + FOREIGN KEY (queue_id) REFERENCES verse.mil_queues , + ADD CONSTRAINT fk_militems_ship + FOREIGN KEY (ship_id) REFERENCES tech.ships; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/130-fleets-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/130-fleets-data.sql new file mode 100644 index 0000000..7d7bb0f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/130-fleets-data.sql @@ -0,0 +1,118 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Fleets +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Fleets +-- + +CREATE TABLE fleets.fleets( + id BIGSERIAL NOT NULL PRIMARY KEY , + owner_id INT NOT NULL , + location_id INT NOT NULL , + name VARCHAR(64) , + attacking BOOLEAN NOT NULL , + status fleet_status NOT NULL , + penalty INT NOT NULL , + CHECK( ( status = 'AVAILABLE' AND penalty = 0 ) + OR ( status <> 'AVAILABLE' AND penalty > 0) ) +); + +CREATE INDEX idx_fleets_owner + ON fleets.fleets ( owner_id ); +CREATE INDEX idx_fleets_location + ON fleets.fleets ( location_id ); +CREATE INDEX idx_fleets_status + ON fleets.fleets ( status , penalty ); + +ALTER TABLE fleets.fleets + ADD CONSTRAINT fk_fleets_owner + FOREIGN KEY ( owner_id ) REFERENCES emp.empires + ON DELETE CASCADE , + ADD CONSTRAINT fk_fleets_location + FOREIGN KEY ( location_id ) REFERENCES verse.planets; + + +-- +-- Ships +-- + +CREATE TABLE fleets.ships( + fleet_id BIGINT NOT NULL , + ship_id INT NOT NULL , + amount INT NOT NULL CHECK( amount >= 0 ) , + damage REAL NOT NULL , + PRIMARY KEY( fleet_id , ship_id ) +); + +CREATE INDEX idx_ships_ship + ON fleets.ships( ship_id ); + +ALTER TABLE fleets.ships + ADD CONSTRAINT fk_ships_fleet + FOREIGN KEY ( fleet_id ) REFERENCES fleets.fleets + ON DELETE CASCADE , + ADD CONSTRAINT fk_ships_ship + FOREIGN KEY ( ship_id ) REFERENCES tech.ships; + + +-- +-- Fleet movements +-- + +CREATE TABLE fleets.movements( + fleet_id BIGINT NOT NULL PRIMARY KEY , + source_id INT NOT NULL , + time_left INT NOT NULL CHECK( time_left > 0 ) , + state_time_left INT NOT NULL CHECK( state_time_left > 0 ) +); + +CREATE INDEX idx_movements_source + ON fleets.movements( source_id ); + +ALTER TABLE fleets.movements + ADD CONSTRAINT fk_movements_fleet + FOREIGN KEY ( fleet_id ) REFERENCES fleets.fleets + ON DELETE CASCADE , + ADD CONSTRAINT fk_movements_source + FOREIGN KEY ( source_id ) REFERENCES verse.planets; + + +-- +-- Movement states, outer space +-- + +CREATE TABLE fleets.ms_space( + movement_id BIGINT NOT NULL PRIMARY KEY , + start_x REAL NOT NULL , + start_y REAL NOT NULL +); + +ALTER TABLE fleets.ms_space + ADD CONSTRAINT fk_msspace_movement + FOREIGN KEY ( movement_id ) REFERENCES fleets.movements + ON DELETE CASCADE; + + +-- +-- Movement states, in system +-- + +CREATE TABLE fleets.ms_system( + movement_id BIGINT NOT NULL PRIMARY KEY , + ref_point_id INT NOT NULL , + outwards BOOLEAN NOT NULL , + past_ref_point BOOLEAN NOT NULL +); + +ALTER TABLE fleets.ms_system + ADD CONSTRAINT fk_mssystem_movement + FOREIGN KEY ( movement_id ) REFERENCES fleets.movements + ON DELETE CASCADE , + ADD CONSTRAINT fk_mssystem_refpoint + FOREIGN KEY ( ref_point_id ) REFERENCES verse.planets; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/140-status-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/140-status-data.sql new file mode 100644 index 0000000..a3c76bb --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/140-status-data.sql @@ -0,0 +1,107 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- System & game updates status +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- System status +-- +CREATE TABLE sys.status( + next_tick BIGINT NOT NULL + DEFAULT 0 , + current_tick BIGINT , + + last_msg_recap TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) , + last_admin_recap TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) , + last_error_recap TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) , + + maintenance_start TIMESTAMP WITHOUT TIME ZONE , + maintenance_end TIMESTAMP WITHOUT TIME ZONE , + maintenance_text TEXT +); + +INSERT INTO sys.status DEFAULT VALUES; + +GRANT SELECT ON sys.status TO :dbuser; + + + +-- +-- Ticker status +-- + +CREATE TYPE ticker_task_status + AS ENUM( 'RUNNING' , 'STOPPED' , 'AUTO' ); + +CREATE TABLE sys.ticker( + id SERIAL PRIMARY KEY , + task_name VARCHAR(64) NOT NULL UNIQUE , + status ticker_task_status NOT NULL , + auto_start TIMESTAMP WITHOUT TIME ZONE +); + +INSERT INTO sys.ticker( task_name , status ) + VALUES ( 'Game update' , 'STOPPED' ); + +GRANT SELECT ON sys.ticker TO :dbuser; + + + +-- +-- Updates +-- +CREATE TABLE sys.updates( + id BIGSERIAL NOT NULL PRIMARY KEY , + gu_type update_type NOT NULL , + status processing_status NOT NULL DEFAULT 'FUTURE' , + last_tick BIGINT NOT NULL DEFAULT -1 +); + +CREATE INDEX idx_updates_finder + ON sys.updates (gu_type, status, last_tick); + + +-- +-- Planet updates +-- +CREATE TABLE verse.updates( + update_id BIGINT NOT NULL PRIMARY KEY , + planet_id INT NOT NULL +); + +CREATE INDEX idx_planetupdates_planet + ON verse.updates (planet_id); + +ALTER TABLE verse.updates + ADD CONSTRAINT fk_planetupdates_update + FOREIGN KEY ( update_id ) REFERENCES sys.updates , + ADD CONSTRAINT fk_planetupdates_planet + FOREIGN KEY ( planet_id ) REFERENCES verse.planets; + + +-- +-- Empire updates +-- +CREATE TABLE emp.updates( + update_id BIGINT NOT NULL PRIMARY KEY , + empire_id INT NOT NULL +); + +CREATE INDEX idx_empireupdates_empire + ON emp.updates( empire_id ); + +ALTER TABLE emp.updates + ADD CONSTRAINT fk_empireupdates_update + FOREIGN KEY ( update_id ) REFERENCES sys.updates , + ADD CONSTRAINT fk_empireupdates_empire + FOREIGN KEY ( empire_id ) REFERENCES emp.empires + ON DELETE CASCADE; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/150-logs-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/150-logs-data.sql new file mode 100644 index 0000000..273827b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/150-logs-data.sql @@ -0,0 +1,126 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- System, user and administrative logs +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- System logs +-- +CREATE TABLE sys.logs( + id BIGSERIAL NOT NULL PRIMARY KEY , + t TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) , + component VARCHAR( 64 ) , + level log_level NOT NULL , + message TEXT NOT NULL +); + +CREATE INDEX idx_syslogs_time + ON sys.logs( t ); +CREATE INDEX idx_syslogs_component + ON sys.logs( component ); +CREATE INDEX idx_syslogs_level + ON sys.logs( level ); + +GRANT SELECT ON sys.logs TO :dbuser; + + +-- +-- System logs, exceptions +-- +CREATE TABLE sys.exceptions( + id BIGSERIAL NOT NULL PRIMARY KEY , + log_id BIGINT NOT NULL , + depth INT NOT NULL CHECK( depth>= 0 ) , + exc_class VARCHAR( 255 ) NOT NULL , + message TEXT +); + +CREATE UNIQUE INDEX idx_exceptions_logdepth + ON sys.exceptions (log_id , depth ); + +ALTER TABLE sys.exceptions + ADD CONSTRAINT fk_exceptions_log + FOREIGN KEY ( log_id ) REFERENCES sys.logs + ON DELETE CASCADE; + +GRANT SELECT ON sys.exceptions TO :dbuser; + + +-- +-- System logs, stack traces +-- +CREATE TABLE sys.stack_traces( + exception_id BIGSERIAL NOT NULL , + depth INT NOT NULL , + location TEXT , + file_name TEXT , + line_number INT , + PRIMARY KEY( exception_id , depth ) +); + +ALTER TABLE sys.stack_traces + ADD CONSTRAINT fk_stacktraces_exception + FOREIGN KEY ( exception_id ) REFERENCES sys.exceptions + ON DELETE CASCADE; + +GRANT SELECT ON sys.stack_traces TO :dbuser; + + +-- +-- User logs +-- +CREATE TABLE users.logs( + t TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) , + credentials_id INT NOT NULL , + level log_level NOT NULL , + message TEXT NOT NULL +); + +CREATE INDEX idx_userlogs_time + ON users.logs( t ); +CREATE INDEX idx_userlogs_level + ON users.logs( level ); +CREATE INDEX idx_userlogs_account + ON users.logs( credentials_id ); + +ALTER TABLE users.logs + ADD CONSTRAINT fk_userlogs_credentials + FOREIGN KEY (credentials_id) REFERENCES users.credentials + ON DELETE CASCADE ON UPDATE CASCADE; + +GRANT SELECT ON users.logs TO :dbuser; + + +-- +-- Administrative logs +-- +CREATE TABLE admin.logs( + t TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now( ) , + admin_id INT NOT NULL , + level log_level NOT NULL , + message TEXT NOT NULL +); + +CREATE INDEX idx_adminlogs_time + ON admin.logs( t ); +CREATE INDEX idx_adminlogs_level + ON admin.logs( level ); +CREATE INDEX idx_adminlogs_admin + ON admin.logs( admin_id ); + +ALTER TABLE admin.logs + ADD CONSTRAINT fk_userlogs_admin + FOREIGN KEY (admin_id) REFERENCES admin.administrators; + + +GRANT SELECT ON admin.logs TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/160-battle-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/160-battle-data.sql new file mode 100644 index 0000000..2672b0d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/160-battle-data.sql @@ -0,0 +1,230 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Battles +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Status change types +-- + +CREATE TYPE battle_planet_change + AS ENUM( 'INIT' , 'RENAME', 'BUILD' , 'DESTROY' , 'BATTLE' ); +CREATE TYPE battle_fleet_change + AS ENUM( 'INIT' , 'BUILD', 'ARRIVE' , 'DEPART' , 'DISBAND' , 'BATTLE' ); + + + +-- +-- Main battle table +-- + +CREATE TABLE battles.battles( + id BIGSERIAL PRIMARY KEY , + location_id INT NOT NULL , + first_tick BIGINT NOT NULL , + last_tick BIGINT +); + +CREATE UNIQUE INDEX idx_battles_uniqueness + ON battles.battles( location_id , last_tick ); + +ALTER TABLE battles.battles + ADD CONSTRAINT fk_battles_location + FOREIGN KEY ( location_id ) REFERENCES verse.planets; + + + +-- +-- Battle planet status +-- + +CREATE TABLE battles.planets( + id BIGSERIAL PRIMARY KEY , + battle_id BIGINT NOT NULL , + tick_identifier BIGINT NOT NULL , + change_type battle_planet_change NOT NULL , + name VARCHAR(20) +); + +CREATE INDEX idx_planets_tick + ON battles.planets( tick_identifier ); + +CREATE UNIQUE INDEX idx_planets_uniquenes + ON battles.planets( battle_id , tick_identifier , change_type ); + +ALTER TABLE battles.planets + ADD CONSTRAINT fk_planets_battle + FOREIGN KEY ( battle_id ) REFERENCES battles.battles + ON DELETE CASCADE; + + + +-- +-- Battle buildings +-- + +CREATE TABLE battles.buildings( + planet_id BIGINT NOT NULL , + building_id INT NOT NULL , + change INT NOT NULL CHECK( change <> 0 ) , + PRIMARY KEY( planet_id , building_id ) +); + +CREATE INDEX idx_buildings_building + ON battles.buildings ( building_id ); + +ALTER TABLE battles.buildings + ADD CONSTRAINT fk_buildings_planet + FOREIGN KEY ( planet_id ) REFERENCES battles.planets + ON DELETE CASCADE , + ADD CONSTRAINT fk_buildings_building + FOREIGN KEY ( building_id ) REFERENCES tech.buildings; + + + +-- +-- Battle - planetary defence power +-- + +CREATE TABLE battles.defences( + battle_id BIGINT NOT NULL , + tick_identifier BIGINT NOT NULL , + power BIGINT NOT NULL , + PRIMARY KEY( battle_id , tick_identifier ) +); + +ALTER TABLE battles.defences + ADD CONSTRAINT fk_defences_battle + FOREIGN KEY ( battle_id ) REFERENCES battles.battles + ON DELETE CASCADE; + + + +-- +-- Empires involved in a battle +-- + +CREATE TABLE battles.empires( + id BIGSERIAL PRIMARY KEY , + name VARCHAR(20) NOT NULL , + empire_id INT +); + +CREATE INDEX idx_empires_name + ON battles.empires( name ); + +CREATE INDEX idx_empires_empire + ON battles.empires( empire_id ); + +ALTER TABLE battles.empires + ADD CONSTRAINT fk_empires_empire + FOREIGN KEY (empire_id) REFERENCES emp.empires + ON DELETE SET NULL; + + + +-- +-- Protagonists +-- + +CREATE TABLE battles.protagonists( + id BIGSERIAL PRIMARY KEY , + battle_id BIGINT NOT NULL , + empire_id BIGINT NOT NULL +); + +CREATE UNIQUE INDEX idx_protagonists_uniqueness + ON battles.protagonists( battle_id , empire_id ); + +CREATE INDEX idx_protagonists_empire + ON battles.protagonists( empire_id ); + +ALTER TABLE battles.protagonists + ADD CONSTRAINT fk_protagonists_battle + FOREIGN KEY (battle_id) REFERENCES battles.battles + ON DELETE CASCADE , + ADD CONSTRAINT fk_protagonists_empire + FOREIGN KEY (empire_id) REFERENCES battles.empires; + + + +-- +-- Planet ownership +-- + +CREATE TABLE battles.planet_ownership( + protagonist_id BIGINT NOT NULL PRIMARY KEY , + abandoned_at BIGINT +); + +ALTER TABLE battles.planet_ownership + ADD CONSTRAINT fk_ownership_protagonist + FOREIGN KEY (protagonist_id) REFERENCES battles.protagonists + ON DELETE CASCADE; + + + +-- +-- Battle status changes +-- + +CREATE TABLE battles.status_changes( + protagonist_id BIGINT NOT NULL , + tick_identifier BIGINT NOT NULL , + attacking BOOLEAN NOT NULL , + PRIMARY KEY( protagonist_id , tick_identifier ) +); + +CREATE INDEX idx_statuschanges_tick + ON battles.status_changes( tick_identifier ); + +ALTER TABLE battles.status_changes + ADD CONSTRAINT fk_statuschanges_protagonist + FOREIGN KEY (protagonist_id) REFERENCES battles.protagonists + ON DELETE CASCADE; + + + +-- +-- Fleets involved in battles +-- + +CREATE TABLE battles.fleets( + id BIGSERIAL PRIMARY KEY , + protagonist_id BIGINT NOT NULL , + tick_identifier BIGINT NOT NULL , + change_type battle_fleet_change NOT NULL +); + +CREATE UNIQUE INDEX idx_fleets_uniqueness + ON battles.fleets( protagonist_id , tick_identifier , change_type ); +CREATE INDEX idx_fleets_tick + ON battles.fleets( tick_identifier ); + +ALTER TABLE battles.fleets + ADD CONSTRAINT fk_fleets_protagonist + FOREIGN KEY (protagonist_id) REFERENCES battles.protagonists + ON DELETE CASCADE; + + + +-- +-- Ships in battle fleets +-- + +CREATE TABLE battles.ships( + fleet_id BIGINT NOT NULL , + ship_id INT NOT NULL , + change INT NOT NULL CHECK( change <> 0 ) +); + +ALTER TABLE battles.ships + ADD CONSTRAINT fk_ships_fleet + FOREIGN KEY ( fleet_id ) REFERENCES battles.fleets + ON DELETE CASCADE , + ADD CONSTRAINT fk_ships_ship + FOREIGN KEY ( ship_id ) REFERENCES tech.ships; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/170-events-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/170-events-data.sql new file mode 100644 index 0000000..186a032 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/170-events-data.sql @@ -0,0 +1,311 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Storage of events (internal messages) +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE TYPE event_type + AS ENUM ( 'QUEUE' , 'EMPIRE' , 'FLEETS' , 'PLANET', 'ALLIANCE', 'ADMIN' , 'BUGS' ); + +CREATE TYPE event_status + AS ENUM( 'TICK' , 'ACTION' , 'READY' , 'SENT' ); + + + +-- +-- Events table +-- + +CREATE TABLE events.events( + event_id BIGSERIAL PRIMARY KEY , + empire_id INT NOT NULL , + tick BIGINT NOT NULL , + real_time TIMESTAMP WITHOUT TIME ZONE + NOT NULL + DEFAULT now() , + evt_type event_type NOT NULL , + evt_subtype INT NOT NULL , + status event_status NOT NULL +); + +CREATE INDEX idx_events_empire + ON events.events (empire_id); + +CREATE INDEX idx_events_time + ON events.events (real_time); + +CREATE INDEX idx_events_lookup + ON events.events( empire_id , tick , evt_type , evt_subtype , status ) + WHERE status IN ( 'TICK' , 'ACTION' ); + +ALTER TABLE events.events + ADD CONSTRAINT fk_events_empire + FOREIGN KEY ( empire_id ) REFERENCES emp.empires + ON DELETE CASCADE; + +GRANT SELECT ON events.events TO :dbuser; + + +-- +-- Build queue events +-- + +CREATE TABLE events.queue_events ( + event_id BIGINT NOT NULL PRIMARY KEY +); + +ALTER TABLE events.queue_events + ADD CONSTRAINT fk_bqevents_event + FOREIGN KEY (event_id) REFERENCES events.events + ON DELETE CASCADE; + + + +-- +-- Build queue event locations +-- + +CREATE TABLE events.bqe_locations( + event_id BIGINT NOT NULL , + location_id INT NOT NULL , + location_name VARCHAR(20) NOT NULL , + PRIMARY KEY( event_id , location_id ) +); + +ALTER TABLE events.bqe_locations + ADD CONSTRAINT fk_bqelocations_event + FOREIGN KEY (event_id) REFERENCES events.queue_events + ON DELETE CASCADE , + ADD CONSTRAINT fk_bqelocations_location + FOREIGN KEY (location_id) REFERENCES verse.planets; + + + +-- +-- Empire events +-- + +CREATE TABLE events.empire_events( + event_id BIGINT NOT NULL PRIMARY KEY , + technology_id INT NOT NULL +); + +CREATE INDEX idx_empevents_tech + ON events.empire_events (technology_id); + +ALTER TABLE events.empire_events + ADD CONSTRAINT fk_empevents_event + FOREIGN KEY (event_id) REFERENCES events.events + ON DELETE CASCADE, + ADD CONSTRAINT fk_empevents_tech + FOREIGN KEY (technology_id) REFERENCES tech.levels; + + + +-- +-- Fleet events +-- + +CREATE TABLE events.fleets_events( + event_id BIGINT NOT NULL PRIMARY KEY , + location_id INT NOT NULL , + location_name VARCHAR(20) NOT NULL +); + +CREATE INDEX idx_flevents_location + ON events.fleets_events( location_id ); + +ALTER TABLE events.fleets_events + ADD CONSTRAINT fk_flevents_event + FOREIGN KEY (event_id) REFERENCES events.events + ON DELETE CASCADE , + ADD CONSTRAINT fk_flevents_location + FOREIGN KEY (location_id) REFERENCES verse.planets; + + + +-- +-- Fleets for fleet events +-- + +CREATE TABLE events.fleet_lists( + id BIGSERIAL PRIMARY KEY , + event_id BIGINT NOT NULL , + owner_id INT , + owner_name VARCHAR(20) NOT NULL , + fleet_name VARCHAR(64) , + fleet_power BIGINT NOT NULL CHECK( fleet_power > 0 ) , + status BOOLEAN , + source_id INT , + source_name VARCHAR(20) , + CHECK( source_id IS NULL AND source_name IS NULL OR source_id IS NOT NULL AND source_name IS NOT NULL ) +); + +CREATE INDEX idx_flelists_event + ON events.fleet_lists( event_id ); + +CREATE INDEX idx_flelists_owner + ON events.fleet_lists( owner_id ) + WHERE owner_id IS NOT NULL; + +CREATE INDEX idx_flelists_source + ON events.fleet_lists( source_id ) + WHERE source_id IS NOT NULL; + +ALTER TABLE events.fleet_lists + ADD CONSTRAINT fk_flelist_event + FOREIGN KEY ( event_id ) REFERENCES events.fleets_events + ON DELETE CASCADE , + ADD CONSTRAINT fk_flelist_owner + FOREIGN KEY ( owner_id ) REFERENCES emp.empires + ON DELETE SET NULL , + ADD CONSTRAINT fk_flelist_source + FOREIGN KEY ( source_id ) REFERENCES verse.planets; + +GRANT SELECT ON events.fleet_lists TO :dbuser; + + + +-- +-- Planet events +-- + +CREATE TABLE events.planet_events( + event_id BIGINT PRIMARY KEY, + location_id INT NOT NULL , + location_name VARCHAR(20) NOT NULL , + empire_id INT , + empire_name VARCHAR(20) , + battle_id BIGINT , + CHECK( battle_id IS NULL AND empire_id IS NULL AND empire_name IS NULL + OR battle_id IS NOT NULL AND empire_id IS NULL AND empire_name IS NULL + OR battle_id IS NULL AND empire_name IS NOT NULL ) +); + +CREATE INDEX idx_pevents_event + ON events.planet_events ( event_id ); + +CREATE INDEX idx_pevents_location + ON events.planet_events ( location_id ); + +CREATE INDEX idx_pevents_empire + ON events.planet_events ( empire_id ) + WHERE empire_id IS NOT NULL; + +CREATE INDEX idx_pevents_battle + ON events.planet_events ( battle_id ) + WHERE battle_id IS NOT NULL; + +ALTER TABLE events.planet_events + ADD CONSTRAINT fk_pevents_event + FOREIGN KEY ( event_id ) REFERENCES events.events + ON DELETE CASCADE , + ADD CONSTRAINT fk_pevents_location + FOREIGN KEY ( location_id ) REFERENCES verse.planets , + ADD CONSTRAINT fk_pevents_empire + FOREIGN KEY ( empire_id ) REFERENCES emp.empires + ON DELETE SET NULL , + ADD CONSTRAINT fk_pevents_battle + FOREIGN KEY ( battle_id ) REFERENCES battles.battles; + + + +-- +-- Alliance events +-- + +CREATE TABLE events.alliance_events( + event_id BIGINT PRIMARY KEY , + alliance_id INT , + alliance_tag VARCHAR( 5 ) NOT NULL , + empire_id INT , + empire_name VARCHAR( 20 ) , + req_result BOOLEAN , + CHECK( req_result IS NULL AND empire_id IS NULL AND empire_name IS NULL + OR req_result IS NOT NULL AND empire_id IS NULL AND empire_name IS NULL + OR req_result IS NULL AND empire_name IS NOT NULL ) +); + +CREATE INDEX idx_aevents_event + ON events.alliance_events ( event_id ); + +CREATE INDEX idx_aevents_alliance + ON events.alliance_events ( alliance_id ) + WHERE alliance_id IS NOT NULL; + +CREATE INDEX idx_aevents_empire + ON events.alliance_events ( empire_id ) + WHERE empire_id IS NOT NULL; + +ALTER TABLE events.alliance_events + ADD CONSTRAINT fk_aevents_event + FOREIGN KEY ( event_id ) REFERENCES events.events + ON DELETE CASCADE , + ADD CONSTRAINT fk_aevents_allliance + FOREIGN KEY ( alliance_id ) REFERENCES emp.alliances + ON DELETE SET NULL , + ADD CONSTRAINT fk_aevents_empire + FOREIGN KEY ( empire_id ) REFERENCES emp.empires + ON DELETE SET NULL; + + + +-- +-- Admin events +-- + +CREATE TABLE events.admin_events( + event_id BIGINT PRIMARY KEY , + n_warnings INT , + location_id INT , + old_name VARCHAR( 20 ) NOT NULL , + new_name VARCHAR( 20 ) +); + +CREATE INDEX idx_adevents_event + ON events.admin_events ( event_id ); + +CREATE INDEX idx_adevents_location + ON events.admin_events ( location_id ) + WHERE location_id IS NOT NULL; + +ALTER TABLE events.admin_events + ADD CONSTRAINT fk_adevents_event + FOREIGN KEY ( event_id ) REFERENCES events.events + ON DELETE CASCADE , + ADD CONSTRAINT fk_adevents_location + FOREIGN KEY ( location_id ) REFERENCES verse.planets; + + + +-- +-- Bug tracking events +-- + +CREATE TABLE events.bug_events( + event_id BIGINT PRIMARY KEY , + bug_id BIGINT NOT NULL , + submitter_id BIGINT NOT NULL +); + +CREATE INDEX idx_btevents_event + ON events.bug_events ( event_id ); + +CREATE INDEX idx_btevents_bug + ON events.bug_events ( bug_id ); + +CREATE INDEX idx_btevents_submitter + ON events.bug_events ( submitter_id ); + + +ALTER TABLE events.bug_events + ADD CONSTRAINT fk_btevents_event + FOREIGN KEY ( event_id ) REFERENCES events.events + ON DELETE CASCADE , + ADD CONSTRAINT fk_btevents_bug + FOREIGN KEY ( bug_id ) REFERENCES bugs.initial_report_events , + ADD CONSTRAINT fk_btevents_submitter + FOREIGN KEY ( submitter_id ) REFERENCES bugs.submitters; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/180-messages-data.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/180-messages-data.sql new file mode 100644 index 0000000..57c26dc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/data/180-messages-data.sql @@ -0,0 +1,235 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Storage of messages +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE TYPE sender_type + AS ENUM( 'ADM', 'EMP' ); + +CREATE TYPE receiver_type + AS ENUM( 'ADM' , 'EMP' , 'ALL' ); + +CREATE TYPE message_status + AS ENUM( 'UNREAD' , 'READ' , 'DELETED' ); + + +-- +-- Message senders +-- + +CREATE TABLE msgs.senders( + id BIGSERIAL PRIMARY KEY , + sender_type sender_type NOT NULL , + name VARCHAR(48) NOT NULL , + empire_id INT , + admin_id INT , + CHECK ( empire_id IS NULL AND admin_id IS NULL + OR sender_type = 'ADM' AND empire_id IS NULL AND admin_id IS NOT NULL + OR sender_type = 'EMP' AND empire_id IS NOT NULL AND admin_id IS NULL ) +); + +CREATE UNIQUE INDEX idx_senders_empires + ON msgs.senders ( empire_id ) + WHERE empire_id IS NOT NULL; + +CREATE UNIQUE INDEX idx_senders_admins + ON msgs.senders ( admin_id ) + WHERE admin_id IS NOT NULL; + +ALTER TABLE msgs.senders + ADD CONSTRAINT fk_senders_empire + FOREIGN KEY ( empire_id ) REFERENCES emp.empires + ON DELETE SET NULL , + ADD CONSTRAINT fk_senders_admin + FOREIGN KEY ( admin_id ) REFERENCES admin.administrators + ON DELETE SET NULL; + + + +-- +-- Message receivers +-- + +CREATE TABLE msgs.receivers( + id BIGSERIAL PRIMARY KEY , + receiver_type receiver_type NOT NULL , + name VARCHAR(48) NOT NULL , + empire_id INT , + admin_id INT , + alliance_id INT , + CHECK ( empire_id IS NULL AND admin_id IS NULL AND alliance_id IS NULL + OR receiver_type = 'ADM' AND empire_id IS NULL AND admin_id IS NOT NULL AND alliance_id IS NULL + OR receiver_type = 'EMP' AND empire_id IS NOT NULL AND admin_id IS NULL AND alliance_id IS NULL + OR receiver_type = 'ALL' AND empire_id IS NULL AND admin_id IS NULL AND alliance_id IS NOT NULL ) +); + +CREATE UNIQUE INDEX idx_receivers_empires + ON msgs.receivers ( empire_id ) + WHERE empire_id IS NOT NULL; + +CREATE UNIQUE INDEX idx_receivers_admins + ON msgs.receivers ( admin_id ) + WHERE admin_id IS NOT NULL; + +CREATE UNIQUE INDEX idx_receivers_alliances + ON msgs.receivers ( alliance_id ) + WHERE alliance_id IS NOT NULL; + +ALTER TABLE msgs.receivers + ADD CONSTRAINT fk_receivers_empire + FOREIGN KEY ( empire_id ) REFERENCES emp.empires + ON DELETE SET NULL , + ADD CONSTRAINT fk_receivers_alliance + FOREIGN KEY ( alliance_id ) REFERENCES emp.alliances + ON DELETE SET NULL , + ADD CONSTRAINT fk_receivers_admin + FOREIGN KEY ( admin_id ) REFERENCES admin.administrators + ON DELETE SET NULL; + + + +-- +-- Text messages +-- + +CREATE TABLE msgs.text_messages( + id BIGSERIAL PRIMARY KEY , + tick BIGINT NOT NULL , + t TIMESTAMP WITHOUT TIME ZONE + NOT NULL DEFAULT now( ) , + title VARCHAR( 64 ) NOT NULL , + contents TEXT NOT NULL +); + +GRANT SELECT ON msgs.text_messages TO :dbuser; + + + +-- +-- Actual messages +-- + +CREATE TABLE msgs.messages( + id BIGSERIAL PRIMARY KEY , + receiver_id BIGINT NOT NULL , + sender_id BIGINT , + text_content_id BIGINT , + event_content_id BIGINT , + CHECK( + sender_id IS NULL AND text_content_id IS NULL AND event_content_id IS NOT NULL + OR sender_id IS NOT NULL AND text_content_id IS NOT NULL AND event_content_id IS NULL ) +); + +CREATE INDEX idx_messages_receiver + ON msgs.messages( receiver_id ); + +CREATE UNIQUE INDEX idx_messages_e_event + ON msgs.messages( event_content_id ) + WHERE event_content_id IS NOT NULL; + +CREATE INDEX idx_messages_sender + ON msgs.messages( sender_id ) + WHERE sender_id IS NOT NULL; + +CREATE INDEX idx_messages_t_text + ON msgs.messages( text_content_id ) + WHERE text_content_id IS NOT NULL; + +ALTER TABLE msgs.messages + ADD CONSTRAINT fk_messages_receiver + FOREIGN KEY ( receiver_id ) REFERENCES msgs.receivers , + ADD CONSTRAINT fk_messages_sender + FOREIGN KEY ( sender_id ) REFERENCES msgs.senders , + ADD CONSTRAINT fk_messages_text + FOREIGN KEY ( text_content_id ) REFERENCES msgs.text_messages , + ADD CONSTRAINT fk_messages_event + FOREIGN KEY ( event_content_id ) REFERENCES events.events + ON DELETE CASCADE; + + + +-- +-- Empire message delivery +-- + +CREATE TABLE msgs.empire_delivery( + id BIGSERIAL PRIMARY KEY , + empire_id INT NOT NULL , + message_id BIGINT NOT NULL , + in_inbox BOOLEAN NOT NULL , + status message_status NOT NULL , + emailed BOOLEAN NOT NULL , + recaped BOOLEAN NOT NULL +); + +CREATE INDEX idx_edelivery_empire + ON msgs.empire_delivery ( empire_id ); + +CREATE UNIQUE INDEX idx_edelivery_message + ON msgs.empire_delivery ( message_id , empire_id , in_inbox ); + +CREATE INDEX idx_edelivery_access + ON msgs.empire_delivery ( empire_id , in_inbox , status ); + +CREATE INDEX idx_edelivery_status + ON msgs.empire_delivery ( status , emailed , recaped ); + +ALTER TABLE msgs.empire_delivery + ADD CONSTRAINT fk_edelivery_empire + FOREIGN KEY ( empire_id ) REFERENCES emp.empires + ON DELETE CASCADE , + ADD CONSTRAINT fk_edelivery_message + FOREIGN KEY ( message_id ) REFERENCES msgs.messages + ON DELETE CASCADE; + + + +-- +-- Admin message delivery +-- + +CREATE TABLE msgs.admin_delivery( + id BIGSERIAL PRIMARY KEY , + admin_id INT NOT NULL , + message_id BIGINT NOT NULL , + in_inbox BOOLEAN NOT NULL , + status message_status NOT NULL , + emailed BOOLEAN NOT NULL +); + +CREATE INDEX idx_adelivery_admin + ON msgs.admin_delivery ( admin_id ); + +CREATE INDEX idx_adelivery_message + ON msgs.admin_delivery ( message_id ); + +CREATE INDEX idx_adelivery_status + ON msgs.admin_delivery ( status , emailed ); + +ALTER TABLE msgs.admin_delivery + ADD CONSTRAINT fk_adelivery_admin + FOREIGN KEY ( admin_id ) REFERENCES admin.administrators + ON DELETE CASCADE , + ADD CONSTRAINT fk_adelivery_message + FOREIGN KEY ( message_id ) REFERENCES msgs.messages; + + + +-- +-- E-mail notification status +-- + +CREATE TABLE msgs.email_notifications( + account_id INT PRIMARY KEY , + last_sent TIMESTAMP WITHOUT TIME ZONE + NOT NULL DEFAULT now() +); + +ALTER TABLE msgs.email_notifications + ADD CONSTRAINT fk_emailnotifications_account + FOREIGN KEY ( account_id ) REFERENCES users.active_accounts + ON DELETE CASCADE ON UPDATE CASCADE; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/000-defs-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/000-defs-functions.sql new file mode 100644 index 0000000..59ba77a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/000-defs-functions.sql @@ -0,0 +1,128 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Definitions management functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- Creates or updates a language definition +-- +-- Parameters: +-- lid Language identifier +-- lnm Language name +-- + +CREATE OR REPLACE FUNCTION defs.uoc_language( lid TEXT , lnm TEXT ) + RETURNS VOID + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + INSERT INTO defs.languages ( language , name ) + VALUES ( lower( lid ) , lnm ); +EXCEPTION + WHEN unique_violation THEN + UPDATE defs.languages SET name = lnm + WHERE language = lower( lid ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION defs.uoc_language( TEXT , TEXT ) TO :dbuser; + + +CREATE OR REPLACE FUNCTION defs.uoc_language( lid TEXT , lnm TEXT , a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Updating language ' || lid ); + PERFORM defs.uoc_language( lid , lnm ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION defs.uoc_language( TEXT, TEXT , INT ) TO :dbuser; + + +-- +-- Creates or updates a translation +-- +-- Parameters: +-- lid Language identifier +-- sid String identifier +-- txt Translation +-- + +CREATE OR REPLACE FUNCTION defs.uoc_translation( lid TEXT , sid TEXT , txt TEXT ) + RETURNS VOID + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + isid INT; + ilid INT; +BEGIN + -- Get language + SELECT INTO ilid id FROM defs.languages + WHERE language = lid; + + -- Create string, if needed + BEGIN + INSERT INTO defs.strings (name) VALUES ( sid ) + RETURNING id INTO isid; + EXCEPTION + WHEN unique_violation THEN + SELECT INTO isid id FROM defs.strings + WHERE name = sid; + END; + + -- Create or update translation + BEGIN + INSERT INTO defs.translations ( string_id , lang_id , translated_string ) + VALUES ( isid , ilid , txt ); + EXCEPTION + WHEN unique_violation THEN + UPDATE defs.translations SET translated_string = txt + WHERE string_id = isid AND lang_id = ilid; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION defs.uoc_translation( TEXT , TEXT , TEXT ) TO :dbuser; + + +CREATE OR REPLACE FUNCTION defs.uoc_translation( lid TEXT , sid TEXT , txt TEXT , a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Updating string ' || sid || ' in language ' || lid ); + PERFORM defs.uoc_translation( lid , sid , txt ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION defs.uoc_translation( TEXT, TEXT , TEXT , INT ) TO :dbuser; + + + +-- +-- Translations view (used to load all translations) +-- + +CREATE VIEW defs.translations_view + AS SELECT l.language AS language_id , l.name AS language_name , + s.name AS string_id , t.translated_string AS translation + FROM defs.translations t + INNER JOIN defs.strings s + ON s.id = t.string_id + INNER JOIN defs.languages l + ON l.id = t.lang_id; + +GRANT SELECT ON defs.translations_view TO :dbuser; + + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/002-sys-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/002-sys-functions.sql new file mode 100644 index 0000000..79a3271 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/002-sys-functions.sql @@ -0,0 +1,158 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- System management functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + +-- +-- Gets the next tick's identifier +-- + +CREATE OR REPLACE FUNCTION sys.get_tick( ) + RETURNS BIGINT + STRICT STABLE + SECURITY INVOKER +AS $$ + SELECT next_tick FROM sys.status; +$$ LANGUAGE SQL; + + + +-- +-- Registers a new ticker task +-- + +CREATE OR REPLACE FUNCTION sys.register_ticker_task( t_name TEXT ) + RETURNS INT + STRICT VOLATILE + SECURITY DEFINER +AS $$ + INSERT INTO sys.ticker ( task_name , status ) + VALUES ( $1 , 'RUNNING' ) + RETURNING id; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION sys.register_ticker_task( TEXT ) TO :dbuser; + + + +-- +-- Indicates that a ticker task was started automatically +-- +-- Parameters: +-- task_id Task identifier +-- + +CREATE OR REPLACE FUNCTION sys.set_task_started( task_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + t_name TEXT; +BEGIN + SELECT INTO t_name task_name FROM sys.ticker + WHERE id = task_id AND status = 'AUTO' FOR UPDATE; + IF FOUND + THEN + UPDATE sys.ticker SET status = 'RUNNING' , auto_start = NULL + WHERE id = task_id; + PERFORM sys.write_log( 'Ticker' , 'INFO'::log_level , 'Scheduled task ''' || t_name + || ''' has been enabled' ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.set_task_started( INT ) TO :dbuser; + + + +-- +-- Starts or stops a task +-- +-- Parameters: +-- admin_id Administrator identifier +-- task_id Task identifier +-- running Whether the task should be started or stopped +-- + +CREATE OR REPLACE FUNCTION sys.set_task_running( admin_id INT , task_id INT , running BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + n_stat ticker_task_status; + t_name TEXT; +BEGIN + n_stat := ( CASE WHEN running THEN 'RUNNING' ELSE 'STOPPED' END ); + SELECT INTO t_name task_name FROM sys.ticker + WHERE id = task_id AND status <> n_stat FOR UPDATE; + IF FOUND + THEN + UPDATE sys.ticker SET status = n_stat , auto_start = NULL + WHERE id = task_id; + PERFORM admin.write_log( admin_id , 'INFO'::log_level , 'Ticker task ''' || t_name + || ''' changed to status ' || n_stat ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.set_task_running( INT , INT , BOOLEAN ) TO :dbuser; + + + +-- +-- Schedules a task to start automatically at a later date +-- +-- Parameters: +-- admin_id Administrator identifier +-- task_id Task identifier +-- delay Delay, in seconds, before the task starts +-- +-- Returns: +-- start_at Time and date at which the task will start +-- + +CREATE OR REPLACE FUNCTION sys.schedule_task( admin_id INT , task_id INT , delay BIGINT , OUT start_at TIMESTAMP WITHOUT TIME ZONE ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + t_name TEXT; +BEGIN + start_at := now() + ( delay || 's' )::INTERVAL; + + SELECT INTO t_name task_name FROM sys.ticker + WHERE id = task_id FOR UPDATE; + IF NOT FOUND + THEN + RETURN; + END IF; + + UPDATE sys.ticker SET status = 'AUTO' , auto_start = start_at WHERE id = task_id; + PERFORM admin.write_log( admin_id , 'INFO'::log_level , 'Ticker task ''' || t_name + || ''' scheduled to start ' || start_at ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.schedule_task( INT , INT , BIGINT ) TO :dbuser; + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/005-logs-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/005-logs-functions.sql new file mode 100644 index 0000000..f7a7c0c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/005-logs-functions.sql @@ -0,0 +1,250 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Logging functions and triggers +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- LOG CLEANUP -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Remove expired entries from a log table +-- +-- Parameters: +-- l_type Log table to clean up +-- + +CREATE OR REPLACE FUNCTION sys.clean_log_table( l_type log_type ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + expiry INT; + expiry_int INTERVAL; +BEGIN + expiry := floor( sys.get_constant( 'log.maxAge.' || lower( l_type::TEXT ) ) ); + expiry_int := ( expiry || 's' )::INTERVAL; + EXECUTE 'DELETE FROM ' || l_type::TEXT || '.logs WHERE t <= $1' + USING now() - expiry_int; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Clean all log tables +-- + +CREATE OR REPLACE FUNCTION sys.clean_logs( ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + lt log_type; +BEGIN + FOR lt IN SELECT x FROM unnest( enum_range( NULL::log_type ) ) AS x + LOOP + PERFORM sys.clean_log_table( lt ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.clean_logs( ) TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- LOG APPENDERS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Write an user log entry +-- + +CREATE OR REPLACE FUNCTION users.write_log( account_id INT , lv log_level , msg TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + INSERT INTO users.logs (credentials_id , level , message) + VALUES ( account_id , lv , msg ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Write an administrative log entry +-- + +CREATE OR REPLACE FUNCTION admin.write_log( adm_id INT , lv log_level , msg TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + INSERT INTO admin.logs ( admin_id , level , message ) + VALUES ( adm_id , lv , msg ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Write a system log entry +-- + +CREATE OR REPLACE FUNCTION sys.write_log( cmp TEXT , lv log_level , msg TEXT , OUT entry_id BIGINT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + INSERT INTO sys.logs( component , level , message ) + VALUES ( cmp , lv , msg ) + RETURNING id INTO entry_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.write_log( TEXT , log_level , TEXT ) TO :dbuser; + + + +-- +-- Append an exception log entry +-- + +CREATE OR REPLACE FUNCTION sys.append_exception( l_id BIGINT , cname TEXT , msg TEXT , OUT entry_id BIGINT ) + CALLED ON NULL INPUT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + d INT; +BEGIN + SELECT INTO d max( depth ) FROM sys.exceptions + WHERE log_id = l_id; + IF d IS NULL THEN + d := 0; + END IF; + d := d + 1; + + INSERT INTO sys.exceptions ( log_id , depth , exc_class , message ) + VALUES ( l_id , d , cname , msg ) + RETURNING id INTO entry_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.append_exception( BIGINT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Append a stack trace entry +-- + +CREATE OR REPLACE FUNCTION sys.append_trace( e_id BIGINT , loc TEXT , f_name TEXT , lnb INT ) + RETURNS VOID + CALLED ON NULL INPUT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + d INT; +BEGIN + SELECT INTO d max( depth ) FROM sys.stack_traces + WHERE exception_id = e_id; + IF d IS NULL THEN + d := 0; + END IF; + d := d + 1; + + INSERT INTO sys.stack_traces ( exception_id , depth , location , file_name , line_number ) + VALUES ( e_id , d , loc , f_name , lnb ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.append_trace( BIGINT , TEXT , TEXT , INT ) TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- LOGS VIEW FOR EASY SELECTION -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +CREATE VIEW sys.system_logs_view + AS SELECT l.id , l.t , l.component , l.level , l.message , + ( CASE WHEN e.id IS NOT NULL THEN l.id ELSE NULL END )::BIGINT AS exception_id + FROM sys.logs l + LEFT OUTER JOIN sys.exceptions e ON e.log_id = l.id AND e.depth = 1; + +GRANT SELECT ON sys.system_logs_view TO :dbuser; + + +CREATE VIEW sys.admin_logs_view + AS SELECT NULL::BIGINT AS id , l.t , a.appear_as AS component , l.level , + l.message , NULL::BIGINT AS exception_id + FROM admin.logs l + INNER JOIN admin.administrators a ON a.id = l.admin_id; + +GRANT SELECT ON sys.admin_logs_view TO :dbuser; + + +CREATE VIEW sys.player_logs_view + AS SELECT NULL::BIGINT AS id , l.t , a.address AS component , l.level , + l.message , NULL::BIGINT AS exception_id + FROM users.logs l + INNER JOIN users.addresses a ON a.id = l.credentials_id; + +GRANT SELECT ON sys.player_logs_view TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- ADMIN ERROR REPORT FUNCTION -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +CREATE OR REPLACE FUNCTION admin.get_error_entries( ) + RETURNS SETOF BIGINT + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + last_report TIMESTAMP WITHOUT TIME ZONE; + new_report TIMESTAMP WITHOUT TIME ZONE; + e_id BIGINT; +BEGIN + new_report := now( ); + SELECT INTO last_report last_error_recap FROM sys.status FOR UPDATE; + UPDATE sys.status SET last_error_recap = new_report; + + RETURN QUERY SELECT id FROM sys.system_logs_view + WHERE t >= last_report AND t < new_report AND exception_id IS NOT NULL + ORDER BY t DESC; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.get_error_entries( ) TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/010-constants-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/010-constants-functions.sql new file mode 100644 index 0000000..f0c78ed --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/010-constants-functions.sql @@ -0,0 +1,318 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Functions that access system constants +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + +-- +-- Creates or gets a constant category +-- +-- Parameters: +-- ccnm Constant category name +-- +-- Returns: +-- the category's identifier +-- + +CREATE OR REPLACE FUNCTION sys.cog_constant_category( ccnm TEXT ) + RETURNS INT + STRICT + VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + ccid INT; +BEGIN + BEGIN + INSERT INTO sys.constant_categories (name) + VALUES (ccnm) + RETURNING id INTO ccid; + EXCEPTION + WHEN unique_violation THEN + SELECT INTO ccid id FROM sys.constant_categories + WHERE name = ccnm + FOR UPDATE; + END; + + RETURN ccid; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates or updates a constant with no boundaries +-- +-- Parameters: +-- cnm Constant name +-- cdesc Constant description +-- ccnm Constant category name +-- dval Default value +-- +-- Returns: +-- the constant's actual value +-- + +CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL ) + RETURNS REAL + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + ccid INT; + occid INT; + cval REAL; +BEGIN + ccid := sys.cog_constant_category( ccnm ); + + BEGIN + INSERT INTO sys.constant_definitions( name , category_id , description , c_value ) + VALUES ( cnm , ccid , cdesc , dval ); + cval := dval; + EXCEPTION + WHEN unique_violation THEN + SELECT INTO occid , cval category_id , c_value FROM sys.constant_definitions + WHERE name = cnm + FOR UPDATE; + + UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc , + min_value = NULL , max_value = NULL + WHERE name = cnm; + + IF occid <> ccid THEN + BEGIN + DELETE FROM sys.constant_categories WHERE id = occid; + EXCEPTION + WHEN foreign_key_violation THEN + -- Do nothing + END; END IF; + END; + + RETURN cval; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL ) TO :dbuser; + + + +-- +-- Creates or updates a constant with a single boundary +-- +-- Parameters: +-- cnm Constant name +-- cdesc Constant description +-- ccnm Constant category name +-- dval Default value +-- bval Bound value +-- ismin Whether the bound value is the minimal or maximal value for the constant +-- +-- Returns: +-- the constant's actual value +-- + +CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL , bval REAL , ismin BOOLEAN ) + RETURNS REAL + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + ccid INT; + occid INT; + cval REAL; + mival REAL; + maval REAL; +BEGIN + IF ismin THEN + mival := bval; + maval := NULL; + ELSE + maval := bval; + mival := NULL; + END IF; + + ccid := sys.cog_constant_category( ccnm ); + + BEGIN + INSERT INTO sys.constant_definitions( name , category_id , description , c_value , min_value , max_value ) + VALUES ( cnm , ccid , cdesc , dval , mival , maval ); + cval := dval; + EXCEPTION + WHEN unique_violation THEN + SELECT INTO occid , cval category_id , c_value FROM sys.constant_definitions + WHERE name = cnm + FOR UPDATE; + + BEGIN + UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc , + min_value = mival , max_value = maval + WHERE name = cnm; + EXCEPTION + WHEN check_violation THEN + UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc , + min_value = mival , max_value = maval , c_value = dval + WHERE name = cnm; + cval := dval; + END; + + + IF occid <> ccid THEN + BEGIN + DELETE FROM sys.constant_categories WHERE id = occid; + EXCEPTION + WHEN foreign_key_violation THEN + -- Do nothing + END; END IF; + END; + + RETURN cval; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL , REAL , BOOLEAN ) TO :dbuser; + + + +-- +-- Creates or updates a constant with both boundaries +-- +-- Parameters: +-- cnm Constant name +-- cdesc Constant description +-- ccnm Constant category name +-- dval Default value +-- mival Minimal value +-- maval Maximal value +-- +-- Returns: +-- the constant's actual value +-- + +CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL , mival REAL , maval REAL ) + RETURNS REAL + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + ccid INT; + occid INT; + cval REAL; +BEGIN + ccid := sys.cog_constant_category( ccnm ); + + BEGIN + INSERT INTO sys.constant_definitions( name , category_id , description , c_value , min_value , max_value ) + VALUES ( cnm , ccid , cdesc , dval , mival , maval ); + cval := dval; + EXCEPTION + WHEN unique_violation THEN + SELECT INTO occid , cval category_id , c_value FROM sys.constant_definitions + WHERE name = cnm + FOR UPDATE; + + BEGIN + UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc , + min_value = mival , max_value = maval + WHERE name = cnm; + EXCEPTION + WHEN check_violation THEN + UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc , + min_value = mival , max_value = maval , c_value = dval + WHERE name = cnm; + cval := dval; + END; + + + IF occid <> ccid THEN + BEGIN + DELETE FROM sys.constant_categories WHERE id = occid; + EXCEPTION + WHEN foreign_key_violation THEN + -- Do nothing + END; END IF; + END; + + RETURN cval; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL , REAL , REAL ) TO :dbuser; + + + +-- +-- Updates a constant's value +-- +-- Parameters: +-- cnm Constant name +-- nval New value +-- aid Administrator attempting to update the constant +-- +-- Returns: +-- TRUE on success, FALSE on failure +-- + +CREATE OR REPLACE FUNCTION sys.set_constant( cnm TEXT , nval REAL , aid INT ) + RETURNS BOOLEAN + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + success BOOLEAN; +BEGIN + BEGIN + UPDATE sys.constant_definitions SET c_value = nval + WHERE name = cnm; + success := FOUND; + EXCEPTION + WHEN check_violation THEN + success := FALSE; + END; + + PERFORM admin.write_log( aid , 'INFO'::log_level , 'Constant "' || cnm || '" changed to ' || nval ); + RETURN success; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.set_constant( TEXT , REAL , INT ) TO :dbuser; + + + +-- +-- Gets a constant's value +-- +-- Parameters: +-- cnm Constant name +-- + +CREATE OR REPLACE FUNCTION sys.get_constant( cnm TEXT ) + RETURNS REAL + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT c_value FROM sys.constant_definitions WHERE name = $1; +$$ LANGUAGE SQL; + + + +-- +-- Constants view +-- + +CREATE VIEW sys.constants_view + AS SELECT cat.name AS category , cns.name AS name , cns.description AS description , + cns.c_value AS value , cns.min_value AS min , cns.max_value AS max + FROM sys.constant_definitions cns + INNER JOIN sys.constant_categories cat + ON cat.id = cns.category_id + ORDER BY cat.name , cns.name; + +GRANT SELECT ON sys.constants_view TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/020-naming-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/020-naming-functions.sql new file mode 100644 index 0000000..bd69b39 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/020-naming-functions.sql @@ -0,0 +1,623 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Names management +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + +-- +-- Creates or returns an empire name +-- +-- Parameters: +-- uid Credentials identifier +-- nnm Empire name to create or return +-- +-- Returns: +-- +X the new empire name's identifier; +-- -1 if the name is banned +-- -2 if the name already exists and is "owned" by another player +-- + +CREATE OR REPLACE FUNCTION naming.goc_empire_name( uid INT, nnm TEXT ) + RETURNS INT + STRICT + VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + nid INT; +BEGIN + PERFORM name FROM naming.banned_names WHERE name = lower( nnm ); + IF FOUND + THEN + RETURN -1; + END IF; + + BEGIN + INSERT INTO naming.empire_names ( owner_id , name ) + VALUES ( uid , nnm ) + RETURNING id INTO nid; + EXCEPTION + WHEN unique_violation THEN + SELECT INTO nid id , owner_id FROM naming.empire_names + WHERE lower( name ) = lower( nnm ) AND owner_id = uid; + IF NOT FOUND THEN + RETURN -2; + END IF; + END; + RETURN nid; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Generates a random name. +-- +-- Parameters: +-- len Length of the random name +-- +-- Returns: +-- the random name +-- + +CREATE OR REPLACE FUNCTION naming.randomize( len INT ) + RETURNS TEXT + STRICT + VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + i INT; + result TEXT; + ok_chars CHAR ARRAY[16] := ARRAY['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']; +BEGIN + result := ''; + FOR i IN 1 .. len + LOOP + result := result || ok_chars[1 + floor( random() * 16 )::int]; + END LOOP; + RETURN result; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Generates a new map name +-- +-- Parameters: +-- prefix Prefix of the map name +-- +-- Returns: +-- the new name's identifier +-- + +CREATE OR REPLACE FUNCTION naming.create_map_name( prefix TEXT ) + RETURNS INT + STRICT + VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + len INT; + nid INT; +BEGIN + len := 20 - ( length( prefix ) + 3 ); + LOOP + BEGIN + INSERT INTO naming.map_names( name ) + VALUES ( prefix || '-[' || naming.randomize( len ) || ']' ) + RETURNING id INTO nid; + RETURN nid; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Resets a map name to a random value +-- +-- Parameters: +-- nid Identifier of the name to reset +-- prefix Prefix of the new name +-- +CREATE OR REPLACE FUNCTION naming.reset_map_name( nid INT , prefix TEXT ) + RETURNS TEXT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + len INT; + n_name TEXT; +BEGIN + len := 20 - ( length( prefix ) + 3 ); + LOOP + BEGIN + n_name := prefix || '-[' || naming.randomize( len ) || ']'; + UPDATE naming.map_names SET name = n_name WHERE id = nid; + RETURN n_name; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Resets an empire name +-- +-- Parameters: +-- nid Identifier of the name to reset +-- prefix Prefix of the new name +-- + +CREATE OR REPLACE FUNCTION naming.reset_empire_name( nid INT , prefix TEXT ) + RETURNS TEXT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + len INT; + n_name TEXT; +BEGIN + len := 20 - length( prefix ); + LOOP + BEGIN + n_name := prefix || naming.randomize( len ); + UPDATE naming.empire_names SET name = n_name WHERE id = nid; + RETURN n_name; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Forcibly changes a map name +-- +-- Parameters: +-- nid Identifier of the name +-- uid Identifier of the user who's changing the name +-- nnm New name +-- +-- Returns: +-- 0 Success +-- -1 Banned name +-- -2 Unavailable name +-- +CREATE OR REPLACE FUNCTION naming.change_map_name( nid INT , uid INT , nnm TEXT ) + RETURNS INT + STRICT + VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + -- Is the name banned? + PERFORM name FROM naming.banned_names WHERE name = lower( nnm ); + IF FOUND + THEN + RETURN -1; + END IF; + + -- Are we *actually* changing it? + PERFORM id FROM naming.map_names + WHERE id = nid AND name <> nnm + FOR UPDATE; + IF NOT FOUND + THEN + RETURN 0; + END IF; + + -- Rename it + BEGIN + UPDATE naming.map_names SET name = nnm + WHERE id = nid; + EXCEPTION + WHEN unique_violation THEN + RETURN -2; + END; + + -- Update change record + BEGIN + INSERT INTO naming.changed_map_names (name_id,named_by) + VALUES (nid , uid); + EXCEPTION + WHEN unique_violation THEN + DELETE FROM naming.validated_map_names WHERE name_id = nid; + UPDATE naming.changed_map_names + SET named_at = now( ), named_by = uid + WHERE name_id = nid; + END; + + RETURN 0; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Changes a map name if enough time has elapsed +-- +-- Parameters: +-- nid Identifier of the name +-- uid Identifier of the user who's changing the name +-- nnm New name +-- mtime Minimal time between renames +-- +-- Returns: +-- 0 Success +-- 1 Banned name +-- 2 Unavailable name +-- 3 Too early +-- +CREATE OR REPLACE FUNCTION naming.change_map_name( nid INT , uid INT , nnm TEXT , mtime INTERVAL ) + RETURNS INT + STRICT + VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + lren TIMESTAMP WITHOUT TIME ZONE; +BEGIN + -- Is the name banned? + PERFORM name FROM naming.banned_names WHERE name = lower( nnm ); + IF FOUND + THEN + RETURN 1; + END IF; + + -- Are we *actually* changing it? + PERFORM id FROM naming.map_names + WHERE id = nid AND name <> nnm + FOR UPDATE; + IF NOT FOUND + THEN + RETURN 0; + END IF; + + -- Check/lock change record + SELECT INTO lren named_at FROM naming.changed_map_names + WHERE name_id = nid FOR UPDATE; + IF FOUND AND lren + mtime > now() + THEN + RETURN 3; + END IF; + + -- Rename it + BEGIN + UPDATE naming.map_names SET name = nnm + WHERE id = nid; + EXCEPTION + WHEN unique_violation THEN + RETURN 2; + END; + + -- Update change record + BEGIN + INSERT INTO naming.changed_map_names (name_id,named_by) + VALUES (nid , uid); + EXCEPTION + WHEN unique_violation THEN + DELETE FROM naming.validated_map_names WHERE name_id = nid; + UPDATE naming.changed_map_names + SET named_at = now( ), named_by = uid + WHERE name_id = nid; + END; + + RETURN 0; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Marks a map name as validated +-- +-- Paramaters: +-- a_id Administrator identifier +-- n_id Name identifier +-- + +CREATE OR REPLACE FUNCTION naming.validate_map_name( a_id INT , n_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + nm TEXT; +BEGIN + SELECT INTO nm name + FROM naming.map_names + WHERE id = n_id; + IF NOT FOUND + THEN + RETURN; + END IF; + + INSERT INTO naming.validated_map_names( name_id , validated_by ) + VALUES ( n_id , a_id ); + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Map name #' || n_id || ' (' || nm || ') validated' ); +EXCEPTION + WHEN unique_violation OR foreign_key_violation THEN + -- Do nothing +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION naming.validate_map_name( INT , INT ) TO :dbuser; + + + +-- +-- Rejects a map name +-- +-- Parameters: +-- a_id Administrator identifier +-- n_id Name identifier +-- ban_name Whether the old name should be banned +-- + +CREATE OR REPLACE FUNCTION naming.reject_map_name( a_id INT , n_id INT , ban_name BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + c_name TEXT; + n_name TEXT; + u_id INT; + warned BOOLEAN; + n_warnings INT; +BEGIN + -- Get current name and player ID + SELECT INTO c_name , u_id n.name , cn.named_by + FROM naming.map_names n + INNER JOIN naming.changed_map_names cn ON cn.name_id = n.id + WHERE n.id = n_id + FOR UPDATE; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Forcibly rename the planet + n_name := naming.reset_map_name( n_id , 'P' ); + + -- Update battle + PERFORM battles.rename_planet( n_id , n_name ); + + -- Send warning + SELECT INTO warned , n_warnings * FROM admin.give_player_warning( a_id , u_id ); + + -- Send internal message + PERFORM events.map_name_rejected_event( u_id , n_id , c_name , n_name , warned , n_warnings ); + PERFORM msgs.deliver_internal( ); + + -- Add validation and log entry + DELETE FROM naming.validated_map_names WHERE name_id = n_id; + INSERT INTO naming.validated_map_names( name_id , validated_by ) + VALUES ( n_id , a_id ); + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Map name #' || n_id || ' (' || c_name || ') rejected' ); + + -- Ban old name + IF ban_name + THEN + BEGIN + INSERT INTO naming.banned_names ( name , added_by ) + VALUES ( lower( c_name ) , a_id ); + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Name "' || lower( c_name ) || '" banned' ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION naming.reject_map_name( INT , INT , BOOLEAN ) TO :dbuser; + + +-- +-- Rejects an empire's name +-- +-- a_id Administrator identifier +-- n_id Name identifier +-- ban_name Whether the old name should be banned +-- + +CREATE OR REPLACE FUNCTION naming.reject_empire_name( a_id INT , n_id INT , ban_name BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + c_name TEXT; + n_name TEXT; + u_id INT; + warned BOOLEAN; + n_warnings INT; +BEGIN + -- Get current name and player ID + SELECT INTO c_name , u_id n.name , n.owner_id + FROM naming.empire_names n WHERE n.id = n_id + FOR UPDATE; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Forcibly rename the empire + n_name := naming.reset_empire_name( n_id , 'Rude Empire ' ); + + -- Update battles + UPDATE battles.empires SET name = n_name WHERE empire_id = n_id; + UPDATE msgs.senders SET name = n_name WHERE sender_type = 'EMP' AND empire_id = n_id; + UPDATE msgs.receivers SET name = n_name WHERE receiver_type = 'EMP' AND empire_id = n_id; + + -- Send warning + SELECT INTO warned , n_warnings * FROM admin.give_player_warning( a_id , u_id ); + + -- Send internal message + PERFORM events.empire_name_rejected_event( n_id , c_name , n_name , warned , n_warnings ); + PERFORM msgs.deliver_internal( ); + + -- Add log entry + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Empire name #' || n_id || ' (' || c_name || ') forcibly renamed' ); + + -- Ban name if requested + IF ban_name + THEN + BEGIN + INSERT INTO naming.banned_names ( name , added_by ) + VALUES ( lower( c_name ) , a_id ); + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Name "' || lower( c_name ) || '" banned' ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION naming.reject_empire_name( INT , INT , BOOLEAN ) TO :dbuser; + + + +-- +-- Forcibly disbands an alliance, sending a warning to its leader +-- +-- Parameters: +-- a_id Administrator identifier +-- al_id Alliance identifier +-- + +CREATE OR REPLACE FUNCTION naming.reject_alliance_name( a_id INT , al_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_id INT; + u_id INT; + c_name TEXT; + warned BOOLEAN; + n_warnings INT; +BEGIN + -- Get current name, leader ID and player ID + SELECT INTO c_name , e_id , u_id a.tag , a.leader_id , n.owner_id + FROM emp.alliances a + INNER JOIN naming.empire_names n ON n.id = a.leader_id + WHERE a.id = al_id FOR UPDATE; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Disband the alliance + PERFORM emp.leave_alliance( e_id ); + + -- Send warning + SELECT INTO warned , n_warnings * FROM admin.give_player_warning( a_id , u_id ); + + -- Send internal message + PERFORM events.alliance_name_rejected_event( e_id , c_name , warned , n_warnings ); + PERFORM msgs.deliver_internal( ); + + -- Add log entry + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Alliance ' || c_name || ' disbanded' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION naming.reject_alliance_name( INT , INT ) TO :dbuser; + + + +-- +-- Allows a modified map name to be renamed earlier than it should +-- +-- Parameters: +-- a_id Administrator identifier +-- n_id Name identifier +-- + +CREATE OR REPLACE FUNCTION naming.allow_map_name_change( a_id INT , n_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + nm TEXT; + mdelay BIGINT; +BEGIN + SELECT INTO nm n.name + FROM naming.map_names n + INNER JOIN naming.changed_map_names c ON c.name_id = n.id + INNER JOIN naming.validated_map_names v ON v.name_id = n.id + WHERE id = n_id + FOR UPDATE; + IF NOT FOUND + THEN + RETURN; + END IF; + + mdelay := 1 + floor( sys.get_constant( 'map.names.minDelay' ) * sys.get_constant( 'map.names.minDelay.units' ) )::BIGINT; + UPDATE naming.changed_map_names + SET named_at = now() - ( mdelay::BIGINT || 's' )::INTERVAL + WHERE name_id = n_id; + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Allowed early modification of map name #' || n_id || ' (' || nm || ')' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION naming.allow_map_name_change( INT , INT ) TO :dbuser; + + + +-- +-- Names and status +-- + +CREATE TYPE name_status + AS ENUM( 'MAP_PENDING' , 'MAP_VALIDATED' , 'EMPIRE' , 'ALLIANCE' ); + +CREATE VIEW naming.names_view + AS SELECT en.id , en.name , ( CASE WHEN e IS NULL THEN NULL ELSE '' END )::TEXT AS extra , + en.owner_id AS account , 'EMPIRE'::name_status AS status + FROM naming.empire_names en + LEFT OUTER JOIN emp.empires e ON en.id = e.name_id + UNION ALL SELECT n.id , n.name , NULL::TEXT AS extra , c.named_by AS account , + ( CASE + WHEN v.name_id IS NULL THEN 'MAP_PENDING' + ELSE 'MAP_VALIDATED' + END )::name_status AS status + FROM naming.map_names n + INNER JOIN naming.changed_map_names c ON c.name_id = n.id + LEFT OUTER JOIN naming.validated_map_names v ON v.name_id = c.name_id + UNION ALL SELECT a.id , a.tag AS name , a.name AS extra , l.owner_id AS account , + 'ALLIANCE'::name_status AS status + FROM emp.alliances a + INNER JOIN naming.empire_names l ON l.id = a.leader_id; + +GRANT SELECT ON naming.names_view TO :dbuser; + + +CREATE VIEW naming.names_status_view + AS SELECT status , count(*) AS count + FROM naming.names_view + GROUP BY status; + +GRANT SELECT ON naming.names_status_view TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/030-tech-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/030-tech-functions.sql new file mode 100644 index 0000000..eb2c74a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/030-tech-functions.sql @@ -0,0 +1,379 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Functions and views for technologies and buildables +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- "Basic" buildables view (buildables that do not depend on any technology) +-- + +CREATE VIEW tech.basic_buildables + AS SELECT b.* FROM tech.buildables b + LEFT OUTER JOIN tech.buildable_requirements r + ON r.buildable_id = b.name_id + WHERE r.buildable_id IS NULL; + + +-- +-- Buildings view +-- + +CREATE VIEW tech.buildings_view + AS SELECT b.name_id , b.description_id , b.cost , b.work , b.upkeep , + bld.workers , bld.output_type , bld.output + FROM tech.buildables b + INNER JOIN tech.buildings bld + ON b.name_id = bld.buildable_id; + + +-- +-- Ships view +-- + +CREATE VIEW tech.ships_view + AS SELECT b.name_id , b.description_id , b.cost , b.work , b.upkeep , + s.flight_time , s.power + FROM tech.buildables b + INNER JOIN tech.ships s + ON b.name_id = s.buildable_id; + + + +-- +-- Creates or updates a technology line +-- +-- Parameters: +-- tln Tech line name +-- tld Tech line description +-- + +CREATE OR REPLACE FUNCTION tech.uoc_line( tln TEXT , tld TEXT ) + RETURNS VOID + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + nid INT; + did INT; +BEGIN + -- Get string identifiers + SELECT INTO nid id FROM defs.strings WHERE name = tln; + SELECT INTO did id FROM defs.strings WHERE name = tld; + + -- Try creating / updating + BEGIN + INSERT INTO tech.lines ( name_id , description_id ) + VALUES ( nid , did ); + EXCEPTION + WHEN unique_violation THEN + UPDATE tech.lines SET description_id = did + WHERE name_id = nid; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION tech.uoc_line( TEXT , TEXT ) TO :dbuser; + + + +-- +-- Creates or updates a technology level +-- +-- Parameters: +-- tln Tech line name +-- lv Level +-- lvn Level name +-- lvd Level description +-- lvp Points +-- lvc Cost +-- + +CREATE OR REPLACE FUNCTION tech.uoc_level( tln TEXT , lv INT , lvn TEXT , lvd TEXT , lvp INT , lvc INT ) + RETURNS VOID + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + lid INT; + nid INT; + did INT; +BEGIN + -- Get tech line + SELECT INTO lid t.name_id + FROM tech.lines t + INNER JOIN defs.strings s + ON s.id = t.name_id + WHERE s.name = tln; + + -- Get name / description IDs + SELECT INTO nid id FROM defs.strings WHERE name = lvn; + SELECT INTO did id FROM defs.strings WHERE name = lvd; + + -- Create or update the level + BEGIN + INSERT INTO tech.levels ( line_id , level , name_id , description_id , points , cost ) + VALUES ( lid , lv , nid , did , lvp , lvc ); + EXCEPTION + WHEN unique_violation THEN + UPDATE tech.levels SET name_id = nid , description_id = did , points = lvp , cost = lvc + WHERE line_id = lid AND level = lv; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION tech.uoc_level( TEXT , INT , TEXT , TEXT , INT , INT ) to :dbuser; + + + +-- +-- Creates or updates a buildable definition +-- +-- Parameters: +-- bdn Buildable name +-- bdd Buildable description +-- bdc Cost +-- bdw Work +-- bdu Upkeep +-- bdtn Dependency (name) +-- bdtl Dependency (level) +-- +-- Returns: +-- the buildable's identifier +-- + +CREATE OR REPLACE FUNCTION tech.uoc_buildable( bdn TEXT , bdd TEXT , bdc INT , bdw INT , bdu INT , bdtn TEXT , bdtl INT ) + RETURNS INT + STRICT + VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + nid INT; + did INT; + tdid INT; +BEGIN + -- Get the various translations + SELECT INTO nid id FROM defs.strings WHERE name = bdn; + SELECT INTO did id FROM defs.strings WHERE name = bdd; + IF bdtn <> '' THEN + SELECT INTO tdid tl.id FROM tech.levels tl + INNER JOIN defs.strings s + ON s.id = tl.line_id + WHERE s.name = bdtn AND tl.level = bdtl; + END IF; + + -- Create or update the definition + BEGIN + INSERT INTO tech.buildables ( name_id , description_id , cost , work , upkeep ) + VALUES ( nid , did , bdc , bdw , bdu ); + EXCEPTION + WHEN unique_violation THEN + UPDATE tech.buildables SET description_id = did , cost = bdc , work = bdw , upkeep = bdu + WHERE name_id = nid; + END; + + -- Set dependencies + DELETE FROM tech.buildable_requirements WHERE buildable_id = nid; + IF bdtn <> '' THEN + INSERT INTO tech.buildable_requirements ( buildable_id , level_id ) + VALUES ( nid , tdid ); + END IF; + + RETURN nid; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Update or create a building definition (no tech dependency) +-- +-- Parameters: +-- bdn Buildable name +-- bdd Buildable description +-- bdc Cost +-- bdw Work +-- bdu Upkeep +-- bdwk Workers +-- bdot Output type +-- bdo Output +-- + +CREATE OR REPLACE FUNCTION tech.uoc_building( bdn TEXT , bdd TEXT , bdc INT , bdw INT , + bdu INT , bdwk INT , bdot building_output_type , bdo INT ) + RETURNS VOID + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + bdid INT; +BEGIN + bdid := tech.uoc_buildable( bdn , bdd , bdc , bdw , bdu , '' , 0 ); + + PERFORM buildable_id FROM tech.ships WHERE buildable_id = bdid; + IF FOUND THEN + RAISE EXCEPTION 'Trying to transform a ship into a building'; + END IF; + + BEGIN + INSERT INTO tech.buildings (buildable_id, workers, output_type, output) + VALUES (bdid , bdwk , bdot , bdo); + EXCEPTION + WHEN unique_violation THEN + UPDATE tech.buildings SET workers = bdwk , output_type = bdot , output = bdo + WHERE buildable_id = bdid; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION tech.uoc_building( TEXT , TEXT , INT , INT , INT , INT , building_output_type , INT ) TO :dbuser; + + + +-- +-- Update or create a building definition (with tech dependency) +-- +-- Parameters: +-- bdn Buildable name +-- bdd Buildable description +-- bdc Cost +-- bdw Work +-- bdu Upkeep +-- bdwk Workers +-- bdot Output type +-- bdo Output +-- bdtn Dependency (name) +-- bdtl Dependency (level) +-- + +CREATE OR REPLACE FUNCTION tech.uoc_building( bdn TEXT , bdd TEXT , bdc INT , bdw INT , + bdu INT , bdwk INT , bdot building_output_type , bdo INT , + bdtn TEXT , bdtl INT ) + RETURNS VOID + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + bdid INT; +BEGIN + bdid := tech.uoc_buildable( bdn , bdd , bdc , bdw , bdu , bdtn , bdtl ); + + PERFORM buildable_id FROM tech.ships WHERE buildable_id = bdid; + IF FOUND THEN + RAISE EXCEPTION 'Trying to transform a ship into a building'; + END IF; + + BEGIN + INSERT INTO tech.buildings (buildable_id, workers, output_type, output) + VALUES (bdid , bdwk , bdot , bdo); + EXCEPTION + WHEN unique_violation THEN + UPDATE tech.buildings SET workers = bdwk , output_type = bdot , output = bdo + WHERE buildable_id = bdid; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION tech.uoc_building( TEXT , TEXT , INT , INT , INT , INT , building_output_type , INT , TEXT , INT ) TO :dbuser; + + + +-- +-- Update or create a ship definition (no tech dependency) +-- +-- Parameters: +-- sn Buildable name +-- sd Buildable description +-- sc Cost +-- sw Work +-- su Upkeep +-- sp Power +-- sft Orbital flight time +-- + +CREATE OR REPLACE FUNCTION tech.uoc_ship( sn TEXT , sd TEXT , sc INT , sw INT , + su INT , sp INT , sft INT ) + RETURNS VOID + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + bdid INT; +BEGIN + bdid := tech.uoc_buildable( sn , sd , sc , sw , su , '' , 0 ); + + PERFORM buildable_id FROM tech.buildings WHERE buildable_id = bdid; + IF FOUND THEN + RAISE EXCEPTION 'Trying to transform a building into a ship'; + END IF; + + BEGIN + INSERT INTO tech.ships (buildable_id, flight_time, power) + VALUES (bdid , sft , sp); + EXCEPTION + WHEN unique_violation THEN + UPDATE tech.ships SET flight_time = sft , power = sp + WHERE buildable_id = bdid; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION tech.uoc_ship( TEXT , TEXT , INT , INT , INT , INT , INT ) TO :dbuser; + + + +-- +-- Update or create a ship definition +-- +-- Parameters: +-- sn Buildable name +-- sd Buildable description +-- sc Cost +-- sw Work +-- su Upkeep +-- sp Power +-- sft Orbital flight time +-- stdn Tech line name +-- stdl Tech level +-- + +CREATE OR REPLACE FUNCTION tech.uoc_ship( sn TEXT , sd TEXT , sc INT , sw INT , + su INT , sp INT , sft INT , stdn TEXT , stdl INT ) + RETURNS VOID + STRICT + VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + bdid INT; +BEGIN + bdid := tech.uoc_buildable( sn , sd , sc , sw , su , stdn , stdl ); + + PERFORM buildable_id FROM tech.buildings WHERE buildable_id = bdid; + IF FOUND THEN + RAISE EXCEPTION 'Trying to transform a building into a ship'; + END IF; + + BEGIN + INSERT INTO tech.ships (buildable_id, flight_time, power) + VALUES (bdid , sft , sp); + EXCEPTION + WHEN unique_violation THEN + UPDATE tech.ships SET flight_time = sft , power = sp + WHERE buildable_id = bdid; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION tech.uoc_ship( TEXT , TEXT , INT , INT , INT , INT , INT , TEXT , INT ) TO :dbuser; + + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/035-users-view.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/035-users-view.sql new file mode 100644 index 0000000..7f1de9d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/035-users-view.sql @@ -0,0 +1,85 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- General account view +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + +-- +-- General account view +-- +-- Allows most account-related data to be loooked up, and computes account statuses. +-- + +CREATE VIEW users.accounts_view + AS SELECT addr.id AS id , addr.address AS address , lang.language AS language , + cred.pass_md5 AS pass_md5 , cred.pass_sha1 AS pass_sha1 , cred.credits AS game_credits , + ( CASE ( ban.account_id IS NULL ) + WHEN TRUE THEN + ( CASE ( iacc.credentials_id IS NULL ) + WHEN TRUE THEN + ( CASE ( aacc.credentials_id IS NULL ) + WHEN TRUE THEN + 'UNCONFIRMED' + ELSE + ( CASE ( vac.status IS NULL ) + WHEN TRUE THEN + 'ACTIVE' + ELSE + ( CASE vac.status + WHEN 'PROCESSED' THEN + 'VACATION' + ELSE + 'START_VACATION' + END ) + END ) + END ) + ELSE + ( CASE ( aacc.credentials_id IS NULL ) + WHEN TRUE THEN + ( CASE ( vkey.credentials_id IS NULL ) + WHEN TRUE THEN + 'DISABLED' + ELSE + 'REACTIVATING' + END ) + ELSE + 'QUITTING' + END ) + END ) + ELSE + 'BANNED' + END ) AS status , + vkey.token AS validation_token , prr.token AS pwd_recovery_token , + acr.token AS address_change_token , naddr.address AS new_address , + aacc.vacation_credits AS vacation_credits , + floor( aacc.vacation_credits / sys.get_constant( 'vacation.cost' ) ) AS vacation_time, + vac.since AS vacation_start , + iacc.since AS inactivity_begin , ires.reason AS inactivity_reason , + ban.ban_id AS ban_request_id + FROM users.addresses addr + INNER JOIN users.credentials cred + ON cred.address_id = addr.id + INNER JOIN defs.languages lang + ON lang.id = cred.language_id + LEFT OUTER JOIN users.validation_keys vkey + ON vkey.credentials_id = cred.address_id + LEFT OUTER JOIN users.pwd_recovery_requests prr + ON prr.credentials_id = cred.address_id AND NOT prr.used + LEFT OUTER JOIN users.address_change_requests acr + ON acr.credentials_id = cred.address_id AND NOT acr.used + LEFT OUTER JOIN users.addresses naddr + ON naddr.id = acr.address_id + LEFT OUTER JOIN users.active_accounts aacc + ON aacc.credentials_id = cred.address_id + LEFT OUTER JOIN users.vacations AS vac + ON vac.account_id = aacc.credentials_id + LEFT OUTER JOIN users.inactive_accounts AS iacc + ON iacc.credentials_id = cred.address_id + LEFT OUTER JOIN users.reasons AS ires + ON ires.account_id = iacc.credentials_id + LEFT OUTER JOIN users.bans AS ban + ON ban.account_id = iacc.credentials_id; + +GRANT SELECT ON users.accounts_view TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/040-empire-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/040-empire-functions.sql new file mode 100644 index 0000000..8c18e73 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/040-empire-functions.sql @@ -0,0 +1,662 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Empire management functions and views +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Empire creation +-- +-- Parameters: +-- nid Empire name identifier +-- pid Planet identifier +-- icash Initial cash +-- +CREATE OR REPLACE FUNCTION emp.create_empire( nid INT , pid INT , icash REAL ) + RETURNS VOID + STRICT + VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + uid BIGINT; + utp update_type; +BEGIN + -- Add empire and give initial planet + INSERT INTO emp.empires ( name_id , cash ) + VALUES ( nid , icash ); + INSERT INTO emp.planets ( planet_id , empire_id ) + VALUES ( pid , nid ); + + -- Add empire update records + FOR utp IN SELECT x FROM unnest( enum_range( NULL::update_type ) ) AS x + WHERE x::text LIKE 'EMPIRE_%' + LOOP + INSERT INTO sys.updates( gu_type ) + VALUES ( utp ) + RETURNING id INTO uid; + INSERT INTO emp.updates ( update_id , empire_id ) + VALUES ( uid , nid ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + +-- +-- Returns a planet owner's empire size +-- + +CREATE OR REPLACE FUNCTION emp.get_size( pid INT ) + RETURNS INT + STRICT STABLE + SECURITY INVOKER +AS $$ + SELECT count( aep.* )::INT + FROM emp.planets ep + INNER JOIN emp.planets aep + ON ep.empire_id = aep.empire_id + WHERE ep.planet_id = $1; +$$ LANGUAGE SQL; + + + +-- +-- Returns the empire associated with an account +-- + +CREATE OR REPLACE FUNCTION emp.get_current( a_id INT , OUT empire_id INT ) + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT e.name_id AS empire_id + FROM users.credentials c + INNER JOIN naming.empire_names en ON en.owner_id = c.address_id + INNER JOIN emp.empires e ON e.name_id = en.id + WHERE c.address_id = $1; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION emp.get_current( INT ) TO :dbuser; + + + +-- +-- Implements a technology +-- + +CREATE OR REPLACE FUNCTION emp.implement_tech( e_id INT , l_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_cash REAL; + lev INT; + cost REAL; +BEGIN + SELECT INTO e_cash , lev , cost e.cash , et.level , tl.cost + FROM emp.empires e + INNER JOIN emp.technologies et + ON et.line_id = l_id AND et.empire_id = e.name_id + INNER JOIN tech.levels tl + ON tl.line_id = l_id AND tl.level = et.level + AND tl.points = floor( et.accumulated ) + AND tl.cost <= e.cash + WHERE e.name_id = e_id + FOR UPDATE OF e , et; + + IF NOT FOUND THEN + RETURN; + END IF; + + UPDATE emp.empires + SET cash = e_cash - cost + WHERE name_id = e_id; + UPDATE emp.technologies + SET level = lev + 1 , accumulated = 0 + WHERE empire_id = e_id AND line_id = l_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.implement_tech( INT , INT ) TO :dbuser; + + + +-- +-- Add an enemy empire +-- +-- Parameters: +-- e_id Empire identifier +-- e_name New enemy name +-- +-- Returns: +-- err_code Error code: +-- 0 on success +-- 1 if the specified empire does not exist +-- 2 if the player is being schizophrenic +-- 3 if the enemy list already contains the specified empire +-- + +CREATE OR REPLACE FUNCTION emp.add_enemy_empire( e_id INT , e_name TEXT , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + en_id INT; +BEGIN + SELECT INTO en_id e.name_id + FROM emp.empires e + INNER JOIN naming.empire_names en ON e.name_id = en.id + WHERE lower( en.name ) = lower( e_name ); + IF NOT FOUND THEN + err_code := 1; + ELSEIF en_id = e_id THEN + err_code := 2; + ELSE + BEGIN + INSERT INTO emp.enemy_empires (empire_id , enemy_id) + VALUES (e_id , en_id); + err_code := 0; + EXCEPTION + WHEN unique_violation THEN + err_code := 3; + END; + END IF; + + IF err_code = 0 THEN + PERFORM emp.switch_enemies( e_id ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.add_enemy_empire( INT , TEXT ) TO :dbuser; + + + +-- +-- Add an enemy alliance +-- +-- Parameters: +-- e_id Empire identifier +-- e_name Alliance tag +-- +-- Returns: +-- err_code Error code: +-- 0 on success +-- 1 if the specified alliance does not exist +-- 2 if the player is adding his/her own alliance +-- 3 if the enemy list already contains the specified alliance +-- + +CREATE OR REPLACE FUNCTION emp.add_enemy_alliance( e_id INT , e_name TEXT , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + en_id INT; + e_ca_id INT; +BEGIN + SELECT INTO en_id a.id + FROM emp.alliances a + WHERE lower( a.tag ) = lower( e_name ); + IF NOT FOUND THEN + err_code := 1; + ELSE + SELECT INTO e_ca_id ea.alliance_id + FROM emp.alliance_members ea + WHERE ea.empire_id = e_id; + IF FOUND AND en_id = e_ca_id THEN + err_code := 2; + ELSE + BEGIN + INSERT INTO emp.enemy_alliances (empire_id , alliance_id) + VALUES (e_id , en_id); + err_code := 0; + EXCEPTION + WHEN unique_violation THEN + err_code := 3; + END; + END IF; + END IF; + + IF err_code = 0 THEN + PERFORM emp.switch_enemies( e_id ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.add_enemy_alliance( INT , TEXT ) TO :dbuser; + + + +-- +-- Remove enemy empires +-- +-- Parameters: +-- e_id Empire identifier +-- rem_ids Identifiers of enemy empires to remove +-- + +CREATE OR REPLACE FUNCTION emp.remove_enemy_empires( e_id INT , rem_ids INT[]) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + DELETE FROM emp.enemy_empires + WHERE empire_id = e_id AND enemy_id IN ( SELECT unnest( rem_ids ) AS id ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.remove_enemy_empires( INT , INT[] ) TO :dbuser; + + + +-- +-- Remove enemy alliances +-- +-- Parameters: +-- e_id Empire identifier +-- rem_ids Identifiers of enemy alliances to remove +-- + +CREATE OR REPLACE FUNCTION emp.remove_enemy_alliances( e_id INT , rem_ids INT[]) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + DELETE FROM emp.enemy_alliances + WHERE empire_id = e_id AND alliance_id IN ( SELECT unnest( rem_ids ) AS id ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.remove_enemy_alliances( INT , INT[] ) TO :dbuser; + + +-- +-- Switch enemies to attack +-- +-- Parameters: +-- e_id Empire identifier +-- + +CREATE OR REPLACE FUNCTION emp.switch_enemies( e_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; +BEGIN + CREATE TEMPORARY TABLE fleet_switches( + loc_id INT , + loc_name VARCHAR(20) , + own_id INT , + own_name VARCHAR(20) , + name VARCHAR(64) , + power BIGINT , + mode BOOLEAN + ) ON COMMIT DROP; + INSERT INTO fleet_switches + SELECT f.location_id , ln.name , f.owner_id , fon.name , + f.name , fs.power , TRUE + FROM fleets.fleets f + INNER JOIN emp.planets ep ON f.location_id = ep.planet_id + INNER JOIN verse.planets p ON p.name_id = ep.planet_id + INNER JOIN emp.enemies el ON el.enemy = f.owner_id + INNER JOIN fleets.stats_view fs ON fs.id = f.id + INNER JOIN naming.map_names ln ON ln.id = f.location_id + INNER JOIN naming.empire_names fon ON fon.id = f.owner_id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE ep.empire_id = e_id AND el.empire = e_id AND m.fleet_id IS NULL + AND NOT f.attacking; + PERFORM events.commit_fleet_switches( TRUE ); + + FOR rec IN SELECT DISTINCT f.location_id AS location , f.owner_id AS owner , b.id AS battle + FROM fleets.fleets f + INNER JOIN emp.planets ep ON f.location_id = ep.planet_id + INNER JOIN verse.planets p ON p.name_id = ep.planet_id + INNER JOIN emp.enemies el ON el.enemy = f.owner_id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + LEFT OUTER JOIN battles.battles b + ON b.location_id = ep.planet_id AND b.last_tick IS NULL + WHERE ep.empire_id = e_id AND el.empire = e_id AND m.fleet_id IS NULL + AND NOT f.attacking + LOOP + -- Set fleets mode + UPDATE fleets.fleets f + SET attacking = TRUE , + status = 'REDEPLOYING' , + penalty = ( CASE + WHEN f2.penalty > ( 1 + fs.flight_time * 40 ) + THEN f2.penalty + ELSE ( 1 + fs.flight_time * 40 ) + END ) + FROM fleets.fleets f2 + INNER JOIN fleets.stats_view fs ON fs.id = f2.id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f2.id + WHERE f2.owner_id = rec.owner AND f2.location_id = rec.location + AND m.fleet_id IS NULL AND f2.id = f.id; + + -- Update battle + PERFORM battles.set_mode( rec.battle , rec.owner , TRUE ); + END LOOP; + + PERFORM msgs.deliver_internal( ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Deletes an empire +-- + +CREATE OR REPLACE FUNCTION emp.delete_empire( e_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + p_id INT; + f_id BIGINT; + fleets BIGINT[]; +BEGIN + -- Lock empire + PERFORM * FROM emp.empires WHERE name_id = e_id FOR UPDATE; + + -- Disband fleets + fleets := '{}'::BIGINT[]; + FOR f_id IN SELECT id FROM fleets.fleets WHERE owner_id = e_id FOR UPDATE + LOOP + fleets := array_append( fleets , f_id ); + END LOOP; + PERFORM fleets.disband( e_id , fleets ); + + -- Abandon planets + FOR p_id IN SELECT planet_id FROM emp.planets WHERE empire_id = e_id + LOOP + PERFORM emp.leave_planet( p_id ); + END LOOP; + + -- Leave alliance + PERFORM emp.leave_alliance( e_id ); + + -- Delete empire + DELETE FROM emp.empires WHERE name_id = e_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Obtains a new planet +-- +-- Parameters: +-- e_id Empire identifier +-- p_name Planet name +-- +-- Returns: +-- err_code Error code: +-- 0 success +-- 1 banned name +-- 2 name unavailable +-- 3 empire has planets +-- +CREATE OR REPLACE FUNCTION emp.get_new_planet( e_id INT , p_name TEXT , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + plid INT; + accid INT; + ccash REAL; + f_id BIGINT; + fleets BIGINT[]; +BEGIN + -- Lock empire and check for existing planets + SELECT INTO ccash cash FROM emp.empires WHERE name_id = e_id FOR UPDATE; + PERFORM * FROM emp.planets WHERE empire_id = e_id LIMIT 1; + IF FOUND + THEN + err_code := 3; + RETURN; + END IF; + SELECT INTO accid owner_id FROM naming.empire_names WHERE id = e_id; + + -- Get random planet and rename it + plid := verse.get_random_planet( ); + IF plid IS NULL THEN + err_code := 2; + ELSE + err_code := - naming.change_map_name( plid , accid , p_name ); + END IF; + IF err_code <> 0 + THEN + RETURN; + END IF; + INSERT INTO emp.planets ( planet_id , empire_id ) + VALUES ( plid , e_id ); + + -- Disband fleets + fleets := '{}'::BIGINT[]; + FOR f_id IN SELECT id FROM fleets.fleets WHERE owner_id = e_id FOR UPDATE + LOOP + fleets := array_append( fleets , f_id ); + END LOOP; + PERFORM fleets.disband( e_id , fleets ); + + -- Reset to initial cash if below + IF ccash < sys.get_constant( 'game.initialCash' ) + THEN + UPDATE emp.empires + SET cash = sys.get_constant( 'game.initialCash' ) + WHERE name_id = e_id; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.get_new_planet( INT , TEXT ) TO :dbuser; + + + + +-- +-- Enemies view +-- + +CREATE VIEW emp.enemies + AS SELECT iq.empire AS empire , iq.enemy AS enemy FROM + ( SELECT ee.empire_id AS empire , ee.enemy_id AS enemy + FROM emp.enemy_empires ee + UNION SELECT ea.empire_id AS empire , am.empire_id AS enemy + FROM emp.enemy_alliances ea + INNER JOIN emp.alliance_members am + ON am.alliance_id = ea.alliance_id AND NOT am.is_pending ) AS iq + ORDER BY iq.empire , iq.enemy; + + +-- +-- General information view +-- + +CREATE VIEW emp.general_information + AS SELECT e.name_id AS id , en.name AS name , + ( CASE + WHEN av.status = 'QUITTING' THEN 'q' + WHEN av.status = 'VACATION' THEN 'v' + WHEN av.status = 'START_VACATION' THEN 's' + ELSE NULL + END ) AS status , + e.cash AS cash , a.tag AS alliance , + st.next_tick AS game_time , + av.id AS account_id + FROM emp.empires e + INNER JOIN naming.empire_names en ON en.id = e.name_id + INNER JOIN users.accounts_view av ON av.id = en.owner_id + LEFT OUTER JOIN emp.alliance_members am + ON am.empire_id = e.name_id AND NOT am.is_pending + LEFT OUTER JOIN emp.alliances a ON a.id = am.alliance_id + CROSS JOIN sys.status st; + +GRANT SELECT ON emp.general_information TO :dbuser; + + +-- +-- Empire planets view +-- + +CREATE VIEW emp.planets_view + AS SELECT e.empire_id AS empire , n.id AS id , n.name AS name + FROM emp.planets e + INNER JOIN verse.planets p ON p.name_id = e.planet_id + INNER JOIN verse.systems s ON s.id = p.system_id + INNER JOIN naming.map_names n ON n.id = e.planet_id + ORDER BY e.empire_id , s.x , s.y , p.orbit; + +GRANT SELECT ON emp.planets_view TO :dbuser; + + +-- +-- Empire overviews +-- + +CREATE VIEW emp.planets_overview + AS SELECT e.name_id AS empire , count( p.* ) AS planets , + sum( floor( p.population) ) AS population , + floor( avg( 100.0 * ph.current / p.population ) ) AS avg_happiness , + floor( sum( pm.income ) ) AS planet_income , + floor( sum( pm.upkeep ) ) AS planet_upkeep + FROM emp.empires e + LEFT OUTER JOIN emp.planets ep ON ep.empire_id = e.name_id + LEFT OUTER JOIN verse.planets p ON p.name_id = ep.planet_id + LEFT OUTER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + LEFT OUTER JOIN verse.planet_money pm ON pm.planet_id = p.name_id + GROUP BY e.name_id; + +CREATE VIEW emp.civ_invest_acc_totals + AS SELECT e.name_id AS empire , sum( cq.money ) AS acc_total + FROM emp.empires e + LEFT OUTER JOIN emp.planets ep ON ep.empire_id = e.name_id + LEFT OUTER JOIN verse.bld_queues cq ON cq.planet_id = ep.planet_id + GROUP BY e.name_id; + +CREATE VIEW emp.civ_investment_view + AS SELECT e.name_id AS empire , + ( sum( bqi.amount * bqid.cost ) - ( CASE WHEN ciat.acc_total IS NULL THEN 0 ELSE ciat.acc_total END ) )::BIGINT AS civ_investment + FROM emp.empires e + LEFT OUTER JOIN emp.planets ep ON ep.empire_id = e.name_id + LEFT OUTER JOIN emp.civ_invest_acc_totals ciat ON ciat.empire = e.name_id + LEFT OUTER JOIN verse.bld_items bqi ON bqi.queue_id = ep.planet_id AND NOT bqi.destroy + LEFT OUTER JOIN tech.buildables bqid ON bqid.name_id = bqi.building_id + GROUP BY e.name_id, ciat.acc_total; + +CREATE VIEW emp.mil_invest_acc_totals + AS SELECT e.name_id AS empire , sum( mq.money ) AS acc_total + FROM emp.empires e + LEFT OUTER JOIN emp.planets ep ON ep.empire_id = e.name_id + LEFT OUTER JOIN verse.mil_queues mq ON mq.planet_id = ep.planet_id + GROUP BY e.name_id; + +CREATE VIEW emp.mil_investment_view + AS SELECT e.name_id AS empire , + ( sum( mqi.amount * mqid.cost ) - ( CASE WHEN miat.acc_total IS NULL THEN 0 ELSE miat.acc_total END ) )::BIGINT AS mil_investment + FROM emp.empires e + LEFT OUTER JOIN emp.planets ep ON ep.empire_id = e.name_id + LEFT OUTER JOIN emp.mil_invest_acc_totals miat ON miat.empire = e.name_id + LEFT OUTER JOIN verse.mil_items mqi ON mqi.queue_id = ep.planet_id + LEFT OUTER JOIN tech.buildables mqid ON mqid.name_id = mqi.ship_id + GROUP BY e.name_id, miat.acc_total; + +CREATE VIEW emp.fleets_overview + AS SELECT e.name_id AS empire , + sum( sd.power * s.amount ) AS fleet_power , + sum( sbd.upkeep * s.amount ) AS fleet_upkeep + FROM emp.empires e + LEFT OUTER JOIN fleets.fleets f ON f.owner_id = e.name_id + LEFT OUTER JOIN fleets.ships s ON s.fleet_id = f.id + LEFT OUTER JOIN tech.ships sd ON sd.buildable_id = s.ship_id + LEFT OUTER JOIN tech.buildables sbd ON sbd.name_id = sd.buildable_id + GROUP BY e.name_id; + +CREATE VIEW emp.new_messages + AS SELECT e.name_id AS empire , count( m.* ) AS new_messages + FROM emp.empires e + LEFT OUTER JOIN msgs.empire_delivery m + ON m.empire_id = e.name_id AND m.in_inbox AND m.status = 'UNREAD' + GROUP BY e.name_id; + + +CREATE VIEW emp.overview + AS SELECT * FROM emp.planets_overview + INNER JOIN emp.fleets_overview USING (empire) + INNER JOIN emp.civ_investment_view USING (empire) + INNER JOIN emp.mil_investment_view USING (empire) + INNER JOIN emp.new_messages USING (empire); + +GRANT SELECT ON emp.overview TO :dbuser; + + +-- +-- Empire tech lines +-- + +CREATE VIEW emp.tech_lines_view + AS SELECT e.name_id AS empire , tl.name_id AS tech_line , + t1.translated_string AS name , + t2.translated_string AS description + FROM emp.empires e + INNER JOIN emp.technologies et ON et.empire_id = e.name_id + INNER JOIN tech.lines tl ON tl.name_id = et.line_id + INNER JOIN naming.empire_names en ON en.id = e.name_id + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t1 ON t1.string_id = tl.name_id AND t1.lang_id = c.language_id + INNER JOIN defs.translations t2 ON t2.string_id = tl.description_id AND t2.lang_id = c.language_id + ORDER BY t1.translated_string; + +GRANT SELECT ON emp.tech_lines_view TO :dbuser; + + +-- +-- Empire technologies +-- + +CREATE VIEW emp.technologies_view + AS SELECT e.name_id AS empire , tl.name_id AS tech_line , + t1.translated_string AS name , + t2.translated_string AS description , + ( et.level > tlv.level ) AS implemented , + floor( 100 * et.accumulated / tlv.points ) AS progress , + tlv.cost AS cost + FROM emp.empires e + INNER JOIN emp.technologies et ON et.empire_id = e.name_id + INNER JOIN tech.lines tl ON tl.name_id = et.line_id + INNER JOIN tech.levels tlv ON tlv.line_id = tl.name_id AND tlv.level <= et.level + INNER JOIN naming.empire_names en ON en.id = e.name_id + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t1 ON t1.string_id = tlv.name_id AND t1.lang_id = c.language_id + INNER JOIN defs.translations t2 ON t2.string_id = tlv.description_id AND t2.lang_id = c.language_id + ORDER BY tl.name_id , tlv.level; + +GRANT SELECT ON emp.technologies_view TO :dbuser; + + +-- +-- Enemy lists +-- + +CREATE VIEW emp.enemy_lists + AS SELECT x.empire AS empire , x.id AS id , x.name AS name , x.alliance AS alliance + FROM ( + SELECT el.empire_id AS empire , el.enemy_id AS id , n.name AS name , FALSE AS alliance + FROM emp.enemy_empires el + INNER JOIN naming.empire_names n ON n.id = el.enemy_id + UNION SELECT el.empire_id AS empire , el.alliance_id AS id , a.tag AS name , TRUE AS alliance + FROM emp.enemy_alliances el + INNER JOIN emp.alliances a ON a.id = el.alliance_id + ) AS x; + +GRANT SELECT ON emp.enemy_lists TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/050-computation-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/050-computation-functions.sql new file mode 100644 index 0000000..e5304c2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/050-computation-functions.sql @@ -0,0 +1,232 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Various functions for in-game computations +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- sigma( x ) = exp( x ) / ( 1 + exp( x ) ) +-- + +CREATE OR REPLACE FUNCTION verse.sigma( x REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ + SELECT ( CASE + WHEN $1 < -100 THEN 0 + WHEN $1 > 100 THEN 1 + ELSE ( exp( $1 ) / ( 1 + exp( $1 ) ) )::REAL + END ); +$$ LANGUAGE SQL; + + + +-- +-- poly( x , a , b , c ) = ( a * x + b ) * x + c +-- + +CREATE OR REPLACE FUNCTION verse.poly( x REAL , a REAL , b REAL , c REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ + SELECT ( $2 * $1 + $3 ) * $1 + $4; +$$ LANGUAGE SQL; + + + +-- +-- Happiness curve, K1 constant +-- + +CREATE OR REPLACE FUNCTION verse.hcc_const_k1( xmax REAL , ymax REAL , xlimit REAL , ylimit REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ + SELECT ( ( $4 - $2 ) / ( ( $3 - $1 ) ^ 2 ) )::REAL; +$$ LANGUAGE SQL; + + + +-- +-- Happiness curve, K2 constant +-- + +CREATE OR REPLACE FUNCTION verse.hcc_const_k2( ylimit REAL , yasymptote REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ + SELECT ( 2 * ( $1 - $2 ) )::REAL; +$$ LANGUAGE SQL; + + + +-- +-- Happiness curve, K3 constant +-- + +CREATE OR REPLACE FUNCTION verse.hcc_const_k3( xmax REAL , ymax REAL , xlimit REAL , ylimit REAL , yasymptote REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ + SELECT ( verse.hcc_const_k1( $1 , $2 , $3 , $4 ) * 4 * ( $3 - $1 ) / ( $5 - $4 ) ) ::REAL; +$$ LANGUAGE SQL; + + + +-- +-- Happiness curve, first part +-- + +CREATE OR REPLACE FUNCTION verse.hcc_part_1( x REAL , ymin REAL , ymax REAL , xmax REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ +DECLARE + v REAL; +BEGIN + v := ( ymin - ymax ) / xmax; + RETURN verse.poly( x , ( v / xmax )::REAL , ( -2 * v )::REAL , ymin ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Happiness curve, second part +-- + +CREATE OR REPLACE FUNCTION verse.hcc_part_2( x REAL , xmax REAL , ymax REAL , xlimit REAL , ylimit REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ +DECLARE + k1 REAL; +BEGIN + k1 := verse.hcc_const_k1( xmax , ymax , xlimit , ylimit ); + RETURN verse.poly( x , k1 , ( -2 * xmax * k1 )::REAL , ( ymax + k1 * xmax * xmax )::REAL ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Happiness curve, third part +-- + +CREATE OR REPLACE FUNCTION verse.hcc_part_3( x REAL , xmax REAL , ymax REAL , xlimit REAL , ylimit REAL , yasymptote REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ +DECLARE + k2 REAL; + k3 REAL; +BEGIN + k2 := verse.hcc_const_k2( ylimit , yasymptote ); + k3 := verse.hcc_const_k3( xmax , ymax , xlimit , ylimit , yasymptote ); + RETURN yasymptote + k2 * ( 1 - verse.sigma( ( k3 * ( x - xlimit ) ) )::REAL ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Happiness curve +-- + +CREATE OR REPLACE FUNCTION verse.happiness_curve( x REAL , ymin REAL , xmax REAL , ymax REAL , xlimit REAL , ylimit REAL , yasymptote REAL ) + RETURNS REAL + STRICT IMMUTABLE SECURITY INVOKER +AS $$ + SELECT (CASE + WHEN $1 < $3 THEN + verse.hcc_part_1( $1 , $2 , $4 , $3 ) + WHEN $1 < $5 THEN + verse.hcc_part_2( $1 , $3 , $4 , $5 , $6 ) + ELSE + verse.hcc_part_3( $1 , $3 , $4 , $5 , $6 , $7 ) + END) +$$ LANGUAGE SQL; + + + +-- +-- Happiness computation +-- + +CREATE OR REPLACE FUNCTION verse.compute_happiness( population REAL , workers REAL , defence REAL , empsize INT ) + RETURNS REAL + STRICT STABLE SECURITY INVOKER + AS $$ +DECLARE + whappiness REAL; + dhappiness REAL; + shappiness REAL; +BEGIN + -- Work-related happiness + whappiness := verse.happiness_curve( + ( workers / population )::REAL , + sys.get_constant( 'game.happiness.noEmployment' ) , 1.0 , 1.0 , + sys.get_constant( 'game.happiness.employmentLimit' ) , 0.5 , 0 + ); + + -- Defence-related happiness + dhappiness := verse.happiness_curve( + ( sys.get_constant( 'game.happiness.popPerDefencePoint' ) * defence / population )::REAL , + sys.get_constant( 'game.happiness.noDefence' ) , 1.0 , 1.0 , + sys.get_constant( 'game.happiness.defenceLimit' ) , 0.5 , 0 + ); + + -- Influence of empire size + shappiness := verse.happiness_curve( + ( empsize::REAL / sys.get_constant( 'game.happiness.idealEmpireSize' ) )::REAL , + sys.get_constant( 'game.happiness.smallEmpire' ) , 1.0 , 1.0 , + sys.get_constant( 'game.happiness.eSizeLimit' ) , 0.5 , 0 + ); + + RETURN ( shappiness * ( whappiness + dhappiness ) / 2.0 )::REAL; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Production adjustment +-- +CREATE OR REPLACE FUNCTION verse.adjust_production( prod REAL , happiness REAL ) + RETURNS REAL + STRICT IMMUTABLE + SECURITY INVOKER +AS $$ + SELECT ( CASE + WHEN $2 < sys.get_constant( 'game.happiness.strike' ) THEN + ( $1 * ( 1 - ( $2 / sys.get_constant( 'game.happiness.strike' ) ) ) )::REAL + ELSE + $1 + END ); +$$ LANGUAGE SQL; + + +-- +-- Income computation +-- + +CREATE OR REPLACE FUNCTION verse.compute_income( population REAL , happiness REAL , cashprod REAL ) + RETURNS REAL + STRICT STABLE + SECURITY INVOKER + AS $$ +DECLARE + base REAL; + badj REAL; + cprod REAL; +BEGIN + badj := ( 1 - verse.adjust_production( 1.0 , happiness ) ) * sys.get_constant( 'game.work.strikeEffect' ); + base := floor( population ) * sys.get_constant( 'game.work.population' ) * ( 1 - badj ); + cprod := verse.adjust_production( cashprod , happiness ) * sys.get_constant( 'game.work.factory' ); + RETURN cprod + base; +END; +$$ LANGUAGE plpgsql; + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/060-universe-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/060-universe-functions.sql new file mode 100644 index 0000000..780986a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/060-universe-functions.sql @@ -0,0 +1,394 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Universe management functions and views +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Obtains a planet's raw production +-- +-- Parameters: +-- pid Planet identifier +-- pt Production type +-- +-- Returns: +-- the planet's raw production of the specified type +-- + +CREATE OR REPLACE FUNCTION verse.get_raw_production( pid INT , pt building_output_type ) + RETURNS REAL + STRICT STABLE + SECURITY DEFINER + AS $$ +DECLARE + rv REAL; +BEGIN + SELECT INTO rv SUM( b.amount * d.output )::REAL + FROM verse.planet_buildings b + INNER JOIN tech.buildings d + ON d.buildable_id = b.building_id AND d.output_type = pt + WHERE b.planet_id = pid; + IF rv IS NULL THEN + rv := 0; + END IF; + RETURN rv; +END; +$$ LANGUAGE plpgsql; + + +-- +-- Map view +-- + +CREATE VIEW verse.map_view + AS SELECT s.x AS x , s.y AS y , p.orbit AS orbit , + n.id AS id , p.picture AS picture , n.name AS name , + ep.empire_id AS owner , + a.id AS alliance_id , a.tag AS tag + FROM verse.planets p + INNER JOIN verse.systems s + ON s.id = p.system_id + INNER JOIN naming.map_names n + ON n.id = p.name_id + LEFT OUTER JOIN emp.planets ep + ON ep.planet_id = p.name_id + LEFT OUTER JOIN emp.alliance_members am + ON ep.empire_id = am.empire_id AND NOT am.is_pending + LEFT OUTER JOIN emp.alliances a + ON a.id = am.alliance_id + ORDER BY s.x , s.y , p.orbit; + + + +-- +-- View of planets that can be assigned to players +-- + +CREATE VIEW verse.available_planets + AS SELECT p.name_id AS name_id + FROM verse.planets p + INNER JOIN verse.planet_happiness ph + ON ph.planet_id = p.name_id + LEFT OUTER JOIN emp.planets ep + ON ep.planet_id = p.name_id + LEFT OUTER JOIN fleets.fleets f + ON f.location_id = p.name_id + WHERE ep.empire_id IS NULL AND ph.target > 0.5 + AND verse.get_raw_production( p.name_id , 'DEF'::building_output_type ) > 0 + AND verse.get_raw_production( p.name_id , 'WORK'::building_output_type ) > 0 + AND ph.current / p.population > sys.get_constant( 'game.happiness.strike' ) + GROUP BY p.name_id HAVING count(f.*) = 0; + + +-- +-- Returns a random free planet, locked for update +-- + +CREATE OR REPLACE FUNCTION verse.get_random_planet( ) + RETURNS INT + STRICT VOLATILE + SECURITY INVOKER +AS $$ + SELECT name_id + FROM verse.planets p + INNER JOIN verse.available_planets + USING ( name_id ) + ORDER BY random() LIMIT 1 + FOR UPDATE OF p; +$$ LANGUAGE SQL; + + + + +-- +-- Obtains a planet's upkeep +-- +-- Parameters: +-- pid Planet identifier +-- +-- Returns: +-- the planet's current upkeep +-- + +CREATE OR REPLACE FUNCTION verse.get_planet_upkeep( pid INT ) + RETURNS REAL + STRICT STABLE + SECURITY INVOKER + AS $$ +DECLARE + rv REAL; +BEGIN + SELECT INTO rv SUM( b.amount * d.upkeep )::REAL + FROM verse.planet_buildings b + INNER JOIN tech.buildables d + ON d.name_id = b.building_id + WHERE b.planet_id = pid; + IF rv IS NULL THEN + rv := 0; + END IF; + RETURN rv; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates a planet +-- +-- Parameters: +-- sid Stellar system ID +-- o Orbit number +-- ipop Initial population +-- npics Amount of planet pictures +-- + +CREATE OR REPLACE FUNCTION verse.create_planet( sid INT , o INT , ipop REAL , npics INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + pnid INT; + bworkers INT; + bpp INT; + uid BIGINT; + utp update_type; + happiness REAL; +BEGIN + -- Planet name and planet + pnid := naming.create_map_name( 'P' ); + INSERT INTO verse.planets ( name_id , system_id , orbit , picture , population ) + VALUES ( pnid , sid , o , 1 + floor( random() * npics ) , ipop ); + + -- Create build queues + INSERT INTO verse.bld_queues( planet_id , money , work ) + VALUES ( pnid , 0 , 0 ); + INSERT INTO verse.mil_queues( planet_id , money , work ) + VALUES ( pnid , 0 , 0 ); + + -- Insert initial buildings + SELECT INTO bworkers SUM( d.workers ) FROM tech.buildings_view d + INNER JOIN tech.basic_buildables b USING( name_id ); + bpp := floor( 0.5 * ipop / bworkers ); + INSERT INTO verse.planet_buildings ( planet_id , building_id , amount , damage ) + SELECT pnid , d.name_id , bpp , 0.0 FROM tech.buildings_view d + INNER JOIN tech.basic_buildables b USING( name_id ); + + -- Compute initial happiness + happiness := verse.compute_happiness( + ipop , bpp * bworkers , + verse.get_raw_production( pnid , 'DEF'::building_output_type ) , + 0 + ); + INSERT INTO verse.planet_happiness ( planet_id , current , target ) + VALUES ( pnid , ipop * happiness , happiness ); + + -- Compute initial income and upkeep + INSERT INTO verse.planet_money ( planet_id , income , upkeep ) + VALUES ( pnid , verse.compute_income( + ipop , happiness , + verse.get_raw_production( pnid , 'CASH'::building_output_type ) + ) , verse.get_planet_upkeep( pnid ) ); + + -- Add planet update records + FOR utp IN SELECT x FROM unnest( enum_range( NULL::update_type ) ) AS x + WHERE x::text LIKE 'PLANET_%' + LOOP + INSERT INTO sys.updates( gu_type ) + VALUES ( utp ) + RETURNING id INTO uid; + INSERT INTO verse.updates ( update_id , planet_id ) + VALUES ( uid , pnid ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates a stellar system +-- +-- Parameters: +-- sx, sy Coordinates +-- ipop Initial population of planets +-- npics Amount of planet pictures +-- + +CREATE OR REPLACE FUNCTION verse.create_system( sx INT , sy INT , ipop REAL , npics INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + sid INT; + orbit INT; +BEGIN + -- Create system + INSERT INTO verse.systems ( x , y ) + VALUES ( sx , sy ) + RETURNING id INTO sid; + + -- Create planets + FOR orbit IN 1 .. 5 + LOOP + PERFORM verse.create_planet( sid , orbit , ipop , npics ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Generate multiple systems at the specified coordinates +-- +-- Parameters: +-- (x0,y0)-(x1,y1) Area to generate +-- ipop Initial population +-- + +CREATE OR REPLACE FUNCTION verse.create_systems( x0 INT , y0 INT , x1 INT , y1 INT , ipop REAL ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + x INT; + y INT; + npics INT; +BEGIN + npics := floor( sys.get_constant( 'game.universe.pictures' ) ); + FOR x IN x0 .. x1 + LOOP + FOR y IN y0 .. y1 + LOOP + PERFORM verse.create_system( x , y , ipop , npics ); + END LOOP; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Generate the initial universe +-- + +CREATE OR REPLACE FUNCTION verse.generate_initial_universe( ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + sz INT; + pop REAL; + npics INT; +BEGIN + sz := floor( sys.get_constant( 'game.universe.initialSize' ) ); + pop := sys.get_constant( 'game.universe.initialPopulation' ); + PERFORM verse.create_systems( -sz , -sz , sz , sz , pop ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Expand the universe +-- + +CREATE OR REPLACE FUNCTION verse.expand_universe( ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + min_x INT; + max_x INT; + min_y INT; + max_y INT; + x_size INT; + y_size INT; + x_axis BOOLEAN; + posit BOOLEAN; + x0 INT; + y0 INT; + x1 INT; + y1 INT; + pop REAL; +BEGIN + -- Get current bounds + SELECT INTO min_x , max_x , min_y , max_y + MIN(x) , MAX(x) , MIN(y) , MAX(y) + FROM verse.systems; + x_size := 1 + max_x - min_x; + y_size := 1 + max_y - min_y; + + -- Find out which axis/direction to use + x_axis := ( x_size = y_size ); + IF x_axis THEN + posit := ( max_x = -min_x ); + ELSE + posit := ( max_y = -min_y ); + END IF; + + -- Compute area coordinates + IF x_axis THEN + x0 := ( CASE posit WHEN TRUE THEN max_x + 1 ELSE min_x - 1 END ); + x1 := x0; + y0 := min_y; + y1 := max_y; + ELSE + y0 := ( CASE posit WHEN TRUE THEN max_y + 1 ELSE min_y - 1 END ); + y1 := y0; + x0 := min_x; + x1 := max_x; + END IF; + + -- Get average population and generate new systems + SELECT INTO pop AVG( population ) FROM verse.planets; + PERFORM verse.create_systems( x0 , y0 , x1 , y1 , pop ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Universe generator function +-- +-- Called by the game engine; generate the initial universe if it is empty, or expand it +-- if the ratio of available planets is too low. +-- + +CREATE OR REPLACE FUNCTION verse.generate( ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + p_count INT; + f_ratio REAL; +BEGIN + -- Get total planet count + SELECT INTO p_count 5 * count(*) + FROM verse.systems; + + -- Empty universe -> initialise + IF p_count = 0 THEN + PERFORM verse.generate_initial_universe( ); + RETURN; + END IF; + + -- Get available planets ratio + SELECT INTO f_ratio count(*)::REAL / p_count::REAL + FROM verse.available_planets; + + -- Expand universe if required + IF f_ratio < sys.get_constant( 'game.universe.minFreeRatio' ) THEN + PERFORM verse.expand_universe( ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.generate() TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/070-users-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/070-users-functions.sql new file mode 100644 index 0000000..46bb65f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/070-users-functions.sql @@ -0,0 +1,1086 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- User management functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- E-mail address creation +-- + +CREATE OR REPLACE FUNCTION users.create_address ( addr TEXT ) + RETURNS INT + STRICT VOLATILE SECURITY INVOKER + AS $$ +DECLARE + pk INT; +BEGIN + INSERT INTO users.addresses (address) VALUES (addr) + RETURNING id INTO pk; + RETURN pk; +EXCEPTION WHEN unique_violation THEN + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Generates a random token. +-- +-- Parameters: +-- len Length of the token +-- +-- Returns: +-- the token +-- + +CREATE OR REPLACE FUNCTION users.make_token( len INT ) + RETURNS TEXT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + i INT; + result TEXT; + ok_chars CHAR ARRAY[16] := ARRAY['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']; +BEGIN + result := ''; + FOR i IN 1 .. len + LOOP + result := result || ok_chars[ 1 + floor( random() * 36 )::INT ]; + END LOOP; + RETURN result; +END; +$$ LANGUAGE plpgsql; + + + + +-- +-- Credentials creation +-- +-- Parameters: +-- addr mail address +-- lang selected language +-- pmd5 MD5 hash of password +-- psha1 SHA-1 hash of password +-- +-- Returns: +-- err_code error code: +-- 0 on success +-- -1 if the address exists +-- -2 if the language does not exist +-- a_id the account's identifier +-- + +CREATE OR REPLACE FUNCTION users.create_credentials ( addr TEXT , lang TEXT , pmd5 TEXT , psha1 TEXT , + OUT err_code INT , OUT a_id INT) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + vkey TEXT; + l_id INT; +BEGIN + -- Get language + SELECT INTO l_id l.id FROM defs.languages l + CROSS JOIN defs.strings s + LEFT OUTER JOIN defs.translations t + ON t.lang_id = l.id AND t.string_id = s.id + WHERE l.language = lang + GROUP BY l.id + HAVING count( s.* ) = count( t.* ); + IF NOT FOUND THEN + err_code := -2; + a_id := NULL; + RETURN; + END IF; + + -- Create address + a_id := users.create_address( addr ); + IF a_id IS NULL + THEN + err_code := -1; + RETURN; + END IF; + + -- Insert credentials + INSERT INTO users.credentials (address_id, pass_md5, pass_sha1, credits, language_id) + VALUES ( a_id , pmd5 , psha1 , floor( sys.get_constant( 'game.initialCredits' ) ) , l_id ); + vkey := users.make_token(64); + INSERT INTO users.validation_keys (credentials_id, token) + VALUES ( a_id , vkey ); + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Account created; validation key: ' || vkey ); + err_code := 0; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.create_credentials(TEXT,TEXT,TEXT,TEXT) TO :dbuser; + + + +-- +-- Attempts to re-activate a disabled account +-- +-- Parameters: +-- addr Account e-mail address +-- +-- Returns: +-- success Whether the operation was successful +-- a_id Account identifier +-- + +CREATE OR REPLACE FUNCTION users.reactivate( IN addr TEXT , OUT success BOOLEAN , OUT a_id INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + vkey TEXT; +BEGIN + SELECT INTO a_id id FROM users.accounts_view + WHERE address = addr AND status = 'DISABLED'; + success := FOUND; + + IF success THEN + vkey := users.make_token( 64 ); + INSERT INTO users.validation_keys (credentials_id, token) + VALUES ( a_id , vkey ); + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Account re-activation requested; validation key: ' || vkey ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.reactivate(TEXT) TO :dbuser; + + + +-- +-- This function is called when an account's validation token cannot be sent. +-- +-- Parameters: +-- a_id Account identifier +-- + +CREATE OR REPLACE FUNCTION users.validation_mail_failure( IN a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + st TEXT; +BEGIN + SELECT INTO st status FROM users.accounts_view WHERE id = a_id; + IF st = 'UNCONFIRMED' THEN + DELETE FROM users.addresses WHERE id = a_id; + ELSEIF st = 'REACTIVATING' THEN + DELETE FROM users.validation_keys WHERE credentials_id = a_id; + ELSE + RAISE EXCEPTION 'Invalid account status % (account #%)' , st , a_id; + END IF; + PERFORM sys.write_log( 'AccountManagement' , 'ERROR'::log_level , 'Account re-activation mail could not be sent for account #' || a_id || ', deleting validation key' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.validation_mail_failure( INT ) TO :dbuser; + + + +-- +-- Request password recovery +-- +-- Parameters: +-- addr account mail address +-- +-- Returns: +-- err_code error code: +-- 0 on success, +-- 1 if there's already a password recovery request for the account +-- 2 if the account doesn't exist. +-- a_id account identifier +-- + +CREATE OR REPLACE FUNCTION users.request_password_recovery( IN addr TEXT , OUT err_code INT , OUT a_id INT) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + vkey TEXT; +BEGIN + SELECT INTO a_id ad.id FROM users.addresses ad + INNER JOIN users.credentials c ON c.address_id = ad.id + INNER JOIN users.accounts_view av ON av.id = ad.id + WHERE ad.address = addr AND av.status IN ( 'ACTIVE' , 'VACATION' , 'START_VACATION' , 'QUITTING' ) + FOR UPDATE OF ad , c; + IF NOT FOUND THEN + err_code := 2; + ELSE + vkey := users.make_token( 64 ); + BEGIN + INSERT INTO users.pwd_recovery_requests (credentials_id , token) + VALUES ( a_id , vkey ); + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Password recovery requested; validation key: ' || vkey ); + err_code := 0; + EXCEPTION + WHEN unique_violation THEN + err_code := 1; + a_id := NULL; + END; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.request_password_recovery( TEXT ) TO :dbuser; + + + +-- +-- Confirm password recovery +-- +-- Parameters: +-- umail account mail address +-- tok recovery token +-- pmd5 new password's MD5 hash +-- psha1 new password's SHA-1 hash +-- +-- Returns: +-- err_code error code: +-- 0 on success +-- 1 if the account doesn't exist, if the token is wrong or if the request is used +-- 2 if the new password is the same as the user's administrative access +-- a_id account identifier +-- + +CREATE OR REPLACE FUNCTION users.confirm_password_recovery( IN umail TEXT, IN tok TEXT, IN pmd5 TEXT, IN psha1 TEXT , + OUT err_code INT , OUT a_id INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + amd5 TEXT; + asha1 TEXT; +BEGIN + SELECT INTO a_id, amd5, asha1 addr.id, admin.pass_md5 , admin.pass_sha1 + FROM users.addresses addr + INNER JOIN users.credentials creds + ON creds.address_id = addr.id + INNER JOIN users.pwd_recovery_requests req + ON req.credentials_id = creds.address_id AND req.token = tok AND NOT req.used + LEFT OUTER JOIN admin.admin_credentials acreds + ON acreds.credentials_id = creds.address_id + LEFT OUTER JOIN admin.administrators admin + ON admin.id = acreds.administrator_id + WHERE addr.address = umail + FOR UPDATE OF creds , addr , req; + + IF NOT FOUND + THEN + err_code := 1; + RETURN; + ELSEIF amd5 IS NOT NULL AND amd5 = pmd5 AND asha1 = psha1 + THEN + err_code := 2; + RETURN; + END IF; + + UPDATE users.pwd_recovery_requests SET used = TRUE WHERE credentials_id = a_id; + UPDATE users.credentials SET pass_md5 = pmd5 , pass_sha1 = psha1 WHERE address_id = a_id; + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Password recovery successful' ); + err_code := 0; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.confirm_password_recovery( TEXT , TEXT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Cancel password recovery request after a mail failure +-- +-- Parameters: +-- a_id account identifier +-- + +CREATE OR REPLACE FUNCTION users.cancel_password_recovery( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + PERFORM users.write_log( a_id , 'ERROR'::log_level , 'Password recovery: could not send e-mail, aborting' ); + DELETE FROM users.pwd_recovery_requests WHERE credentials_id = a_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Request mail address change +-- +-- Parameters: +-- cid account identifier +-- nmail new address +-- +-- Returns: +-- err_code 0 on success +-- -1 if there's already such a request in the DB +-- -2 if the mail address exists +-- + +CREATE OR REPLACE FUNCTION users.request_address_change( cid INT , nmail TEXT , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + vkey TEXT; +BEGIN + vkey := users.make_token( 64 ); + INSERT INTO users.address_change_requests( credentials_id , address_id , token ) + VALUES ( cid , users.create_address( nmail ) , vkey ); + err_code := 0; + PERFORM users.write_log( cid , 'INFO'::log_level , 'E-mail address change requested; validation key: ' || vkey ); +EXCEPTION + WHEN unique_violation THEN + err_code := -1; + WHEN not_null_violation THEN + err_code := -2; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.request_address_change( INT , TEXT ) TO :dbuser; + + + +-- +-- Confirm mail address change +-- +-- Parameters: +-- cid account identifier +-- tok validation token +-- +-- Returns: +-- n_id The account's new identifier +-- + +CREATE OR REPLACE FUNCTION users.confirm_address_change( cid INT , tok TEXT , OUT n_id INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + pk INT; + npk INT; + oaddr TEXT; +BEGIN + SELECT INTO pk, npk, oaddr addr.id , acr.address_id , addr.address + FROM users.addresses addr, users.credentials creds, users.address_change_requests acr + WHERE addr.id = cid AND creds.address_id = cid AND acr.credentials_id = cid + AND acr.token = tok + AND NOT acr.used + FOR UPDATE; + + IF FOUND + THEN + UPDATE users.credentials SET address_id = npk WHERE address_id = pk; + UPDATE users.address_change_requests SET used = TRUE WHERE credentials_id = npk; + DELETE FROM users.addresses WHERE id = pk; + n_id := npk; + PERFORM users.write_log( npk , 'INFO'::log_level , 'E-mail address change confirmed (old address: ' + || oaddr || ')' ); + ELSE + n_id := 0; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.confirm_address_change( INT , TEXT ) TO :dbuser; + + + +-- +-- Cancels an address change request +-- +-- Parameters: +-- cid account identifier +-- + +CREATE OR REPLACE FUNCTION users.cancel_address_change( cid INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE users.address_change_requests + SET used = TRUE + WHERE credentials_id = cid; + PERFORM users.write_log( cid , 'INFO'::log_level , 'E-mail address change aborted' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.cancel_address_change( INT ) TO :dbuser; + + + +-- +-- Account validation +-- +-- /!\ Transaction rollback required if there is an error /!\ +-- +-- Parameters: +-- addr Account email address +-- vtoken Validation token +-- empname Empire name +-- plname Initial planet name +-- +-- Returns: +-- account_error 0 on success +-- 1 if the account's status is incorrect +-- 2 if the validation token doesn't match +-- empire_error 0 on success +-- 1 if the name is banned +-- 2 if the empire name is unavailable +-- planet_error 0 on success +-- 1 if the name is banned +-- 2 if the planet name is unavailable +-- + +CREATE OR REPLACE FUNCTION users.validate( addr TEXT , vtoken TEXT , empname TEXT , plname TEXT , + OUT account_error INT , OUT empire_error INT , OUT planet_error INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + accid INT; + astat TEXT; + empid INT; + plid INT; +BEGIN + -- Initialise return values + account_error := 0; + empire_error := 0; + planet_error := 0; + + -- Find account + SELECT INTO accid c.address_id + FROM users.credentials c + INNER JOIN users.addresses a + ON a.id = c.address_id + WHERE a.address = addr + FOR UPDATE; + IF NOT FOUND THEN + PERFORM sys.write_log( 'AccountManagement' , 'WARNING'::log_level , 'account for "' + || addr || '" not found' ); + account_error := 1; + RETURN; + END IF; + + -- Get account status + SELECT INTO astat status FROM users.accounts_view + WHERE id = accid; + IF astat NOT IN ('UNCONFIRMED' , 'REACTIVATING') THEN + PERFORM users.write_log( accid , 'WARNING'::log_level , 'incorrect account status: ' || astat ); + account_error := 1; + ELSE + -- Delete validation key + DELETE FROM users.validation_keys + WHERE credentials_id = accid AND token = vtoken; + IF NOT FOUND THEN + PERFORM users.write_log( accid , 'WARNING'::log_level , 'confirmation code "' + || vtoken || '" not found' ); + account_error := 2; + END IF; + END IF; + + -- Create / get empire + empid := naming.goc_empire_name( accid , empname ); + IF empid < 0 THEN + empire_error := -empid; + END IF; + + -- Get free planet, rename it + plid := verse.get_random_planet( ); + IF plid IS NULL THEN + PERFORM users.write_log( accid , 'WARNING'::log_level , 'no free planets found!' ); + planet_error := 2; + ELSE + planet_error := - naming.change_map_name( plid , accid , plname ); + END IF; + + -- Activate account and create empire + IF planet_error = 0 AND empire_error = 0 AND account_error = 0 THEN + IF astat = 'REACTIVATING' THEN + DELETE FROM users.inactive_accounts + WHERE credentials_id = accid; + END IF; + INSERT INTO users.active_accounts (credentials_id, vacation_credits) + VALUES ( accid , sys.get_constant( 'vacation.initial' ) ); + + PERFORM emp.create_empire( empid , plid , sys.get_constant( 'game.initialCash' ) ); + PERFORM users.write_log( accid , 'INFO'::log_level , 'created empire #' || empid + || ' ("' || empname || '") with initial planet #' || plid || ' ("' || plname || '")' ); + END IF; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an inactive account (used by command line tools) +-- +-- Parameters: +-- addr mail address +-- lang selected language +-- pmd5 MD5 hash of password +-- psha1 SHA-1 hash of password +-- +-- Returns: +-- err_code error code: +-- 0 on success +-- -1 if the address exists +-- -2 if the language does not exist +-- a_id the account's identifier +-- + +CREATE OR REPLACE FUNCTION users.create_inactive_account ( addr TEXT , lang TEXT , pmd5 TEXT , psha1 TEXT , + OUT err_code INT , OUT a_id INT) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + vkey TEXT; + l_id INT; +BEGIN + -- Get language + SELECT INTO l_id l.id FROM defs.languages l + CROSS JOIN defs.strings s + LEFT OUTER JOIN defs.translations t + ON t.lang_id = l.id AND t.string_id = s.id + WHERE l.language = lang + GROUP BY l.id + HAVING count( s.* ) = count( t.* ); + IF NOT FOUND THEN + err_code := -2; + a_id := NULL; + RETURN; + END IF; + + -- Create address + a_id := users.create_address( addr ); + IF a_id IS NULL + THEN + err_code := -1; + RETURN; + END IF; + + -- Insert credentials + INSERT INTO users.credentials (address_id, pass_md5, pass_sha1, credits, language_id) + VALUES ( a_id , pmd5 , psha1 , floor( sys.get_constant( 'game.initialCredits' ) ) , l_id ); + INSERT INTO users.inactive_accounts ( credentials_id , since , status ) + VALUES ( a_id , now() - '1s'::INTERVAL , 'PROCESSED' ); + err_code := 0; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.create_inactive_account(TEXT,TEXT,TEXT,TEXT) TO :dbuser; + + +-- +-- Sets an account's language +-- +-- Parameters: +-- u_mail User address +-- l_tid Language identifier +-- + +CREATE OR REPLACE FUNCTION users.set_language( u_mail TEXT , l_tid TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + l_id INT; +BEGIN + SELECT INTO l_id l.id FROM defs.languages l + CROSS JOIN defs.strings s + LEFT OUTER JOIN defs.translations t + ON t.lang_id = l.id AND t.string_id = s.id + WHERE l.language = l_tid + GROUP BY l.id + HAVING count( s.* ) = count( t.* ); + IF NOT FOUND THEN + RETURN; + END IF; + + UPDATE users.credentials c SET language_id = l_id + FROM users.addresses a + WHERE c.address_id = a.id AND a.address = u_mail; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.set_language( TEXT , TEXT ) TO :dbuser; + + + +-- +-- Sets an account's password +-- +-- Parameters: +-- u_id Account identifier +-- p_sha1 SHA1 hash of the new password +-- p_md5 MD-5 hash of the new password +-- +-- Returns: +-- success Whether the operation was successful +-- + +CREATE OR REPLACE FUNCTION users.set_password( u_id INT , p_sha1 TEXT , p_md5 TEXT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + amd5 TEXT; + asha1 TEXT; +BEGIN + SELECT INTO amd5, asha1 admin.pass_md5 , admin.pass_sha1 + FROM users.credentials creds + LEFT OUTER JOIN admin.admin_credentials acreds + ON acreds.credentials_id = creds.address_id + LEFT OUTER JOIN admin.administrators admin + ON admin.id = acreds.administrator_id + WHERE creds.address_id = u_id + FOR UPDATE OF creds; + + IF amd5 IS NOT NULL AND amd5 = p_md5 AND asha1 = p_sha1 + THEN + success := FALSE; + ELSE + UPDATE users.credentials + SET pass_md5 = p_md5 , pass_sha1 = p_sha1 + WHERE address_id = u_id; + PERFORM users.write_log( u_id , 'INFO'::log_level , 'Password changed' ); + success := TRUE; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.set_password( INT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Causes old password recovery requests to expire +-- + +CREATE OR REPLACE FUNCTION users.expire_pwd_recovery_requests() + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER +AS $$ + DELETE FROM users.pwd_recovery_requests + WHERE created <= now() - ( floor( sys.get_constant('accounts.prrDelay') ) || 's' )::INTERVAL; +$$ LANGUAGE SQL; + + + +-- +-- Causes old address change requests to expire +-- + +CREATE OR REPLACE FUNCTION users.expire_addr_change_requests() + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; +BEGIN + FOR rec IN SELECT * FROM users.address_change_requests + WHERE created <= now() - ( floor( sys.get_constant('accounts.acrDelay') ) || 's' )::INTERVAL + FOR UPDATE + LOOP + IF rec.address_id = rec.credentials_id THEN + DELETE FROM users.address_change_requests + WHERE credentials_id = rec.credentials_id; + ELSE + DELETE FROM users.addresses + WHERE id = rec.address_id; + END IF; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Causes unconfirmed new accounts to be deleted and unconfirmed reactived accounts to be disabled +-- + +CREATE OR REPLACE FUNCTION users.expire_validation_keys() + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; +BEGIN + FOR rec IN SELECT v.credentials_id AS id , ( ia.credentials_id IS NULL ) AS was_new + FROM users.validation_keys v + INNER JOIN users.credentials c ON c.address_id = v.credentials_id + INNER JOIN users.addresses a ON c.address_id = a.id + LEFT OUTER JOIN users.inactive_accounts ia ON ia.credentials_id = c.address_id + WHERE v.created <= now() - ( floor( sys.get_constant('accounts.cacDelay') ) || 's' )::INTERVAL + FOR UPDATE OF v , c , a + LOOP + IF rec.was_new + THEN + DELETE FROM users.credentials WHERE address_id = rec.id; + DELETE FROM users.addresses WHERE id = rec.id; + ELSE + DELETE FROM users.validation_keys WHERE credentials_id = rec.id; + END IF; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Handle account requests expiry +-- + +CREATE OR REPLACE FUNCTION users.expire_requests( ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + PERFORM users.expire_pwd_recovery_requests(); + PERFORM users.expire_addr_change_requests(); + PERFORM users.expire_validation_keys(); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.expire_requests() TO :dbuser; + + + +-- +-- Disable quitting accounts +-- + +CREATE TYPE quitting_account AS ( + id INT , + address TEXT , + language TEXT +); + +CREATE OR REPLACE FUNCTION users.process_quit_requests( ) + RETURNS SETOF quitting_account + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + addr quitting_account; + rec RECORD; +BEGIN + UPDATE users.inactive_accounts + SET status = 'PROCESSING' + WHERE status = 'FUTURE' AND since <= now(); + + FOR rec IN SELECT ia.credentials_id AS account , e.name_id AS empire , + ma.address AS address , l.language AS language + FROM users.inactive_accounts ia + INNER JOIN users.credentials c ON c.address_id = ia.credentials_id + INNER JOIN defs.languages l ON l.id = c.language_id + INNER JOIN users.active_accounts aa ON aa.credentials_id = ia.credentials_id + INNER JOIN users.addresses ma ON ma.id = c.address_id + INNER JOIN naming.empire_names en ON en.owner_id = ia.credentials_id + INNER JOIN emp.empires e ON e.name_id = en.id + WHERE ia.status = 'PROCESSING' + FOR UPDATE OF ia , c , aa , ma , en , e + LOOP + PERFORM emp.delete_empire( rec.empire ); + DELETE FROM users.active_accounts WHERE credentials_id = rec.account; + UPDATE users.inactive_accounts + SET status = 'PROCESSED' + WHERE credentials_id = rec.account; + + addr.id = rec.account; + addr.address = rec.address; + addr.language := rec.language; + RETURN NEXT addr; + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.process_quit_requests( ) TO :dbuser; + + + +-- +-- Sets an account in the QUITTING status +-- +-- Parameters: +-- a_id Account identifier +-- r_txt Reason +-- + +CREATE OR REPLACE FUNCTION users.set_account_quit( a_id INT , r_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + -- Verify and lock record + PERFORM aa.credentials_id FROM users.active_accounts aa + INNER JOIN users.credentials c ON aa.credentials_id = c.address_id + LEFT OUTER JOIN users.inactive_accounts ia ON ia.credentials_id = c.address_id + LEFT OUTER JOIN users.vacations v ON v.account_id = aa.credentials_id + WHERE aa.credentials_id = a_id AND ia.credentials_id IS NULL AND v.account_id IS NULL + FOR UPDATE OF aa , c; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Insert de-activation record + INSERT INTO users.inactive_accounts ( credentials_id , status , since ) + VALUES ( a_id , 'FUTURE' , now() + ( floor( sys.get_constant( 'accounts.quitDelay' ) ) || 's' )::INTERVAL ); + IF r_txt <> '' THEN + INSERT INTO users.reasons ( account_id , reason ) + VALUES ( a_id , r_txt ); + END IF; + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Quitting' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.set_account_quit( INT , TEXT ) TO :dbuser; + + + +-- +-- Prevents an account from being disabled +-- +-- Parameters: +-- a_id Account identifier +-- r_txt Reason +-- + +CREATE OR REPLACE FUNCTION users.cancel_account_quit( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + -- Verify and lock record + PERFORM aa.credentials_id FROM users.active_accounts aa + INNER JOIN users.credentials c ON aa.credentials_id = c.address_id + INNER JOIN users.inactive_accounts ia ON ia.credentials_id = c.address_id + LEFT OUTER JOIN users.bans b ON b.account_id = aa.credentials_id + WHERE aa.credentials_id = a_id AND b.account_id IS NULL AND ia.status = 'FUTURE' + FOR UPDATE OF aa , c , ia; + IF NOT FOUND + THEN + RETURN; + END IF; + DELETE FROM users.inactive_accounts WHERE credentials_id = a_id; + PERFORM users.write_log( a_id , 'INFO'::log_level , 'No longer quitting' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.cancel_account_quit( INT ) TO :dbuser; + + + +-- +-- Prepares an account for vacation mode +-- +-- Parameters: +-- a_id Account identifier +-- + +CREATE OR REPLACE FUNCTION users.set_vacation( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + PERFORM aa.credentials_id FROM users.active_accounts aa + INNER JOIN users.credentials c ON aa.credentials_id = c.address_id + LEFT OUTER JOIN users.vacations v ON v.account_id = aa.credentials_id + LEFT OUTER JOIN users.inactive_accounts ia ON ia.credentials_id = aa.credentials_id + WHERE aa.credentials_id = a_id AND v.account_id IS NULL AND ia.credentials_id IS NULL + AND aa.vacation_credits > 0 + FOR UPDATE OF aa , c; + IF NOT FOUND + THEN + RETURN; + END IF; + + INSERT INTO users.vacations ( account_id , since , status ) + VALUES ( a_id , now() + ( floor( sys.get_constant( 'vacation.delay' ) ) || 's' )::INTERVAL , 'FUTURE' ); + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Preparing to enter vacation mode' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.set_vacation( INT ) TO :dbuser; + + + +-- +-- Causes an account to exit vacation mode, or to avoid entering it +-- +-- Parameters: +-- a_id Account identifier +-- + +CREATE OR REPLACE FUNCTION users.leave_vacation( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + active BOOLEAN; + e_id INT; +BEGIN + SELECT INTO active , e_id ( v.status = 'PROCESSED' ) , e.name_id + FROM users.active_accounts aa + INNER JOIN users.credentials c ON aa.credentials_id = c.address_id + INNER JOIN users.vacations v ON v.account_id = aa.credentials_id + INNER JOIN naming.empire_names en ON en.owner_id = v.account_id + INNER JOIN emp.empires e ON e.name_id = en.id + WHERE aa.credentials_id = a_id + FOR UPDATE OF v , aa , c; + IF NOT FOUND + THEN + RETURN; + END IF; + + IF active + THEN + PERFORM emp.switch_enemies( e_id ); + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Left vacation mode' ); + ELSE + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Cancelled vacation mode' ); + END IF; + + DELETE FROM users.vacations WHERE account_id = a_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.leave_vacation( INT ) TO :dbuser; + + + +-- +-- Manage vacation credits and activate / disable vacation mode +-- + +CREATE OR REPLACE FUNCTION users.process_vacations( ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + a_id INT; + e_id INT; +BEGIN + -- Increase vacation credits for accounts that are not quitting or on/entering vacation + UPDATE users.active_accounts aa + SET vacation_credits = aa.vacation_credits + 1 + FROM users.credentials c + LEFT OUTER JOIN users.vacations v ON v.account_id = c.address_id + LEFT OUTER JOIN users.inactive_accounts ia ON ia.credentials_id = c.address_id + WHERE aa.credentials_id = c.address_id AND v.account_id IS NULL AND ia.credentials_id IS NULL + AND aa.vacation_credits < floor( sys.get_constant( 'vacation.max' ) ); + + -- Process accounts that should enter vacation mode + FOR a_id , e_id IN SELECT v.account_id , e.name_id + FROM users.vacations v + INNER JOIN users.active_accounts aa ON aa.credentials_id = v.account_id + INNER JOIN users.credentials c ON c.address_id = v.account_id + INNER JOIN naming.empire_names n ON n.owner_id = v.account_id + INNER JOIN emp.empires e ON e.name_id = n.id + WHERE v.status = 'FUTURE' AND v.since <= now( ) + FOR UPDATE OF v , aa , c , n , e + LOOP + UPDATE users.vacations SET status = 'PROCESSED' WHERE account_id = a_id; + END LOOP; + + -- Decrease vacation credits + UPDATE users.active_accounts aa + SET vacation_credits = ( CASE + WHEN aa.vacation_credits > floor( sys.get_constant( 'vacation.cost' ) ) THEN + aa.vacation_credits - floor( sys.get_constant( 'vacation.cost' ) ) + ELSE + 0 + END ) + FROM users.vacations v + WHERE aa.credentials_id = v.account_id AND v.status = 'PROCESSED'; + + -- Process accounts that should exit vacation mode + FOR a_id , e_id IN SELECT v.account_id , e.name_id + FROM users.vacations v + INNER JOIN users.active_accounts aa ON aa.credentials_id = v.account_id + INNER JOIN users.credentials c ON c.address_id = v.account_id + INNER JOIN naming.empire_names n ON n.owner_id = v.account_id + INNER JOIN emp.empires e ON e.name_id = n.id + WHERE v.status = 'PROCESSED' AND aa.vacation_credits = 0 + FOR UPDATE OF v , aa , c , n , e + LOOP + PERFORM users.write_log( a_id , 'INFO'::log_level , 'Out of vacation credits - leaving vacation mode' ); + PERFORM users.sessions_terminate( users.sessions_login( a_id , 'N/A' , 'vac_end' , 'N/A' ) , 'MANUAL' ); + DELETE FROM users.vacations WHERE account_id = a_id; + PERFORM emp.switch_enemies( e_id ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.process_vacations( ) TO :dbuser; + + + +-- +-- Grants credits to an account +-- +-- Parameters: +-- a_id Administrator identifier +-- c_id Account identifier +-- c_inc Credits to grant +-- + +CREATE OR REPLACE FUNCTION admin.grant_user_credits( a_id INT , c_id INT , c_inc INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE users.credentials SET credits = credits + c_inc + WHERE address_id = c_id; + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Granted ' || c_inc || ' credit(s) to user #' || c_id ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.grant_user_credits( INT , INT , INT ) TO :dbuser; + + + +-- +-- View for mail address change requests +-- + +CREATE VIEW users.mail_change_view + AS SELECT r.credentials_id AS id , r.used , + ( r.created + ( floor( sys.get_constant( 'accounts.acrDelay' ) ) || 's' )::INTERVAL ) AS expires , + ( CASE + WHEN r.used THEN + NULL + ELSE + a.address + END ) AS new_address + FROM users.address_change_requests r + INNER JOIN users.addresses a ON a.id = r.address_id; + +GRANT SELECT ON users.mail_change_view TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/075-session-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/075-session-functions.sql new file mode 100644 index 0000000..ad7785f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/075-session-functions.sql @@ -0,0 +1,313 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- User sessions functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- MAIN SESSION VIEW -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +CREATE VIEW users.sessions + AS SELECT s.* , e.ended , e.end_type , c.name AS client_name , c.exclusive + FROM users.session_starts s + INNER JOIN defs.session_clients c ON c.id = s.client_id + LEFT OUTER JOIN users.session_ends e ON s.id = e.id + ORDER BY e.ended DESC NULLS FIRST , s.started DESC; + +GRANT SELECT ON users.sessions TO :dbuser; + + +CREATE VIEW users.last_session + AS SELECT credentials_id , max( id ) AS session_id + FROM users.session_starts + GROUP BY credentials_id; + + +CREATE VIEW users.last_online + AS SELECT ls.credentials_id , ( CASE WHEN se.id IS NULL THEN now() ELSE se.ended END ) AS t + FROM users.last_session ls + LEFT OUTER JOIN users.session_ends se ON se.id = ls.session_id; + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- SESSION MANAGEMENT FUNCTIONS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Marks all active sessions as terminated due to server restart +-- + +CREATE OR REPLACE FUNCTION users.sessions_server_restart( ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + INSERT INTO users.session_ends( id , end_type ) + SELECT s.id , 'SERVER'::session_termination_type + FROM users.session_starts s + LEFT OUTER JOIN users.session_ends e USING ( id ) + WHERE e.id IS NULL; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION users.sessions_server_restart( ) TO :dbuser; + + + +-- +-- Registers a session's initialisation +-- +-- Parameters: +-- c_id Credentials identifier +-- s_name Session name +-- c_type Client type name +-- s_addr Session address +-- +-- Returns: +-- s_id Session identifier +-- + +CREATE OR REPLACE FUNCTION users.sessions_login( c_id INT , s_name TEXT , c_type TEXT , s_addr TEXT , OUT s_id BIGINT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + cl_id INT; + excl BOOLEAN; + as_id BIGINT; + as_nm TEXT; +BEGIN + -- Get client type parameters + SELECT INTO cl_id , excl id , exclusive + FROM defs.session_clients + WHERE name = c_type; + IF NOT FOUND + THEN + RAISE EXCEPTION 'Client session type "%" not found' , c_type; + END IF; + + -- Close all active, exclusive sessions from the same user if the new session is exclusive + IF excl + THEN + FOR as_id , as_nm IN SELECT s.id , s.session + FROM users.session_starts s + INNER JOIN defs.session_clients c + ON s.client_id = c.id AND c.exclusive + LEFT OUTER JOIN users.session_ends e ON s.id = e.id + WHERE s.credentials_id = c_id AND e.id IS NULL + FOR UPDATE OF s + LOOP + PERFORM users.write_log( c_id , 'WARNING'::log_level , 'Terminating exclusive session "' || as_nm + || '" due to new exlusive session' ); + INSERT INTO users.session_ends ( id , end_type ) + VALUES ( as_id , 'EXCLUSIVE'::session_termination_type ); + END LOOP; + END IF; + + -- Add new session + INSERT INTO users.session_starts ( credentials_id , client_id , session , from_address ) + VALUES ( c_id , cl_id , s_name , s_addr ) + RETURNING id INTO s_id; + PERFORM users.write_log( c_id , 'DEBUG'::log_level , 'Logged in from ' || s_addr + || ' with client ' || c_type || '; session #' || s_id ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.sessions_login( INT , TEXT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Terminates a session +-- +-- Parameters: +-- s_id Session identifier +-- e_type Session end type +-- + +CREATE OR REPLACE FUNCTION users.sessions_terminate( s_id BIGINT , e_type session_termination_type ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + c_id INT; +BEGIN + -- Get user identifier + SELECT INTO c_id s.credentials_id + FROM users.session_starts s + LEFT OUTER JOIN users.session_ends e USING ( id ) + WHERE s.id = s_id AND e.id IS NULL + FOR UPDATE OF s; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Terminate session + INSERT INTO users.session_ends ( id , end_type ) + VALUES ( s_id , e_type ); + PERFORM users.write_log( c_id , 'DEBUG'::log_level , 'Session #' || s_id + || ' ended, termination type: ' || e_type ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.sessions_terminate( BIGINT , session_termination_type ) TO :dbuser; + + + + + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- INACTIVITY CHECKS AND SESSION CLEAN-UP -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + +-- +-- User account record, used to send e-mails +-- + +CREATE TYPE inactive_account_record AS ( + id INT , + address TEXT , + language TEXT +); + + + +-- +-- Checks for accounts that should receive an inactivity warning e-mail +-- +-- Returns: +-- A set of user account records +-- + +CREATE OR REPLACE FUNCTION users.check_inactivity_emails() + RETURNS SETOF inactive_account_record + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + in_units BIGINT; + in_mail BIGINT; + in_time INTERVAL; + a_rec inactive_account_record; +BEGIN + in_units := floor( sys.get_constant( 'accounts.inactivity.units' ) ); + in_mail := floor( sys.get_constant( 'accounts.inactivity.warningMail' ) ); + in_time := ( (in_units * in_mail ) || 's' )::INTERVAL; + + FOR a_rec IN SELECT cr.address_id AS id , ad.address , lg.language + FROM users.last_online lo + INNER JOIN users.credentials cr ON lo.credentials_id = cr.address_id + INNER JOIN users.addresses ad ON ad.id = cr.address_id + INNER JOIN defs.languages lg ON lg.id = cr.language_id + INNER JOIN users.active_accounts aa ON aa.credentials_id = lo.credentials_id + LEFT OUTER JOIN users.vacations vac ON vac.account_id = lo.credentials_id + LEFT OUTER JOIN users.inactivity_emails im ON im.account_id = lo.credentials_id + WHERE vac IS NULL AND im IS NULL AND now() - lo.t > in_time + FOR UPDATE OF cr , aa , ad + LOOP + INSERT INTO users.inactivity_emails ( account_id ) VALUES ( a_rec.id ); + PERFORM users.write_log( a_rec.id , 'INFO'::log_level , 'Sending inactivity warning e-mail' ); + RETURN NEXT a_rec; + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.check_inactivity_emails() TO :dbuser; + + + +-- +-- Removes inactivity e-mail records when users have logged on *after* the e-mail was sent +-- Disables inactive accounts, and lists them +-- + + +CREATE OR REPLACE FUNCTION users.check_inactivity( ) + RETURNS SETOF inactive_account_record + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + in_units BIGINT; + in_drop BIGINT; + in_time INTERVAL; + a_rec RECORD; + r_rec inactive_account_record; +BEGIN + in_units := floor( sys.get_constant( 'accounts.inactivity.units' ) ); + in_drop := floor( sys.get_constant( 'accounts.inactivity.deletion' ) ); + in_time := ( (in_units * in_drop ) || 's' )::INTERVAL; + + -- Delete inactivity email records for players who've logged in since the mail was sent + DELETE FROM users.inactivity_emails WHERE account_id IN ( + SELECT lo.credentials_id + FROM users.last_online lo + INNER JOIN users.inactivity_emails im + ON im.account_id = lo.credentials_id AND im.mail_sent <= lo.t + ); + + -- Disable inactive user accounts + FOR a_rec IN SELECT cr.address_id AS id , ad.address , lg.language , e.name_id AS e_id + FROM users.inactivity_emails im + INNER JOIN users.credentials cr ON im.account_id = cr.address_id + INNER JOIN users.active_accounts aa ON aa.credentials_id = im.account_id + INNER JOIN users.addresses ad ON ad.id = cr.address_id + INNER JOIN defs.languages lg ON lg.id = cr.language_id + INNER JOIN naming.empire_names en ON en.owner_id = cr.address_id + INNER JOIN emp.empires e ON e.name_id = en.id + WHERE now() - im.mail_sent > in_time + FOR UPDATE OF cr , aa , ad , lg , en , e + LOOP + PERFORM users.write_log( a_rec.id , 'INFO'::log_level , 'Disabling account due to inactivity' ); + PERFORM emp.delete_empire( a_rec.e_id ); + DELETE FROM users.active_accounts WHERE credentials_id = a_rec.id; + INSERT INTO users.inactive_accounts ( credentials_id , since , status ) + VALUES ( a_rec.id , now() - '1s'::INTERVAL , 'PROCESSED' ); + r_rec := ( a_rec.id , a_rec.address, a_rec.language ); + RETURN NEXT r_rec; + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.check_inactivity() TO :dbuser; + + + +-- +-- Destroys old, inactive accounts +-- + +CREATE OR REPLACE FUNCTION users.delete_old_accounts( ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + DELETE FROM users.addresses WHERE id IN ( + SELECT ia.credentials_id + FROM users.inactive_accounts ia + LEFT OUTER JOIN admin.admin_credentials ac USING ( credentials_id ) + LEFT OUTER JOIN admin.administrators ad ON ad.id = ac.administrator_id + WHERE now() - since >= '6 months'::INTERVAL AND ( ad IS NULL OR ad.privileges = 0 ) + ); +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION users.delete_old_accounts() TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/080-buildings-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/080-buildings-functions.sql new file mode 100644 index 0000000..f463129 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/080-buildings-functions.sql @@ -0,0 +1,84 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Buildings views and management functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Construct buildings on a planet +-- +-- Parameters: +-- pid Planet identifier +-- bid Building type +-- bcnt Amount of buildings +-- + +CREATE OR REPLACE FUNCTION verse.do_construct_buildings( pid INT , bid INT , bcnt INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + LOOP + UPDATE verse.planet_buildings + SET amount = amount + bcnt + WHERE planet_id = pid AND building_id = bid; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO verse.planet_buildings( planet_id , building_id , amount , damage ) + VALUES( pid , bid , bcnt , 0 ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing, try updating again. + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Destroy buildings on a planet +-- +-- Parameters: +-- pid Planet identifier +-- bid Building type +-- bcnt Amount of buildings +-- +-- Returns: +-- amount of buildings that were destroyed +-- + +CREATE OR REPLACE FUNCTION verse.do_destroy_buildings( pid INT , bid INT , bcnt INT ) + RETURNS INT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + tmp INT; +BEGIN + UPDATE verse.planet_buildings + SET amount = amount - bcnt + WHERE planet_id = pid AND building_id = bid; + + IF FOUND THEN + RETURN bcnt; + END IF; + + RETURN 0; +EXCEPTION + WHEN check_violation THEN + SELECT INTO tmp amount FROM verse.planet_buildings + WHERE planet_id = pid AND building_id = bid + FOR UPDATE; + UPDATE verse.planet_buildings + SET amount = 0 + WHERE planet_id = pid AND building_id = bid; + RETURN tmp; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/100-status-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/100-status-functions.sql new file mode 100644 index 0000000..77ef113 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/100-status-functions.sql @@ -0,0 +1,107 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- System status functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Enter maintenance mode +-- +-- Parameters: +-- a_id Administrator identifier +-- reason_txt Maintenance reason +-- duration Expected duration (minutes) +-- +-- Returns: +-- success TRUE on success, FALSE if the system was already in maintenance mode +-- + +CREATE OR REPLACE FUNCTION sys.enter_maintenance_mode( IN a_id INT , IN reason_txt TEXT , IN duration INT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE sys.status + SET maintenance_start = NOW( ) , + maintenance_end = NOW( ) + ( duration || 'm' )::INTERVAL , + maintenance_text = reason_txt + WHERE maintenance_start IS NULL; + success := FOUND; + IF success + THEN + PERFORM admin.write_log( a_id , 'WARNING'::log_level , 'enabled maintenance mode for ' || + duration || ' minutes; reason: ' || reason_txt ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.enter_maintenance_mode( INT , TEXT , INT ) TO :dbuser; + + + +-- +-- Extend maintenance mode duration +-- +-- Parameters: +-- a_id Administrator identifier +-- ext_duration Expected extended duration (minutes) +-- +-- Returns: +-- success TRUE on success, FALSE if the system was not in maintenance mode +-- + +CREATE OR REPLACE FUNCTION sys.extend_maintenance_mode( IN a_id INT , IN ext_duration INT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE sys.status + SET maintenance_end = NOW( ) + ( ext_duration || 'm' )::INTERVAL + WHERE maintenance_start IS NOT NULL; + success := FOUND; + IF success + THEN + PERFORM admin.write_log( a_id , 'WARNING'::log_level , 'extended maintenance mode duration by ' || + ext_duration || ' minutes' ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.extend_maintenance_mode( INT , INT ) TO :dbuser; + + + + +-- +-- Exit maintenance mode +-- +-- Parameters: +-- a_id Administrator identifier +-- +-- Returns: +-- success TRUE on success, FALSE if the system was not in maintenance mode +-- + +CREATE OR REPLACE FUNCTION sys.exit_maintenance_mode( IN a_id INT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE sys.status + SET maintenance_start = NULL , + maintenance_end = NULL , + maintenance_text = NULL + WHERE maintenance_start IS NOT NULL; + success := FOUND; + IF success + THEN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'terminated maintenance mode' ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.exit_maintenance_mode( INT ) TO :dbuser; + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/110-prefs-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/110-prefs-functions.sql new file mode 100644 index 0000000..e294da9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/110-prefs-functions.sql @@ -0,0 +1,283 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Preference definitions and values functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Preferences view +-- + +CREATE VIEW users.preferences_view + AS SELECT acc.credentials_id AS account_id , + grp.name AS group_name , + grpn.translated_string AS group_i18n_name , + pref.name AS pref_name , + prefn.translated_string AS pref_i18n_name , + prefd.translated_string AS pref_i18n_description , + pref.java_type AS pref_type , + ( CASE ( upr.pref_value IS NULL ) + WHEN TRUE THEN pref.default_value + ELSE upr.pref_value + END ) AS value + FROM users.active_accounts acc + INNER JOIN users.credentials cred + ON cred.address_id = acc.credentials_id + CROSS JOIN defs.preference_definitions pref + INNER JOIN defs.preference_groups grp + ON grp.id = pref.group_id + INNER JOIN defs.translations grpn + ON grpn.lang_id = cred.language_id AND grpn.string_id = grp.display_id + INNER JOIN defs.translations prefn + ON prefn.lang_id = cred.language_id AND prefn.string_id = pref.disp_name_id + INNER JOIN defs.translations prefd + ON prefd.lang_id = cred.language_id AND prefd.string_id = pref.disp_desc_id + LEFT OUTER JOIN users.preferences upr + ON upr.definition_id = pref.id AND upr.account_id = acc.credentials_id + ORDER BY acc.credentials_id , grp.name , pref.name; + +GRANT SELECT ON users.preferences_view TO :dbuser; + + +-- +-- Definitions view +-- + +CREATE VIEW defs.preferences_view + AS SELECT grp.name AS group_name , gds.name AS group_display , pref.name AS name , + pns.name AS d_name , pds.name AS d_desc , + pref.java_type AS java_type , pref.default_value AS default_value + FROM defs.preference_definitions pref + INNER JOIN defs.preference_groups grp ON grp.id = pref.group_id + INNER JOIN defs.strings gds ON gds.id = grp.display_id + INNER JOIN defs.strings pns ON pns.id = pref.disp_name_id + INNER JOIN defs.strings pds ON pds.id = pref.disp_desc_id + ORDER BY grp.name , pref.name; + +GRANT SELECT ON defs.preferences_view TO :dbuser; + + +-- +-- Group registration +-- +-- Parameters: +-- g_name Group name +-- g_display Display name identifier +-- +-- Returns: +-- success Whether the operation was successful or not +-- + +CREATE OR REPLACE FUNCTION defs.uoc_preference_group( g_name TEXT , g_display TEXT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + did INT; +BEGIN + SELECT INTO did id FROM defs.strings WHERE name = g_display; + success := FOUND; + IF NOT success THEN + RETURN; + END IF; + + LOOP + UPDATE defs.preference_groups SET display_id = did + WHERE name = g_name; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO defs.preference_groups (name , display_id) + VALUES (g_name , did); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing. + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION defs.uoc_preference_group( TEXT , TEXT ) TO :dbuser; + + +-- +-- Preference definition registration +-- +-- Parameters: +-- g_name Group name +-- p_name Preference name +-- d_name Display name identifier +-- d_desc Display description identifier +-- j_type Java type name +-- d_val Serialised default value +-- +-- Returns: +-- err_code Error code +-- 0 on success +-- 1 if the group is missing +-- 2 if one of the strings is missing +-- 3 if the definition exists but has a different type +-- + +CREATE OR REPLACE FUNCTION defs.uoc_preference( g_name TEXT , p_name TEXT , d_name TEXT , d_desc TEXT , j_type TEXT , d_val TEXT, + OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + g_id INT; + n_id INT; + d_id INT; + p_id INT; + o_type TEXT; +BEGIN + -- Get group identifier + SELECT INTO g_id id FROM defs.preference_groups WHERE name = g_name; + IF NOT FOUND THEN + err_code := 1; + RETURN; + END IF; + + -- Get strings + SELECT INTO n_id id FROM defs.strings WHERE name = d_name; + SELECT INTO d_id id FROM defs.strings WHERE name = d_desc; + IF n_id IS NULL OR d_id IS NULL THEN + err_code := 2; + RETURN; + END IF; + + LOOP + -- Try updating + SELECT INTO p_id , o_type id , java_type + FROM defs.preference_definitions + WHERE name = p_name + FOR UPDATE; + IF FOUND THEN + -- Make sure the type didn't change + IF o_type <> j_type THEN + err_code := 3; + ELSE + err_code := 0; + UPDATE defs.preference_definitions + SET disp_name_id = n_id , disp_desc_id = d_id , group_id = g_id + WHERE id = p_id; + END IF; + EXIT; + END IF; + + -- Try inserting + BEGIN + INSERT INTO defs.preference_definitions (group_id , name , disp_name_id , disp_desc_id , java_type , default_value ) + VALUES ( g_id , p_name , n_id , d_id , j_type , d_val ); + err_code := 0; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION defs.uoc_preference( TEXT , TEXT , TEXT , TEXT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Set a preference's default value +-- +-- Parameters: +-- a_id Administrator identifier +-- p_name Preference name +-- p_val Preference default value +-- + +CREATE OR REPLACE FUNCTION defs.set_preference_default( a_id INT , p_name TEXT , p_val TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE defs.preference_definitions SET default_value = p_val WHERE name = p_name; + IF FOUND + THEN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Changed default value of preference "' || p_name + || '" to "' || p_val || '"' ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION defs.set_preference_default( INT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Resets an account's preferences +-- +-- Parameters: +-- a_id Account identifier +-- + +CREATE OR REPLACE FUNCTION users.reset_preferences( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + DELETE FROM users.preferences WHERE account_id = a_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.reset_preferences( INT ) TO :dbuser; + + + +-- +-- Sets a preference +-- +-- Parameters: +-- a_id Account identifier +-- p_name Preference name +-- p_val New value +-- + +CREATE OR REPLACE FUNCTION users.set_preference( a_id INT , p_name TEXT , p_val TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + p_id INT; +BEGIN + -- Get preference identifier + SELECT INTO p_id id FROM defs.preference_definitions + WHERE name = p_name; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Update or add preference + LOOP + UPDATE users.preferences SET pref_value = p_val + WHERE account_id = a_id AND definition_id = p_id; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO users.preferences( account_id , definition_id , pref_value ) + VALUES( a_id , p_id , p_val ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION users.set_preference( INT , TEXT , TEXT ) TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/120-map-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/120-map-functions.sql new file mode 100644 index 0000000..ed0fcbd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/120-map-functions.sql @@ -0,0 +1,58 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Map display functions and related types +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- Map entry +CREATE TYPE map_entry_type AS ( + x INT , + y INT , + orbit INT , + id INT , + picture INT , + name TEXT , + tag TEXT , + display empire_relation_type +); + + +-- +-- Generates the map from an empire's point of view +-- +-- Parameters: +-- e_id the empire viewing the map +-- min_x minimal X coordinate +-- min_y minimal Y coordinate +-- max_x maximal X coordinate +-- max_y maximal Y coordinate +-- +-- Returns: +-- a set of map entries +-- + +CREATE OR REPLACE FUNCTION verse.get_map( e_id INT , min_x INT , min_y INT , max_x INT , max_y INT ) + RETURNS SETOF map_entry_type + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT mv.x AS x , mv.y AS y , mv.orbit AS orbit , mv.id AS id , mv.picture AS picture , + mv.name AS name , mv.tag AS tag , + (CASE + WHEN mv.owner = $1 THEN 'OWN' + WHEN mv.alliance_id IS NOT NULL AND mv.alliance_id = ea.alliance_id THEN 'ALLIED' + WHEN en.alliance_id IS NOT NULL THEN 'ENEMY' + ELSE NULL + END )::empire_relation_type AS display + FROM verse.map_view mv + LEFT OUTER JOIN emp.alliance_members ea + ON ea.empire_id = $1 AND NOT is_pending + LEFT OUTER JOIN emp.enemy_alliances en + ON en.empire_id = $1 AND en.alliance_id = mv.alliance_id + WHERE x BETWEEN $2 AND $4 AND y BETWEEN $3 AND $5; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION verse.get_map( INT , INT , INT , INT , INT ) TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/140-planets-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/140-planets-functions.sql new file mode 100644 index 0000000..06247c1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/140-planets-functions.sql @@ -0,0 +1,1102 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Planet views and management functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- Planet access +CREATE TYPE planet_access_type + AS ENUM( 'BASIC' , 'PRESENT' , 'OWNER' ); + + +-- Basic planet view +CREATE TYPE planet_basic_data AS ( + access planet_access_type , + x INT , + y INT , + orbit INT , + picture INT , + name TEXT , + tag TEXT +); + + +-- Planet orbital view +CREATE TYPE planet_orbital_data AS ( + population BIGINT , + defence BIGINT , + own_power BIGINT , + friendly_power BIGINT , + hostile_power BIGINT , + battle_id BIGINT +); + + +-- Planet owner view +CREATE TYPE planet_owner_data AS ( + happiness INT , + h_change INT , + income BIGINT , + upkeep BIGINT , + can_rename BOOLEAN , + can_abandon BOOLEAN , + abandon_time INT +); + + +-- Buildings view +CREATE TYPE planet_building_data AS ( + id INT , + name TEXT , + description TEXT , + amount INT , + jobs INT , + upkeep BIGINT , + p_type building_output_type , + p_value BIGINT +); + + +-- Build queue items +CREATE TYPE queue_item_data AS ( + name TEXT , + description TEXT , + amount INT , + destroy BOOLEAN , + investment BIGINT , + time_left BIGINT +); + + +-- Type for buildings available on a planet +CREATE TYPE buildable_building_data AS ( + id INT , + name TEXT , + description TEXT , + cost INT , + time_to_build BIGINT , + upkeep INT , + workers INT , + p_type building_output_type , + p_value INT +); + + +-- Type for ships available on a planet +CREATE TYPE buildable_ship_data AS ( + id INT , + name TEXT , + description TEXT , + cost INT , + time_to_build BIGINT , + upkeep INT , + flight_time INT , + power INT +); + + + +-- +-- Determines an empire's access on a planet +-- +-- Parameters: +-- e_id Empire identifier +-- p_id Planet identifier +-- +-- Returns: +-- a basic planet view entry +-- + +CREATE OR REPLACE FUNCTION verse.get_planet_basics( e_id INT , p_id INT ) + RETURNS planet_basic_data + STRICT STABLE + SECURITY DEFINER + AS $$ +DECLARE + o_id INT; + n_flt BIGINT; + rv planet_basic_data; +BEGIN + PERFORM name_id FROM verse.planets WHERE name_id = p_id; + IF NOT FOUND THEN + RETURN NULL; + END IF; + + SELECT INTO o_id ep.empire_id + FROM emp.planets ep + WHERE ep.planet_id = p_id; + + SELECT INTO n_flt count( f.* ) + FROM fleets.fleets f + LEFT OUTER JOIN fleets.movements fm + ON fm.fleet_id = f.id + WHERE f.location_id = p_id AND f.owner_id = e_id AND fm.fleet_id IS NULL; + + IF NOT FOUND THEN + RETURN NULL; + ELSEIF o_id = e_id THEN + rv.access := 'OWNER'; + ELSEIF n_flt > 0 THEN + rv.access := 'PRESENT'; + ELSE + rv.access := 'BASIC'; + END IF; + + SELECT INTO rv.x , rv.y , rv.orbit , rv.name , rv.tag , rv.picture + x , y , orbit , name , tag , picture + FROM verse.map_view + WHERE id = p_id; + RETURN rv; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.get_planet_basics( INT , INT ) TO :dbuser; + + + +-- +-- Gets a planet's orbital view from an empire's point of view +-- +-- Parameters: +-- e_id Empire identifier +-- p_id Planet identifier +-- +-- Returns: +-- an orbital planet view entry +-- + +CREATE OR REPLACE FUNCTION verse.get_orbital_view( e_id INT , p_id INT ) + RETURNS planet_orbital_data + STRICT STABLE + SECURITY DEFINER + AS $$ +DECLARE + rv planet_orbital_data; + happ REAL; + e_att BOOLEAN; + rec RECORD; +BEGIN + -- Get the planet's population and defence + SELECT INTO rv.population , happ + floor( p.population )::BIGINT , ( ph.current / p.population )::REAL + FROM verse.planets p + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + WHERE p.name_id = p_id; + rv.defence := round( verse.adjust_production( verse.get_raw_production( p_id , 'DEF' ) , happ ) ); + + -- Get the empire's fleet mode + SELECT INTO e_att f.attacking + FROM fleets.fleets f + LEFT OUTER JOIN fleets.movements fm + ON fm.fleet_id = f.id + WHERE fm.fleet_id IS NULL AND f.owner_id = p_id AND f.location_id = p_id + LIMIT 1; + IF NOT FOUND THEN + e_att := FALSE; + END IF; + + -- Get fleet powers + FOR rec IN SELECT (CASE + WHEN f.owner_id = e_id THEN 'O' + WHEN f.attacking = e_att THEN 'F' + ELSE 'H' + END) AS f_type , sum( fs.amount * fsd.power ) AS power + FROM fleets.fleets f + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + INNER JOIN fleets.ships fs ON fs.fleet_id = f.id + INNER JOIN tech.ships fsd ON fsd.buildable_id = fs.ship_id + WHERE f.location_id = p_id AND m.fleet_id IS NULL + GROUP BY f.attacking , ( f.owner_id = e_id ) + LOOP + IF rec.f_type = 'O' THEN + rv.own_power = rec.power; + ELSEIF rec.f_type = 'F' THEN + rv.friendly_power = rec.power; + ELSE + rv.hostile_power = rec.power; + END IF; + END LOOP; + + -- Battle ID + SELECT INTO rv.battle_id id FROM battles.battles + WHERE location_id = p_id AND last_tick IS NULL; + + RETURN rv; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.get_orbital_view( INT , INT ) TO :dbuser; + + + +-- +-- Gets a planet's view from its owner's point of view +-- +-- Parameters: +-- e_id Empire identifier +-- p_id Planet identifier +-- +-- Returns: +-- an owner planet view entry +-- + +CREATE OR REPLACE FUNCTION verse.get_owner_view( e_id INT , p_id INT ) + RETURNS planet_owner_data + STRICT STABLE + SECURITY DEFINER + AS $$ +DECLARE + rv planet_owner_data; + t_happ INT; + h_chg INT; + mdelay BIGINT; + r_time INTERVAL; +BEGIN + -- Get income, upkeep, current and target happiness + SELECT INTO rv.income , rv.upkeep , rv.happiness , t_happ + floor( pm.income )::INT , floor( pm.upkeep )::INT , + floor( 100 * ph.current / p.population )::INT , + floor( 100 * ph.target )::INT + FROM verse.planets p + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.planet_money pm ON pm.planet_id = p.name_id + WHERE p.name_id = p_id; + + -- Compute happiness change indicator + h_chg := t_happ - rv.happiness; + IF h_chg = 0 THEN + rv.h_change := 0; + ELSE + rv.h_change := ( CASE WHEN abs( h_chg ) > 10 THEN 2 ELSE 1 END ); + IF h_chg < 0 THEN + rv.h_change := -rv.h_change; + END IF; + END IF; + + -- Check whether the planet can be renamed + mdelay := floor( sys.get_constant( 'map.names.minDelay' ) * sys.get_constant( 'map.names.minDelay.units' ) )::BIGINT; + r_time := ( mdelay::BIGINT || 's' )::INTERVAL; + SELECT INTO rv.can_rename + ( cmn.name_id IS NULL ) + FROM naming.map_names n + LEFT OUTER JOIN naming.changed_map_names cmn + ON cmn.name_id = n.id AND cmn.named_at > now() - r_time + WHERE n.id = p_id; + + -- Get abandon time + SELECT INTO rv.abandon_time time_left + FROM emp.abandon + WHERE planet_id = p_id; + IF FOUND THEN + rv.can_abandon := FALSE; + ELSE + -- Check whether the planet can be abandoned + SELECT INTO rv.can_abandon + ( COUNT(ep.*) > 1 ) + FROM emp.planets ep + LEFT OUTER JOIN emp.abandon a + ON a.planet_id = ep.planet_id + WHERE ep.empire_id = e_id AND a.planet_id IS NULL; + END IF; + + RETURN rv; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.get_owner_view( INT , INT ) TO :dbuser; + + + +-- +-- Get a planet's buildings list using an empire's language settings +-- +-- Parameters: +-- e_id Empire identifier +-- p_id Planet identifier +-- +-- Returns: +-- a set of buildings data entries +-- + +CREATE OR REPLACE FUNCTION verse.get_buildings_view( e_id INT , p_id INT ) + RETURNS SETOF planet_building_data + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT b.building_id AS id , + t1.translated_string AS name , t2.translated_string AS description , + b.amount AS amount , + ( bd.workers * b.amount )::INT AS jobs , + ( bd.upkeep * b.amount )::BIGINT AS upkeep , + bd.output_type AS p_type , + floor( verse.adjust_production( ( bd.output * b.amount )::REAL , + ( ph.current / p.population )::REAL ) + )::BIGINT AS p_value + FROM verse.planet_buildings b + INNER JOIN verse.planets p ON p.name_id = b.planet_id + INNER JOIN verse.planet_happiness ph ON ph.planet_id = b.planet_id + INNER JOIN tech.buildings_view bd ON bd.name_id = b.building_id + INNER JOIN naming.empire_names en ON en.id = $1 + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t1 ON t1.string_id = bd.name_id AND t1.lang_id = c.language_id + INNER JOIN defs.translations t2 ON t2.string_id = bd.description_id AND t2.lang_id = c.language_id + WHERE b.planet_id = $2 AND b.amount > 0 + ORDER BY t1.translated_string; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION verse.get_buildings_view( INT , INT ) TO :dbuser; + + + +-- +-- Get a planet's construction queue +-- +-- Parameters: +-- p_id Planet identifier +-- +-- Returns: +-- the queue's items +-- + +CREATE OR REPLACE FUNCTION verse.get_build_queue( p_id INT ) + RETURNS SETOF queue_item_data + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT t1.translated_string AS name , t2.translated_string AS description , + qi.amount AS amount , qi.destroy AS destroy , + ( CASE + WHEN qi.destroy THEN 0 + ELSE floor( qi.amount * bd.cost - ( CASE WHEN qi.queue_order = 0 THEN q.money ELSE 0 END ) ) + END )::BIGINT AS investment , + ( CASE + WHEN ceil( verse.adjust_production( ( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) )::REAL , ( ph.current / p.population )::REAL ) ) = 0 THEN NULL + ELSE ceil( ( qi.amount * bd.work * ( CASE WHEN qi.destroy THEN sys.get_constant( 'game.work.destructionWork' ) ELSE 1 END ) - ( CASE WHEN qi.queue_order = 0 THEN q.work ELSE 0 END ) ) + / verse.adjust_production( ( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) )::REAL , ( ph.current / p.population )::REAL ) ) + END )::BIGINT AS time_left + FROM verse.planets p + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.bld_queues q ON q.planet_id = p.name_id + INNER JOIN verse.bld_items qi ON qi.queue_id = q.planet_id + INNER JOIN tech.buildables bd ON bd.name_id = qi.building_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN naming.empire_names en ON en.id = ep.empire_id + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t1 ON t1.string_id = bd.name_id AND t1.lang_id = c.language_id + INNER JOIN defs.translations t2 ON t2.string_id = bd.description_id AND t2.lang_id = c.language_id + WHERE p.name_id = $1 + ORDER BY qi.queue_order; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION verse.get_build_queue( INT ) TO :dbuser; + + + +-- +-- Get a planet's military queue +-- +-- Parameters: +-- p_id Planet identifier +-- +-- Returns: +-- the queue's items +-- + +CREATE OR REPLACE FUNCTION verse.get_military_queue( p_id INT ) + RETURNS SETOF queue_item_data + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT t1.translated_string AS name , t2.translated_string AS description , + qi.amount AS amount , FALSE AS destroy , + floor( qi.amount * bd.cost - ( CASE WHEN qi.queue_order = 0 THEN q.money ELSE 0 END ) )::BIGINT AS investment , + ( CASE + WHEN ceil( verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ( ph.current / p.population )::REAL ) ) = 0 THEN NULL + ELSE ceil( ( qi.amount * bd.work - ( CASE WHEN qi.queue_order = 0 THEN q.work ELSE 0 END ) ) + / verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ( ph.current / p.population )::REAL ) ) + END )::BIGINT AS time_left + FROM verse.planets p + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.mil_queues q ON q.planet_id = p.name_id + INNER JOIN verse.mil_items qi ON qi.queue_id = q.planet_id + INNER JOIN tech.buildables bd ON bd.name_id = qi.ship_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN naming.empire_names en ON en.id = ep.empire_id + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t1 ON t1.string_id = bd.name_id AND t1.lang_id = c.language_id + INNER JOIN defs.translations t2 ON t2.string_id = bd.description_id AND t2.lang_id = c.language_id + WHERE p.name_id = $1 + ORDER BY qi.queue_order; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION verse.get_military_queue( INT ) TO :dbuser; + + + +-- +-- Get the list of which buildings an empire can build on a planet +-- +-- Parameters: +-- p_id Planet identifier +-- +-- Returns: +-- the list of buildings +-- + +CREATE OR REPLACE FUNCTION verse.get_available_buildings( p_id INT ) + RETURNS SETOF buildable_building_data + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT bv.name_id AS id , t1.translated_string AS name , t2.translated_string AS description , + bv.cost AS cost , + ( CASE + WHEN ceil( pdat.p_work ) = 0 THEN NULL + ELSE ceil( bv.work / pdat.p_work ) + END )::BIGINT AS time_to_build , + bv.upkeep AS upkeep , bv.workers AS workers , bv.output_type AS p_type , bv.output AS p_value + FROM ( + SELECT bv.* + FROM tech.buildings_view bv + INNER JOIN tech.basic_buildables bb USING( name_id ) + UNION SELECT bv.* + FROM tech.buildings_view bv + INNER JOIN tech.buildable_requirements r ON r.buildable_id = bv.name_id + INNER JOIN tech.levels l ON l.id = r.level_id + INNER JOIN emp.planets ep ON ep.planet_id = $1 + INNER JOIN emp.technologies t + ON t.empire_id = ep.empire_id AND t.line_id = l.line_id AND t.level > l.level + ) AS bv , ( + SELECT verse.adjust_production( ( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) )::REAL , ( ph.current / p.population )::REAL ) AS p_work , + c.language_id AS language + FROM verse.planets p + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN naming.empire_names en ON en.id = ep.empire_id + INNER JOIN users.credentials c ON c.address_id = en.owner_id + WHERE p.name_id = $1 + ) AS pdat , + defs.translations t1 , defs.translations t2 + WHERE t1.lang_id = pdat.language AND t1.string_id = bv.name_id AND t2.lang_id = pdat.language AND t2.string_id = bv.description_id + ORDER BY t1.translated_string; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION verse.get_available_buildings( INT ) TO :dbuser; + + + +-- +-- Get the list of which ships an empire can build on a planet +-- +-- Parameters: +-- p_id Planet identifier +-- +-- Returns: +-- the list of ships +-- + +CREATE OR REPLACE FUNCTION verse.get_available_ships( p_id INT ) + RETURNS SETOF buildable_ship_data + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT bv.name_id AS id , t1.translated_string AS name , t2.translated_string AS description , + bv.cost AS cost , + ( CASE + WHEN ceil( pdat.p_work ) = 0 THEN NULL + ELSE ceil( bv.work / pdat.p_work ) + END )::BIGINT AS time_to_build , + bv.upkeep AS upkeep , bv.flight_time * 2 AS flight_time , bv.power AS power + FROM ( + SELECT bv.* + FROM tech.ships_view bv + INNER JOIN tech.basic_buildables bb USING( name_id ) + UNION SELECT bv.* + FROM tech.ships_view bv + INNER JOIN tech.buildable_requirements r ON r.buildable_id = bv.name_id + INNER JOIN tech.levels l ON l.id = r.level_id + INNER JOIN emp.planets ep ON ep.planet_id = $1 + INNER JOIN emp.technologies t + ON t.empire_id = ep.empire_id AND t.line_id = l.line_id AND t.level > l.level + ) AS bv , ( + SELECT verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ( ph.current / p.population )::REAL ) AS p_work , + c.language_id AS language + FROM verse.planets p + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN naming.empire_names en ON en.id = ep.empire_id + INNER JOIN users.credentials c ON c.address_id = en.owner_id + WHERE p.name_id = $1 + ) AS pdat , + defs.translations t1 , defs.translations t2 + WHERE t1.lang_id = pdat.language AND t1.string_id = bv.name_id AND t2.lang_id = pdat.language AND t2.string_id = bv.description_id + ORDER BY t1.translated_string; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION verse.get_available_ships( INT ) TO :dbuser; + + + +-- +-- Rename a planet +-- +-- Parameters: +-- p_id Planet identifier +-- nnm New name +-- +-- Returns: +-- err_code Error code: +-- 0 Success +-- 1 Banned name +-- 2 Unavailable name +-- 3 Too early +-- + +CREATE OR REPLACE FUNCTION verse.rename_planet( p_id INT , nnm TEXT , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + c_id INT; + mdelay BIGINT; +BEGIN + SELECT INTO c_id n.owner_id + FROM emp.planets ep + INNER JOIN naming.empire_names n ON n.id = ep.empire_id + WHERE ep.planet_id = p_id; + mdelay := floor( sys.get_constant( 'map.names.minDelay' ) * sys.get_constant( 'map.names.minDelay.units' ) )::BIGINT; + err_code := naming.change_map_name( p_id , c_id , nnm , ( mdelay || 's' )::INTERVAL ); + + IF err_code = 0 THEN + PERFORM battles.rename_planet( p_id , nnm ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.rename_planet( INT , TEXT ) TO :dbuser; + + + +-- +-- Flush a planet's civilian construction queue +-- +-- Parameters: +-- p_id Planet identifier +-- + +CREATE OR REPLACE FUNCTION verse.flush_build_queue( p_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_id INT; + q_cash REAL; +BEGIN + SELECT INTO e_id , q_cash e.name_id , q.money + FROM verse.planets p + INNER JOIN verse.bld_queues q ON q.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + WHERE p.name_id = p_id + FOR UPDATE; + IF NOT FOUND THEN + RETURN; + END IF; + + DELETE FROM verse.bld_items WHERE queue_id = p_id; + UPDATE verse.bld_queues SET money = 0 , work = 0 WHERE planet_id = p_id; + UPDATE emp.empires + SET cash = cash + q_cash * sys.get_constant('game.work.cancelRecovery') + WHERE name_id = e_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.flush_build_queue( INT ) TO :dbuser; + + + +-- +-- Flush a planet's military construction queue +-- +-- Parameters: +-- p_id Planet identifier +-- + +CREATE OR REPLACE FUNCTION verse.flush_military_queue( p_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_id INT; + q_cash REAL; +BEGIN + SELECT INTO e_id , q_cash e.name_id , q.money + FROM verse.planets p + INNER JOIN verse.mil_queues q ON q.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + WHERE p.name_id = p_id + FOR UPDATE; + IF NOT FOUND THEN + RETURN; + END IF; + + DELETE FROM verse.mil_items WHERE queue_id = p_id; + UPDATE verse.mil_queues SET money = 0 , work = 0 WHERE planet_id = p_id; + UPDATE emp.empires + SET cash = cash + q_cash * sys.get_constant('game.work.cancelRecovery') + WHERE name_id = e_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.flush_military_queue( INT ) TO :dbuser; + + + +-- +-- Adds an item to a planet's military queue +-- +-- Parameters: +-- p_id Planet identifier +-- s_id Ship type identifier +-- s_cnt Amount of ships to build +-- + +CREATE OR REPLACE FUNCTION verse.add_military_item( p_id INT , s_id INT , s_cnt INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_id INT; + qlen INT; + dep_level INT; + has_level INT; +BEGIN + IF s_cnt < 1 THEN + RETURN; + END IF; + + -- Lock empire and planet + SELECT INTO e_id e.name_id + FROM verse.planets p + INNER JOIN verse.mil_queues q ON q.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + WHERE p.name_id = p_id + FOR UPDATE OF p , q , ep , e; + IF NOT FOUND THEN + RETURN; + END IF; + + -- Check technologies + SELECT INTO dep_level , has_level l.level , t.level + FROM tech.ships s + LEFT OUTER JOIN tech.buildable_requirements r + ON r.buildable_id = s.buildable_id + LEFT OUTER JOIN tech.levels l + ON l.id = r.level_id + LEFT OUTER JOIN emp.technologies t + ON t.empire_id = e_id AND t.line_id = l.line_id AND t.level > l.level + WHERE s.buildable_id = s_id; + IF NOT FOUND OR ( has_level IS NULL AND dep_level IS NOT NULL ) THEN + RETURN; + END IF; + + -- Check queue length + SELECT INTO qlen count( * ) FROM verse.mil_items WHERE queue_id = p_id; + IF qlen >= 5 THEN + RETURN; + END IF; + + -- Insert queue item + INSERT INTO verse.mil_items ( queue_id , queue_order , ship_id , amount ) + VALUES ( p_id , qlen , s_id , s_cnt ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.add_military_item( INT , INT , INT ) TO :dbuser; + + + +-- +-- Adds building constructions to a planet's civilian queue +-- +-- Parameters: +-- p_id Planet identifier +-- b_id Building type identifier +-- b_cnt Amount of ships to build +-- + +CREATE OR REPLACE FUNCTION verse.construct_buildings( p_id INT , b_id INT , b_cnt INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_id INT; + qlen INT; + dep_level INT; + has_level INT; +BEGIN + IF b_cnt < 1 THEN + RETURN; + END IF; + + -- Lock empire and planet + SELECT INTO e_id e.name_id + FROM verse.planets p + INNER JOIN verse.bld_queues q ON q.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + WHERE p.name_id = p_id + FOR UPDATE OF p , q , ep , e; + IF NOT FOUND THEN + RETURN; + END IF; + + -- Check technologies + SELECT INTO dep_level , has_level l.level , t.level + FROM tech.buildings b + LEFT OUTER JOIN tech.buildable_requirements r + ON r.buildable_id = b.buildable_id + LEFT OUTER JOIN tech.levels l + ON l.id = r.level_id + LEFT OUTER JOIN emp.technologies t + ON t.empire_id = e_id AND t.line_id = l.line_id AND t.level > l.level + WHERE b.buildable_id = b_id; + IF NOT FOUND OR ( has_level IS NULL AND dep_level IS NOT NULL ) THEN + RETURN; + END IF; + + -- Check queue length + SELECT INTO qlen count( * ) FROM verse.bld_items WHERE queue_id = p_id; + IF qlen >= 5 THEN + RETURN; + END IF; + + -- Insert queue item + INSERT INTO verse.bld_items ( queue_id , queue_order , building_id , amount , destroy ) + VALUES ( p_id , qlen , b_id , b_cnt , FALSE ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.construct_buildings( INT , INT , INT ) TO :dbuser; + + + +-- +-- Adds building destructions to a planet's civilian queue +-- +-- Parameters: +-- p_id Planet identifier +-- b_id Building type identifier +-- b_cnt Amount of ships to build +-- +-- Returns: +-- success Whether the orders could be added to the queue +-- (only failures related to the amount of buildings are reported) +-- + +CREATE OR REPLACE FUNCTION verse.destroy_buildings( p_id INT , b_id INT , b_cnt INT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_id INT; + qlen INT; + built INT; + in_queue INT; +BEGIN + IF b_cnt < 1 THEN + RETURN; + END IF; + + -- Lock empire and planet + SELECT INTO e_id e.name_id + FROM verse.planets p + INNER JOIN verse.bld_queues q ON q.planet_id = p.name_id + INNER JOIN verse.planet_buildings b ON b.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + WHERE p.name_id = p_id + FOR UPDATE OF p , q , ep , e , b; + IF NOT FOUND THEN + success := TRUE; + RETURN; + END IF; + + -- Check queue length + SELECT INTO qlen count( * ) FROM verse.bld_items WHERE queue_id = p_id; + IF qlen >= 5 THEN + success := TRUE; + RETURN; + END IF; + + -- Check existing buildings and build queue contents + SELECT INTO built amount + FROM verse.planet_buildings + WHERE planet_id = p_id AND building_id = b_id; + IF NOT FOUND THEN + built := 0; + END IF; + SELECT INTO in_queue sum( amount * ( CASE WHEN destroy THEN -1 ELSE 1 END ) ) + FROM verse.bld_items + WHERE queue_id = p_id AND building_id = b_id; + IF in_queue IS NULL THEN + in_queue := 0; + END IF; + + success := ( b_cnt <= in_queue + built ); + IF NOT success THEN + success := FALSE; + RETURN; + END IF; + + -- Insert queue item + INSERT INTO verse.bld_items ( queue_id , queue_order , building_id , amount , destroy ) + VALUES ( p_id , qlen , b_id , b_cnt , TRUE ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.destroy_buildings( INT , INT , INT ) TO :dbuser; + + + +-- +-- Start abandoning a planet +-- +-- Parameters: +-- p_id Planet to abandon +-- +-- Returns: +-- tta Time to abandon +-- + +CREATE OR REPLACE FUNCTION verse.abandon( p_id INT , OUT tta INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + PERFORM ep.planet_id + FROM emp.planets ep + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + INNER JOIN verse.planets p ON p.name_id = ep.planet_id + INNER JOIN verse.planet_money pm ON pm.planet_id = p.name_id + WHERE ep.planet_id = p_id + FOR UPDATE; + IF NOT FOUND THEN + tta := 0; + RETURN; + END IF; + + tta := floor( sys.get_constant( 'game.timeToAbandon' ) ); + BEGIN + INSERT INTO emp.abandon ( planet_id , time_left ) + VALUES ( p_id , tta ); + UPDATE verse.planet_money SET income = 0 + WHERE planet_id = p_id; + EXCEPTION + WHEN unique_violation THEN + tta := 0; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION verse.abandon( INT ) TO :dbuser; + + + +-- +-- Cancels planet abandon +-- +-- Parameters: +-- p_id Planet not to abandon +-- + +CREATE OR REPLACE FUNCTION verse.cancel_abandon( p_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + DELETE FROM emp.abandon WHERE planet_id = $1; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION verse.cancel_abandon( INT ) TO :dbuser; + + + +-- +-- Prepares a planet for abandon or ownership transfer +-- +-- Parameters: +-- p_id Planet identifier +-- + +CREATE OR REPLACE FUNCTION emp.leave_planet( p_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + bp_id BIGINT; +BEGIN + PERFORM verse.flush_military_queue( p_id ); + PERFORM verse.flush_build_queue( p_id ); + DELETE FROM emp.abandon WHERE planet_id = p_id; + DELETE FROM emp.planets WHERE planet_id = p_id; + + -- Update battle records + SELECT INTO bp_id bpo.protagonist_id + FROM battles.battles b + INNER JOIN battles.protagonists bp ON bp.battle_id = b.id + INNER JOIN battles.planet_ownership bpo ON bpo.protagonist_id = bp.id + WHERE b.location_id = p_id AND b.last_tick IS NULL; + IF FOUND + THEN + UPDATE battles.planet_ownership + SET abandoned_at = sys.get_tick() - 1 + WHERE protagonist_id = bp_id; + END IF; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Inflicts battle damage to a planet's stationary defences +-- +-- Parameters: +-- p_id Planet identifier +-- t_power Total defences +-- dmg Damage to inflict +-- b_id Battle identifier +-- tick Current tick +-- + +CREATE OR REPLACE FUNCTION verse.inflict_battle_damage( p_id INT , t_power BIGINT , dmg REAL , b_id BIGINT , tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + bp_id BIGINT; + st_dmg REAL; + n_dest INT; +BEGIN + PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Inflicting ' || dmg + || ' damage to planet #' || p_id ); + + bp_id := NULL; + FOR rec IN SELECT b.building_id , b.amount , b.damage , ( b.amount * bd.output ) AS power , + bd.output AS s_power + FROM verse.planet_buildings b + INNER JOIN tech.buildings bd ON bd.buildable_id = b.building_id + WHERE b.planet_id = p_id AND b.amount > 0 AND bd.output_type = 'DEF' + LOOP + st_dmg := rec.damage + ( dmg * rec.power / t_power ) / rec.s_power; + n_dest := floor( st_dmg ); + st_dmg := st_dmg - n_dest; + IF n_dest >= rec.amount THEN + n_dest := rec.amount; + st_dmg := 0; + END IF; + + PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Building type #' || rec.building_id + || ' - Damage ' || st_dmg || '; destruction: ' || n_dest ); + + -- Apply damage + UPDATE verse.planet_buildings + SET damage = st_dmg , amount = amount - n_dest + WHERE planet_id = p_id AND building_id = rec.building_id; + + -- Update battle record + CONTINUE WHEN n_dest = 0; + IF bp_id IS NULL THEN + bp_id := battles.goc_planet( b_id , 'BATTLE'::battle_planet_change , tick ); + END IF; + PERFORM battles.record_building_change( bp_id , rec.building_id , -n_dest ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Inflicts debt-related damage to all buildings of an empire +-- +-- Parameters: +-- e_id Empire identifer +-- t_upkeep Total building upkeep +-- debt Daily debt +-- d_ratio Debt damage ratio +-- + +CREATE OR REPLACE FUNCTION verse.handle_debt( e_id INT , t_upkeep REAL , debt REAL , d_ratio REAL ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + tick BIGINT; + tot_damage REAL; + p_rec RECORD; + b_rec RECORD; + bp_id BIGINT; + b_damage REAL; + n_destroy INT; +BEGIN + tick := sys.get_tick( ) - 1; + tot_damage := t_upkeep * d_ratio / debt; + PERFORM sys.write_log( 'EmpireDebt' , 'DEBUG'::log_level , 'Inflicting debt damage to buildings; total upkeep: ' + || t_upkeep || ', damage ratio: ' || d_ratio || ', total damage: ' || tot_damage ); + + FOR p_rec IN SELECT ep.planet_id AS planet , b.id AS battle + FROM emp.planets ep + LEFT OUTER JOIN battles.battles b + ON b.location_id = ep.planet_id AND b.last_tick IS NULL + WHERE ep.empire_id = e_id + LOOP + bp_id := NULL; + + FOR b_rec IN SELECT b.building_id AS building , b.amount AS amount , + ( b.amount * bb.upkeep )::REAL AS upkeep , + b.damage AS damage , ( bd.output_type = 'DEF' ) AS is_def + FROM verse.planet_buildings b + INNER JOIN tech.buildables bb ON bb.name_id = b.building_id + INNER JOIN tech.buildings bd ON bd.buildable_id = b.building_id + WHERE b.amount > 0 AND b.planet_id = p_rec.planet + LOOP + -- Compute damage and destruction + b_damage := b_rec.damage + tot_damage * b_rec.upkeep / t_upkeep; + n_destroy := floor( b_damage ); + IF n_destroy >= b_rec.amount + THEN + n_destroy := b_rec.amount; + b_damage := 0; + ELSE + b_damage := b_damage - n_destroy; + END IF; + + -- Update entry + UPDATE verse.planet_buildings + SET amount = amount - n_destroy , damage = b_damage + WHERE building_id = b_rec.building AND planet_id = p_rec.planet; + + -- Update battle + CONTINUE WHEN p_rec.battle IS NULL OR NOT b_rec.is_def OR n_destroy = 0; + IF bp_id IS NULL + THEN + bp_id := battles.goc_planet( p_rec.battle , 'DESTROY'::battle_planet_change , tick ); + END IF; + PERFORM battles.record_building_change( bp_id , b_rec.building , -n_destroy ); + END LOOP; + END LOOP; +END; +$$ LANGUAGE plpgsql; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/150-battle-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/150-battle-functions.sql new file mode 100644 index 0000000..ef34b5e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/150-battle-functions.sql @@ -0,0 +1,839 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Battle functions and utility views +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Checks if a battle needs to start at a given location +-- +-- Parameters: +-- l_id Location to check +-- +-- Returns: +-- Whether or not a new battle is to be added +-- + +CREATE OR REPLACE FUNCTION battles.check_start( l_id INT ) + RETURNS BOOLEAN + STRICT STABLE + SECURITY INVOKER + AS $$ +BEGIN + PERFORM p.name_id + FROM verse.planets p + INNER JOIN fleets.fleets f ON f.location_id = p.name_id AND f.attacking + LEFT OUTER JOIN fleets.movements m + ON m.fleet_id = f.id + LEFT OUTER JOIN battles.battles b + ON b.location_id = p.name_id AND last_tick IS NULL + WHERE p.name_id = l_id AND m.fleet_id IS NULL and b.id IS NULL; + RETURN FOUND; +END; +$$ LANGUAGE plpgsql; + + +-- +-- Creates or returns an empire's battle record +-- +-- Parameters: +-- e_id Empire identifier +-- +-- Returns: +-- the empire battle record's identifier +-- + +CREATE OR REPLACE FUNCTION battles.goc_empire( e_id INT ) + RETURNS BIGINT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + r_id BIGINT; +BEGIN + LOOP + SELECT INTO r_id id FROM battles.empires + WHERE empire_id = e_id; + EXIT WHEN FOUND; + + INSERT INTO battles.empires ( name , empire_id ) + SELECT name , id FROM naming.empire_names + WHERE id = e_id + RETURNING id INTO r_id; + + PERFORM * FROM battles.empires + WHERE empire_id = e_id AND id <> r_id; + EXIT WHEN NOT FOUND; + + DELETE FROM battles.empires WHERE id = r_id; + END LOOP; + RETURN r_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates or returns a protagonist's record +-- +-- Parameters: +-- b_id Battle identifier +-- e_id Empire identifier +-- mode Protagonist mode +-- tick Current tick +-- + +CREATE OR REPLACE FUNCTION battles.goc_protagonist( b_id BIGINT , e_id INT , mode BOOLEAN , tick BIGINT ) + RETURNS BIGINT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + be_id BIGINT; + p_id BIGINT; + lmode BOOLEAN; +BEGIN + be_id := battles.goc_empire( e_id ); + + LOOP + SELECT INTO p_id id FROM battles.protagonists + WHERE battle_id = b_id AND empire_id = be_id; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO battles.protagonists ( battle_id , empire_id ) + VALUES ( b_id , be_id ) + RETURNING id INTO p_id; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + + SELECT INTO lmode attacking + FROM battles.status_changes WHERE protagonist_id = p_id + ORDER BY tick_identifier DESC LIMIT 1; + IF NOT FOUND OR lmode <> mode + THEN + INSERT INTO battles.status_changes ( protagonist_id , tick_identifier , attacking ) + VALUES ( p_id , tick , mode ); + END IF; + + RETURN p_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Initialises a battle record +-- +-- Parameters: +-- l_id Location +-- tick The current tick's identifier +-- +-- Returns: +-- the battle's identifier +-- + +CREATE OR REPLACE FUNCTION battles.initialise( l_id INT , tick BIGINT ) + RETURNS BIGINT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + -- Battle ID + b_id BIGINT; + -- Battle planet ID + bp_id BIGINT; + -- Record for list operations + rec RECORD; + -- Protagonist ID + prot_id BIGINT; + -- Fleet status record ID + bf_id BIGINT; + -- Planet owner + po_id INT; +BEGIN + -- Create main battle record + INSERT INTO battles.battles ( location_id , first_tick ) + VALUES ( l_id , tick ) + RETURNING id INTO b_id; + + -- Create planet record + INSERT INTO battles.planets( battle_id , tick_identifier , change_type , name ) + SELECT b_id , tick , 'INIT'::battle_planet_change , n.name + FROM naming.map_names n WHERE n.id = l_id + RETURNING id INTO bp_id; + + -- Insert list of initial buildings + INSERT INTO battles.buildings ( planet_id , building_id , change ) + SELECT bp_id , b.building_id , b.amount + FROM verse.planet_buildings b + INNER JOIN tech.buildings bd ON bd.buildable_id = b.building_id + WHERE b.planet_id = l_id AND bd.output_type = 'DEF' AND b.amount > 0; + + -- Insert defensive power + INSERT INTO battles.defences ( battle_id , tick_identifier , power ) + SELECT b_id , tick , floor( verse.adjust_production( + verse.get_raw_production( p.name_id , 'DEF' ) , ph.current / p.population ) ) + FROM verse.planets p + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + WHERE p.name_id = l_id; + + -- Add protagonists and initial status + SELECT INTO po_id empire_id FROM emp.planets ep WHERE ep.planet_id = l_id; + FOR rec IN SELECT f.owner_id AS id , f.attacking AS mode + FROM fleets.fleets f + INNER JOIN naming.empire_names n ON n.id = f.owner_id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE f.location_id = l_id AND m.fleet_id IS NULL + UNION SELECT ep.empire_id AS id , FALSE AS mode + FROM emp.planets ep + WHERE ep.planet_id = l_id + LOOP + prot_id := battles.goc_protagonist( b_id , rec.id , rec.mode , tick ); + IF po_id = rec.id THEN + INSERT INTO battles.planet_ownership ( protagonist_id ) + VALUES ( prot_id ); + END IF; + + -- Insert fleets + INSERT INTO battles.fleets ( protagonist_id , tick_identifier , change_type ) + VALUES ( prot_id , tick , 'INIT'::battle_fleet_change ) + RETURNING id INTO bf_id; + INSERT INTO battles.ships ( fleet_id , ship_id , change ) + SELECT bf_id , s.ship_id , sum( s.amount ) + FROM fleets.fleets f + INNER JOIN fleets.ships s ON s.fleet_id = f.id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE f.owner_id = rec.id AND f.location_id = l_id + AND m.fleet_id IS NULL AND f.status <> 'DEPLOYING' + GROUP BY s.ship_id; + END LOOP; + + RETURN b_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Adds fleet ship changes +-- + +CREATE OR REPLACE FUNCTION battles.add_fleet_change( f_id BIGINT , s_id INT , l_change INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + LOOP + UPDATE battles.ships SET change = change + l_change + WHERE fleet_id = f_id AND ship_id = s_id; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO battles.ships ( fleet_id , ship_id , change ) + VALUES ( f_id , s_id , l_change ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Gets or create a planet's change record +-- +-- Parameters: +-- b_id Battle identifier +-- ctype Change type +-- tick Tick identifier +-- +-- Returns: +-- the planet's change record +-- + +CREATE OR REPLACE FUNCTION battles.goc_planet( b_id BIGINT , ctype battle_planet_change , tick BIGINT ) + RETURNS BIGINT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + pr_id BIGINT; +BEGIN + LOOP + SELECT INTO pr_id id FROM battles.planets + WHERE battle_id = b_id AND change_type = ctype + AND tick_identifier = tick; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO battles.planets( battle_id , tick_identifier , change_type ) + VALUES ( b_id , tick , ctype ) + RETURNING id INTO pr_id; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + + RETURN pr_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Records building changes +-- +-- Parameters: +-- pcr_id Planet change record +-- bt_id Building type +-- amount Amount +-- + +CREATE OR REPLACE FUNCTION battles.record_building_change( pcr_id BIGINT , bt_id INT , amount INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + LOOP + UPDATE battles.buildings + SET change = change + amount + WHERE planet_id = pcr_id AND building_id = bt_id; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO battles.buildings ( planet_id , building_id , change ) + VALUES ( pcr_id , bt_id , amount ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Adds buildings to a planet's buildings list +-- +-- Parameters: +-- p_id Planet identifier +-- bt_id Building type +-- amount Amount of buildings to add +-- tick Current tick identifier +-- + +CREATE OR REPLACE FUNCTION battles.add_buildings( p_id INT , bt_id INT , amount INT , tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + b_id BIGINT; + pcr_id BIGINT; +BEGIN + -- Check building type + PERFORM buildable_id FROM tech.buildings WHERE buildable_id = bt_id AND output_type = 'DEF'; + IF NOT FOUND THEN + RETURN; + END IF; + + -- Get battle identifier + SELECT INTO b_id id FROM battles.battles + WHERE location_id = p_id AND last_tick IS NULL; + IF NOT FOUND THEN + RETURN; + END IF; + + -- Record changes + pcr_id := battles.goc_planet( b_id , 'BUILD' , tick ); + PERFORM battles.record_building_change( pcr_id , bt_id , amount ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Removes buildings to a planet's buildings list +-- +-- Parameters: +-- p_id Planet identifier +-- bt_id Building type +-- amount Amount of buildings to remove +-- bdmg Whether the losses have been caused by battle damage +-- tick Current tick identifier +-- + +CREATE OR REPLACE FUNCTION battles.remove_buildings( p_id INT , bt_id INT , amount INT , bdmg BOOLEAN , tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + b_id BIGINT; + pcr_id BIGINT; +BEGIN + -- Check building type + PERFORM buildable_id FROM tech.buildings WHERE buildable_id = bt_id AND output_type = 'DEF'; + IF NOT FOUND THEN + RETURN; + END IF; + + -- Get battle identifier + SELECT INTO b_id id FROM battles.battles + WHERE location_id = p_id AND last_tick IS NULL; + IF NOT FOUND THEN + RETURN; + END IF; + + -- Record changes + pcr_id := battles.goc_planet( b_id , ( CASE WHEN bdmg THEN 'BATTLE' ELSE 'DESTROY' END )::battle_planet_change , tick ); + PERFORM battles.record_building_change( pcr_id , bt_id , -amount ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Adds a record when the planet is renamed +-- +-- Parameters: +-- p_id Planet identifier +-- nnm New name +-- + +CREATE OR REPLACE FUNCTION battles.rename_planet( p_id INT , nnm TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + b_id BIGINT; + pcr_id BIGINT; +BEGIN + -- Get battle identifier + SELECT INTO b_id id FROM battles.battles + WHERE location_id = p_id AND last_tick IS NULL; + IF NOT FOUND THEN + RETURN; + END IF; + + -- Record change + pcr_id := battles.goc_planet( b_id , 'RENAME' , sys.get_tick() ); + UPDATE battles.planets + SET name = nnm + WHERE id = pcr_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Gets or creates a fleet change record +-- +-- Parameters: +-- bp_id Protagonist identifier +-- tick Tick identifier +-- ctype Change type +-- + +CREATE OR REPLACE FUNCTION battles.goc_fleet_change( bp_id BIGINT , tick BIGINT , ctype battle_fleet_change ) + RETURNS BIGINT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + bf_id BIGINT; +BEGIN + LOOP + SELECT INTO bf_id id FROM battles.fleets + WHERE protagonist_id = bp_id AND tick_identifier = tick AND change_type = ctype; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO battles.fleets ( protagonist_id , tick_identifier , change_type ) + VALUES ( bp_id , tick , ctype ) + RETURNING id INTO bf_id; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + RETURN bf_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Adds a fleet to the battle +-- +-- Parameters: +-- b_id Battle identifier +-- f_id Fleet identifier +-- dep Whether the fleet was added at the end of its deployment phase +-- tick Current tick +-- + +CREATE OR REPLACE FUNCTION battles.add_fleet( b_id BIGINT , f_id BIGINT , dep BOOLEAN , tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + e_id INT; + f_att BOOLEAN; + bp_id BIGINT; + bf_id BIGINT; + ctype battle_fleet_change; + rec RECORD; +BEGIN + -- Get owner's protagonist record + SELECT INTO e_id , f_att owner_id , attacking + FROM fleets.fleets + WHERE id = f_id; + bp_id := battles.goc_protagonist( b_id , e_id , f_att , tick ); + + -- Try getting or creating the fleet's record + ctype := ( CASE WHEN dep THEN 'BUILD' ELSE 'ARRIVE' END ); + bf_id := battles.goc_fleet_change( bp_id , tick , ctype ); + + -- Insert or update fleet ships + FOR rec IN SELECT ship_id , amount FROM fleets.ships WHERE fleet_id = f_id + LOOP + PERFORM battles.add_fleet_change( bf_id , rec.ship_id , rec.amount ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Removes a fleet from the battle +-- +-- Parameters: +-- b_id Battle identifier +-- f_id Fleet identifier +-- ctype Change type +-- tick Current tick +-- + +CREATE OR REPLACE FUNCTION battles.remove_fleet( b_id BIGINT , f_id BIGINT , ctype battle_fleet_change , tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + e_id INT; + f_att BOOLEAN; + bp_id BIGINT; + bf_id BIGINT; + rec RECORD; +BEGIN + -- Get owner's protagonist record + SELECT INTO e_id , f_att owner_id , attacking + FROM fleets.fleets + WHERE id = f_id; + bp_id := battles.goc_protagonist( b_id , e_id , f_att , tick ); + + -- Try getting or creating the fleet's record + bf_id := battles.goc_fleet_change( bp_id , tick , ctype ); + + -- Insert or update fleet ships + FOR rec IN SELECT ship_id , amount FROM fleets.ships WHERE fleet_id = f_id + LOOP + PERFORM battles.add_fleet_change( bf_id , rec.ship_id , - rec.amount ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sets an empire's mode +-- +-- Parameters: +-- b_id Battle identifier +-- e_id Empire identifier +-- att Whether the empire is attacking or defending +-- + +CREATE OR REPLACE FUNCTION battles.set_mode( b_id BIGINT , e_id INT , att BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + tick BIGINT; + p_id BIGINT; +BEGIN + SELECT INTO p_id p.id + FROM battles.empires e + INNER JOIN battles.protagonists p ON p.empire_id = e.id + WHERE e.empire_id = e_id AND p.battle_id = b_id; + IF NOT FOUND THEN + RETURN; + END IF; + + tick := sys.get_tick( ); + LOOP + DELETE FROM battles.status_changes + WHERE protagonist_id = p_id AND tick_identifier = tick AND attacking = ( NOT att ); + EXIT WHEN FOUND; + + BEGIN + INSERT INTO battles.status_changes ( protagonist_id , tick_identifier , attacking ) + VALUES ( p_id , tick , att ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + + PERFORM * FROM battles.status_changes + WHERE protagonist_id = p_id AND tick_identifier = tick AND attacking = att; + EXIT WHEN FOUND; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Inflicts damage to one side of the engagement +-- +-- Parameters: +-- b_id Battle identifer +-- dmg Amount of damage to inflict +-- att Whether damage is being inflicted to attacking fleets +-- tick Current tick identifier +-- + +CREATE OR REPLACE FUNCTION battles.inflict_damage( b_id BIGINT , dmg REAL , att BOOLEAN , tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + planet INT; + tot_power BIGINT; + st_power BIGINT; + rec RECORD; +BEGIN + -- Get total power from fleets + SELECT INTO tot_power sum( fs.power ) + FROM battles.battles b + LEFT OUTER JOIN fleets.fleets f ON f.location_id = b.location_id AND f.attacking = att + LEFT OUTER JOIN fleets.stats_view fs ON fs.id = f.id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE b.id = b_id AND m.fleet_id IS NULL; + IF tot_power IS NULL THEN + tot_power := 0; + END IF; + SELECT INTO planet location_id FROM battles.battles WHERE id = b_id; + + -- If damage is being inflicted to defence forces, handle defence buildings + IF NOT att THEN + st_power := battles.get_defence_power( b_id , tick ); + tot_power := tot_power + st_power; + PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'About to inflict planet damage; total power: ' || tot_power + || '; planet power: ' || st_power || '; computed damage: ' || ( dmg * st_power / tot_power )::REAL ); + IF st_power <> 0 THEN + PERFORM verse.inflict_battle_damage( planet , st_power , ( dmg * st_power / tot_power )::REAL , b_id , tick ); + END IF; + END IF; + + -- Inflict damage to fleets + FOR rec IN SELECT f.id , fs.power + FROM battles.battles b + INNER JOIN fleets.fleets f ON f.location_id = b.location_id + INNER JOIN fleets.stats_view fs ON fs.id = f.id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE b.id = b_id AND m.fleet_id IS NULL AND f.attacking = att + LOOP + PERFORM fleets.inflict_battle_damage( rec.id , ( dmg * rec.power / tot_power )::REAL , b_id , tick ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Computes the size/power of a planet's defences at a given tick +-- + +CREATE TYPE planet_defence_size AS ( + item_id INT , + amount INT +); + +CREATE OR REPLACE FUNCTION battles.get_defence_size( b_id BIGINT , tick BIGINT ) + RETURNS SETOF planet_defence_size + STRICT STABLE + SECURITY INVOKER +AS $$ + SELECT bb.building_id AS item_id , sum( bb.change )::INT AS amount + FROM battles.planets bp + INNER JOIN battles.buildings bb ON bb.planet_id = bp.id + WHERE bp.battle_id = $1 AND bp.tick_identifier <= $2 + GROUP BY bb.building_id; +$$ LANGUAGE SQL; + + +CREATE OR REPLACE FUNCTION battles.set_defence_power( b_id BIGINT , tick BIGINT , pw BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + IF battles.get_defence_power( b_id , tick ) <> pw + THEN + LOOP + UPDATE battles.defences SET power = pw + WHERE battle_id = b_id AND tick_identifier = tick; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO battles.defences ( battle_id , tick_identifier , power ) + VALUES ( b_id , tick , pw ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- EMPTY + END; + END LOOP; + END IF; +END; +$$ LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION battles.get_defence_power( b_id BIGINT , tick BIGINT ) + RETURNS BIGINT + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT power FROM battles.defences + WHERE battle_id = $1 AND tick_identifier = ( + SELECT max( tick_identifier ) FROM battles.defences + WHERE battle_id = $1 AND tick_identifier <= $2 + ); +$$ LANGUAGE SQL; + + + +-- +-- Lists battle protagonists in a specific mode at a given tick +-- + +CREATE OR REPLACE FUNCTION battles.get_protagonists_with_mode( b_id BIGINT , tick BIGINT , mode BOOLEAN ) + RETURNS SETOF BIGINT + STRICT STABLE + SECURITY INVOKER +AS $$ + SELECT protagonist_id + FROM battles.status_changes c + INNER JOIN ( + SELECT sc.protagonist_id , max( sc.tick_identifier ) AS tick_identifier + FROM battles.status_changes sc + INNER JOIN battles.protagonists p ON p.id = sc.protagonist_id + WHERE sc.tick_identifier <= $2 AND p.battle_id = $1 + GROUP BY protagonist_id + ) x USING ( protagonist_id , tick_identifier ) + WHERE c.attacking = $3; +$$ LANGUAGE SQL; + + + +-- +-- Computes the size/power of fleets in a specific mode at a given tick +-- + +CREATE TYPE battle_fleet_size AS ( + protagonist_id BIGINT , + ship_id INT , + amount INT +); + +CREATE OR REPLACE FUNCTION battles.get_fleets_composition( b_id BIGINT , tick BIGINT ) + RETURNS SETOF battle_fleet_size + STRICT STABLE + SECURITY INVOKER +AS $$ + SELECT bp.id AS protagonist_id , bs.ship_id AS item_id , sum( bs.change )::INT AS amount + FROM battles.fleets bf + INNER JOIN battles.protagonists bp ON bp.id = bf.protagonist_id + INNER JOIN battles.ships bs ON bs.fleet_id = bf.id + WHERE bp.battle_id = $1 AND bf.tick_identifier <= $2 + GROUP BY bp.id , bs.ship_id; +$$ LANGUAGE SQL; + + +CREATE TYPE battle_fleet_power AS ( + protagonist_id BIGINT , + power BIGINT +); + + +CREATE OR REPLACE FUNCTION battles.get_fleets_power( b_id BIGINT , tick BIGINT ) + RETURNS SETOF battle_fleet_power + STRICT STABLE + SECURITY INVOKER +AS $$ + SELECT ds.protagonist_id , ( CASE + WHEN sum( ds.amount * s.power ) IS NULL THEN + 0 + ELSE + sum( ds.amount * s.power ) + END ) AS power + FROM battles.get_fleets_composition( $1 , $2 ) ds + INNER JOIN tech.ships s ON s.buildable_id = ds.ship_id + GROUP BY ds.protagonist_id; +$$ LANGUAGE SQL; + + +CREATE OR REPLACE FUNCTION battles.get_biggest_fleet_owner( b_id BIGINT , tick BIGINT ) + RETURNS INT + STRICT STABLE + SECURITY INVOKER +AS $$ + SELECT e.empire_id + FROM battles.get_fleets_power( $1 , $2 ) fp + INNER JOIN battles.protagonists bp ON bp.id = fp.protagonist_id + INNER JOIN battles.empires e ON e.id = bp.empire_id + ORDER BY fp.power DESC + LIMIT 1; +$$ LANGUAGE SQL; + + +CREATE OR REPLACE FUNCTION battles.get_fleets_power( b_id BIGINT , tick BIGINT , mode BOOLEAN ) + RETURNS BIGINT + STRICT STABLE + SECURITY DEFINER +AS $$ + SELECT ( CASE + WHEN sum( fp.power ) IS NULL THEN + 0 + ELSE + sum( fp.power ) + END )::BIGINT + FROM battles.get_fleets_power( $1 , $2 ) fp + INNER JOIN battles.get_protagonists_with_mode( $1 , $2 , $3 ) pm + ON fp.protagonist_id = pm; +$$ LANGUAGE SQL; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/160-battle-views.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/160-battle-views.sql new file mode 100644 index 0000000..c649e10 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/160-battle-views.sql @@ -0,0 +1,483 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Views that are used to display battles +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Battle status view +-- + +CREATE VIEW battles.current_status + AS SELECT location_id AS location , id , ( battles.get_defence_power( id , sys.get_tick() ) + battles.get_fleets_power( id , sys.get_tick() , FALSE ) ) AS defence , + battles.get_fleets_power( id , sys.get_tick() , TRUE ) AS attack + FROM battles.battles WHERE last_tick IS NULL; + +GRANT SELECT ON battles.current_status TO :dbuser; + + + +-- +-- Viewable battles, by empire +-- + +CREATE VIEW battles.empire_list_view + AS SELECT be.empire_id AS empire , b.id AS battle , + bpt.id AS protagonist , + b.first_tick , b.last_tick , + p.name_id AS planet , + s.x , s.y , p.orbit , + bpl.name + FROM battles.empires be + INNER JOIN battles.protagonists bpt ON bpt.empire_id = be.id + INNER JOIN battles.battles b ON b.id = bpt.battle_id + INNER JOIN verse.planets p ON p.name_id = b.location_id + INNER JOIN verse.systems s ON s.id = p.system_id + INNER JOIN battles.planets bpl ON bpl.battle_id = b.id AND bpl.change_type = 'INIT' + WHERE be.empire_id IS NOT NULL; + +GRANT SELECT ON battles.empire_list_view TO :dbuser; + + +-- +-- Ticks to include in a battle display +-- + +CREATE VIEW battles.battle_ticks_view + AS SELECT x.battle , x.tick FROM ( + SELECT battle_id AS battle , tick_identifier AS tick + FROM battles.planets + UNION SELECT battle_id AS battle , tick_identifier AS tick + FROM battles.defences + UNION SELECT bp.battle_id AS battle , bsc.tick_identifier AS tick + FROM battles.status_changes bsc + INNER JOIN battles.protagonists bp ON bp.id = bsc.protagonist_id + UNION SELECT bp.battle_id AS battle , bf.tick_identifier AS tick + FROM battles.fleets bf + INNER JOIN battles.protagonists bp ON bp.id = bf.protagonist_id + UNION SELECT id AS battle , last_tick AS tick + FROM battles.battles + WHERE last_tick IS NOT NULL + ) x + ORDER BY x.tick; + +GRANT SELECT ON battles.battle_ticks_view TO :dbuser; + + + +-- +-- Mode history view +-- + +CREATE OR REPLACE FUNCTION battles.get_protagonist_status_at( bp_id BIGINT , tick_id BIGINT ) + RETURNS BOOLEAN + STRICT IMMUTABLE + SECURITY DEFINER +AS $$ + SELECT attacking FROM battles.status_changes + WHERE protagonist_id = $1 AND tick_identifier <= $2 + ORDER BY tick_identifier DESC LIMIT 1; +$$ LANGUAGE SQL; + +CREATE VIEW battles.mode_history_view + AS SELECT btv.battle , btv.tick , bp.id AS protagonist , + be.id AS empire_id , be.name AS empire_name , + battles.get_protagonist_status_at( bp.id , btv.tick ) AS attacking + FROM battles.battle_ticks_view btv + INNER JOIN battles.protagonists bp ON bp.battle_id = btv.battle + INNER JOIN battles.empires be ON be.id = bp.empire_id + ORDER BY btv.tick , be.name; + +GRANT SELECT ON battles.mode_history_view TO :dbuser; + + + +-- +-- Ships history +-- + +CREATE VIEW battles.protagonist_ships + AS SELECT DISTINCT bf.protagonist_id , bs.ship_id + FROM battles.fleets bf + INNER JOIN battles.ships bs ON bs.fleet_id = bf.id; + +CREATE OR REPLACE FUNCTION battles.get_lost_ships( bp_id BIGINT , tick_id BIGINT, ship_id INT ) + RETURNS BIGINT + STRICT IMMUTABLE + SECURITY DEFINER +AS $$ + SELECT -sum( fs.change ) + FROM battles.ships fs + INNER JOIN battles.fleets bf ON fs.fleet_id = bf.id + WHERE bf.protagonist_id = $1 AND bf.tick_identifier <= $2 + AND bf.change_type = 'BATTLE' AND fs.ship_id = $3 +$$ LANGUAGE SQL; + + +CREATE OR REPLACE FUNCTION battles.get_current_ships( bp_id BIGINT , tick_id BIGINT, ship_id INT ) + RETURNS BIGINT + STRICT IMMUTABLE + SECURITY DEFINER +AS $$ + SELECT sum( fs.change ) + FROM battles.ships fs + INNER JOIN battles.fleets bf ON fs.fleet_id = bf.id + WHERE bf.protagonist_id = $1 AND bf.tick_identifier <= $2 + AND fs.ship_id = $3 +$$ LANGUAGE SQL; + + +CREATE VIEW battles.fleets_history + AS SELECT elv.empire , elv.battle , btv.tick , + bpt.id AS protagonist , t.translated_string AS ship_type , + battles.get_current_ships( bpt.id , btv.tick , bps.ship_id ) AS current , + battles.get_lost_ships( bpt.id , btv.tick , bps.ship_id ) AS lost , + s.power AS ship_power + FROM battles.empire_list_view elv + INNER JOIN battles.battle_ticks_view btv USING (battle) + INNER JOIN battles.protagonists bpt ON bpt.battle_id = elv.battle + INNER JOIN battles.protagonist_ships bps ON bps.protagonist_id = bpt.id + INNER JOIN tech.ships s ON s.buildable_id = bps.ship_id + INNER JOIN naming.empire_names en ON en.id = elv.empire + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t + ON t.lang_id = c.language_id AND t.string_id = bps.ship_id + ORDER BY s.power; + +GRANT SELECT ON battles.fleets_history TO :dbuser; + + + +-- +-- Protagonist presence in a battle at any given tick +-- + +CREATE VIEW battles.protagonist_ship_types + AS SELECT DISTINCT bp.id AS protagonist , bs.ship_id AS ship_type + FROM battles.protagonists bp + INNER JOIN battles.fleets bf ON bf.protagonist_id = bp.id + INNER JOIN battles.ships bs ON bs.fleet_id = bf.id; + +CREATE VIEW battles.ships_at_tick + AS SELECT btv.battle , btv.tick , bp.id AS protagonist , + sum( battles.get_current_ships( bp.id , btv.tick, bs.ship_type ) ) AS ships + FROM battles.battle_ticks_view btv + INNER JOIN battles.protagonists bp ON bp.battle_id = btv.battle + INNER JOIN battles.protagonist_ship_types bs ON bs.protagonist = bp.id + GROUP BY btv.battle , btv.tick , bp.id; + +CREATE OR REPLACE FUNCTION battles.get_current_ships( bp_id BIGINT , tick_id BIGINT ) + RETURNS BIGINT + STRICT IMMUTABLE + SECURITY DEFINER +AS $$ + SELECT ( CASE WHEN sum( fs.change ) IS NULL THEN 0 ELSE sum( fs.change ) END ) + FROM battles.ships fs + INNER JOIN battles.fleets bf ON fs.fleet_id = bf.id + WHERE bf.protagonist_id = $1 AND bf.tick_identifier <= $2 +$$ LANGUAGE SQL; + + +CREATE VIEW battles.protagonist_presence + AS SELECT btv.battle , btv.tick , bp.id AS protagonist , + ( bpo.protagonist_id IS NOT NULL + OR battles.get_current_ships( bp.id , btv.tick ) > 0 ) AS present , + ( bpo.protagonist_id IS NOT NULL ) AS planet_owner + FROM battles.battle_ticks_view btv + INNER JOIN battles.protagonists bp ON bp.battle_id = btv.battle + LEFT OUTER JOIN battles.planet_ownership bpo + ON bpo.protagonist_id = bp.id AND ( bpo.abandoned_at IS NULL OR bpo.abandoned_at > btv.tick ); + +GRANT SELECT ON battles.protagonist_presence TO :dbuser; + + +-- +-- Buildings history +-- + + +CREATE VIEW battles.buildings_list + AS SELECT DISTINCT bp.battle_id AS battle , bb.building_id + FROM battles.planets bp + INNER JOIN battles.buildings bb ON bb.planet_id = bp.id; + + +CREATE OR REPLACE FUNCTION battles.get_current_buildings( b_id BIGINT , tick_id BIGINT , building_id INT ) + RETURNS BIGINT + STRICT IMMUTABLE + SECURITY DEFINER +AS $$ + SELECT sum( change ) + FROM battles.buildings b + INNER JOIN battles.planets bp ON bp.id = b.planet_id + WHERE bp.battle_id = $1 AND bp.tick_identifier <= $2 AND b.building_id = $3; +$$ LANGUAGE SQL; + + +CREATE OR REPLACE FUNCTION battles.get_lost_buildings( b_id BIGINT , tick_id BIGINT , building_id INT ) + RETURNS BIGINT + STRICT IMMUTABLE + SECURITY DEFINER +AS $$ + SELECT -sum( change ) + FROM battles.buildings b + INNER JOIN battles.planets bp ON bp.id = b.planet_id + WHERE bp.battle_id = $1 AND bp.tick_identifier <= $2 + AND b.building_id = $3 AND bp.change_type = 'BATTLE'; +$$ LANGUAGE SQL; + + +CREATE VIEW battles.raw_buildings_history + AS SELECT btv.battle , btv.tick , bbl.building_id , + battles.get_current_buildings( btv.battle , btv.tick , bbl.building_id ) AS current , + battles.get_lost_buildings( btv.battle , btv.tick , bbl.building_id ) AS lost , + b.output AS raw_power + FROM battles.battle_ticks_view btv + INNER JOIN battles.buildings_list bbl USING (battle) + INNER JOIN tech.buildings b ON b.buildable_id = bbl.building_id; + +CREATE VIEW battles.raw_buildings_power + AS SELECT rbh.battle , rbh.tick , + sum( rbh.current * rbh.raw_power ) AS raw_power , + battles.get_defence_power( rbh.battle , rbh.tick ) AS actual_power + FROM battles.raw_buildings_history rbh + GROUP BY rbh.battle , rbh.tick; + + +CREATE VIEW battles.buildings_history + AS SELECT elv.empire , rbh.battle , rbh.tick , + t.translated_string AS building , + ( CASE WHEN rbh.current IS NULL THEN 0 ELSE rbh.current END ) AS current , + ( CASE WHEN rbh.lost IS NULL THEN 0 ELSE rbh.lost END ) AS lost , + ( CASE + WHEN rbp.raw_power = 0 THEN + rbh.raw_power + ELSE + rbh.raw_power::REAL * rbp.actual_power::REAL / rbp.raw_power::REAL + END )::REAL AS power + FROM battles.empire_list_view elv + INNER JOIN battles.raw_buildings_history rbh USING (battle) + INNER JOIN battles.raw_buildings_power rbp USING (battle,tick) + INNER JOIN naming.empire_names en ON en.id = elv.empire + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t + ON t.string_id = rbh.building_id AND t.lang_id = c.language_id + ORDER BY rbp.raw_power; + +GRANT SELECT ON battles.buildings_history TO :dbuser; + + + +-- +-- Events +-- + +CREATE VIEW battles.rename_events + AS SELECT bp.battle_id AS battle , bp.tick_identifier AS tick , + 'RENAME'::TEXT AS event_type , TRUE AS is_planet , + NULL::BIGINT AS event_id , bp.name AS name , NULL::BOOLEAN AS attack + FROM battles.planets bp + WHERE bp.change_type = 'RENAME'; + +CREATE VIEW battles.switch_events + AS SELECT bp.battle_id AS battle , bsc.tick_identifier AS tick , + 'SWITCH'::TEXT AS event_type , FALSE AS is_planet , + NULL::BIGINT AS event_id , be.name AS name , bsc.attacking AS attack + FROM battles.status_changes bsc + INNER JOIN battles.protagonists bp ON bp.id = bsc.protagonist_id + INNER JOIN battles.empires be ON be.id = bp.empire_id + INNER JOIN battles.battles b + ON b.id = bp.battle_id AND bsc.tick_identifier > b.first_tick; + +CREATE VIEW battles.arrive_events + AS SELECT bp.battle_id AS battle , bf.tick_identifier AS tick , + 'ARRIVE'::TEXT AS event_type , FALSE AS is_planet , + bf.id AS event_id , be.name AS name , + battles.get_protagonist_status_at( bp.id , bf.tick_identifier ) AS attack + FROM battles.fleets bf + INNER JOIN battles.protagonists bp ON bp.id = bf.protagonist_id + INNER JOIN battles.empires be ON be.id = bp.empire_id + WHERE bf.change_type = 'ARRIVE'; + +CREATE VIEW battles.depart_events + AS SELECT bp.battle_id AS battle , bf.tick_identifier AS tick , + 'DEPART'::TEXT AS event_type , FALSE AS is_planet , + bf.id AS event_id , be.name AS name , + battles.get_protagonist_status_at( bp.id , bf.tick_identifier ) AS attack + FROM battles.fleets bf + INNER JOIN battles.protagonists bp ON bp.id = bf.protagonist_id + INNER JOIN battles.empires be ON be.id = bp.empire_id + WHERE bf.change_type = 'DEPART'; + +CREATE VIEW battles.fleet_destroy_events + AS SELECT bp.battle_id AS battle , bf.tick_identifier AS tick , + 'DESTROY'::TEXT AS event_type , FALSE AS is_planet , + bf.id AS event_id , be.name AS name , + battles.get_protagonist_status_at( bp.id , bf.tick_identifier ) AS attack + FROM battles.fleets bf + INNER JOIN battles.protagonists bp ON bp.id = bf.protagonist_id + INNER JOIN battles.empires be ON be.id = bp.empire_id + WHERE bf.change_type = 'DISBAND'; + +CREATE VIEW battles.fleet_build_events + AS SELECT bp.battle_id AS battle , bf.tick_identifier AS tick , + 'BUILD'::TEXT AS event_type , FALSE AS is_planet , + bf.id AS event_id , be.name AS name , + battles.get_protagonist_status_at( bp.id , bf.tick_identifier ) AS attack + FROM battles.fleets bf + INNER JOIN battles.protagonists bp ON bp.id = bf.protagonist_id + INNER JOIN battles.empires be ON be.id = bp.empire_id + WHERE bf.change_type = 'BUILD'; + +CREATE VIEW battles.bld_destroy_events + AS SELECT bp.battle_id AS battle , bp.tick_identifier AS tick , + 'DESTROY'::TEXT AS event_type , TRUE AS is_planet , + bp.id AS event_id , NULL::TEXT AS name , FALSE AS attack + FROM battles.planets bp + WHERE bp.change_type = 'DESTROY'; + +CREATE VIEW battles.bld_build_events + AS SELECT bp.battle_id AS battle , bp.tick_identifier AS tick , + 'BUILD'::TEXT AS event_type , TRUE AS is_planet , + bp.id AS event_id , NULL::TEXT AS name , FALSE AS attack + FROM battles.planets bp + WHERE bp.change_type = 'BUILD'; + + +CREATE VIEW battles.events_history + AS SELECT x.* FROM ( + SELECT * FROM battles.rename_events + UNION ALL SELECT * FROM battles.switch_events + UNION ALL SELECT * FROM battles.arrive_events + UNION ALL SELECT * FROM battles.depart_events + UNION ALL SELECT * FROM battles.fleet_destroy_events + UNION ALL SELECT * FROM battles.fleet_build_events + UNION ALL SELECT * FROM battles.bld_destroy_events + UNION ALL SELECT * FROM battles.bld_build_events + ) x + ORDER BY x.tick DESC , x.is_planet DESC , x.event_type , x.attack , x.name; + +GRANT SELECT ON battles.events_history TO :dbuser; + + +-- +-- Ships/buildings for events +-- + +CREATE VIEW battles.planet_event_items + AS SELECT elv.empire AS empire , TRUE AS is_planet , bp.id AS event_id , + bp.battle_id AS battle , bp.tick_identifier AS tick , + t.translated_string AS nature , abs( bb.change ) AS amount , + b.output AS power + FROM battles.empire_list_view elv + INNER JOIN battles.planets bp ON bp.battle_id = elv.battle + INNER JOIN battles.buildings bb ON bb.planet_id = bp.id + INNER JOIN naming.empire_names en ON en.id = elv.empire + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t + ON t.lang_id = c.language_id AND t.string_id = bb.building_id + INNER JOIN tech.buildings b ON b.buildable_id = bb.building_id + WHERE bp.change_type NOT IN ( 'INIT', 'BATTLE' ); + +CREATE VIEW battles.fleet_event_items + AS SELECT elv.empire AS empire , FALSE AS is_planet , bf.id AS event_id , + bp.battle_id AS battle , bf.tick_identifier AS tick , + t.translated_string AS nature , abs( bs.change ) AS amount , + s.power AS power + FROM battles.empire_list_view elv + INNER JOIN battles.protagonists bp ON bp.battle_id = elv.battle + INNER JOIN battles.fleets bf ON bf.protagonist_id = bp.id + INNER JOIN battles.ships bs ON bs.fleet_id = bf.id + INNER JOIN naming.empire_names en ON en.id = elv.empire + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN defs.translations t + ON t.lang_id = c.language_id AND t.string_id = bs.ship_id + INNER JOIN tech.ships s ON s.buildable_id = bs.ship_id + WHERE bf.change_type NOT IN ( 'INIT', 'BATTLE' ); + +CREATE VIEW battles.event_items + AS SELECT x.* FROM ( + SELECT * FROM battles.planet_event_items + UNION ALL SELECT * FROM battles.fleet_event_items + ) x + ORDER BY x.power; + +GRANT SELECT ON battles.event_items TO :dbuser; + + + +-- +-- Battles list +-- + +CREATE VIEW battles.last_presence + AS SELECT protagonist , max( tick ) AS last_present + FROM battles.protagonist_presence + WHERE present + GROUP BY protagonist; + +CREATE VIEW battles.first_presence + AS SELECT protagonist , min( tick ) AS first_present + FROM battles.protagonist_presence + WHERE present + GROUP BY protagonist; + +CREATE VIEW battles.last_update + AS SELECT p.id AS protagonist , max( u.tick ) AS last_update + FROM battles.protagonists p + INNER JOIN battles.battle_ticks_view u ON u.battle = p.battle_id + GROUP BY p.id; + +CREATE VIEW battles.full_battles_list + AS SELECT elv.empire , elv.battle , elv.planet , elv.x , elv.y , elv.orbit , elv.name , + fp.first_present AS first_tick , ( CASE + WHEN elv.last_tick IS NOT NULL THEN + lp.last_present + WHEN lp.last_present = lu.last_update THEN + NULL + ELSE + lp.last_present + END )::BIGINT AS last_tick , lu.last_update , + ( elv.last_tick IS NOT NULL ) AS finished + FROM battles.empire_list_view elv + INNER JOIN battles.first_presence fp USING (protagonist) + INNER JOIN battles.last_presence lp USING (protagonist) + INNER JOIN battles.last_update lu USING (protagonist); + +CREATE TABLE battles.finished_battles_list( + empire INT NOT NULL , + battle BIGINT NOT NULL , + planet INT NOT NULL , + x INT NOT NULL , + y INT NOT NULL , + orbit INT NOT NULL , + name VARCHAR( 20 ) NOT NULL , + first_tick BIGINT , + last_tick BIGINT , + last_update BIGINT , + PRIMARY KEY( empire , battle ) +); + +CREATE VIEW battles.current_battles_list + AS SELECT elv.empire , elv.battle , elv.planet , elv.x , elv.y , elv.orbit , elv.name , + fp.first_present AS first_tick , ( CASE + WHEN lp.last_present = lu.last_update THEN + NULL + ELSE + lp.last_present + END )::BIGINT AS last_tick , lu.last_update + FROM battles.empire_list_view elv + INNER JOIN battles.first_presence fp USING (protagonist) + INNER JOIN battles.last_presence lp USING (protagonist) + INNER JOIN battles.last_update lu USING (protagonist) + WHERE elv.last_tick IS NULL; + + +CREATE VIEW battles.battles_list + AS SELECT fbl.* , TRUE AS finished FROM battles.finished_battles_list fbl + UNION ALL SELECT cbl.* , FALSE AS finished FROM battles.current_battles_list cbl; + +GRANT SELECT ON battles.battles_list TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/163-alliance-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/163-alliance-functions.sql new file mode 100644 index 0000000..dcb5245 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/163-alliance-functions.sql @@ -0,0 +1,354 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Alliance views and management functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Alliances public information +-- + +CREATE VIEW emp.alliances_public + AS SELECT a.id AS id , a.tag AS tag , a.name AS name , + a.leader_id AS leader_id , n.name AS leader_name , + count( p.* ) AS planets + FROM emp.alliances a + INNER JOIN naming.empire_names n + ON n.id = a.leader_id + LEFT OUTER JOIN emp.alliance_members am + ON am.alliance_id = a.id AND NOT am.is_pending + LEFT OUTER JOIN emp.planets p + ON p.empire_id = am.empire_id + GROUP BY a.id , a.tag , a.name , a.leader_id , n.name; + +GRANT SELECT ON emp.alliances_public TO :dbuser; + + + +-- +-- Alliance members / pending requests +-- + +CREATE VIEW emp.alliance_membership + AS SELECT a.alliance_id AS alliance , a.empire_id AS id , + n.name AS name , a.is_pending AS pending + FROM emp.alliance_members a + INNER JOIN naming.empire_names n + ON n.id = a.empire_id + ORDER BY n.name; + +GRANT SELECT ON emp.alliance_membership TO :dbuser; + + + +-- +-- Alliance planets +-- + +CREATE VIEW emp.alliance_planets + AS SELECT a.alliance_id AS alliance , + a.empire_id AS owner_id , en.name AS owner_name , + s.x AS x , s.y AS y , p.orbit AS orbit , + ep.planet_id AS planet_id , pn.name AS planet_name , + ( bcs IS NOT NULL ) AS battle , bcs.defence , bcs.attack + FROM emp.alliance_members a + INNER JOIN naming.empire_names en ON en.id = a.empire_id + INNER JOIN emp.planets ep ON ep.empire_id = a.empire_id + INNER JOIN verse.planets p ON p.name_id = ep.planet_id + INNER JOIN verse.systems s ON s.id = p.system_id + INNER JOIN naming.map_names pn ON pn.id = ep.planet_id + LEFT OUTER JOIN battles.current_status bcs ON bcs.location = p.name_id + WHERE NOT a.is_pending + ORDER BY en.name , s.x , s.y , p.orbit; + +GRANT SELECT ON emp.alliance_planets TO :dbuser; + + +-- +-- Creates an alliance +-- +-- Parameters: +-- e_id Empire identifier +-- a_tag Alliance tag +-- a_name Alliance name +-- +-- Returns: +-- a_id Alliance identifier (NULL on failure) +-- + +CREATE OR REPLACE FUNCTION emp.create_alliance( e_id INT , a_tag TEXT , a_name TEXT , OUT a_id INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + BEGIN + INSERT INTO emp.alliances ( tag , name , leader_id ) + VALUES ( a_tag , a_name , e_id ) + RETURNING id INTO a_id; + EXCEPTION + WHEN unique_violation THEN + a_id := NULL; + RETURN; + END; + + BEGIN + INSERT INTO emp.alliance_members ( alliance_id , empire_id , is_pending ) + VALUES ( a_id , e_id , FALSE ); + EXCEPTION + WHEN unique_violation THEN + DELETE FROM emp.alliances WHERE id = a_id; + a_id := NULL; + RETURN; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.create_alliance( INT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Requests to join an alliance +-- +-- Parameters: +-- e_id Empire identifier +-- a_id Alliance identifier +-- +-- Returns: +-- success Whether the operation was successful or not +-- + +CREATE OR REPLACE FUNCTION emp.join_alliance( e_id INT , a_id INT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + INSERT INTO emp.alliance_members( empire_id , alliance_id ) + VALUES ( e_id , a_id ); + DELETE FROM emp.enemy_alliances + WHERE empire_id = e_id AND alliance_id = a_id; + PERFORM events.alliance_request_event( a_id , e_id ); + PERFORM msgs.deliver_internal( ); + success := TRUE; +EXCEPTION + WHEN unique_violation THEN + success := FALSE; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.join_alliance( INT , INT ) TO :dbuser; + + + +-- +-- Removes an empire's pending alliance membership +-- +-- Parameters: +-- e_id Empire identifier +-- + +CREATE OR REPLACE FUNCTION emp.cancel_join( e_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + DELETE FROM emp.alliance_members WHERE empire_id = $1 AND is_pending; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION emp.cancel_join( INT ) TO :dbuser; + + + +-- +-- Leave an alliance +-- +-- Parameters: +-- e_id Empire identifier +-- + +CREATE OR REPLACE FUNCTION emp.leave_alliance( e_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + l_id INT; + a_id INT; +BEGIN + SELECT INTO a_id , l_id a.id , a.leader_id + FROM emp.alliance_members m + INNER JOIN emp.alliances a ON a.id = m.alliance_id + WHERE m.empire_id = e_id AND NOT m.is_pending + FOR UPDATE; + + IF FOUND THEN + IF l_id = e_id THEN + PERFORM events.alliance_disband_event( a_id ); + DELETE FROM emp.alliances WHERE id = a_id; + ELSE + DELETE FROM emp.alliance_members WHERE empire_id = e_id; + PERFORM events.alliance_quit_event( a_id , e_id ); + END IF; + PERFORM msgs.deliver_internal( ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.leave_alliance( INT ) TO :dbuser; + + + +-- +-- Transfer alliance leadership +-- +-- Parameters: +-- e_id Empire identifier of an alliance's leader +-- to_id Empire identifier of the alliance member who is being made the new leader +-- + +CREATE OR REPLACE FUNCTION emp.transfer_leadership( e_id INT , to_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + a_id INT; +BEGIN + SELECT INTO a_id a.id + FROM emp.alliance_members m + INNER JOIN emp.alliances a ON a.id = m.alliance_id AND a.leader_id = e_id + WHERE m.empire_id = to_id AND NOT m.is_pending + FOR UPDATE; + + IF FOUND THEN + UPDATE emp.alliances SET leader_id = to_id WHERE id = a_id; + PERFORM events.alliance_lchange_event( a_id , e_id ); + PERFORM msgs.deliver_internal( ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.transfer_leadership( INT , INT ) TO :dbuser; + + + +-- +-- Accept new members into an alliance +-- +-- Parameters: +-- e_id Empire identifier +-- r_ids Requests to accept +-- + +CREATE OR REPLACE FUNCTION emp.accept_members( e_id INT , r_ids INT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + a_id INT; + re_id INT; +BEGIN + SELECT INTO a_id id FROM emp.alliances WHERE leader_id = e_id FOR UPDATE; + IF NOT FOUND THEN + RETURN; + END IF; + + FOR re_id IN SELECT m.empire_id FROM emp.alliance_members m + INNER JOIN unnest( r_ids ) rid ON m.empire_id = rid + WHERE m.is_pending + LOOP + PERFORM events.alliance_response_event( a_id , re_id , TRUE ); + END LOOP; + PERFORM msgs.deliver_internal( ); + + UPDATE emp.alliance_members SET is_pending = FALSE + WHERE alliance_id = a_id AND empire_id IN ( SELECT * FROM unnest( r_ids ) ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.accept_members( INT , INT[] ) TO :dbuser; + + + +-- +-- Reject membership requests +-- +-- Parameters: +-- e_id Empire identifier +-- r_ids Requests to reject +-- + +CREATE OR REPLACE FUNCTION emp.reject_members( e_id INT , r_ids INT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + a_id INT; + re_id INT; +BEGIN + SELECT INTO a_id id FROM emp.alliances WHERE leader_id = e_id FOR UPDATE; + IF NOT FOUND THEN + RETURN; + END IF; + + FOR re_id IN SELECT m.empire_id FROM emp.alliance_members m + INNER JOIN unnest( r_ids ) rid ON m.empire_id = rid + WHERE m.is_pending + LOOP + PERFORM events.alliance_response_event( a_id , re_id , FALSE ); + END LOOP; + PERFORM msgs.deliver_internal( ); + + DELETE FROM emp.alliance_members + WHERE alliance_id = a_id AND is_pending + AND empire_id IN ( SELECT * FROM unnest( r_ids ) ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.reject_members( INT , INT[] ) TO :dbuser; + + + +-- +-- Kick members from an alliance +-- +-- Parameters: +-- e_id Empire identifier +-- kick_ids Requests to reject +-- + +CREATE OR REPLACE FUNCTION emp.kick_members( e_id INT , kick_ids INT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + a_id INT; + k_id INT; +BEGIN + SELECT INTO a_id id FROM emp.alliances WHERE leader_id = e_id FOR UPDATE; + IF NOT FOUND THEN + RETURN; + END IF; + + FOR k_id IN SELECT m.empire_id FROM emp.alliance_members m + INNER JOIN unnest( kick_ids ) rid ON m.empire_id = rid + WHERE NOT m.is_pending + LOOP + PERFORM events.alliance_kick_event( a_id , k_id ); + END LOOP; + PERFORM msgs.deliver_internal( ); + + DELETE FROM emp.alliance_members + WHERE alliance_id = a_id AND NOT is_pending + AND empire_id IN ( SELECT * FROM unnest( kick_ids ) ) + AND empire_id <> e_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION emp.kick_members( INT , INT[] ) TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/165-fleets-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/165-fleets-functions.sql new file mode 100644 index 0000000..f7d802c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/165-fleets-functions.sql @@ -0,0 +1,1497 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Fleets views and management functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Merges two fleets' ships into the first fleet +-- /!\ The second fleet is *not* deleted. /!\ +-- +-- Parameters: +-- mt_id Merge target identifier +-- ms_id Merge source identifier +-- + +CREATE OR REPLACE FUNCTION fleets.merge_ships( mt_id BIGINT , ms_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + CREATE TEMPORARY TABLE flt_merge( LIKE fleets.ships ); + + INSERT INTO flt_merge (fleet_id , ship_id , amount , damage ) + SELECT mt_id , s.ship_id , sum( s.amount ) , sum( s.damage ) + FROM fleets.ships s + WHERE s.fleet_id IN ( mt_id , ms_id ) + GROUP BY s.ship_id; + + DELETE FROM fleets.ships WHERE fleet_id = mt_id; + INSERT INTO fleets.ships SELECT * FROM flt_merge; + + DROP TABLE flt_merge; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Compute duration of in-system movement +-- +-- Source and destination "orbits" are actually real numbers, which indicate a fleet's +-- current location. Orbit 5.5 is the system's outer limit, therefore the range for +-- these numbers is [1;5.5]. +-- +-- Parameters: +-- f_time Fleet flight time +-- s_orbit Source orbit +-- d_orbit Destination orbit +-- +-- Returns: +-- the in-system movement's duration +-- + +CREATE OR REPLACE FUNCTION fleets.compute_insystem_duration( f_time INT , s_orbit REAL , d_orbit REAL ) + RETURNS INT + STRICT IMMUTABLE + SECURITY INVOKER + AS $$ +DECLARE + tm INT; +BEGIN + tm := round( abs( s_orbit - d_orbit ) * 2.0 * f_time ); + RETURN ( CASE WHEN tm = 0 THEN 1 ELSE tm END ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Compute duration of outer space movement +-- +-- Parameters: +-- f_time Fleet flight time +-- s_x Source X coordinate +-- s_y Source Y coordinate +-- d_x Destination X coordinate +-- d_y Destination Y coordinate +-- +-- Returns: +-- the outer space movement's duration +-- + +CREATE OR REPLACE FUNCTION fleets.compute_outerspace_duration( f_time INT , s_x REAL , s_y REAL , d_x REAL , d_y REAL ) + RETURNS INT + STRICT IMMUTABLE + SECURITY INVOKER + AS $$ +DECLARE + tm INT; +BEGIN + tm := round( sqrt( ( s_x - d_x ) ^ 2 + ( s_y - d_y ) ^ 2 ) * f_time * 15.0 ); + RETURN ( CASE WHEN tm = 0 THEN 1 ELSE tm END ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Compute the current orbit of a fleet flying in a system +-- +-- Parameters: +-- f_time Fleet flight time +-- rp_orbit Orbit of the reference point +-- outwards Whether the fleet is moving outwards or inwards +-- past_rp Whether the fleet has passed the reference point or not +-- ft_left Remaining flight time +-- +-- Returns; +-- The real number indicating the fleet's position +-- + +CREATE OR REPLACE FUNCTION fleets.compute_current_orbit( + f_time INT , rp_orbit INT , outwards BOOLEAN , past_rp BOOLEAN , ft_left INT ) + RETURNS REAL + STRICT IMMUTABLE + SECURITY INVOKER + AS $$ +DECLARE + dist REAL; + dir REAL; + rloc REAL; +BEGIN + dist := 1.0 - ft_left::REAL / f_time::REAL; + dir := ( CASE WHEN outwards THEN 0.5 ELSE -0.5 END ); + IF past_rp THEN + rloc := rp_orbit; + ELSEIF outwards THEN + rloc := rp_orbit - 0.5; + ELSE + rloc := rp_orbit + 0.5; + END IF; + RETURN rloc + dir * dist; +END; +$$ LANGUAGE plpgsql; + + + + +-- +-- Compute the current coordinates of a fleet flying in outer space +-- +-- Parameters: +-- f_time Fleet flight time +-- s_x Source X coordinate +-- s_y Source Y coordinate +-- d_x Destination X coordinate +-- d_y Destination Y coordinate +-- r_time Remaining flight time +-- +-- Returns: +-- c_x Current X coordinate +-- c_y Current Y coordinate +-- + +CREATE OR REPLACE FUNCTION fleets.compute_current_location( + f_time INT , s_x REAL , s_y REAL , d_x REAL , d_y REAL , r_time INT , + OUT c_x REAL , OUT c_y REAL ) + STRICT IMMUTABLE + SECURITY INVOKER + AS $$ +DECLARE + tot_time REAL; +BEGIN + tot_time := fleets.compute_outerspace_duration( f_time , s_x , s_y , d_x , d_y ); + c_x := s_x + ( d_x - s_x ) * ( 1 - r_time / tot_time ); + c_y := s_y + ( d_y - s_y ) * ( 1 - r_time / tot_time ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Compute the duration and direction for a planet-to-planet flight +-- +-- /!\ Marked as immutable, but does in fact query the DB. Planets don't move around. +-- +-- Parameters: +-- f_time Fleet flight time +-- s_id Source planet identifier +-- d_id Destination planet identifier +-- +-- Returns: +-- duration Flight duration +-- direction Whether the fleet is moving inwards (FALSE) or outwards (TRUE) +-- + +CREATE OR REPLACE FUNCTION fleets.compute_flight_init( + f_time INT , s_id INT , d_id INT , + OUT duration INT , OUT direction BOOLEAN ) + STRICT IMMUTABLE + SECURITY INVOKER + AS $$ +DECLARE + s_rec RECORD; + d_rec RECORD; +BEGIN + IF s_id = d_id THEN + RETURN; + END IF; + + -- Get source planet coordinates, orbit and system ID + SELECT INTO s_rec s.x AS x , s.y AS y , p.orbit AS orbit , s.id AS sid + FROM verse.planets p + INNER JOIN verse.systems s ON s.id = p.system_id + WHERE p.name_id = s_id; + + -- Get destination planet coordinates, orbit and system ID + SELECT INTO d_rec s.x AS x , s.y AS y , p.orbit AS orbit , s.id AS sid + FROM verse.planets p + INNER JOIN verse.systems s ON s.id = p.system_id + WHERE p.name_id = d_id; + + IF s_rec.sid = d_rec.sid THEN + -- Movement in the same system + duration := fleets.compute_insystem_duration( f_time , s_rec.orbit , d_rec.orbit ); + direction := ( d_rec.orbit > s_rec.orbit ); + ELSE + -- Movement to another system + duration := fleets.compute_insystem_duration( f_time , s_rec.orbit , 5.5 ) + + fleets.compute_insystem_duration( f_time , d_rec.orbit , 5.5 ) + + fleets.compute_outerspace_duration( f_time , s_rec.x , s_rec.y , d_rec.x , d_rec.y ); + direction := TRUE; + END IF; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Compute a flight's duration from an in-system redirection +-- +-- /!\ Marked as immutable, but does in fact query the DB. Planets don't move around. +-- +-- Parameters: +-- f_time Fleet flight time +-- s_sys Source system +-- s_orbit Source "orbit" as a real number +-- d_id Destination planet +-- +-- Returns: +-- duration Flight duration +-- direction Whether the fleet is moving inwards (FALSE) or outwards (TRUE) +-- s_duration State duration +-- ref_point Reference point +-- past_rp Whether the fleet has passed the reference point or is moving +-- towards it +-- + +CREATE OR REPLACE FUNCTION fleets.compute_insystem_redirect( + f_time INT , s_sys INT , s_orbit REAL , d_id INT , + OUT duration INT , OUT direction BOOLEAN , OUT s_duration INT , + OUT ref_point INT , OUT past_rp BOOLEAN ) + STRICT IMMUTABLE + SECURITY INVOKER + AS $$ +DECLARE + s_rec RECORD; + d_rec RECORD; + torb REAL; + rporb INT; +BEGIN + -- Get destination planet coordinates, orbit and system ID + SELECT INTO d_rec s.x AS x , s.y AS y , p.orbit AS orbit , s.id AS sid + FROM verse.planets p + INNER JOIN verse.systems s ON s.id = p.system_id + WHERE p.name_id = d_id; + + IF d_rec.sid = s_sys THEN + -- Movement in the same system + duration := fleets.compute_insystem_duration( f_time , s_orbit , d_rec.orbit ); + direction := ( d_rec.orbit > s_orbit ); + ELSE + -- Movement to another system + SELECT INTO s_rec x , y FROM verse.systems WHERE id = s_sys; + duration := fleets.compute_insystem_duration( f_time , s_orbit , 5.5 ) + + fleets.compute_insystem_duration( f_time , d_rec.orbit , 5.5 ) + + fleets.compute_outerspace_duration( f_time , s_rec.x , s_rec.y , d_rec.x , d_rec.y ); + direction := TRUE; + END IF; + + -- Compute state duration and reference point + IF s_orbit::NUMERIC % 0.5 = 0 THEN + s_duration := f_time; + past_rp := ( s_orbit::NUMERIC % 1 = 0); + rporb := ( CASE WHEN direction THEN ceil( s_orbit ) ELSE floor( s_orbit ) END ); + ELSE + torb := s_orbit * 2; + IF direction THEN + torb := ceil( torb ); + ELSE + torb := floor( torb ); + END IF; + s_duration := fleets.compute_insystem_duration( f_time , s_orbit , ( torb / 2 )::REAL ); + rporb := round( s_orbit ); + past_rp := ( CASE WHEN direction THEN ( rporb::REAL <= s_orbit ) ELSE ( rporb::REAL >= s_orbit ) END ); + END IF; + SELECT INTO ref_point name_id FROM verse.planets p + WHERE p.system_id = s_sys AND orbit = rporb; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Compute a flight's duration from an outer space redirection +-- +-- /!\ Marked as immutable, but does in fact query the DB. Planets don't move around. +-- +-- Parameters: +-- f_time Fleet flight time +-- s_x Source X coordinate +-- s_y Source Y coordinate +-- d_id Destination planet +-- +-- Returns: +-- duration Flight duration +-- s_duration State duration +-- + +CREATE OR REPLACE FUNCTION fleets.compute_outerspace_redirect( + f_time INT , s_x REAL , s_y REAL , d_id INT , + OUT duration INT , OUT s_duration INT ) + STRICT IMMUTABLE + SECURITY INVOKER + AS $$ +DECLARE + s_rec RECORD; + d_rec RECORD; +BEGIN + -- Get destination planet coordinates, orbit and system ID + SELECT INTO d_rec s.x AS x , s.y AS y , p.orbit AS orbit , s.id AS sid + FROM verse.planets p + INNER JOIN verse.systems s ON s.id = p.system_id + WHERE p.name_id = d_id; + + s_duration := fleets.compute_outerspace_duration( f_time , s_x , s_y , d_rec.x , d_rec.y ); + duration := fleets.compute_insystem_duration( f_time , d_rec.orbit , 5.5 ) + s_duration; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Give movement orders to a set of fleets +-- +-- Parameters: +-- emp_id Expected owner identifier +-- fleet_ids Array of fleet identifiers +-- dest_id Destination planet +-- + +CREATE OR REPLACE FUNCTION fleets.set_movement_orders( emp_id INT , fleet_ids BIGINT[] , dest_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + dur INT; + s_dur INT; + dir BOOLEAN; + rpid INT; + prp BOOLEAN; + cx REAL; + cy REAL; +BEGIN + -- Lock fleets and planets + PERFORM * FROM fleets.fleets f + INNER JOIN emp.empires e ON e.name_id = f.owner_id + INNER JOIN verse.planets p ON f.location_id = p.name_id + WHERE f.id = ANY( fleet_ids ) AND f.status = 'AVAILABLE' + AND e.name_id = emp_id AND f.location_id <> dest_id + FOR UPDATE OF p , f; + + FOR rec IN SELECT f.id AS id , f.location_id AS location , + fs.flight_time AS flight_time , b.id AS battle , + p.orbit AS orbit , s.x AS x , s.y AS y , + m.time_left AS mv_time , m.state_time_left AS mv_state_time , + osms.start_x AS os_start_x , osms.start_y AS os_start_y , + isms.ref_point_id AS is_ref_point , isms.outwards AS is_outwards , + isms.past_ref_point AS is_past_ref_point , + rp.system_id AS is_ref_point_system , rp.orbit AS is_ref_point_orbit + FROM fleets.fleets f + INNER JOIN emp.empires e ON e.name_id = f.owner_id + INNER JOIN verse.planets p ON f.location_id = p.name_id + INNER JOIN verse.systems s ON s.id = p.system_id + INNER JOIN fleets.stats_view fs ON fs.id = f.id + LEFT OUTER JOIN battles.battles b + ON b.location_id = f.location_id AND b.last_tick IS NULL + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + LEFT OUTER JOIN fleets.ms_space osms ON osms.movement_id = f.id + LEFT OUTER JOIN fleets.ms_system isms ON isms.movement_id = f.id + LEFT OUTER JOIN verse.planets rp ON isms.ref_point_id = rp.name_id + WHERE f.id = ANY( fleet_ids ) AND f.status = 'AVAILABLE' + AND e.name_id = emp_id AND f.location_id <> dest_id + LOOP + IF rec.mv_time IS NULL THEN + -- New fleet movement + SELECT INTO dur, dir duration , direction + FROM fleets.compute_flight_init( rec.flight_time , rec.location , dest_id ); + INSERT INTO fleets.movements ( fleet_id , source_id, time_left , state_time_left ) + VALUES ( rec.id , rec.location , dur , rec.flight_time ); + INSERT INTO fleets.ms_system( movement_id , ref_point_id , outwards , past_ref_point ) + VALUES ( rec.id , rec.location , dir , TRUE ); + UPDATE fleets.fleets SET location_id = dest_id + WHERE id = rec.id; + + -- Remove fleet from battle (if there is one) + PERFORM battles.remove_fleet( rec.battle , rec.id , 'DEPART'::battle_fleet_change , sys.get_tick() ); + ELSE + -- Fleet redirection + IF rec.is_ref_point IS NULL THEN + -- Fleet moving in outer space + PERFORM sys.write_log( 'Fleets' , 'TRACE'::log_level , 'About to perform outer space redirect; ' + || 'OOFT/2 = ' || rec.flight_time || '; start(x;y)= (' || rec.os_start_x || ';' || rec.os_start_y + || '); dest(x;y)= (' || rec.x || ';' || rec.y || '); time left: ' || rec.mv_state_time ); + SELECT INTO cx , cy c_x , c_y FROM fleets.compute_current_location( + rec.flight_time , rec.os_start_x , rec.os_start_y , rec.x , rec.y , + rec.mv_state_time ); + PERFORM sys.write_log( 'Fleets' , 'TRACE'::log_level , 'Computed current coordinates: (' || cx + || ';' || cy || ')' ); + SELECT INTO dur , s_dur duration , s_duration + FROM fleets.compute_outerspace_redirect( rec.flight_time , cx , cy , dest_id ); + PERFORM sys.write_log( 'Fleets' , 'TRACE'::log_level , 'Computed new total/state duration: ' + || dur || ' / ' || s_dur ); + UPDATE fleets.ms_space SET start_x = cx , start_y = cy + WHERE movement_id = rec.id; + ELSE + -- Fleet moving in a system + cx := fleets.compute_current_orbit( rec.flight_time , rec.is_ref_point_orbit , rec.is_outwards , + rec.is_past_ref_point , rec.mv_state_time ); + SELECT INTO dur, dir , s_dur , rpid , prp duration , direction , s_duration , ref_point , past_rp + FROM fleets.compute_insystem_redirect( rec.flight_time , rec.is_ref_point_system , cx , dest_id ); + UPDATE fleets.ms_system SET ref_point_id = rpid , outwards = dir , past_ref_point = prp + WHERE movement_id = rec.id; + END IF; + + UPDATE fleets.movements SET time_left = dur , state_time_left = s_dur + WHERE fleet_id = rec.id; + UPDATE fleets.fleets + SET status = 'REDIRECTING' , + penalty = rec.flight_time * 2 , + location_id = dest_id + WHERE id = rec.id; + END IF; + END LOOP; + + -- Prepare fleet departure events + CREATE TEMPORARY TABLE fleet_departures( + loc_id INT , + loc_name VARCHAR(20) , + own_id INT , + own_name VARCHAR(20) , + name VARCHAR(64) , + power BIGINT , + mode BOOLEAN + ) ON COMMIT DROP; + INSERT INTO fleet_departures + SELECT fm.source_id , sn.name , f.owner_id , fon.name , + f.name , fs.power , f.attacking + FROM fleets.fleets f + INNER JOIN fleets.stats_view fs ON fs.id = f.id + INNER JOIN fleets.movements fm ON fm.fleet_id = f.id + INNER JOIN naming.map_names sn ON sn.id = fm.source_id + INNER JOIN naming.empire_names fon ON fon.id = f.owner_id + WHERE f.id = ANY( fleet_ids ) AND f.owner_id = emp_id AND f.status = 'AVAILABLE'; + PERFORM events.commit_fleet_departures( ); + PERFORM msgs.deliver_internal( ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Fleet movement command +-- +-- Parameters: +-- emp_id Identifier of the empire who supposedly owns the fleets +-- fleet_ids List of fleets to order around +-- dest Name of the destination +-- +-- Returns: +-- success Whether the destination was found or not. +-- + +CREATE OR REPLACE FUNCTION fleets.move_fleets( emp_id INT , fleet_ids BIGINT[] , dest TEXT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + dest_id INT; +BEGIN + SELECT INTO dest_id id FROM naming.map_names + WHERE lower( name ) = lower(dest); + success := FOUND; + + IF success THEN + PERFORM fleets.set_movement_orders( emp_id , fleet_ids , dest_id ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION fleets.move_fleets( INT , BIGINT[] , TEXT ) TO :dbuser; + + + +-- +-- Renames a set of fleets +-- +-- Parameters: +-- emp_id Identifier of the empire who supposedly owns the fleets +-- fleet_ids List of fleets to rename +-- n_name New name +-- + +CREATE OR REPLACE FUNCTION fleets.rename_fleets( emp_id INT , fleet_ids BIGINT[] , n_name TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE fleets.fleets + SET name = ( CASE WHEN $3 = '' THEN NULL ELSE $3 END ) + WHERE owner_id = $1 + AND id IN ( SELECT unnest AS id FROM unnest( $2 ) ); +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION fleets.rename_fleets( INT , BIGINT[] , TEXT ) TO :dbuser; + + + +-- +-- Prepares a fleet splitting command +-- +-- Parameters: +-- f_id Fleet identifier +-- n_fleets Amount of fleets to create +-- nnm New name for the fleets +-- +-- Returns: +-- success Whether the operation was successful +-- + +CREATE OR REPLACE FUNCTION fleets.init_split( f_id BIGINT , n_fleets INT , nnm TEXT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + o_name TEXT; + ifm BOOLEAN; + att BOOLEAN; + loc INT; + own INT; +BEGIN + IF n_fleets < 1 THEN + success := FALSE; + RETURN; + END IF; + + SELECT INTO o_name , ifm , loc , att , own + f.name , ( m.fleet_id IS NOT NULL ) , f.location_id , f.attacking , f.owner_id + FROM fleets.fleets f + INNER JOIN emp.empires e ON e.name_id = f.owner_id + INNER JOIN verse.planets p ON p.name_id = f.location_id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE f.id = f_id + FOR UPDATE OF f , e , p; + success := FOUND; + IF NOT success THEN + RETURN; + END IF; + + CREATE TEMPORARY TABLE fleet_split_main ( + fleet_id BIGINT , + fleets INT , + location INT , + owner INT , + attacking BOOLEAN , + new_name VARCHAR(40) , + moving BOOLEAN + ) ON COMMIT DROP; + INSERT INTO fleet_split_main + VALUES ( f_id , n_fleets , loc , own , att , (CASE WHEN nnm = '' THEN o_name ELSE nnm END ) , ifm ); + + CREATE TEMPORARY TABLE fleet_split_ships ( + ship_type INT , + initial_amount INT , + split_amount INT + ) ON COMMIT DROP; + INSERT INTO fleet_split_ships + SELECT ship_id , amount , 0::INT + FROM fleets.ships + WHERE fleet_id = f_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION fleets.init_split( BIGINT , INT , TEXT ) TO :dbuser; + + + +-- +-- Sets the amount of ships of a given type to split off. +-- +-- Parameters: +-- st_id Ship type identifier +-- n_ships Amount +-- + +CREATE OR REPLACE FUNCTION fleets.set_split_ships( st_id INT , n_ships INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE fleet_split_ships + SET split_amount = n_ships + WHERE ship_type = st_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION fleets.set_split_ships( INT , INT ) TO :dbuser; + + + +-- +-- Verifies a fleet split command information +-- + +CREATE OR REPLACE FUNCTION fleets.check_split() + RETURNS BOOLEAN + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + n_fleets INT; + ssum INT; + nsum INT; + rec RECORD; +BEGIN + SELECT INTO n_fleets fleets FROM fleet_split_main; + ssum := 0; + nsum := 0; + FOR rec IN SELECT initial_amount , split_amount FROM fleet_split_ships + LOOP + IF rec.split_amount < 0 OR rec.split_amount * n_fleets > rec.initial_amount THEN + RETURN FALSE; + END IF; + ssum := ssum + rec.initial_amount - rec.split_amount * n_fleets; + nsum := nsum + rec.split_amount; + END LOOP; + RETURN ( ssum > 0 AND nsum > 0 ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Executes a fleet split command information +-- + +CREATE OR REPLACE FUNCTION fleets.split_fleet( ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + main RECORD; + i INT; + nf_id BIGINT; + mv_rec fleets.movements%ROWTYPE; + ism_rec fleets.ms_system%ROWTYPE; + osm_rec fleets.ms_space%ROWTYPE; + old_ft INT; + new_ft INT; + sp_ft INT; + x REAL; + y REAL; + cx REAL; + cy REAL; + sid INT; +BEGIN + SELECT INTO main * FROM fleet_split_main; + + -- Cache trajectory + IF main.moving THEN + SELECT INTO mv_rec * FROM fleets.movements WHERE fleet_id = main.fleet_id; + SELECT INTO ism_rec * FROM fleets.ms_system WHERE movement_id = main.fleet_id; + SELECT INTO osm_rec * FROM fleets.ms_space WHERE movement_id = main.fleet_id; + SELECT INTO old_ft flight_time FROM fleets.stats_view WHERE id = main.fleet_id; + END IF; + + -- Update existing fleet + UPDATE fleets.ships s + SET amount = amount - fss.split_amount * main.fleets + FROM fleet_split_ships fss + WHERE fleet_id = main.fleet_id AND s.ship_id = fss.ship_type; + DELETE FROM fleets.ships WHERE fleet_id = main.fleet_id AND amount = 0; + + -- Did the speed change? + IF main.moving THEN + SELECT INTO new_ft flight_time FROM fleets.stats_view WHERE id = main.fleet_id; + IF new_ft <> old_ft THEN + IF ism_rec IS NULL THEN + -- Outer space movement + SELECT INTO x , y s.x::REAL , s.y::REAL + FROM verse.planets p + INNER JOIN verse.systems s ON s.id = p.system_id + WHERE p.name_id = main.location; + SELECT INTO cx , cy c_x , c_y FROM fleets.compute_current_location( + old_ft , osm_rec.start_x , osm_rec.start_y , x , y , + mv_rec.state_time_left ); + UPDATE fleets.ms_space + SET start_x = cx , start_y = cy + WHERE movement_id = main.fleet_id; + UPDATE fleets.movements m + SET time_left = r.duration , state_time_left = r.s_duration + FROM fleets.compute_outerspace_redirect( new_ft , cx , cy , main.location ) r + WHERE m.fleet_id = main.fleet_id; + ELSE + -- System movement + SELECT INTO y , sid orbit , system_id + FROM verse.planets + WHERE name_id = ism_rec.ref_point_id; + x := fleets.compute_current_orbit( old_ft , y::INT , ism_rec.outwards , + ism_rec.past_ref_point , mv_rec.state_time_left ); + UPDATE fleets.movements m + SET time_left = r.duration , state_time_left = r.s_duration + FROM fleets.compute_insystem_redirect( new_ft , sid , x , main.location ) r + WHERE m.fleet_id = main.fleet_id; + END IF; + END IF; + END IF; + + sp_ft := NULL; + FOR i IN 1 .. main.fleets + LOOP + -- Main fleet record + INSERT INTO fleets.fleets ( owner_id , location_id , name , attacking , status , penalty ) + VALUES ( main.owner , main.location , main.new_name , main.attacking , 'AVAILABLE' , 0 ) + RETURNING id INTO nf_id; + + -- Fleet ships + INSERT INTO fleets.ships ( fleet_id , ship_id , amount , damage ) + SELECT nf_id , s.ship_type , s.split_amount , 0 + FROM fleet_split_ships s + WHERE s.split_amount > 0; + + IF main.moving THEN + IF sp_ft IS NULL THEN + SELECT INTO sp_ft flight_time FROM fleets.stats_view WHERE id = nf_id; + IF sp_ft <> old_ft THEN + IF ism_rec IS NULL THEN + -- Outer space movement + SELECT INTO x , y s.x::REAL , s.y::REAL + FROM verse.planets p + INNER JOIN verse.systems s ON s.id = p.system_id + WHERE p.name_id = main.location; + SELECT INTO cx , cy c_x , c_y FROM fleets.compute_current_location( + old_ft , osm_rec.start_x , osm_rec.start_y , x , y , + mv_rec.state_time_left ); + osm_rec.start_x := cx; + osm_rec.start_y := cy; + SELECT INTO mv_rec.time_left , mv_rec.state_time_left + duration , s_duration + FROM fleets.compute_outerspace_redirect( sp_ft , cx , cy , main.location ); + ELSE + -- System movement + SELECT INTO y , sid orbit , system_id + FROM verse.planets + WHERE name_id = ism_rec.ref_point_id; + x := fleets.compute_current_orbit( old_ft , y::INT , ism_rec.outwards , + ism_rec.past_ref_point , mv_rec.state_time_left ); + SELECT INTO mv_rec.time_left , mv_rec.state_time_left + duration , s_duration + FROM fleets.compute_insystem_redirect( sp_ft , sid , x , main.location ); + END IF; + END IF; + END IF; + + -- Insert fleet movement records + INSERT INTO fleets.movements ( fleet_id , source_id , time_left , state_time_left ) + VALUES ( nf_id , mv_rec.source_id , mv_rec.time_left , mv_rec.state_time_left ); + IF ism_rec IS NULL THEN + INSERT INTO fleets.ms_space ( movement_id , start_x , start_y ) + VALUES ( nf_id , osm_rec.start_x , osm_rec.start_y ); + ELSE + INSERT INTO fleets.ms_system ( movement_id , ref_point_id , outwards , past_ref_point ) + VALUES ( nf_id , ism_rec.ref_point_id , ism_rec.outwards , ism_rec.past_ref_point ); + END IF; + END IF; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Finalises a fleet split command +-- +-- Parameters: +-- simulate Whether the split command was only being simulated +-- +-- Returns: +-- success Whether the operation was / would have been successful +-- + +CREATE OR REPLACE FUNCTION fleets.execute_split( simulate BOOLEAN , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + success := fleets.check_split(); + IF success AND NOT simulate THEN + PERFORM fleets.split_fleet(); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION fleets.execute_split( BOOLEAN ) TO :dbuser; + + + +-- +-- Set fleet mode +-- +-- Parameters: +-- e_id Empire who supposedly owns the fleets +-- f_ids Fleet identifiers +-- att Whether the fleets are to be set to attack +-- + +CREATE OR REPLACE FUNCTION fleets.set_mode( e_id INT , f_ids BIGINT[] , att BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + rec RECORD; +BEGIN + -- Prepare events table + CREATE TEMPORARY TABLE fleet_switches( + loc_id INT , + loc_name VARCHAR(20) , + own_id INT , + own_name VARCHAR(20) , + name VARCHAR(64) , + power BIGINT , + mode BOOLEAN + ) ON COMMIT DROP; + + -- Lock records + PERFORM f.id FROM fleets.fleets f + INNER JOIN verse.planets p ON p.name_id = f.location_id + INNER JOIN unnest( f_ids ) fid ON f.id = fid + WHERE f.owner_id = e_id AND f.attacking <> att + FOR UPDATE OF f , p; + + -- Handle moving fleets + UPDATE fleets.fleets f SET attacking = att + FROM fleets.movements m + WHERE f.owner_id = e_id AND f.id IN ( SELECT * FROM unnest( f_ids ) ) + AND m.fleet_id = f.id AND f.attacking <> att; + + -- Handle fleets on planets + FOR rec IN SELECT DISTINCT f.location_id AS location , ep.empire_id AS planet_owner , + b.id AS battle , ( el.enemy IS NOT NULL ) AS enemy , + ( v.status = 'PROCESSED' AND b.id IS NULL ) AS on_vacation + FROM fleets.fleets f + INNER JOIN unnest( f_ids ) fid ON f.id = fid + LEFT OUTER JOIN battles.battles b + ON b.location_id = f.location_id AND b.last_tick IS NULL + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + LEFT OUTER JOIN emp.planets ep ON ep.planet_id = f.location_id + LEFT OUTER JOIN emp.enemies el + ON el.empire = ep.empire_id AND el.enemy = e_id + LEFT OUTER JOIN naming.empire_names en ON en.id = ep.empire_id + LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id + WHERE f.owner_id = e_id AND m.fleet_id IS NULL AND f.attacking <> att + LOOP + -- Can't switch on own planets, on planets whose owner have the fleets' owner in their EL + -- or on planets which have entered vacation mode + CONTINUE WHEN e_id = rec.planet_owner OR rec.enemy OR rec.on_vacation; + + -- Prepare events + INSERT INTO fleet_switches + SELECT f.location_id , ln.name , f.owner_id , fon.name , + f.name , fs.power , att + FROM fleets.fleets f + INNER JOIN emp.planets ep ON f.location_id = ep.planet_id + INNER JOIN fleets.stats_view fs ON fs.id = f.id + INNER JOIN naming.map_names ln ON ln.id = f.location_id + INNER JOIN naming.empire_names fon ON fon.id = f.owner_id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE f.owner_id = e_id AND f.location_id = rec.location + AND m.fleet_id IS NULL; + + -- Set fleets mode + UPDATE fleets.fleets f + SET attacking = att , + status = 'REDEPLOYING' , + penalty = ( CASE + WHEN f2.penalty > ( 1 + fs.flight_time * ( CASE WHEN att THEN 40 ELSE 10 END ) ) + THEN f2.penalty + ELSE ( 1 + fs.flight_time * ( CASE WHEN att THEN 40 ELSE 10 END ) ) + END ) + FROM fleets.fleets f2 + INNER JOIN fleets.stats_view fs ON fs.id = f2.id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f2.id + WHERE f2.owner_id = e_id AND f2.location_id = rec.location + AND m.fleet_id IS NULL AND f2.id = f.id; + + -- Update battle + PERFORM battles.set_mode( rec.battle , e_id , att ); + END LOOP; + + PERFORM events.commit_fleet_switches( FALSE ); + PERFORM msgs.deliver_internal( ); + + DROP TABLE fleet_switches; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION fleets.set_mode( INT , BIGINT[] , BOOLEAN ) TO :dbuser; + + + +-- +-- Disband fleets +-- +-- Parameters: +-- e_id Empire who supposedly owns the fleets +-- f_ids Fleet identifiers +-- + +CREATE OR REPLACE FUNCTION fleets.disband( e_id INT , f_ids BIGINT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + rec RECORD; +BEGIN + -- Lock all fleets and, if necessary, remove them from battles + FOR rec IN SELECT f.id AS fleet , + ( CASE + WHEN m.fleet_id IS NULL AND f.status <> 'DEPLOYING' THEN + b.id + ELSE + NULL + END ) AS battle + FROM fleets.fleets f + INNER JOIN unnest( f_ids ) fid ON f.id = fid + INNER JOIN verse.planets p ON p.name_id = f.location_id + LEFT OUTER JOIN battles.battles b + ON b.location_id = f.location_id AND b.last_tick IS NULL + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE f.owner_id = e_id + FOR UPDATE OF p , f + LOOP + PERFORM battles.remove_fleet( rec.battle , rec.fleet , 'DISBAND'::battle_fleet_change , sys.get_tick( ) ); + END LOOP; + + -- Delete fleets + DELETE FROM fleets.fleets + WHERE id IN ( SELECT * FROM unnest( f_ids ) ) AND owner_id = e_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION fleets.disband( INT , BIGINT[] ) TO :dbuser; + + + +-- +-- Inflicts battle damage to a fleet +-- +-- Parameters: +-- f_id Fleet identifier +-- dmg Damage to inflict +-- b_id Battle identifier +-- tick Current tick +-- + +CREATE OR REPLACE FUNCTION fleets.inflict_battle_damage( f_id BIGINT , dmg REAL , b_id BIGINT , tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + f_power BIGINT; + f_att BOOLEAN; + e_id INT; + bp_id BIGINT; + bf_id BIGINT; + rec RECORD; + st_dmg REAL; + n_dest INT; + found INT; + deleted INT; +BEGIN + PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Inflicting ' + || dmg || ' damage to fleet #' || f_id ); + + -- Get total fleet power and battle protagonist + SELECT INTO f_power , e_id , f_att fs.power , f.owner_id , f.attacking + FROM fleets.fleets f + INNER JOIN fleets.stats_view fs USING( id ) + WHERE id = f_id; + bp_id := battles.goc_protagonist( b_id , e_id , f_att , tick ); + bf_id := NULL; + + found := 0; + deleted := 0; + FOR rec IN SELECT s.ship_id , ( s.amount * sd.power ) AS t_power , + sd.power AS s_power , s.damage AS damage , + s.amount AS amount + FROM fleets.ships s + INNER JOIN tech.ships sd ON sd.buildable_id = s.ship_id + WHERE s.fleet_id = f_id + LOOP + -- Compute ships to destroy + found := found + 1; + st_dmg := rec.damage + ( dmg * rec.t_power / f_power ) / rec.s_power; + n_dest := floor( st_dmg ); + + IF n_dest >= rec.amount THEN + -- All ships destroyed + deleted := deleted + 1; + DELETE FROM fleets.ships WHERE fleet_id = f_id AND ship_id = rec.ship_id; + n_dest := rec.amount; + ELSE + -- Inflict damage + UPDATE fleets.ships + SET amount = amount - n_dest , + damage = st_dmg - n_dest + WHERE fleet_id = f_id AND ship_id = rec.ship_id; + END IF; + + IF n_dest > 0 THEN + -- Update fleet change record + IF bf_id IS NULL THEN + bf_id := battles.goc_fleet_change( bp_id , tick , 'BATTLE'::battle_fleet_change ); + END IF; + PERFORM battles.add_fleet_change( bf_id , rec.ship_id , - n_dest ); + END IF; + END LOOP; + + -- If all ships were destroyed, delete the fleet + IF found = deleted THEN + DELETE FROM fleets.fleets WHERE id = f_id; + END IF; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Inflicts debt-related damage to all fleets of an empire +-- +-- Parameters: +-- e_id Empire identifer +-- t_upkeep Total fleet upkeep +-- debt Daily debt +-- d_ratio Debt damage ratio +-- + +CREATE OR REPLACE FUNCTION fleets.handle_debt( e_id INT , t_upkeep REAL , debt REAL , d_ratio REAL ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + tot_damage REAL; + f_rec RECORD; + s_rec RECORD; + n_found INT; + n_killed INT; + s_killed INT; + s_damage REAL; + n_ships INT; + tick BIGINT; + bp_id BIGINT; + bf_id BIGINT; + mv_rec fleets.movements%ROWTYPE; + ism_rec fleets.ms_system%ROWTYPE; + osm_rec fleets.ms_space%ROWTYPE; + x REAL; + y REAL; + cx REAL; + cy REAL; + sid INT; +BEGIN + tick := sys.get_tick( ) - 1; + tot_damage := t_upkeep * d_ratio / debt; + PERFORM sys.write_log( 'EmpireDebt' , 'DEBUG'::log_level , 'Inflicting debt damage to fleets; total upkeep: ' + || t_upkeep || ', damage ratio: ' || d_ratio || ', total damage: ' || tot_damage ); + + FOR f_rec IN SELECT f.id AS fleet , f.status , f.location_id AS location , + ( m.fleet_id IS NOT NULL ) AS moving , b.id AS battle , + fs.flight_time , f.attacking + FROM fleets.fleets f + INNER JOIN fleets.stats_view fs ON fs.id = f.id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + LEFT OUTER JOIN battles.battles b + ON b.location_id = f.location_id AND b.last_tick IS NULL + WHERE f.owner_id = e_id + FOR UPDATE OF f + LOOP + -- Get battle information + IF f_rec.battle IS NOT NULL AND NOT f_rec.moving AND f_rec.status <> 'DEPLOYING' + THEN + bp_id := battles.goc_protagonist( f_rec.battle , e_id , f_rec.attacking , tick ); + bf_id := NULL; + END IF; + + -- Damage ships + n_found := 0; + n_killed := 0; + s_killed := 0; + FOR s_rec IN SELECT s.ship_id AS ship , s.amount AS amount , s.damage AS damage , + ( d.upkeep * s.amount )::REAL AS upkeep + FROM fleets.ships s + INNER JOIN tech.buildables d ON d.name_id = s.ship_id + WHERE s.fleet_id = f_rec.fleet + LOOP + n_found := n_found + 1; + s_damage := s_rec.damage + tot_damage * s_rec.upkeep / t_upkeep; + n_ships := floor( s_damage ); + IF n_ships >= s_rec.amount + THEN + -- All ships destroyed + DELETE FROM fleets.ships WHERE fleet_id = f_rec.fleet AND ship_id = s_rec.ship; + n_killed := n_killed + 1; + s_killed := s_killed + s_rec.amount; + n_ships := s_rec.amount; + ELSE + -- Simple damage + UPDATE fleets.ships + SET amount = s_rec.amount - n_ships , + damage = s_damage - n_ships + WHERE fleet_id = f_rec.fleet AND ship_id = s_rec.ship; + s_killed := s_killed + n_ships; + END IF; + + IF n_ships > 0 AND f_rec.battle IS NOT NULL AND NOT f_rec.moving AND f_rec.status <> 'DEPLOYING' + THEN + -- Update battle + IF bf_id IS NULL THEN + bf_id := battles.goc_fleet_change( bp_id , tick , 'DISBAND'::battle_fleet_change ); + END IF; + PERFORM battles.add_fleet_change( bf_id , s_rec.ship , - n_ships ); + END IF; + END LOOP; + + -- No ships destroyed + CONTINUE WHEN s_killed = 0; + + IF n_killed = n_found + THEN + -- Destroy fleet + DELETE FROM fleets.fleets WHERE id = f_rec.fleet; + ELSEIF f_rec.moving AND n_killed > 0 + THEN + -- Flight time may have changed, update fleet accordingly + SELECT INTO n_found flight_time FROM fleets.stats_view WHERE id = f_rec.fleet; + CONTINUE WHEN n_found = f_rec.flight_time; + + -- Get movement records + SELECT INTO mv_rec * FROM fleets.movements WHERE fleet_id = f_rec.fleet; + SELECT INTO ism_rec * FROM fleets.ms_system WHERE movement_id = f_rec.fleet; + SELECT INTO osm_rec * FROM fleets.ms_space WHERE movement_id = f_rec.fleet; + + IF ism_rec IS NULL THEN + -- Outer space movement + SELECT INTO x , y s.x::REAL , s.y::REAL + FROM verse.planets p + INNER JOIN verse.systems s ON s.id = p.system_id + WHERE p.name_id = f_rec.location; + SELECT INTO cx , cy c_x , c_y FROM fleets.compute_current_location( + f_rec.flight_time , osm_rec.start_x , osm_rec.start_y , x , y , + mv_rec.state_time_left ); + UPDATE fleets.ms_space + SET start_x = cx , start_y = cy + WHERE movement_id = f_rec.fleet; + UPDATE fleets.movements m + SET time_left = r.duration , state_time_left = r.s_duration + FROM fleets.compute_outerspace_redirect( n_found , cx , cy , f_rec.location ) r + WHERE m.fleet_id = f_rec.fleet; + ELSE + -- System movement + SELECT INTO y , sid orbit , system_id + FROM verse.planets + WHERE name_id = ism_rec.ref_point_id; + x := fleets.compute_current_orbit( f_rec.flight_time , y::INT , ism_rec.outwards , + ism_rec.past_ref_point , mv_rec.state_time_left ); + UPDATE fleets.movements m + SET time_left = r.duration , state_time_left = r.s_duration + FROM fleets.compute_insystem_redirect( n_found , sid , x , f_rec.location ) r + WHERE m.fleet_id = f_rec.fleet; + END IF; + END IF; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + + +-- +-- Merge fleets +-- +-- Parameters: +-- e_id Empire who supposedly owns the fleets +-- f_ids Fleet identifiers +-- + +CREATE OR REPLACE FUNCTION fleets.merge( e_id INT , f_ids BIGINT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + rec RECORD; +BEGIN + -- Create temporary tables + CREATE TEMPORARY TABLE merged_fleets( + location INT , + fleet BIGINT , + n_merged INT DEFAULT 1 + ) ON COMMIT DROP; + CREATE TEMPORARY TABLE merged_ships( LIKE fleets.ships ) ON COMMIT DROP; + + -- Find all fleets + FOR rec IN SELECT f.id AS fleet , f.location_id AS location + FROM fleets.fleets f + INNER JOIN unnest( f_ids ) fid ON f.id = fid + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE f.status = 'AVAILABLE' AND f.owner_id = e_id AND m.fleet_id IS NULL + FOR UPDATE OF f + LOOP + UPDATE merged_fleets SET n_merged = n_merged + 1 WHERE location = rec.location; + + IF FOUND THEN + -- Update existing record + UPDATE merged_ships ms + SET amount = ms.amount + s.amount , + damage = ms.damage + s.damage + FROM merged_fleets f , fleets.ships s + WHERE f.location = rec.location AND ms.fleet_id = f.fleet + AND s.fleet_id = rec.fleet AND ms.ship_id = s.ship_id; + DELETE FROM fleets.fleets WHERE id = rec.fleet; + ELSE + -- Create new record + INSERT INTO merged_fleets ( location , fleet ) + VALUES ( rec.location , rec.fleet ); + INSERT INTO merged_ships (fleet_id , ship_id , amount , damage ) + SELECT rec.fleet , s.buildable_id , 0 , 0 + FROM tech.ships s; + UPDATE merged_ships ms + SET amount = ms.amount + s.amount , + damage = ms.damage + s.damage + FROM merged_fleets f , fleets.ships s + WHERE f.location = rec.location AND ms.fleet_id = f.fleet + AND s.fleet_id = rec.fleet AND ms.ship_id = s.ship_id; + DELETE FROM fleets.ships WHERE fleet_id = rec.fleet; + END IF; + END LOOP; + + INSERT INTO fleets.ships + SELECT * FROM merged_ships WHERE amount > 0; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION fleets.merge( INT , BIGINT[] ) TO :dbuser; + + + +-- +-- Fleet locations list +-- + +CREATE VIEW fleets.locations_list_view + AS SELECT ep.empire_id AS empire , ep.planet_id AS location , FALSE AS attacking + FROM emp.planets ep + UNION SELECT f.owner_id AS empire , f.location_id AS location , f.attacking AS attacking + FROM fleets.fleets f + LEFT OUTER JOIN fleets.movements m + ON m.fleet_id = f.id + WHERE m.fleet_id IS NULL; + + + +-- +-- Fleet stats +-- + +CREATE VIEW fleets.stats_view + AS SELECT f.id , + sum( fs.amount * fsd.power ) AS power , + max( fsd.flight_time ) AS flight_time + FROM fleets.fleets f + INNER JOIN fleets.ships fs + ON fs.fleet_id = f.id + INNER JOIN tech.ships fsd + ON fsd.buildable_id = fs.ship_id + GROUP BY f.id; + + +-- +-- Fleet locations view +-- + +CREATE VIEW fleets.locations_view + AS SELECT llv.* , mv.name , mv.x , mv.y , mv.orbit , mv.picture , mv.tag , + floor( p.population )::BIGINT AS population , + floor( verse.adjust_production( verse.get_raw_production( p.name_id , 'DEF' ) , ph.current / p.population ) )::BIGINT AS defence , + bcs.id AS battle , + ( CASE WHEN llv.attacking THEN bcs.attack ELSE bcs.defence END ) AS friendly_power , + ( CASE WHEN llv.attacking THEN bcs.defence ELSE bcs.attack END ) AS hostile_power , + ( ep.empire_id = llv.empire ) AS is_own , + ( v.account_id IS NOT NULL AND bcs.id IS NULL ) AS on_vacation + FROM fleets.locations_list_view llv + INNER JOIN verse.planets p ON p.name_id = llv.location + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.map_view mv ON mv.id = p.name_id + LEFT OUTER JOIN battles.current_status bcs ON bcs.location = llv.location + LEFT OUTER JOIN emp.planets ep ON ep.planet_id = p.name_id + LEFT OUTER JOIN naming.empire_names en ON en.id = ep.empire_id + LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id AND v.status = 'PROCESSED' + ORDER BY mv.x , mv.y , mv.orbit; + +GRANT SELECT ON fleets.locations_view TO :dbuser; + + +-- +-- Fleet owners view +-- + + +CREATE VIEW fleets.owners_view + AS SELECT DISTINCT llv.empire , llv.location , f.owner_id AS id , n.name AS name , + ( CASE + WHEN f.owner_id = llv.empire THEN 'OWN' + WHEN f.attacking = llv.attacking THEN 'ALLIED' + ELSE 'ENEMY' + END )::empire_relation_type AS relation + FROM fleets.locations_list_view llv + INNER JOIN fleets.fleets f + ON f.location_id = llv.location + INNER JOIN naming.empire_names n + ON n.id = f.owner_id + LEFT OUTER JOIN fleets.movements m + ON m.fleet_id = f.id + WHERE m.fleet_id IS NULL; + +GRANT SELECT ON fleets.owners_view TO :dbuser; + + + +-- +-- Static fleets view +-- + +CREATE VIEW fleets.static_fleets + AS SELECT ov.empire , ov.location , ov.id AS owner , + f.id , f.name , f.status , f.penalty , + fs.power , fs.flight_time * 2 AS flight_time + FROM fleets.owners_view ov + INNER JOIN fleets.fleets f + ON f.location_id = ov.location AND f.owner_id = ov.id + INNER JOIN fleets.stats_view fs + ON fs.id = f.id + LEFT OUTER JOIN fleets.movements m + ON m.fleet_id = f.id + WHERE m.fleet_id IS NULL; + +GRANT SELECT ON fleets.static_fleets TO :dbuser; + + +-- +-- Location of fleets moving in outer space +-- + +CREATE VIEW fleets.outer_space_fleets + AS SELECT s.movement_id AS id , m.state_time_left AS time_left , + s.start_x AS x0 , s.start_y AS y0 , + ts.x::REAL AS x1 , ts.y::REAL AS y1 + FROM fleets.ms_space s + INNER JOIN fleets.movements m ON m.fleet_id = s.movement_id + INNER JOIN fleets.fleets f ON m.fleet_id = f.id + INNER JOIN verse.planets p ON p.name_id = f.location_id + INNER JOIN verse.systems ts ON ts.id = p.system_id; + + + +-- +-- Location of fleets moving inside systems +-- + +CREATE VIEW fleets.system_fleets + AS SELECT s.movement_id AS id , iss.x AS x , iss.y AS y , + n.id AS planet , n.name AS name + FROM fleets.ms_system s + INNER JOIN verse.planets isp ON isp.name_id = s.ref_point_id + INNER JOIN verse.systems iss ON iss.id = isp.system_id + INNER JOIN naming.map_names n ON n.id = isp.name_id; + + + +-- +-- Moving fleets view +-- + +CREATE VIEW fleets.moving_fleets + AS SELECT f.owner_id AS empire , f.id , f.name , + f.status , f.penalty , f.attacking , + fs.power , fs.flight_time * 2 AS flight_time , + m.time_left , + m.source_id AS from_id , sn.name AS from_name , + f.location_id AS to_id , dn.name AS to_name , + ( CASE + WHEN osf.id IS NULL THEN isf.x + ELSE ( osf.x1 - osf.time_left::REAL * ( osf.x1 - osf.x0 ) + / fleets.compute_outerspace_duration( fs.flight_time , osf.x0 , osf.y0 , osf.x1 , osf.y1 ) ) + END )::REAL AS cx , + ( CASE + WHEN osf.id IS NULL THEN isf.y + ELSE ( osf.y1 - osf.time_left::REAL * ( osf.y1 - osf.y0 ) + / fleets.compute_outerspace_duration( fs.flight_time , osf.x0 , osf.y0 , osf.x1 , osf.y1 ) ) + END )::REAL AS cy , + ( CASE + WHEN osf.id IS NULL THEN isf.planet + ELSE NULL + END )::INT AS nearest_id , + ( CASE + WHEN osf.id IS NULL THEN isf.name + ELSE NULL + END )::TEXT AS nearest_name + FROM fleets.fleets f + INNER JOIN fleets.movements m ON m.fleet_id = f.id + INNER JOIN fleets.stats_view fs ON fs.id = f.id + INNER JOIN naming.map_names sn ON sn.id = m.source_id + INNER JOIN naming.map_names dn ON dn.id = f.location_id + LEFT OUTER JOIN fleets.system_fleets isf ON isf.id = m.fleet_id + LEFT OUTER JOIN fleets.outer_space_fleets osf ON osf.id = f.id; + +GRANT SELECT ON fleets.moving_fleets TO :dbuser; + + + +-- +-- List of fleets visible to an empire +-- + +CREATE VIEW fleets.visible_fleets_list + AS SELECT empire , id FROM fleets.static_fleets + UNION SELECT empire , id FROM fleets.moving_fleets; + + + +-- +-- List of fleets ships +-- + +CREATE VIEW fleets.ships_view + AS SELECT vfl.empire , vfl.id , fs.ship_id , fs.amount , + ( fs.amount * fsd.power ) AS power , + t.translated_string AS name + FROM fleets.visible_fleets_list vfl + INNER JOIN naming.empire_names en ON vfl.empire = en.id + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN fleets.ships fs ON fs.fleet_id = vfl.id + INNER JOIN tech.ships fsd ON fsd.buildable_id = fs.ship_id + INNER JOIN defs.translations t ON t.lang_id = c.language_id AND t.string_id = fsd.buildable_id + ORDER BY fsd.power; + +GRANT SELECT ON fleets.ships_view TO :dbuser; + + + +-- +-- Short view for static fleets +-- + +CREATE VIEW fleets.short_static_fleets + AS SELECT sf.empire , sf.location AS location_id , + fl.name AS location_name , + fl.x::REAL AS x , fl.y::REAL AS y , + sf.id , sf.name , sf.status , sf.penalty , + fl.attacking , sf.power , sf.flight_time + FROM fleets.static_fleets sf + INNER JOIN fleets.locations_view fl USING( location , empire ) + WHERE sf.empire = sf.owner; + +GRANT SELECT ON fleets.short_static_fleets TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/167-planet-list.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/167-planet-list.sql new file mode 100644 index 0000000..ca6ed36 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/167-planet-list.sql @@ -0,0 +1,150 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Views for empires' planet lists +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- +-- Basic planet information +-- + +CREATE VIEW emp.planets_list_basic + AS SELECT e.name_id AS empire , + p.name_id AS id , n.name , + s.x , s.y , p.orbit , + p.population , ph.current / p.population::REAL AS happiness , + floor( pm.income )::BIGINT AS income , + floor( pm.upkeep )::BIGINT AS upkeep + FROM emp.empires e + INNER JOIN emp.planets ep ON ep.empire_id = e.name_id + INNER JOIN verse.planets p ON p.name_id = ep.planet_id + INNER JOIN naming.map_names n ON n.id = p.name_id + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.planet_money pm ON pm.planet_id = p.name_id + INNER JOIN verse.systems s ON s.id = p.system_id; + + +-- +-- Production +-- + +CREATE VIEW emp.planets_list_prod + AS SELECT id , + verse.adjust_production( verse.get_raw_production( id , 'WORK') , happiness ) AS military_production , + verse.adjust_production( verse.get_raw_production( id , 'CASH') , happiness ) AS industrial_production , + verse.adjust_production( verse.get_raw_production( id , 'POP') , happiness ) AS growth_production , + verse.adjust_production( verse.get_raw_production( id , 'DEF') , happiness ) AS static_defence + FROM emp.planets_list_basic; + + +-- +-- Civilian investment +-- + +CREATE VIEW emp.planets_list_civ_invest + AS SELECT q.planet_id AS id , sum( CASE WHEN qi.destroy THEN 0 ELSE qi.amount * qb.cost END ) - q.money AS civ_investment + FROM verse.bld_queues q + INNER JOIN verse.bld_items qi ON qi.queue_id = q.planet_id + INNER JOIN tech.buildables qb ON qb.name_id = qi.building_id + GROUP BY q.planet_id , q.money; + + +-- +-- Military investment +-- + +CREATE VIEW emp.planets_list_mil_invest + AS SELECT q.planet_id AS id , sum( qi.amount * qb.cost ) - q.money AS mil_investment + FROM verse.mil_queues q + INNER JOIN verse.mil_items qi ON qi.queue_id = q.planet_id + INNER JOIN tech.buildables qb ON qb.name_id = qi.ship_id + GROUP BY q.planet_id , q.money; + + +-- +-- First item on civilian queues +-- + +CREATE VIEW emp.planets_list_civ_top + AS SELECT qi.queue_id AS id , qi.amount AS civ_amount , qi.destroy AS civ_destroy , t.translated_string AS civ_name + FROM verse.bld_items qi + INNER JOIN emp.planets ep ON ep.planet_id = qi.queue_id + INNER JOIN naming.empire_names en ON en.id = ep.empire_id + INNER JOIN users.credentials cred ON cred.address_id = en.owner_id + INNER JOIN defs.translations t ON t.lang_id = cred.language_id AND t.string_id = qi.building_id + WHERE qi.queue_order = 0; + + +-- +-- First item on military queues +-- + +CREATE VIEW emp.planets_list_mil_top + AS SELECT qi.queue_id AS id , qi.amount AS mil_amount , t.translated_string AS mil_name + FROM verse.mil_items qi + INNER JOIN emp.planets ep ON ep.planet_id = qi.queue_id + INNER JOIN naming.empire_names en ON en.id = ep.empire_id + INNER JOIN users.credentials cred ON cred.address_id = en.owner_id + INNER JOIN defs.translations t ON t.lang_id = cred.language_id AND t.string_id = qi.ship_id + WHERE qi.queue_order = 0; + + +-- +-- Fleets +-- + +CREATE VIEW emp.planets_list_fleets + AS SELECT f.location_id AS id , ( CASE + WHEN f.owner_id = ep.empire_id THEN 0 + WHEN f.attacking THEN 2 + ELSE 1 + END ) AS rel_type , sum( fs.power )::BIGINT AS power + FROM fleets.fleets f + INNER JOIN emp.planets ep ON f.location_id = ep.planet_id + INNER JOIN fleets.stats_view fs ON fs.id = f.id + LEFT OUTER JOIN fleets.movements fm ON fm.fleet_id = f.id + WHERE fm IS NULL + GROUP BY f.location_id , ( CASE + WHEN f.owner_id = ep.empire_id THEN 0 + WHEN f.attacking THEN 2 + ELSE 1 + END ); + + +-- +-- Actual planet list +-- + +CREATE VIEW emp.planets_list + AS SELECT e.empire , e.id , e.name , e.x , e.y , e.orbit , + floor( e.population )::BIGINT AS population , + floor( 100 * e.happiness )::INT AS happiness , + e.income , e.upkeep , + floor( p.military_production )::BIGINT AS military_production , + floor( p.industrial_production )::BIGINT AS industrial_production , + floor( p.growth_production )::BIGINT AS growth_production , + ( CASE WHEN ci IS NULL THEN 0 ELSE floor( ci.civ_investment ) END )::BIGINT AS civ_investment , + ct.civ_amount , ct.civ_destroy , ct.civ_name , + ( CASE WHEN mi IS NULL THEN 0 ELSE floor( mi.mil_investment ) END )::BIGINT AS mil_investment , + mt.mil_amount , mt.mil_name , + floor( p.static_defence )::BIGINT AS static_defence , + ( CASE WHEN of IS NULL THEN 0 ELSE of.power END ) AS own_fleet , + ( CASE WHEN ff IS NULL THEN 0 ELSE ff.power END ) AS friendly_fleet , + ( CASE WHEN hf IS NULL THEN 0 ELSE hf.power END ) AS hostile_fleet , + b.id AS battle + FROM emp.planets_list_basic e + INNER JOIN emp.planets_list_prod p USING ( id ) + LEFT OUTER JOIN emp.planets_list_civ_invest ci USING ( id ) + LEFT OUTER JOIN emp.planets_list_civ_top ct USING ( id ) + LEFT OUTER JOIN emp.planets_list_mil_invest mi USING ( id ) + LEFT OUTER JOIN emp.planets_list_mil_top mt USING ( id ) + LEFT OUTER JOIN emp.planets_list_fleets of ON of.id = e.id AND of.rel_type = 0 + LEFT OUTER JOIN emp.planets_list_fleets ff ON ff.id = e.id AND ff.rel_type = 1 + LEFT OUTER JOIN emp.planets_list_fleets hf ON hf.id = e.id AND hf.rel_type = 2 + LEFT OUTER JOIN battles.battles b ON b.location_id = e.id AND b.last_tick IS NULL + ORDER BY e.x , e.y , e.orbit; + +GRANT SELECT ON emp.planets_list TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/170-event-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/170-event-functions.sql new file mode 100644 index 0000000..24f5e41 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/170-event-functions.sql @@ -0,0 +1,928 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Functions and views to create and manipulate events +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- EVENT CREATION FUNCTIONS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + +-- +-- Creates a battle start event +-- +-- Parameters: +-- b_id Battle identifier +-- + +CREATE OR REPLACE FUNCTION events.battle_start_event( b_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + l_id INT; + l_name TEXT; + pe_id INT; + c_tick BIGINT; + evt_id BIGINT; +BEGIN + -- Get location name and identifier + SELECT INTO l_id , l_name b.location_id , n.name + FROM battles.battles b + INNER JOIN naming.map_names n ON n.id = b.location_id + WHERE b.id = b_id; + + -- Create message for all protagonists + c_tick := sys.get_tick( ) - 1; + FOR pe_id IN SELECT be.empire_id + FROM battles.battles b + INNER JOIN battles.protagonists bp ON bp.battle_id = b.id + INNER JOIN battles.empires be ON be.id = bp.empire_id + WHERE b.id = b_id + LOOP + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( pe_id , c_tick , 'PLANET' , 0 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.planet_events ( event_id , location_id , location_name , battle_id) + VALUES ( evt_id , l_id , l_name , b_id ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates a battle end event +-- +-- Parameters: +-- b_id Battle identifier +-- + +CREATE OR REPLACE FUNCTION events.battle_end_event( b_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + l_id INT; + l_name TEXT; + pe_id INT; + c_tick BIGINT; + evt_id BIGINT; +BEGIN + -- Get location name and identifier + SELECT INTO l_id , l_name b.location_id , n.name + FROM battles.battles b + INNER JOIN naming.map_names n ON n.id = b.location_id + WHERE b.id = b_id; + + -- Create message for all protagonists + c_tick := sys.get_tick( ) - 1; + FOR pe_id IN SELECT empire FROM battles.battles_list + WHERE battle = b_id AND last_update = last_tick + LOOP + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( pe_id , c_tick , 'PLANET' , 1 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.planet_events ( event_id , location_id , location_name , battle_id) + VALUES ( evt_id , l_id , l_name , b_id ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates a strike start / end event +-- +-- Parameters: +-- p_id Planet identifier +-- sevt Whether to create a strike start or a strike end event +-- + +CREATE OR REPLACE FUNCTION events.strike_event( p_id INT , sevt BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + p_name TEXT; + po_id INT; + c_tick BIGINT; + evt_id BIGINT; +BEGIN + -- Get location name and owner identifier + SELECT INTO p_name , po_id n.name , ep.empire_id + FROM naming.map_names n + INNER JOIN emp.planets ep ON ep.planet_id = n.id + WHERE n.id = p_id; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Create message + c_tick := sys.get_tick( ) - 1; + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( po_id , c_tick , 'PLANET' , ( CASE WHEN sevt THEN 2 ELSE 3 END ) , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.planet_events ( event_id , location_id , location_name ) + VALUES ( evt_id , p_id , p_name ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates events for a planet's ownership change +-- +-- Parameters: +-- p_id Planet identifier +-- no_id New owner's identifier +-- + +CREATE OR REPLACE FUNCTION events.planet_ochange_events( p_id INT , no_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + p_name VARCHAR(20); + no_name VARCHAR(20); + oo_id INT; + oo_name VARCHAR(20); + evt_id BIGINT; + c_tick BIGINT; +BEGIN + c_tick := sys.get_tick( ) - 1; + + -- Get new owner's name and the planet's name + SELECT INTO p_name name FROM naming.map_names WHERE id = p_id; + SELECT INTO no_name name FROM naming.empire_names WHERE id = no_id; + + -- Get previous owner's name and identifier + SELECT INTO oo_id , oo_name ep.empire_id , n.name + FROM emp.planets ep + INNER JOIN naming.empire_names n ON n.id = ep.empire_id + WHERE ep.planet_id = p_id; + + -- If there is a previous owner, add planet loss event + IF FOUND + THEN + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( oo_id , c_tick , 'PLANET' , 4 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.planet_events ( event_id , location_id , location_name , empire_id , empire_name ) + VALUES ( evt_id , p_id , p_name , no_id , no_name ); + END IF; + + -- Add planet taking event + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( no_id , c_tick , 'PLANET' , 6 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.planet_events ( event_id , location_id , location_name , empire_id , empire_name ) + VALUES ( evt_id , p_id , p_name , oo_id , oo_name ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an event for planet abandon +-- +-- Parameters: +-- p_id Planet identifier +-- + +CREATE OR REPLACE FUNCTION events.planet_abandon_event( p_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + p_name VARCHAR(20); + po_id INT; + oo_name VARCHAR(20); + evt_id BIGINT; +BEGIN + -- Get owner's ID and planet's name + SELECT INTO p_name , po_id n.name , ep.empire_id + FROM naming.map_names n + INNER JOIN emp.planets ep ON ep.planet_id = n.id + WHERE n.id = p_id; + + -- Add abandon event + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( po_id , sys.get_tick( ) - 1 , 'PLANET' , 5 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.planet_events ( event_id , location_id , location_name ) + VALUES ( evt_id , p_id , p_name ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an event for a technology's availability +-- +-- Parameters: +-- e_id Empire identifier +-- t_id Technology identifier +-- + +CREATE OR REPLACE FUNCTION events.tech_ready_event( e_id INT , t_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + evt_id BIGINT; +BEGIN + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( e_id , sys.get_tick( ) - 1 , 'EMPIRE' , 0 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.empire_events ( event_id , technology_id ) + VALUES ( evt_id , t_id ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an event for start/end of debt +-- +-- Parameters: +-- e_id Empire identifier +-- sevt Whether this is the start or the end +-- + +CREATE OR REPLACE FUNCTION events.debt_event( e_id INT , sevt BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER +AS $$ + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( $1 , sys.get_tick( ) - 1 , 'EMPIRE' , ( CASE WHEN $2 THEN 1 ELSE 2 END ) , 'READY' ); +$$ LANGUAGE SQL; + + + +-- +-- Creates a "pending request" event +-- +-- Parameters: +-- a_id Alliance identifier +-- e_id Empire identifier +-- + +CREATE OR REPLACE FUNCTION events.alliance_request_event( a_id INT , e_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + a_tag TEXT; + al_id INT; + e_name TEXT; + evt_id BIGINT; +BEGIN + -- Get the alliance's name and leader ID + SELECT INTO a_tag , al_id tag , leader_id FROM emp.alliances WHERE id = a_id; + + -- Get the joining player's name + SELECT INTO e_name name FROM naming.empire_names WHERE id = e_id; + + -- Create the event + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( al_id , sys.get_tick( ) , 'ALLIANCE' , 0 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.alliance_events ( event_id , alliance_id , alliance_tag , empire_id , empire_name ) + VALUES ( evt_id , a_id , a_tag , e_id , e_name ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates a request validation/rejection event +-- +-- Parameters: +-- a_id Alliance identifier +-- e_id Empire identifier +-- acc Whether the request was accepted or rejected +-- + +CREATE OR REPLACE FUNCTION events.alliance_response_event( a_id INT , e_id INT , acc BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + a_tag TEXT; + e_name TEXT; + evt_id BIGINT; +BEGIN + -- Get the alliance's name and leader ID + SELECT INTO a_tag tag FROM emp.alliances WHERE id = a_id; + + -- Get the requesting player's name + SELECT INTO e_name name FROM naming.empire_names WHERE id = e_id; + + -- Create the event + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( e_id , sys.get_tick( ) , 'ALLIANCE' , 1 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.alliance_events ( event_id , alliance_id , alliance_tag , req_result ) + VALUES ( evt_id , a_id , a_tag , acc ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates a leadership change event +-- +-- Parameters: +-- a_id Alliance identifier +-- ol_id Previous leader's identifier +-- + +CREATE OR REPLACE FUNCTION events.alliance_lchange_event( a_id INT , ol_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + a_tag TEXT; + al_id INT; + al_name TEXT; + am_id INT; + evt_id BIGINT; +BEGIN + -- Get alliance tag, leader ID and leader name + SELECT INTO a_tag , al_id , al_name a.tag , a.leader_id , n.name + FROM emp.alliances a + INNER JOIN naming.empire_names n ON n.id = a.leader_id + WHERE a.id = a_id; + + -- Notify both members and pending members + FOR am_id IN SELECT empire_id FROM emp.alliance_members + WHERE alliance_id = a_id AND empire_id <> ol_id + LOOP + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( am_id , sys.get_tick( ) , 'ALLIANCE' , 2 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.alliance_events ( event_id , alliance_id , alliance_tag , empire_id , empire_name ) + VALUES ( evt_id , a_id , a_tag , al_id , al_name ); + END LOOP; + +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an alliance kick event +-- +-- Parameters: +-- a_id Alliance identifier +-- ol_id Member being kicked +-- + +CREATE OR REPLACE FUNCTION events.alliance_kick_event( a_id INT , k_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + a_tag TEXT; + al_id INT; + k_name TEXT; + am_id INT; + evt_id BIGINT; +BEGIN + -- Get alliance tag and leader ID + SELECT INTO a_tag , al_id a.tag , a.leader_id + FROM emp.alliances a + INNER JOIN naming.empire_names n ON n.id = a.leader_id + WHERE a.id = a_id; + SELECT INTO k_name name FROM naming.empire_names WHERE id = k_id; + + -- Notify members + FOR am_id IN SELECT empire_id FROM emp.alliance_members + WHERE alliance_id = a_id AND empire_id <> al_id AND NOT is_pending + LOOP + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( am_id , sys.get_tick( ) , 'ALLIANCE' , 3 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.alliance_events ( event_id , alliance_id , alliance_tag , empire_id , empire_name ) + VALUES ( evt_id , a_id , a_tag , k_id , k_name ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an alliance quit event +-- +-- Parameters: +-- a_id Alliance identifier +-- q_id Member quitting the alliance +-- + +CREATE OR REPLACE FUNCTION events.alliance_quit_event( a_id INT , q_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + a_tag TEXT; + q_name TEXT; + am_id INT; + evt_id BIGINT; +BEGIN + -- Get alliance tag and quitter name + SELECT INTO a_tag a.tag FROM emp.alliances a WHERE a.id = a_id; + SELECT INTO q_name name FROM naming.empire_names WHERE id = q_id; + + -- Notify members + FOR am_id IN SELECT empire_id FROM emp.alliance_members + WHERE alliance_id = a_id AND NOT is_pending + LOOP + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( am_id , sys.get_tick( ) , 'ALLIANCE' , 4 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.alliance_events ( event_id , alliance_id , alliance_tag , empire_id , empire_name ) + VALUES ( evt_id , a_id , a_tag , q_id , q_name ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an alliance disband event +-- +-- Parameters: +-- a_id Alliance identifier +-- q_id Member quitting the alliance +-- + +CREATE OR REPLACE FUNCTION events.alliance_disband_event( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + a_tag TEXT; + al_id INT; + am_id INT; + evt_id BIGINT; +BEGIN + -- Get alliance tag and quitter name + SELECT INTO a_tag , al_id a.tag , leader_id FROM emp.alliances a WHERE a.id = a_id; + + -- Notify members + FOR am_id IN SELECT empire_id FROM emp.alliance_members + WHERE alliance_id = a_id AND empire_id <> al_id + LOOP + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( am_id , sys.get_tick( ) , 'ALLIANCE' , 5 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.alliance_events ( event_id , alliance_id , alliance_tag ) + VALUES ( evt_id , a_id , a_tag ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates empty build queue events or updates existing ones +-- +-- Parameters: +-- e_id Empire identifier +-- p_id Planet identifier +-- mqueue Whether the empty queue is the military or civilian queue +-- c_tick Current tick +-- + +CREATE OR REPLACE FUNCTION events.empty_queue_events( e_id INT , p_id INT , mqueue BOOLEAN , c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + evt_st INT; + evt_id BIGINT; + p_name TEXT; +BEGIN + evt_st := ( CASE WHEN mqueue THEN 1 ELSE 0 END ); + SELECT INTO evt_id event_id FROM events.events + WHERE evt_type = 'QUEUE' AND evt_subtype = evt_st + AND empire_id = e_id AND tick = c_tick; + + IF NOT FOUND + THEN + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( e_id , c_tick , 'QUEUE' , evt_st , 'TICK' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.queue_events VALUES ( evt_id ); + END IF; + + SELECT INTO p_name name FROM naming.map_names WHERE id = p_id; + INSERT INTO events.bqe_locations VALUES ( evt_id , p_id , p_name ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Commits fleet arrival events from the "fleet_arrivals" temporary table +-- +-- Parameters: +-- c_tick Current tick identifier +-- + +CREATE OR REPLACE FUNCTION events.commit_fleet_arrivals( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + l_id INT; + l_name TEXT; + tg_id INT; + tg_mode BOOLEAN; + evt_id BIGINT; +BEGIN + FOR l_id , l_name , tg_id , tg_mode + IN SELECT DISTINCT a.loc_id , a.loc_name , l.empire , l.attacking + FROM fleet_arrivals a + INNER JOIN fleets.locations_list_view l ON l.location = a.loc_id + LOOP + -- Create event record + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( tg_id , c_tick , 'FLEETS' , 0 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.fleets_events( event_id , location_id , location_name ) + VALUES ( evt_id , l_id , l_name ); + + -- List fleets + INSERT INTO events.fleet_lists ( event_id , owner_id , owner_name , fleet_name , fleet_power , status , source_id , source_name ) + SELECT evt_id , a.own_id , a.own_name , a.name , a.power , ( CASE + WHEN tg_id = a.own_id + THEN tg_mode + ELSE + ( tg_mode <> a.mode ) + END ) , a.src_id , a.src_name + FROM fleet_arrivals a + WHERE loc_id = l_id + ORDER BY ( a.own_id = tg_id ) DESC , a.mode , own_name , name NULLS LAST; + END LOOP; + DROP TABLE fleet_arrivals; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Commits fleet departure events from the "fleet_departures" temporary table +-- + +CREATE OR REPLACE FUNCTION events.commit_fleet_departures( ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + l_id INT; + l_name TEXT; + tg_id INT; + tg_mode BOOLEAN; + evt_id BIGINT; + c_tick BIGINT; +BEGIN + c_tick := sys.get_tick( ); + FOR l_id , l_name , tg_id , tg_mode + IN SELECT DISTINCT a.loc_id , a.loc_name , l.empire , l.attacking + FROM fleet_departures a + INNER JOIN fleets.locations_list_view l + ON l.location = a.loc_id AND l.empire <> a.own_id + LOOP + -- Create event record + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( tg_id , c_tick , 'FLEETS' , 1 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.fleets_events( event_id , location_id , location_name ) + VALUES ( evt_id , l_id , l_name ); + + -- List fleets + INSERT INTO events.fleet_lists ( event_id , owner_id , owner_name , fleet_name , fleet_power , status ) + SELECT evt_id , a.own_id , a.own_name , a.name , a.power , ( tg_mode <> a.mode ) + FROM fleet_departures a + WHERE loc_id = l_id AND own_id <> tg_id + ORDER BY a.mode , own_name , name NULLS LAST; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Commits fleet mode change events from the "fleet_switches" temporary table +-- +-- Parameters: +-- els Whether the switch was caused through the enemy list +-- + +CREATE OR REPLACE FUNCTION events.commit_fleet_switches( els BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + l_id INT; + l_name TEXT; + tg_id INT; + tg_mode BOOLEAN; + evt_id BIGINT; + c_tick BIGINT; + own_c BIGINT; + other_c BIGINT; +BEGIN + c_tick := sys.get_tick( ); + FOR l_id , l_name , tg_id , tg_mode + IN SELECT DISTINCT a.loc_id , a.loc_name , l.empire , l.attacking + FROM fleet_switches a + INNER JOIN fleets.locations_list_view l + ON l.location = a.loc_id + LOOP + -- Handle other fleets + SELECT INTO other_c count(*) FROM fleet_switches WHERE loc_id = l_id AND own_id <> tg_id; + IF other_c > 0 + THEN + -- Create event record + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( tg_id , c_tick , 'FLEETS' , 2 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.fleets_events( event_id , location_id , location_name ) + VALUES ( evt_id , l_id , l_name ); + + -- List fleets + INSERT INTO events.fleet_lists ( event_id , owner_id , owner_name , fleet_name , fleet_power , status ) + SELECT evt_id , a.own_id , a.own_name , a.name , a.power , a.mode + FROM fleet_switches a + WHERE loc_id = l_id AND own_id <> tg_id + ORDER BY a.mode , own_name , name NULLS LAST; + END IF; + + -- Handle own fleets + CONTINUE WHEN NOT els; + SELECT INTO own_c count(*) FROM fleet_switches WHERE loc_id = l_id AND own_id = tg_id; + CONTINUE WHEN own_c = 0; + + -- Create event record + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( tg_id , c_tick , 'FLEETS' , 3 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.fleets_events( event_id , location_id , location_name ) + VALUES ( evt_id , l_id , l_name ); + + -- List fleets + INSERT INTO events.fleet_lists ( event_id , owner_id , owner_name , fleet_name , fleet_power , status ) + SELECT evt_id , a.own_id , a.own_name , a.name , a.power , a.mode + FROM fleet_switches a + WHERE loc_id = l_id AND own_id = tg_id + ORDER BY a.mode , own_name , name NULLS LAST; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates a map name rejection event +-- +-- Parameters: +-- u_id Account identifier +-- n_id Name identifier +-- o_name Old name +-- n_name New name +-- w_sent Whether a warning was sent +-- w_count Current warnings +-- + +CREATE OR REPLACE FUNCTION events.map_name_rejected_event( u_id INT , n_id INT , o_name TEXT , n_name TEXT , w_sent BOOLEAN , w_count INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + e_id INT; + evt_id BIGINT; +BEGIN + -- Get empire identifier + SELECT INTO e_id e.name_id + FROM emp.empires e + INNER JOIN naming.empire_names en ON en.id = e.name_id + WHERE en.owner_id = u_id; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Add event + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( e_id , sys.get_tick( ) - 1 , 'ADMIN' , 0 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.admin_events( event_id , n_warnings , location_id , old_name , new_name ) + VALUES( evt_id , ( CASE WHEN w_sent THEN w_count ELSE NULL END ) , n_id , o_name , n_name ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an empire name rejection event +-- +-- Parameters: +-- n_id Name identifier +-- o_name Old name +-- n_name New name +-- w_sent Whether a warning was sent +-- w_count Current warnings +-- + +CREATE OR REPLACE FUNCTION events.empire_name_rejected_event( n_id INT , o_name TEXT , n_name TEXT , w_sent BOOLEAN , w_count INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + evt_id BIGINT; +BEGIN + -- Add event + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( n_id , sys.get_tick( ) - 1 , 'ADMIN' , 1 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.admin_events( event_id , n_warnings ,old_name , new_name ) + VALUES( evt_id , ( CASE WHEN w_sent THEN w_count ELSE NULL END ) , o_name , n_name ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates an alliance name rejection event +-- +-- Parameters: +-- n_id Empire identifier +-- o_name Alliance name +-- w_sent Whether a warning was sent +-- w_count Current warnings +-- + +CREATE OR REPLACE FUNCTION events.alliance_name_rejected_event( n_id INT , o_name TEXT , w_sent BOOLEAN , w_count INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + evt_id BIGINT; +BEGIN + -- Add event + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( n_id , sys.get_tick( ) - 1 , 'ADMIN' , 2 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.admin_events( event_id , n_warnings , old_name ) + VALUES( evt_id , ( CASE WHEN w_sent THEN w_count ELSE NULL END ) , o_name ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates events for updated bug reports +-- +-- Parameters: +-- e_id Empire identifier +-- br_id Bug report identifier +-- s_id Submitter identifier +-- + +CREATE OR REPLACE FUNCTION events.bug_report_updated_event( e_id INT , br_id BIGINT , s_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + evt_id BIGINT; +BEGIN + INSERT INTO events.events ( empire_id , tick , evt_type , evt_subtype , status ) + VALUES ( e_id , sys.get_tick( ) - 1 , 'BUGS' , 0 , 'READY' ) + RETURNING event_id INTO evt_id; + INSERT INTO events.bug_events( event_id , bug_id , submitter_id ) + VALUES ( evt_id , br_id , s_id ); +END; +$$ LANGUAGE plpgsql; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- EVENTS VIEWS, USED BY THE MESSAGE SYSTEM -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Main events lists +-- + +CREATE VIEW events.queue_events_view + AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , ed.* + FROM events.events e + INNER JOIN events.queue_events ed USING (event_id); + +GRANT SELECT ON events.queue_events_view TO :dbuser; + + +CREATE VIEW events.empire_events_view + AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , s.name AS technology + FROM events.events e + LEFT OUTER JOIN events.empire_events ed USING (event_id) + LEFT OUTER JOIN tech.levels tl ON tl.id = ed.technology_id + LEFT OUTER JOIN defs.strings s ON s.id = tl.name_id + WHERE e.evt_type = 'EMPIRE'; + +GRANT SELECT ON events.empire_events_view TO :dbuser; + + +CREATE VIEW events.fleets_events_view + AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , + ed.* , s.x , s.y , p.orbit + FROM events.events e + INNER JOIN events.fleets_events ed USING (event_id) + INNER JOIN verse.planets p ON p.name_id = ed.location_id + INNER JOIN verse.systems s ON s.id = p.system_id; + +GRANT SELECT ON events.fleets_events_view TO :dbuser; + + +CREATE VIEW events.planet_events_view + AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , + ed.* , s.x , s.y , p.orbit + FROM events.events e + INNER JOIN events.planet_events ed USING (event_id) + INNER JOIN verse.planets p ON p.name_id = ed.location_id + INNER JOIN verse.systems s ON s.id = p.system_id; + +GRANT SELECT ON events.planet_events_view TO :dbuser; + + +CREATE VIEW events.alliance_events_view + AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , ed.* + FROM events.events e + INNER JOIN events.alliance_events ed USING (event_id); + +GRANT SELECT ON events.alliance_events_view TO :dbuser; + + +CREATE VIEW events.admin_events_view + AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , ed.* + FROM events.events e + INNER JOIN events.admin_events ed USING ( event_id ); + +GRANT SELECT ON events.admin_events_view TO :dbuser; + + +CREATE VIEW events.bugs_events_view + AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , ed.bug_id , + bs.is_admin AS submitter_admin , bs.name AS submitter_name + FROM events.events e + INNER JOIN events.bug_events ed USING ( event_id ) + INNER JOIN bugs.submitters bs USING ( submitter_id ); + +GRANT SELECT ON events.bugs_events_view TO :dbuser; + + +-- +-- Queue event locations +-- + +CREATE VIEW events.queue_locations_view + AS SELECT bqe.* , s.x , s.y , p.orbit + FROM events.bqe_locations bqe + INNER JOIN verse.planets p ON p.name_id = bqe.location_id + INNER JOIN verse.systems s ON s.id = p.system_id; + +GRANT SELECT ON events.queue_locations_view TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/180-messages-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/180-messages-functions.sql new file mode 100644 index 0000000..e7319b0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/180-messages-functions.sql @@ -0,0 +1,1277 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Functions and views to handle messages +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- INTERNAL FUNCTIONS THAT HANDLE SENDING MESSAGES -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + +-- +-- Creates or retrieves a sender record +-- +-- Parameters: +-- r_type Sender type +-- r_id Sender identifier +-- + +CREATE OR REPLACE FUNCTION msgs.goc_sender( s_type sender_type , s_id INT ) + RETURNS BIGINT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + snd_id BIGINT; + s_name TEXT; +BEGIN + LOOP + SELECT INTO snd_id id FROM msgs.senders + WHERE ( CASE s_type + WHEN 'EMP' THEN + empire_id = s_id + ELSE + admin_id = s_id + END ); + EXIT WHEN FOUND; + + BEGIN + IF s_type = 'EMP' + THEN + SELECT INTO s_name name FROM naming.empire_names + WHERE id = s_id; + INSERT INTO msgs.senders( sender_type , name , empire_id ) + VALUES ( s_type , s_name , s_id ) + RETURNING id INTO snd_id; + ELSE + SELECT INTO s_name appear_as FROM admin.administrators + WHERE id = s_id; + INSERT INTO msgs.senders( sender_type , name , admin_id ) + VALUES ( s_type , s_name , s_id ) + RETURNING id INTO snd_id; + END IF; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + RETURN snd_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Creates or retrieves a receiver record +-- +-- Parameters: +-- r_type Receiver type +-- r_id Receiver identifier +-- + +CREATE OR REPLACE FUNCTION msgs.goc_receiver( r_type receiver_type , r_id INT ) + RETURNS BIGINT + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec_id BIGINT; + r_name TEXT; +BEGIN + LOOP + SELECT INTO rec_id id FROM msgs.receivers + WHERE ( CASE r_type + WHEN 'EMP' THEN + empire_id = r_id + WHEN 'ADM' THEN + admin_id = r_id + ELSE + alliance_id = r_id + END ); + EXIT WHEN FOUND; + + BEGIN + IF r_type = 'EMP' + THEN + SELECT INTO r_name name FROM naming.empire_names + WHERE id = r_id; + INSERT INTO msgs.receivers( receiver_type , name , empire_id ) + VALUES ( r_type , r_name , r_id ) + RETURNING id INTO rec_id; + ELSEIF r_type = 'ADM' + THEN + SELECT INTO r_name appear_as FROM admin.administrators + WHERE id = r_id; + INSERT INTO msgs.receivers( receiver_type , name , admin_id ) + VALUES ( r_type , r_name , r_id ) + RETURNING id INTO rec_id; + ELSE + SELECT INTO r_name tag FROM emp.alliances + WHERE id = r_id; + INSERT INTO msgs.receivers( receiver_type , name , alliance_id ) + VALUES ( r_type , r_name , r_id ) + RETURNING id INTO rec_id; + END IF; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + RETURN rec_id; +END; +$$ LANGUAGE plpgsql; + + +-- +-- Stores a message in an empire's message box +-- +-- Parameters: +-- e_id Empire identifier +-- m_id Message identifier +-- received Whether the message is to be delivered in the inbox or in the outbox +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_to_empire( e_id INT , m_id BIGINT , received BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER +AS $$ + INSERT INTO msgs.empire_delivery ( empire_id , message_id , in_inbox , status , emailed , recaped ) + VALUES ( $1 , $2 , $3 , ( CASE WHEN $3 THEN 'UNREAD' ELSE 'READ' END )::message_status , NOT $3 , NOT $3 ); +$$ LANGUAGE SQL; + + + +-- +-- Stores a message in an administrator's message box +-- +-- Parameters: +-- a_id Administrator identifier +-- m_id Message identifier +-- received Whether the message is to be delivered in the inbox or in the outbox +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_to_admin( a_id INT , m_id BIGINT , received BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER +AS $$ + INSERT INTO msgs.admin_delivery ( admin_id , message_id , in_inbox , status , emailed ) + VALUES ( $1 , $2 , $3 , ( CASE WHEN $3 THEN 'UNREAD' ELSE 'READ' END )::message_status , NOT $3 ); +$$ LANGUAGE SQL; + + + +-- +-- Deliver new internal messages to an empire +-- +-- Parameters: +-- e_id Empire identifier +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_internal( e_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec_id BIGINT; + evt_id BIGINT; + msg_id BIGINT; + max_id BIGINT; +BEGIN + rec_id := msgs.goc_receiver( 'EMP'::receiver_type , e_id ); + max_id := 0; + FOR evt_id IN SELECT event_id FROM events.events + WHERE empire_id = e_id AND status = 'READY' + FOR UPDATE + LOOP + INSERT INTO msgs.messages ( receiver_id , event_content_id ) + VALUES ( rec_id , evt_id ) + RETURNING id INTO msg_id; + PERFORM msgs.deliver_to_empire( e_id , msg_id , TRUE ); + CONTINUE WHEN max_id > evt_id; + max_id := evt_id; + END LOOP; + UPDATE events.events SET status = 'SENT' + WHERE empire_id = e_id AND status = 'READY' AND event_id <= max_id; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Deliver pending internal messages +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_internal( ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + e_id INT; +BEGIN + FOR e_id IN SELECT DISTINCT empire_id FROM events.events + WHERE status = 'READY' + LOOP + PERFORM msgs.deliver_internal( e_id ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sends a message from an empire to an empire +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_private( se_id INT , de_id INT , ttl_txt TEXT , cnt_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + snd_id BIGINT; + rec_id BIGINT; + tm_id BIGINT; + msg_id BIGINT; +BEGIN + snd_id := msgs.goc_sender( 'EMP'::sender_type , se_id ); + rec_id := msgs.goc_receiver( 'EMP'::receiver_type , de_id ); + + INSERT INTO msgs.text_messages ( tick , title , contents ) + VALUES ( sys.get_tick() - 1 , ttl_txt , cnt_txt ) + RETURNING id INTO tm_id; + INSERT INTO msgs.messages ( sender_id , receiver_id , text_content_id ) + VALUES ( snd_id , rec_id , tm_id ) + RETURNING id INTO msg_id; + PERFORM msgs.deliver_to_empire( de_id , msg_id , TRUE ); + PERFORM msgs.deliver_to_empire( se_id , msg_id , FALSE ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sends a message from an empire to an alliance +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_alliance( se_id INT , da_id INT , ttl_txt TEXT , cnt_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + emp_id INT; + snd_id BIGINT; + rec_id BIGINT; + tm_id BIGINT; + msg_id BIGINT; +BEGIN + snd_id := msgs.goc_sender( 'EMP'::sender_type , se_id ); + rec_id := msgs.goc_receiver( 'ALL'::receiver_type , da_id ); + + INSERT INTO msgs.text_messages ( tick , title , contents ) + VALUES ( sys.get_tick() - 1 , ttl_txt , cnt_txt ) + RETURNING id INTO tm_id; + INSERT INTO msgs.messages ( sender_id , receiver_id , text_content_id ) + VALUES ( snd_id , rec_id , tm_id ) + RETURNING id INTO msg_id; + + SELECT INTO emp_id alliance_id FROM emp.alliance_members WHERE empire_id = se_id AND NOT is_pending; + IF FOUND AND emp_id = da_id + THEN + FOR emp_id IN SELECT empire_id FROM emp.alliance_members + WHERE empire_id <> se_id AND NOT is_pending + AND alliance_id = da_id + LOOP + PERFORM msgs.deliver_to_empire( emp_id , msg_id , TRUE ); + END LOOP; + ELSE + SELECT INTO emp_id leader_id FROM emp.alliances WHERE id = da_id; + PERFORM msgs.deliver_to_empire( emp_id , msg_id , TRUE ); + END IF; + PERFORM msgs.deliver_to_empire( se_id , msg_id , FALSE ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sends a message from an empire to an administrator +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_toadmin( se_id INT , da_id INT , ttl_txt TEXT , cnt_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + snd_id BIGINT; + rec_id BIGINT; + tm_id BIGINT; + msg_id BIGINT; +BEGIN + snd_id := msgs.goc_sender( 'EMP'::sender_type , se_id ); + rec_id := msgs.goc_receiver( 'ADM'::receiver_type , da_id ); + + INSERT INTO msgs.text_messages ( tick , title , contents ) + VALUES ( sys.get_tick() - 1 , ttl_txt , cnt_txt ) + RETURNING id INTO tm_id; + INSERT INTO msgs.messages ( sender_id , receiver_id , text_content_id ) + VALUES ( snd_id , rec_id , tm_id ) + RETURNING id INTO msg_id; + PERFORM msgs.deliver_to_admin( da_id , msg_id , TRUE ); + PERFORM msgs.deliver_to_empire( se_id , msg_id , FALSE ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sends a message from an administrator to an empire +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_admin_toempire( sa_id INT , de_id INT , ttl_txt TEXT , cnt_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + snd_id BIGINT; + rec_id BIGINT; + tm_id BIGINT; + msg_id BIGINT; +BEGIN + snd_id := msgs.goc_sender( 'ADM'::sender_type , sa_id ); + rec_id := msgs.goc_receiver( 'EMP'::receiver_type , de_id ); + + INSERT INTO msgs.text_messages ( tick , title , contents ) + VALUES ( sys.get_tick() - 1 , ttl_txt , cnt_txt ) + RETURNING id INTO tm_id; + INSERT INTO msgs.messages ( sender_id , receiver_id , text_content_id ) + VALUES ( snd_id , rec_id , tm_id ) + RETURNING id INTO msg_id; + PERFORM msgs.deliver_to_empire( de_id , msg_id , TRUE ); + PERFORM msgs.deliver_to_admin( sa_id , msg_id , FALSE ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sends a message from an administrator to an administrator +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_admin_toadmin( sa_id INT , da_id INT , ttl_txt TEXT , cnt_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + snd_id BIGINT; + rec_id BIGINT; + tm_id BIGINT; + msg_id BIGINT; +BEGIN + snd_id := msgs.goc_sender( 'ADM'::sender_type , sa_id ); + rec_id := msgs.goc_receiver( 'ADM'::receiver_type , da_id ); + + INSERT INTO msgs.text_messages ( tick , title , contents ) + VALUES ( sys.get_tick() - 1 , ttl_txt , cnt_txt ) + RETURNING id INTO tm_id; + INSERT INTO msgs.messages ( sender_id , receiver_id , text_content_id ) + VALUES ( snd_id , rec_id , tm_id ) + RETURNING id INTO msg_id; + PERFORM msgs.deliver_to_admin( da_id , msg_id , TRUE ); + PERFORM msgs.deliver_to_admin( sa_id , msg_id , FALSE ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sends a message from an administrator to all empires +-- + +CREATE OR REPLACE FUNCTION msgs.deliver_admin_spam( sa_id INT , ttl_txt TEXT , cnt_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + de_id INT; + snd_id BIGINT; + rec_id BIGINT; + tm_id BIGINT; + msg_id BIGINT; +BEGIN + PERFORM admin.write_log( sa_id , 'INFO'::log_level , 'Sending spam "' || ttl_txt || '"' ); + + snd_id := msgs.goc_sender( 'ADM'::sender_type , sa_id ); + INSERT INTO msgs.text_messages ( tick , title , contents ) + VALUES ( sys.get_tick() - 1 , ttl_txt , cnt_txt ) + RETURNING id INTO tm_id; + + FOR de_id IN SELECT name_id FROM emp.empires + LOOP + rec_id := msgs.goc_receiver( 'EMP'::receiver_type , de_id ); + INSERT INTO msgs.messages ( sender_id , receiver_id , text_content_id ) + VALUES ( snd_id , rec_id , tm_id ) + RETURNING id INTO msg_id; + PERFORM msgs.deliver_to_empire( de_id , msg_id , TRUE ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION msgs.deliver_admin_spam( INT , TEXT , TEXT ) TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- EMPIRE MESSAGE BOX AND MESSAGE SENDER -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + +-- +-- Empire inbox +-- + +CREATE VIEW msgs.empire_inbox + AS SELECT db.id , db.empire_id , ( db.status = 'READ' ) AS read , + ( CASE + WHEN s.id IS NULL + THEN 'INT' + ELSE s.sender_type::TEXT + END ) AS sender_type , + ( CASE + WHEN s.id IS NULL + THEN NULL::INT + WHEN s.sender_type = 'EMP' + THEN s.empire_id + ELSE s.admin_id + END ) AS sender_id , + s.name AS sender_name , r.receiver_type , + ( CASE + WHEN r.receiver_type = 'EMP' + THEN r.empire_id + WHEN r.receiver_type = 'ALL' + THEN r.alliance_id + ELSE r.admin_id + END ) AS receiver_id , r.name AS receiver_name , + ( tm.id IS NULL ) AS internal_message , + ( CASE + WHEN tm.id IS NULL + THEN evt.event_id + ELSE tm.id + END ) AS content_id , + ( CASE + WHEN tm.id IS NULL + THEN evt.real_time + ELSE tm.t + END ) AS r_time + FROM msgs.empire_delivery db + INNER JOIN msgs.messages m ON m.id = db.message_id + INNER JOIN msgs.receivers r ON r.id = m.receiver_id + LEFT OUTER JOIN msgs.senders s ON m.sender_id = s.id + LEFT OUTER JOIN events.events evt ON evt.event_id = m.event_content_id + LEFT OUTER JOIN msgs.text_messages tm ON tm.id = m.text_content_id + WHERE db.in_inbox AND db.status <> 'DELETED' + ORDER BY ( CASE + WHEN tm.id IS NULL + THEN evt.real_time + ELSE tm.t + END ) DESC; + +GRANT SELECT ON msgs.empire_inbox TO :dbuser; + + +-- +-- Empire outbox +-- + +CREATE VIEW msgs.empire_outbox + AS SELECT db.id , db.empire_id , TRUE AS read , + 'EMP'::TEXT AS sender_type , db.empire_id AS sender_id , en.name AS sender_name , + r.receiver_type , + ( CASE + WHEN r.receiver_type = 'EMP' + THEN r.empire_id + WHEN r.receiver_type = 'ALL' + THEN r.alliance_id + ELSE r.admin_id + END ) AS receiver_id , r.name AS receiver_name , + FALSE AS internal_message , + tm.id AS content_id , tm.t AS r_time + FROM msgs.empire_delivery db + INNER JOIN msgs.messages m ON m.id = db.message_id + INNER JOIN msgs.receivers r ON r.id = m.receiver_id + INNER JOIN msgs.text_messages tm ON tm.id = m.text_content_id + INNER JOIN naming.empire_names en ON en.id = db.empire_id + WHERE NOT db.in_inbox AND db.status <> 'DELETED' + ORDER BY tm.t DESC; + +GRANT SELECT ON msgs.empire_outbox TO :dbuser; + + +-- +-- Sends a message from an empire to a target +-- +-- Parameters: +-- e_id Empire sending a message +-- to_type Type of message target (empire, alliance or admin) +-- to_name Name of the message target +-- ttl_txt Title of the message +-- cnt_txt Contents of the message +-- do_send Whether the message should actually be sent (used to verify target existence) +-- +-- Returns: +-- err_code Error code: +-- 0 success +-- 1 unknown target +-- 2 too soon +-- + +CREATE OR REPLACE FUNCTION msgs.send_message( e_id INT , to_type receiver_type , to_name TEXT , ttl_txt TEXT , + cnt_txt TEXT , do_send BOOLEAN , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + tg_id INT; + s_meth TEXT; +BEGIN + -- Find target and sending method + IF to_type = 'ADM' + THEN + s_meth := 'toadmin'; + SELECT INTO tg_id id FROM admin.administrators + WHERE lower( appear_as ) = lower( to_name ); + ELSEIF to_type = 'EMP' + THEN + s_meth := 'private'; + SELECT INTO tg_id id FROM naming.empire_names n + INNER JOIN emp.empires e ON e.name_id = n.id + WHERE lower( name ) = lower( to_name ); + ELSE + s_meth := 'alliance'; + SELECT INTO tg_id id FROM emp.alliances + WHERE lower( tag ) = lower( to_name ); + END IF; + IF NOT FOUND + THEN + err_code := 1; + RETURN; + END IF; + + -- Check last message sent by this empire + PERFORM r_time FROM msgs.empire_outbox WHERE empire_id = e_id AND r_time > now() - '20s'::INTERVAL; + IF FOUND + THEN + err_code := 2; + RETURN; + END IF; + + -- Send message (or not) + IF do_send + THEN + PERFORM sys.write_log( 'Messages' , 'DEBUG'::log_level , 'Delivering message from empire #' || e_id + || ' using method ' || s_meth || ' with target identifier ' || tg_id || ' (title text null? ' + || ( ttl_txt IS NULL ) || ' ; content text null? ' || (cnt_txt IS NULL) || ')' ); + EXECUTE 'SELECT msgs.deliver_' || s_meth || '( $1 , $2 , $3 , $4 )' + USING e_id , tg_id , ttl_txt , cnt_txt; + ELSE + PERFORM sys.write_log( 'Messages' , 'DEBUG'::log_level , 'Simulated message delivery from empire #' || e_id + || ' using method ' || s_meth || ' with target identifier ' || tg_id || ' (title text null? ' + || ( ttl_txt IS NULL ) || ' ; content text null? ' || (cnt_txt IS NULL) || ')' ); + END IF; + err_code := 0; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION msgs.send_message( INT , receiver_type , TEXT , TEXT , TEXT , BOOLEAN ) TO :dbuser; + + + +-- +-- Marks specific messages as read in an empire's inbox +-- +-- Parameters: +-- e_id Empire identifier +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.empire_mark_read( e_id INT , m_ids BIGINT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.empire_delivery + SET status = 'READ' + WHERE empire_id = $1 AND status = 'UNREAD' AND id = ANY( $2 ) AND in_inbox +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.empire_mark_read( INT , BIGINT[] ) TO :dbuser; + + + +-- +-- Marks all messages as read in an empire's inbox +-- +-- Parameters: +-- e_id Empire identifier +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.empire_mark_read( e_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.empire_delivery + SET status = 'READ' + WHERE empire_id = $1 AND status = 'UNREAD' AND in_inbox +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.empire_mark_read( INT ) TO :dbuser; + + + +-- +-- Marks specific messages as unread in an empire's inbox +-- +-- Parameters: +-- e_id Empire identifier +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.empire_mark_unread( e_id INT , m_ids BIGINT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.empire_delivery + SET status = 'UNREAD' + WHERE empire_id = $1 AND status = 'READ' AND id = ANY( $2 ) AND in_inbox +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.empire_mark_unread( INT , BIGINT[] ) TO :dbuser; + + + +-- +-- Marks all messages as unread in an empire's inbox +-- +-- Parameters: +-- e_id Empire identifier +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.empire_mark_unread( e_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.empire_delivery + SET status = 'UNREAD' + WHERE empire_id = $1 AND status = 'READ' AND in_inbox +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.empire_mark_unread( INT ) TO :dbuser; + + + +-- +-- Marks specific messages as deleted in an empire's inbox or outbox +-- +-- Parameters: +-- e_id Empire identifier +-- inbox Whether the affected messages are in the empire's inbox or in its outbox +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.empire_delete( e_id INT , inbox BOOLEAN , m_ids BIGINT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.empire_delivery + SET status = 'DELETED' + WHERE empire_id = $1 AND status <> 'DELETED' AND id = ANY( $3 ) AND in_inbox = $2 +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.empire_delete( INT , BOOLEAN , BIGINT[] ) TO :dbuser; + + + +-- +-- Marks all messages as deleted in an empire's inbox or outbox +-- +-- Parameters: +-- e_id Empire identifier +-- inbox Whether the affected messages are in the empire's inbox or in its outbox +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.empire_delete( e_id INT , inbox BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.empire_delivery + SET status = 'DELETED' + WHERE empire_id = $1 AND status <> 'DELETED' AND in_inbox = $2 +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.empire_delete( INT , BOOLEAN ) TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- ADMINISTRATOR MESSAGE BOX AND MESSAGE SENDER -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Admin inbox +-- + +CREATE VIEW msgs.admin_inbox + AS SELECT db.id , db.admin_id , ( db.status = 'READ' ) AS read , + s.sender_type::TEXT AS sender_type , + ( CASE + WHEN s.sender_type = 'EMP' + THEN s.empire_id + ELSE s.admin_id + END ) AS sender_id , + s.name AS sender_name , r.receiver_type , + ( CASE + WHEN r.receiver_type = 'EMP' + THEN r.empire_id + ELSE r.admin_id + END ) AS receiver_id , r.name AS receiver_name , + FALSE AS internal_message , + tm.id AS content_id , + tm.t AS r_time + FROM msgs.admin_delivery db + INNER JOIN msgs.messages m ON m.id = db.message_id + INNER JOIN msgs.receivers r ON r.id = m.receiver_id + INNER JOIN msgs.senders s ON m.sender_id = s.id + INNER JOIN msgs.text_messages tm ON tm.id = m.text_content_id + WHERE db.in_inbox AND db.status <> 'DELETED' + ORDER BY tm.t DESC; + +GRANT SELECT ON msgs.admin_inbox TO :dbuser; + + +-- +-- Admin outbox +-- + +CREATE VIEW msgs.admin_outbox + AS SELECT db.id , db.admin_id , TRUE AS read , + 'ADM'::TEXT AS sender_type , db.admin_id AS sender_id , + a.appear_as AS sender_name , r.receiver_type , + ( CASE + WHEN r.receiver_type = 'EMP' + THEN r.empire_id + ELSE r.admin_id + END ) AS receiver_id , r.name AS receiver_name , + FALSE AS internal_message , + tm.id AS content_id , + tm.t AS r_time + FROM msgs.admin_delivery db + INNER JOIN admin.administrators a ON a.id = db.admin_id + INNER JOIN msgs.messages m ON m.id = db.message_id + INNER JOIN msgs.receivers r ON r.id = m.receiver_id + INNER JOIN msgs.text_messages tm ON tm.id = m.text_content_id + WHERE NOT db.in_inbox AND db.status <> 'DELETED' + ORDER BY tm.t DESC; + +GRANT SELECT ON msgs.admin_outbox TO :dbuser; + + + +-- +-- Sends a message from an administrator to a target +-- +-- Parameters: +-- a_id Administrator sending a message +-- to_type Type of message target (empire or admin) +-- to_name Name of the message target +-- ttl_txt Title of the message +-- cnt_txt Contents of the message +-- do_send Whether the message should actually be sent (used to verify target existence) +-- +-- Returns: +-- err_code Error code: +-- 0 success +-- 1 unknown target +-- + +CREATE OR REPLACE FUNCTION msgs.send_admin_message( a_id INT , to_type receiver_type , to_name TEXT , ttl_txt TEXT , + cnt_txt TEXT , do_send BOOLEAN , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + tg_id INT; + s_meth TEXT; +BEGIN + -- Find target and sending method + IF to_type = 'ADM' + THEN + s_meth := 'toadmin'; + SELECT INTO tg_id id FROM admin.administrators + WHERE lower( appear_as ) = lower( to_name ); + ELSEIF to_type = 'EMP' + THEN + s_meth := 'toempire'; + SELECT INTO tg_id id FROM naming.empire_names n + INNER JOIN emp.empires e ON e.name_id = n.id + WHERE lower( name ) = lower( to_name ); + ELSE + err_code := 1; + RETURN; + END IF; + IF NOT FOUND + THEN + err_code := 1; + RETURN; + ELSEIF to_type = 'EMP' AND do_send + THEN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Sending message "' || ttl_txt + || '" to empire #' || tg_id || ' ("' || to_name || '")' ); + END IF; + + -- Send message (or not) + IF do_send + THEN + PERFORM sys.write_log( 'Messages' , 'DEBUG'::log_level , 'Delivering message from admin #' || a_id + || ' using method ' || s_meth || ' with target identifier ' || tg_id || ' (title text null? ' + || ( ttl_txt IS NULL ) || ' ; content text null? ' || (cnt_txt IS NULL) || ')' ); + EXECUTE 'SELECT msgs.deliver_admin_' || s_meth || '( $1 , $2 , $3 , $4 )' + USING a_id , tg_id , ttl_txt , cnt_txt; + ELSE + PERFORM sys.write_log( 'Messages' , 'DEBUG'::log_level , 'Simulated message delivery from admin #' || a_id + || ' using method ' || s_meth || ' with target identifier ' || tg_id || ' (title text null? ' + || ( ttl_txt IS NULL ) || ' ; content text null? ' || (cnt_txt IS NULL) || ')' ); + END IF; + err_code := 0; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION msgs.send_admin_message( INT , receiver_type , TEXT , TEXT , TEXT , BOOLEAN ) TO :dbuser; + + + +-- +-- Marks specific messages as read in an admin's inbox +-- +-- Parameters: +-- a_id Admin identifier +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.admin_mark_read( a_id INT , m_ids BIGINT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.admin_delivery + SET status = 'READ' + WHERE admin_id = $1 AND status = 'UNREAD' AND id = ANY( $2 ) AND in_inbox +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.admin_mark_read( INT , BIGINT[] ) TO :dbuser; + + + +-- +-- Marks all messages as read in an admin's inbox +-- +-- Parameters: +-- a_id Admin identifier +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.admin_mark_read( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.admin_delivery + SET status = 'READ' + WHERE admin_id = $1 AND status = 'UNREAD' AND in_inbox +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.admin_mark_read( INT ) TO :dbuser; + + + +-- +-- Marks specific messages as unread in an admin's inbox +-- +-- Parameters: +-- a_id Admin identifier +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.admin_mark_unread( a_id INT , m_ids BIGINT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.admin_delivery + SET status = 'UNREAD' + WHERE admin_id = $1 AND status = 'READ' AND id = ANY( $2 ) AND in_inbox +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.admin_mark_unread( INT , BIGINT[] ) TO :dbuser; + + + +-- +-- Marks all messages as unread in an admin's inbox +-- +-- Parameters: +-- a_id Admin identifier +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.admin_mark_unread( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.admin_delivery + SET status = 'UNREAD' + WHERE admin_id = $1 AND status = 'READ' AND in_inbox +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.admin_mark_unread( INT ) TO :dbuser; + + + +-- +-- Marks specific messages as deleted in an admin's inbox or outbox +-- +-- Parameters: +-- a_id Admin identifier +-- inbox Whether the affected messages are in the admin's inbox or in its outbox +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.admin_delete( a_id INT , inbox BOOLEAN , m_ids BIGINT[] ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.admin_delivery + SET status = 'DELETED' + WHERE admin_id = $1 AND status <> 'DELETED' AND id = ANY( $3 ) AND in_inbox = $2 +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.admin_delete( INT , BOOLEAN , BIGINT[] ) TO :dbuser; + + + +-- +-- Marks all messages as deleted in an admin's inbox or outbox +-- +-- Parameters: +-- e_id Admin identifier +-- inbox Whether the affected messages are in the admin's inbox or in its outbox +-- m_ids Message identifiers +-- + +CREATE OR REPLACE FUNCTION msgs.admin_delete( e_id INT , inbox BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.admin_delivery + SET status = 'DELETED' + WHERE admin_id = $1 AND status <> 'DELETED' AND in_inbox = $2 +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.admin_delete( INT , BOOLEAN ) TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- VIEWS/FUNCTIONS USED BY THE E-MAIL NOTIFICATIONS / RECAP SYSTEM -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- General mailing information +-- + +CREATE VIEW msgs.last_unmailed_view + AS SELECT empire_id AS empire , max( id ) AS message + FROM msgs.empire_delivery + WHERE NOT emailed + GROUP BY empire_id; + +CREATE VIEW msgs.last_unrecaped_view + AS SELECT empire_id AS empire , max( id ) AS message + FROM msgs.empire_delivery + WHERE NOT recaped + GROUP BY empire_id; + +CREATE VIEW msgs.mail_sender_view + AS SELECT e.name_id AS empire , en.name AS empire_name , + lang.language AS language , addr.address AS address , + pprv.value AS on_private , pall.value AS on_alliance , + pint.value AS on_internal , padm.value AS on_admin , + lum.message AS last_unmailed , lrm.message AS last_unrecaped , + ( emn.account_id IS NULL ) AS can_notify + FROM emp.empires e + LEFT OUTER JOIN msgs.last_unmailed_view lum + ON lum.empire = e.name_id + LEFT OUTER JOIN msgs.last_unrecaped_view lrm + ON lrm.empire = e.name_id + INNER JOIN naming.empire_names en ON en.id = e.name_id + INNER JOIN users.credentials cred ON cred.address_id = en.owner_id + INNER JOIN defs.languages lang ON lang.id = cred.language_id + INNER JOIN users.addresses addr ON addr.id = cred.address_id + INNER JOIN users.preferences_view pprv + ON pprv.account_id = addr.id AND pprv.pref_name = 'mailOnPM' + INNER JOIN users.preferences_view pall + ON pall.account_id = addr.id AND pall.pref_name = 'mailOnAlliance' + INNER JOIN users.preferences_view pint + ON pint.account_id = addr.id AND pint.pref_name = 'mailOnIM' + INNER JOIN users.preferences_view padm + ON padm.account_id = addr.id AND padm.pref_name = 'mailOnAdmin' + LEFT OUTER JOIN msgs.email_notifications emn + ON emn.account_id = addr.id; + + +CREATE OR REPLACE FUNCTION msgs.get_mail_data( ) + RETURNS SETOF msgs.mail_sender_view + STRICT VOLATILE + SECURITY DEFINER +AS $$ + DELETE FROM msgs.email_notifications + WHERE now() - last_sent >= '1h'::interval; + SELECT * FROM msgs.mail_sender_view; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.get_mail_data( ) TO :dbuser; + + +-- +-- Instant notifications view and update function +-- + +CREATE VIEW msgs.empire_instant + AS SELECT db.id , db.empire_id , + ( CASE + WHEN s.id IS NULL + THEN 'INT' + ELSE s.sender_type::TEXT + END ) AS sender_type , + ( CASE + WHEN s.id IS NULL + THEN NULL::INT + WHEN s.sender_type = 'EMP' + THEN s.empire_id + ELSE s.admin_id + END ) AS sender_id , + s.name AS sender_name , r.receiver_type , + ( CASE + WHEN r.receiver_type = 'EMP' + THEN r.empire_id + WHEN r.receiver_type = 'ALL' + THEN r.alliance_id + ELSE r.admin_id + END ) AS receiver_id , r.name AS receiver_name , + ( tm.id IS NULL ) AS internal_message , + ( CASE + WHEN tm.id IS NULL + THEN evt.event_id + ELSE tm.id + END ) AS content_id , + ( CASE + WHEN tm.id IS NULL + THEN evt.real_time + ELSE tm.t + END ) AS r_time + FROM msgs.empire_delivery db + INNER JOIN msgs.messages m ON m.id = db.message_id + INNER JOIN msgs.receivers r ON r.id = m.receiver_id + LEFT OUTER JOIN msgs.senders s ON m.sender_id = s.id + LEFT OUTER JOIN events.events evt ON evt.event_id = m.event_content_id + LEFT OUTER JOIN msgs.text_messages tm ON tm.id = m.text_content_id + WHERE db.in_inbox AND db.status = 'UNREAD' AND NOT db.emailed + ORDER BY ( CASE + WHEN tm.id IS NULL + THEN evt.real_time + ELSE tm.t + END ) DESC; + +GRANT SELECT ON msgs.empire_instant TO :dbuser; + + +CREATE OR REPLACE FUNCTION msgs.mark_instant_notifications( e_id INT , m_id BIGINT , sending BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE msgs.empire_delivery SET emailed = TRUE + WHERE empire_id = e_id AND id <= m_id; + IF sending + THEN + INSERT INTO msgs.email_notifications ( account_id ) + SELECT owner_id FROM naming.empire_names WHERE id = e_id; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION msgs.mark_instant_notifications( INT , BIGINT , BOOLEAN ) TO :dbuser; + + + +-- +-- Recaps view, update function and check function +-- + +CREATE VIEW msgs.empire_recap + AS SELECT db.id , db.empire_id , + ( CASE + WHEN s.id IS NULL + THEN 'INT' + ELSE s.sender_type::TEXT + END ) AS sender_type , + ( CASE + WHEN s.id IS NULL + THEN NULL::INT + WHEN s.sender_type = 'EMP' + THEN s.empire_id + ELSE s.admin_id + END ) AS sender_id , + s.name AS sender_name , r.receiver_type , + ( CASE + WHEN r.receiver_type = 'EMP' + THEN r.empire_id + WHEN r.receiver_type = 'ALL' + THEN r.alliance_id + ELSE r.admin_id + END ) AS receiver_id , r.name AS receiver_name , + ( tm.id IS NULL ) AS internal_message , + ( CASE + WHEN tm.id IS NULL + THEN evt.event_id + ELSE tm.id + END ) AS content_id , + ( CASE + WHEN tm.id IS NULL + THEN evt.real_time + ELSE tm.t + END ) AS r_time + FROM msgs.empire_delivery db + INNER JOIN msgs.messages m ON m.id = db.message_id + INNER JOIN msgs.receivers r ON r.id = m.receiver_id + LEFT OUTER JOIN msgs.senders s ON m.sender_id = s.id + LEFT OUTER JOIN events.events evt ON evt.event_id = m.event_content_id + LEFT OUTER JOIN msgs.text_messages tm ON tm.id = m.text_content_id + WHERE db.in_inbox AND NOT db.recaped + ORDER BY ( CASE + WHEN tm.id IS NULL + THEN evt.real_time + ELSE tm.t + END ) DESC; + +GRANT SELECT ON msgs.empire_recap TO :dbuser; + + +CREATE OR REPLACE FUNCTION msgs.mark_recaps( e_id INT , m_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + UPDATE msgs.empire_delivery SET recaped = TRUE + WHERE empire_id = $1 AND id <= $2; +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.mark_recaps( INT , BIGINT ) TO :dbuser; + + +CREATE OR REPLACE FUNCTION msgs.is_recap_time( ) + RETURNS BOOLEAN + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + UPDATE sys.status SET last_msg_recap = now() + WHERE now() - last_msg_recap > '1d'::INTERVAL; + RETURN FOUND; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION msgs.is_recap_time( ) TO :dbuser; + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- CLEANUP FUNCTION -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + +CREATE OR REPLACE FUNCTION msgs.cleanup() + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER +AS $$ + DELETE FROM msgs.empire_delivery + WHERE emailed AND recaped AND status = 'DELETED'; + DELETE FROM msgs.admin_delivery + WHERE emailed AND status = 'DELETED'; + DELETE FROM msgs.messages WHERE id IN ( + SELECT m.id FROM msgs.messages m + LEFT OUTER JOIN msgs.empire_delivery ed ON m.id = ed.message_id + LEFT OUTER JOIN msgs.admin_delivery ad ON m.id = ad.message_id + WHERE ad.id IS NULL AND ed.id IS NULL + ); + DELETE FROM msgs.receivers WHERE id IN ( + SELECT r.id FROM msgs.receivers r + LEFT OUTER JOIN msgs.messages m ON m.receiver_id = r.id + WHERE m.id IS NULL + ); + DELETE FROM msgs.senders WHERE id IN ( + SELECT s.id FROM msgs.senders s + LEFT OUTER JOIN msgs.messages m ON m.sender_id = s.id + WHERE m.id IS NULL + ); + DELETE FROM msgs.text_messages WHERE id IN ( + SELECT t.id FROM msgs.text_messages t + LEFT OUTER JOIN msgs.messages m ON m.text_content_id = t.id + WHERE m.id IS NULL + ); + DELETE FROM events.events WHERE event_id IN ( + SELECT e.event_id FROM events.events e + LEFT OUTER JOIN msgs.messages m ON m.event_content_id = e.event_id + WHERE m.id IS NULL AND e.status = 'SENT' + ); +$$ LANGUAGE SQL; + +GRANT EXECUTE ON FUNCTION msgs.cleanup( ) TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/190-admin-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/190-admin-functions.sql new file mode 100644 index 0000000..fdf8c79 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/190-admin-functions.sql @@ -0,0 +1,937 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Functions and views to manage administrative accounts +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- ADMINISTRATOR MANAGEMENT FUNCTIONS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Creates an administrative user +-- +-- Parameters: +-- u_addr User account address +-- a_name Administrative name +-- privs Administrative privileges +-- +-- Returns: +-- err_code Error code: +-- 0 success +-- 1 unknown user +-- 2 invalid user status +-- 3 name already in use +-- 4 user already has admin access +-- admin_id Administrator ID or NULL on failure +-- + +CREATE OR REPLACE FUNCTION admin.create_admin( IN u_addr TEXT , IN a_name TEXT , IN privs INT , + OUT err_code INT , OUT admin_id INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + u_id INT; + u_stat TEXT; + p_sha1 TEXT; + p_md5 TEXT; +BEGIN + -- Get user ID, status and password hashes + SELECT INTO u_id , u_stat , p_sha1 , p_md5 id , status , pass_sha1 , pass_md5 + FROM users.accounts_view + WHERE address = lower( u_addr ); + IF NOT FOUND + THEN + err_code := 1; + RETURN; + ELSEIF u_stat IN ( 'UNCONFIRMED' , 'BANNED' ) + THEN + err_code := 2; + RETURN; + END IF; + + -- Try adding the admin's record + BEGIN + INSERT INTO admin.administrators ( appear_as , pass_md5 , pass_sha1 , privileges ) + VALUES ( a_name , p_md5 , p_sha1 , privs ) + RETURNING id INTO admin_id; + EXCEPTION + WHEN unique_violation THEN + err_code := 3; + RETURN; + END; + + -- Add the admin <-> user relation + BEGIN + INSERT INTO admin.admin_credentials ( administrator_id , credentials_id ) + VALUES ( admin_id , u_id ); + err_code := 0; + PERFORM admin.write_log( admin_id , 'INFO'::log_level , 'Administrator ' || a_name || ' created' ); + EXCEPTION + WHEN unique_violation THEN + DELETE FROM admin.administrators WHERE id = admin_id; + err_code := 4; + admin_id := NULL; + END; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.create_admin( TEXT, TEXT , INT ) TO :dbuser; + + + +-- +-- Type indicating the result of a connection attempt +-- + +CREATE TYPE admin_connection_result + AS ENUM( 'SUCCESS' , 'PASSWORD' , 'INACTIVE' ); + + + +-- +-- Log a connection attempt +-- +-- Parameters: +-- a_id Administrator identifier +-- c_res Connection attempt result +-- addr IP address +-- + +CREATE OR REPLACE FUNCTION admin.log_connection( a_id INT , c_res admin_connection_result , addr TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + IF c_res = 'SUCCESS' + THEN + PERFORM admin.write_log( a_id , 'DEBUG'::log_level , 'Successful login attempt from ' || addr ); + ELSEIF c_res = 'PASSWORD' + THEN + PERFORM admin.write_log( a_id , 'WARNING'::log_level , 'Failed login attempt from ' || addr + || ' (incorrect password)' ); + ELSEIF c_res = 'INACTIVE' + THEN + PERFORM admin.write_log( a_id , 'WARNING'::log_level , 'Failed login attempt from ' || addr + || ' (inactive administrator)' ); + ELSE + RAISE EXCEPTION 'Unknown connection attempt result value: %' , c_res; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.log_connection( INT , admin_connection_result , TEXT ) TO :dbuser; + + + +-- +-- Log a disconnection +-- +-- Parameters: +-- a_id Administrator identifier +-- + +CREATE OR REPLACE FUNCTION admin.log_disconnection( a_id INT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + PERFORM admin.write_log( a_id , 'DEBUG'::log_level , 'Administrator disconnected' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.log_disconnection( INT ) TO :dbuser; + + + +-- +-- Modifies an administrator's password +-- +-- Parameters: +-- a_id Administrator identifier +-- p_sha1 SHA-1 hash of the new password +-- p_md5 MD5 hash of the new password +-- +-- Returns: +-- success Whether the operation was successful +-- + +CREATE OR REPLACE FUNCTION admin.set_password( a_id INT , p_sha1 TEXT , p_md5 TEXT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + u_sha1 TEXT; + u_md5 TEXT; +BEGIN + SELECT INTO u_sha1 , u_md5 c.pass_sha1 , c.pass_md5 + FROM admin.admins_view a + INNER JOIN users.credentials c ON c.address_id = a.account_id + WHERE a.administrator_id = a_id AND a.active; + success := ( FOUND AND u_sha1 <> p_sha1 AND u_md5 <> p_md5 ); + + IF success + THEN + UPDATE admin.administrators + SET pass_sha1 = p_sha1 , pass_md5 = p_md5 + WHERE id = a_id; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.set_password( INT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Resets an administrator's password to his/her player account password +-- +-- Parameters: +-- a_id Administrator identifier +-- su_id Superuser identifier +-- +-- Returns: +-- success Whether the operation was successful +-- + +CREATE OR REPLACE FUNCTION admin.reset_password( a_id INT , su_id INT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + u_sha1 TEXT; + u_md5 TEXT; + a_name TEXT; +BEGIN + SELECT INTO u_sha1 , u_md5 , a_name c.pass_sha1 , c.pass_md5 , a.name + FROM admin.admins_view a + INNER JOIN users.credentials c ON c.address_id = a.account_id + WHERE a.administrator_id = a_id AND a.active; + success := FOUND; + + IF success + THEN + UPDATE admin.administrators SET pass_sha1 = u_sha1 , pass_md5 = u_md5 + WHERE id = a_id; + PERFORM admin.write_log( su_id , 'INFO'::log_level , 'Reset password of administrator ' || a_name ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.reset_password( INT , INT ) TO :dbuser; + + + +-- +-- Modifies an administrator's privileges +-- +-- Parameters: +-- a_id Administrator identifier +-- su_id Superuser identifier +-- n_privs New privileges +-- +-- Returns: +-- success Whether the operation was successful +-- + +CREATE OR REPLACE FUNCTION admin.set_privileges( a_id INT , su_id INT , n_privs INT , OUT success BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + a_name TEXT; + o_privs INT; +BEGIN + SELECT INTO a_name , o_privs a.name , a.privileges + FROM admin.admins_view a + WHERE a.administrator_id = a_id AND a.address IS NOT NULL; + success := FOUND; + + IF success AND n_privs <> o_privs + THEN + UPDATE admin.administrators SET privileges = n_privs + WHERE id = a_id; + PERFORM admin.write_log( su_id , 'INFO'::log_level , 'Set privileges of administrator ' || a_name + || ' from ' || o_privs || ' to ' || n_privs ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.set_privileges( INT , INT , INT ) TO :dbuser; + + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- ADMINISTRATOR VIEWS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Active administrators +-- + +CREATE VIEW admin.admins_view + AS SELECT adm.id AS administrator_id , adm.appear_as AS name , adm.privileges AS privileges , + adm.pass_sha1 , adm.pass_md5 , addr.id AS account_id , addr.address AS address , + ( addr.id IS NOT NULL AND privileges <> 0 ) AS active , + ( adm.pass_sha1 = cred.pass_sha1 AND adm.pass_md5 = cred.pass_md5 ) AS pass_change_required + FROM admin.administrators adm + LEFT OUTER JOIN admin.admin_credentials ac ON ac.administrator_id = adm.id + LEFT OUTER JOIN users.credentials cred ON cred.address_id = ac.credentials_id + LEFT OUTER JOIN users.addresses addr ON addr.id = ac.credentials_id; + +GRANT SELECT ON admin.admins_view TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- BANHAMMER FUNCTIONS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Creates a ban request +-- +-- Parameters: +-- a_id Administrator identifier +-- u_id User identifier +-- r_txt Reason for the ban request +-- +-- Returns: +-- Whether the operation was successful or not +-- + +CREATE OR REPLACE FUNCTION admin.add_ban_request( a_id INT , u_id INT , r_txt TEXT ) + RETURNS BOOLEAN + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + ban_id INT; +BEGIN + INSERT INTO admin.ban_requests ( requested_by , reason ) + VALUES ( a_id , r_txt ) + RETURNING id INTO ban_id; + + BEGIN + INSERT INTO admin.active_ban_requests( request_id , credentials_id ) + VALUES( ban_id , u_id ); + RETURN TRUE; + EXCEPTION + WHEN unique_violation THEN + DELETE FROM admin.ban_requests WHERE id = ban_id; + RETURN FALSE; + END; +END; +$$ LANGUAGE plpgsql; + + + + +-- +-- Creates a ban request using an email address as the source +-- +-- Parameters: +-- a_id Administrator identifier +-- u_addr Target user's address +-- r_txt Reason for the ban request +-- +-- Returns: +-- err_code Error code: +-- 0 success +-- 1 user not found +-- 2 duplicate request +-- + +CREATE OR REPLACE FUNCTION admin.request_ban_on_address( a_id INT , u_addr TEXT , r_txt TEXT , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + u_id INT; +BEGIN + SELECT INTO u_id id FROM users.accounts_view + WHERE address = u_addr; + IF NOT FOUND + THEN + err_code := 1; + RETURN; + END IF; + + IF admin.add_ban_request( a_id , u_id , r_txt ) + THEN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Requested ban of user #' || u_id || ' (address: ' || u_addr || ')' ); + err_code := 0; + ELSE + err_code := 2; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.request_ban_on_address( INT , TEXT, TEXT ) TO :dbuser; + + + +-- +-- Creates a ban request using an empire name as the source +-- +-- Parameters: +-- a_id Administrator identifier +-- u_emp Target user's empire name +-- r_txt Reason for the ban request +-- +-- Returns: +-- err_code Error code: +-- 0 success +-- 1 user not found +-- 2 duplicate request +-- + +CREATE OR REPLACE FUNCTION admin.request_ban_on_empire( a_id INT , u_emp TEXT , r_txt TEXT , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + u_id INT; +BEGIN + SELECT INTO u_id owner_id FROM naming.empire_names + WHERE lower(name) = lower(u_emp); + IF NOT FOUND + THEN + err_code := 1; + RETURN; + END IF; + + IF admin.add_ban_request( a_id , u_id , r_txt ) + THEN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Requested ban of user #' || u_id || ' (empire name: ' || u_emp || ')' ); + err_code := 0; + ELSE + err_code := 2; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.request_ban_on_empire( INT , TEXT, TEXT ) TO :dbuser; + + + +-- +-- Rejects a ban request +-- +-- Parameters: +-- a_id Administrator identifier +-- b_id Ban request identifier +-- r_txt Rejection reason +-- + +CREATE OR REPLACE FUNCTION admin.reject_ban_request( a_id INT , b_id INT , r_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + u_id INT; +BEGIN + -- Make sure the request exists and hasn't been validated + SELECT INTO u_id credentials_id FROM admin.active_ban_requests + WHERE request_id = b_id AND NOT validated + FOR UPDATE; + IF NOT FOUND + THEN + RETURN; + END IF; + PERFORM * FROM admin.ban_requests WHERE id = b_id FOR UPDATE; + + -- Insert archive entry + INSERT INTO admin.archived_ban_requests( request_id , credentials_id ) + VALUES ( b_id , u_id ); + INSERT INTO admin.rejected_ban_requests( request_id , rejected_by , reason ) + VALUES ( b_id , a_id , r_txt ); + DELETE FROM admin.active_ban_requests WHERE request_id = b_id; + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Rejected ban of user #' || u_id ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.reject_ban_request( INT , INT , TEXT ) TO :dbuser; + + + +-- +-- Confirms a ban request +-- +-- Parameters: +-- a_id Administrator identifier +-- b_id Ban request identifier +-- +-- Returns: +-- success Whether the operation was successful +-- addr User's email address +-- lang User's language +-- r_txt Reason for the ban +-- + +CREATE OR REPLACE FUNCTION admin.confirm_ban_request( a_id INT , b_id INT , OUT success BOOLEAN , OUT addr TEXT , OUT lang TEXT , OUT r_txt TEXT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + u_id INT; + br_id INT; +BEGIN + -- Make sure there is an active, unvalidated ban request + SELECT INTO u_id credentials_id FROM admin.active_ban_requests + WHERE request_id = b_id AND NOT validated FOR UPDATE; + IF NOT FOUND + THEN + success := FALSE; + RETURN; + END IF; + + -- Make sure the request was created by another admin + SELECT INTO br_id , r_txt requested_by , reason FROM admin.ban_requests + WHERE id = b_id AND requested_by <> a_id + FOR UPDATE; + IF NOT FOUND + THEN + success := FALSE; + RETURN; + END IF; + + -- Mark request as validated + INSERT INTO admin.validated_ban_requests ( request_id , validated_by ) + VALUES ( b_id , a_id ); + UPDATE admin.active_ban_requests SET validated = TRUE + WHERE request_id = b_id; + + -- Update account + PERFORM * FROM users.credentials WHERE address_id = u_id FOR UPDATE; + LOOP + UPDATE users.inactive_accounts SET since = now( ) , status = 'PROCESSED' + WHERE credentials_id = u_id; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO users.inactive_accounts ( credentials_id , since , status ) + VALUES ( u_id , now() , 'PROCESSED' ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + + -- Insert ban entry + INSERT INTO users.bans ( account_id , ban_id ) + VALUES( u_id , b_id ); + + -- Set ban reason + LOOP + UPDATE users.reasons SET reason = r_txt WHERE account_id = u_id; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO users.reasons( account_id , reason ) + VALUES ( u_id , r_txt ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + + success := TRUE; + SELECT INTO addr , lang a.address , l.language + FROM users.credentials c + INNER JOIN users.addresses a ON a.id = c.address_id + INNER JOIN defs.languages l ON l.id = c.language_id + WHERE c.address_id = u_id; + + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Confirmed ban request on user #' || u_id ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.confirm_ban_request( INT , INT ) TO :dbuser; + + + +-- +-- Lifts an existing ban +-- +-- Parameters: +-- a_id Administrator identifier +-- b_id Ban identifier +-- +-- Returns: +-- success Whether the operation was successful +-- addr User's email address +-- lang User's language +-- + +CREATE OR REPLACE FUNCTION admin.lift_ban( a_id INT , b_id INT , OUT success BOOLEAN , OUT addr TEXT , OUT lang TEXT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + u_id INT; + redeem BOOLEAN; +BEGIN + -- Find / lock the ban and user records + SELECT INTO u_id , redeem ab.credentials_id , ( aa.credentials_id IS NOT NULL ) + FROM admin.active_ban_requests ab + INNER JOIN admin.ban_requests br ON br.id = ab.request_id + INNER JOIN users.credentials c ON c.address_id = ab.credentials_id + LEFT OUTER JOIN users.active_accounts aa ON aa.credentials_id = c.address_id + WHERE ab.request_id = b_id AND ab.validated + FOR UPDATE OF ab , br , c; + IF NOT FOUND + THEN + success := FALSE; + RETURN; + END IF; + + -- Delete the ban and reason records, and redeem the account if possible + DELETE FROM users.bans WHERE account_id = u_id; + DELETE FROM users.reasons WHERE account_id = u_id; + IF redeem + THEN + DELETE FROM users.inactive_accounts WHERE credentials_id = u_id; + END IF; + + -- Delete active and validated ban entries + DELETE FROM admin.validated_ban_requests WHERE request_id = b_id; + DELETE FROM admin.active_ban_requests WHERE request_id = b_id; + + -- Insert archive records + INSERT INTO admin.archived_ban_requests( request_id , credentials_id ) + VALUES ( b_id , u_id ); + INSERT INTO admin.rejected_ban_requests( request_id , rejected_by , reason ) + VALUES ( b_id , a_id , '(ban lifted)' ); + + success := TRUE; + SELECT INTO addr , lang a.address , l.language + FROM users.credentials c + INNER JOIN users.addresses a ON a.id = c.address_id + INNER JOIN defs.languages l ON l.id = c.language_id + WHERE c.address_id = u_id; + + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Ban on user #' || u_id || ' has been lifted' + || (CASE WHEN redeem THEN ' (empire redeemed)' ELSE '' END) ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.lift_ban( INT , INT ) TO :dbuser; + + + +-- +-- Causes ban requests to expire +-- + +CREATE OR REPLACE FUNCTION admin.expire_ban_requests( ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + b_id INT; + u_id INT; +BEGIN + FOR b_id , u_id IN SELECT br.id , ab.credentials_id FROM admin.ban_requests br + INNER JOIN admin.active_ban_requests ab + ON ab.request_id = br.id AND NOT validated + WHERE now() - br.requested >= ( floor( sys.get_constant( 'accounts.banExpiration') ) || 's' )::INTERVAL + FOR UPDATE + LOOP + INSERT INTO admin.archived_ban_requests ( request_id , credentials_id ) + VALUES ( b_id , u_id ); + DELETE FROM admin.active_ban_requests WHERE request_id = b_id; + PERFORM sys.write_log( 'Bans' , 'INFO'::log_level , 'Ban request #' || b_id + || ' (user account #' || u_id || ') expired' ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.expire_ban_requests( ) TO :dbuser; + + + +-- +-- Checks for banned players who still have empires past the expiration delay +-- and deletes the empires. +-- +-- Returns: +-- Whether an empire was deleted +-- + +CREATE OR REPLACE FUNCTION admin.delete_banned_empires( ) + RETURNS BOOLEAN + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_id INT; + a_id INT; +BEGIN + SELECT INTO e_id , a_id e.name_id , c.address_id + FROM emp.empires e + INNER JOIN naming.empire_names en ON en.id = e.name_id + INNER JOIN users.credentials c ON c.address_id = en.owner_id + INNER JOIN users.active_accounts aa ON aa.credentials_id = c.address_id + INNER JOIN users.inactive_accounts ia ON ia.credentials_id = c.address_id + INNER JOIN users.bans b ON b.account_id = ia.credentials_id + WHERE now() - ia.since >= ( floor( sys.get_constant( 'accounts.banDelay') ) || 's' )::INTERVAL + FOR UPDATE LIMIT 1; + IF NOT FOUND + THEN + RETURN FALSE; + END IF; + + -- Delete empire and active account record + PERFORM emp.delete_empire( e_id ); + DELETE FROM users.active_accounts WHERE credentials_id = a_id; + PERFORM sys.write_log( 'Bans' , 'INFO'::log_level , 'Deleted empire #' || e_id + || ' (user account #' || a_id || ')' ); + + RETURN TRUE; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.delete_banned_empires( ) TO :dbuser; + + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- VIEWS RELATED TO THE BANHAMMER -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Pending requests +-- + +CREATE VIEW admin.pending_bans + AS SELECT r.id , r.requested_by AS requested_by_id , a.appear_as AS requested_by_name , + r.reason , r.requested , ab.credentials_id AS account_id , ad.address AS account_mail + FROM admin.ban_requests r + INNER JOIN admin.active_ban_requests ab + ON ab.request_id = r.id AND NOT ab.validated + INNER JOIN admin.administrators a ON a.id = r.requested_by + INNER JOIN users.addresses ad ON ad.id = ab.credentials_id; + +GRANT SELECT ON admin.pending_bans TO :dbuser; + + +-- +-- Expired / rejected ban requests +-- + +CREATE VIEW admin.cancelled_bans + AS SELECT r.id , r.requested_by AS requested_by_id , a.appear_as AS requested_by_name , + r.reason , r.requested , ab.credentials_id AS account_id , ad.address AS account_mail , + ab.updated , ( rb.request_id IS NULL ) AS expired , + rb.rejected_by AS rejected_by_id , ra.appear_as AS rejected_by_name , + rb.reason AS rejection_reason + FROM admin.ban_requests r + INNER JOIN admin.administrators a ON a.id = r.requested_by + INNER JOIN admin.archived_ban_requests ab ON ab.request_id = r.id + INNER JOIN users.addresses ad ON ad.id = ab.credentials_id + LEFT OUTER JOIN admin.rejected_ban_requests rb ON rb.request_id = r.id + LEFT OUTER JOIN admin.administrators ra ON ra.id = rb.rejected_by; + +GRANT SELECT ON admin.cancelled_bans TO :dbuser; + + +-- +-- Active bans +-- + +CREATE VIEW admin.active_bans + AS SELECT r.id , r.requested_by AS requested_by_id , a.appear_as AS requested_by_name , + r.reason , r.requested , ab.credentials_id AS account_id , ad.address AS account_mail , + vr.validated AS updated , ( ua.credentials_id IS NOT NULL ) AS redeemable , + vr.validated_by AS validated_by_id , va.appear_as AS validated_by_name + FROM admin.ban_requests r + INNER JOIN admin.administrators a ON a.id = r.requested_by + INNER JOIN admin.active_ban_requests ab ON ab.request_id = r.id AND validated + INNER JOIN users.addresses ad ON ad.id = ab.credentials_id + INNER JOIN admin.validated_ban_requests vr ON vr.request_id = r.id + INNER JOIN admin.administrators va ON va.id = vr.validated_by + LEFT OUTER JOIN users.active_accounts ua ON ua.credentials_id = ab.credentials_id; + +GRANT SELECT ON admin.active_bans TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- WARNING SYSTEM FUNCTIONS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Adds a warning to a player's account, triggering an automatic ban request if necessary +-- +-- Parameters: +-- a_id Administrator identifier +-- u_id Player identifier +-- +-- Returns: +-- given Whether a warning was issued or not +-- c_count Current amount of warnings for this player +-- + +CREATE OR REPLACE FUNCTION admin.give_player_warning( a_id INT , u_id INT , OUT given BOOLEAN , OUT c_count INT ) + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + last_rec TIMESTAMP WITHOUT TIME ZONE; +BEGIN + LOOP + SELECT INTO c_count , last_rec warnings, last_received + FROM admin.warnings WHERE credentials_id = u_id + FOR UPDATE; + IF FOUND + THEN + given := ( now() - last_rec >= ( floor(sys.get_constant('accounts.warnings.grace')) || 's' )::INTERVAL ); + IF given + THEN + c_count := c_count + 1; + UPDATE admin.warnings SET last_received = now( ) , warnings = c_count + WHERE credentials_id = u_id; + END IF; + EXIT; + END IF; + + BEGIN + INSERT INTO admin.warnings ( credentials_id ) VALUES ( u_id ); + given := TRUE; + c_count := 1; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + + IF given + THEN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Warning given to user #' || u_id || ' (' + || c_count || ' warning(s) total)' ); + + IF c_count >= sys.get_constant( 'accounts.warnings.autoBan' ) + THEN + IF admin.add_ban_request( a_id , u_id , 'Automatic ban after ' || c_count || ' warnings' ) + THEN + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Added automatic ban for user ' || u_id ); + END IF; + END IF; + END IF; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Causes old warnings to expire +-- + +CREATE OR REPLACE FUNCTION admin.expire_warnings( ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + e_time INTERVAL; + g_time INTERVAL; +BEGIN + e_time := ( floor( sys.get_constant( 'accounts.warnings.expiration' ) + * sys.get_constant( 'accounts.warnings.expiration.units' ) ) + || 's' ) :: INTERVAL; + g_time := ( floor(sys.get_constant('accounts.warnings.grace')) || 's' )::INTERVAL; + UPDATE admin.warnings SET last_received = now( ) - g_time , warnings = warnings - 1 + WHERE now() - last_received >= e_time AND warnings > 0; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.expire_warnings( ) TO :dbuser; + + + +-- +-- Finds out if it is time to send the administrative recap e-mails +-- + +CREATE OR REPLACE FUNCTION admin.is_recap_time( OUT is_time TIMESTAMP WITHOUT TIME ZONE ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + SELECT INTO is_time last_admin_recap FROM sys.status + WHERE now() - last_admin_recap >= '12 hours'::INTERVAL + FOR UPDATE; + IF FOUND + THEN + UPDATE sys.status SET last_admin_recap = now( ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION admin.is_recap_time( ) TO :dbuser; + + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- USERS VIEW -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +CREATE VIEW admin.user_empires + AS SELECT en.* + FROM emp.empires e + INNER JOIN naming.empire_names en ON e.name_id = en.id; + +CREATE VIEW admin.users_list + AS SELECT av.* , ue.id AS current_empire_id , ue.name AS current_empire , + a1.id AS ban_req_id , a1.appear_as AS ban_req_name , + a2.id AS ban_val_id , a2.appear_as AS ban_val_name , + ( CASE WHEN w IS NULL THEN 0 ELSE w.warnings END ) AS warnings_count , + w.last_received AS warnings_last + FROM users.accounts_view av + LEFT OUTER JOIN admin.user_empires ue ON ue.owner_id = av.id + LEFT OUTER JOIN admin.ban_requests br ON br.id = av.ban_request_id + LEFT OUTER JOIN admin.validated_ban_requests vbr ON vbr.request_id = br.id + LEFT OUTER JOIN admin.administrators a1 ON a1.id = br.requested_by + LEFT OUTER JOIN admin.administrators a2 ON a2.id = vbr.validated_by + LEFT OUTER JOIN admin.warnings w ON w.credentials_id = av.id + ORDER BY av.address; + +GRANT SELECT ON admin.users_list TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/200-bugs-functions.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/200-bugs-functions.sql new file mode 100644 index 0000000..f8d7282 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/200-bugs-functions.sql @@ -0,0 +1,1277 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Bug tracking system functions and views +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- HELPER FUNCTIONS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Creates or gets a submitter from an administrator +-- +-- Parameters: +-- a_id Administrator identifier +-- +-- Returns: +-- s_id The submitter record's identifier +-- + +CREATE OR REPLACE FUNCTION bugs.goc_admin_submitter( a_id INT , OUT s_id BIGINT ) + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + a_name TEXT; +BEGIN + a_name := NULL; + LOOP + -- Try finding an existing record + SELECT INTO s_id s.submitter_id + FROM bugs.submitters s + INNER JOIN bugs.admin_submitters a USING ( submitter_id ) + WHERE a.admin_id = a_id; + EXIT WHEN FOUND; + + -- Try creating the admin submitter + IF a_name IS NULL + THEN + SELECT INTO a_name appear_as FROM admin.administrators WHERE id = a_id; + END IF; + INSERT INTO bugs.submitters ( is_admin , name ) + VALUES ( TRUE , a_name) + RETURNING submitter_id INTO s_id; + BEGIN + INSERT INTO bugs.admin_submitters ( submitter_id , admin_id ) + VALUES ( s_id , a_id ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + DELETE FROM bugs.submitters WHERE id = s_id; + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Gets a submitter from an empire identifier +-- +-- Parameters: +-- e_id Empire identifier +-- +-- Returns: +-- s_id The submitter record's identifier +-- + +CREATE OR REPLACE FUNCTION bugs.get_user_submitter( e_id INT ) + RETURNS BIGINT + STRICT STABLE + SECURITY INVOKER +AS $$ + SELECT s.submitter_id + FROM emp.empires e + INNER JOIN naming.empire_names en ON en.id = e.name_id + INNER JOIN bugs.user_submitters s ON s.account_id = en.owner_id + WHERE e.name_id = $1; +$$ LANGUAGE SQL; + + + +-- +-- Creates or gets a submitter from an empire identifier +-- +-- Parameters: +-- e_id Empire identifier +-- +-- Returns: +-- s_id The submitter record's identifier +-- + +CREATE OR REPLACE FUNCTION bugs.goc_user_submitter( e_id INT , OUT s_id BIGINT ) + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + a_id INT; + a_name TEXT; +BEGIN + SELECT INTO a_id , a_name ac.credentials_id , en.name + FROM emp.empires e + INNER JOIN naming.empire_names en ON en.id = e.name_id + INNER JOIN users.active_accounts ac ON ac.credentials_id = en.owner_id + WHERE e.name_id = e_id; + LOOP + -- Try finding an existing record + SELECT INTO s_id s.submitter_id + FROM bugs.submitters s + INNER JOIN bugs.user_submitters a USING ( submitter_id ) + WHERE a.account_id = a_id; + EXIT WHEN FOUND; + + -- Try creating the submitter + INSERT INTO bugs.submitters ( is_admin , name ) + VALUES ( FALSE , a_name) + RETURNING submitter_id INTO s_id; + BEGIN + INSERT INTO bugs.user_submitters ( submitter_id , account_id ) + VALUES ( s_id , a_id ); + EXIT; + EXCEPTION + WHEN unique_violation THEN + DELETE FROM bugs.submitters WHERE id = s_id; + END; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Posts a new bug report +-- +-- Parameters: +-- is_admin Whether the specified identifier corresponds to an administrator or to an empire +-- u_id User identifier +-- r_ttl Bug report title +-- r_desc Bug description +-- +-- Returns: +-- br_id The bug report's identifier +-- bg_id The bug report's group identifier +-- + +CREATE OR REPLACE FUNCTION bugs.post_report( is_admin BOOLEAN , u_id INT , r_ttl TEXT , r_desc TEXT , OUT br_id BIGINT , OUT bg_id BIGINT ) + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + sub_id BIGINT; +BEGIN + -- Get the submitter's identifier + IF is_admin + THEN + sub_id := bugs.goc_admin_submitter( u_id ); + ELSE + sub_id := bugs.goc_user_submitter( u_id ); + END IF; + + -- Create the bug report's group + INSERT INTO bugs.groups DEFAULT VALUES + RETURNING group_id INTO bg_id; + + -- Post the initial report + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( bg_id , sub_id , 'INIT' ) + RETURNING event_id INTO br_id; + INSERT INTO bugs.initial_report_events ( event_id , title , description ) + VALUES ( br_id , r_ttl , r_desc ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sends an internal message to all user submitters +-- + +CREATE OR REPLACE FUNCTION bugs.update_notification( br_id BIGINT , sub_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + grp_id BIGINT; + oe_id INT; + obr_id BIGINT; +BEGIN + -- Get the report's group id + SELECT INTO grp_id group_id FROM bugs.events WHERE event_id = br_id; + + -- Find user submitters and send them a message + FOR oe_id , obr_id IN SELECT DISTINCT mv.empire_id , mv.bug_report_id + FROM bugs.br_user_view mv + INNER JOIN naming.empire_names en ON en.id = mv.empire_id + INNER JOIN bugs.user_submitters us ON us.account_id = en.owner_id + INNER JOIN bugs.events evt + ON evt.submitter_id = us.submitter_id AND evt.group_id = mv.group_id + WHERE mv.group_id = grp_id AND NOT mv.updated AND us.submitter_id <> sub_id + LOOP + PERFORM events.bug_report_updated_event( oe_id , obr_id , sub_id ); + PERFORM msgs.deliver_internal( oe_id ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Sends an internal message to all user submitters for TWO bug reports (used when merging) +-- + +CREATE OR REPLACE FUNCTION bugs.update_notification( br1_id BIGINT , br2_id BIGINT , sub_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + grp1_id BIGINT; + grp2_id BIGINT; + oe_id INT; + obr_id BIGINT; +BEGIN + -- Get the report's group id + SELECT INTO grp1_id group_id FROM bugs.events WHERE event_id = br1_id; + SELECT INTO grp2_id group_id FROM bugs.events WHERE event_id = br2_id; + + -- Find user submitters and send them a message + FOR oe_id , obr_id IN SELECT DISTINCT mv.empire_id , mv.bug_report_id + FROM bugs.br_user_view mv + INNER JOIN naming.empire_names en ON en.id = mv.empire_id + INNER JOIN bugs.user_submitters us ON us.account_id = en.owner_id + INNER JOIN bugs.events evt + ON evt.submitter_id = us.submitter_id AND evt.group_id = mv.group_id + WHERE mv.group_id IN ( grp1_id , grp2_id ) AND NOT mv.updated AND us.submitter_id <> sub_id + LOOP + PERFORM events.bug_report_updated_event( oe_id , obr_id , sub_id ); + PERFORM msgs.deliver_internal( oe_id ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- VIEWS USED TO ACCESS BUG REPORTS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +CREATE VIEW bugs.br_groups + AS SELECT group_id , event_id AS bug_report_id , submitter_id AS initial_submitter_id + FROM bugs.events + INNER JOIN bugs.initial_report_events USING ( event_id ); + +CREATE VIEW bugs.br_first_report + AS SELECT group_id , min( bug_report_id ) AS bug_report_id + FROM bugs.br_groups + GROUP BY group_id; + +GRANT SELECT ON bugs.br_first_report TO :dbuser; + +CREATE VIEW bugs.br_first_submitter_report + AS SELECT group_id , initial_submitter_id , min( bug_report_id ) AS bug_report_id + FROM bugs.br_groups + GROUP BY group_id , initial_submitter_id; + +CREATE VIEW bugs.br_group_submitters + AS SELECT DISTINCT group_id , submitter_id FROM bugs.events; + +CREATE VIEW bugs.br_submitters + AS SELECT submitter_id , is_admin , name , + ( CASE + WHEN is_admin THEN admin_id + ELSE account_id + END ) AS user_id + FROM bugs.submitters + LEFT OUTER JOIN bugs.admin_submitters USING (submitter_id) + LEFT OUTER JOIN bugs.user_submitters USING (submitter_id); + +CREATE VIEW bugs.br_updates + AS SELECT group_id , max(event_id) AS last_update_id + FROM bugs.events + GROUP BY group_id; + +CREATE VIEW bugs.br_user_updates + AS SELECT group_id , max(event_id) AS last_update_id + FROM bugs.events + LEFT OUTER JOIN bugs.comment_events USING( event_id ) + WHERE visible IS NULL OR visible + GROUP BY group_id; + +CREATE VIEW bugs.br_update_types + AS SELECT group_id , e_type , max( event_id ) AS last_event_id + FROM bugs.events + GROUP BY group_id , e_type; + +CREATE VIEW bugs.br_status + AS SELECT g.group_id , + ( CASE + WHEN u.last_event_id IS NULL THEN 'PENDING'::TEXT + ELSE s.status::TEXT + END ) AS status + FROM bugs.groups g + LEFT OUTER JOIN bugs.br_update_types u + ON u.group_id = g.group_id AND u.e_type = 'STATUS' + LEFT OUTER JOIN bugs.status_change_events s ON s.event_id = u.last_event_id; + +GRANT SELECT ON bugs.br_status TO :dbuser; + + +CREATE VIEW bugs.br_visibility + AS SELECT g.group_id , + ( CASE + WHEN u.last_event_id IS NULL THEN FALSE + ELSE v.visible + END ) AS visible + FROM bugs.groups g + LEFT OUTER JOIN bugs.br_update_types u + ON u.group_id = g.group_id AND u.e_type = 'VISIBILITY' + LEFT OUTER JOIN bugs.visibility_events v ON v.event_id = u.last_event_id; + +CREATE VIEW bugs.br_main_view + AS SELECT fr.group_id , v.visible , s.status , lue.t AS last_update , + lus.is_admin AS last_submitter_admin , lus.name AS last_submitter_name , lus.user_id AS last_submitter_uid + FROM bugs.br_first_report fr + INNER JOIN bugs.br_visibility v ON v.group_id = fr.group_id + INNER JOIN bugs.br_status s ON s.group_id = fr.group_id + INNER JOIN bugs.br_updates lu ON lu.group_id = fr.group_id + INNER JOIN bugs.events lue ON lue.event_id = lu.last_update_id + INNER JOIN bugs.br_submitters lus ON lus.submitter_id = lue.submitter_id; + + +CREATE VIEW bugs.br_main_user_view + AS SELECT fr.group_id , v.visible , s.status , lue.t AS last_update , + lus.is_admin AS last_submitter_admin , lus.name AS last_submitter_name , lus.user_id AS last_submitter_uid + FROM bugs.br_first_report fr + INNER JOIN bugs.br_visibility v ON v.group_id = fr.group_id + INNER JOIN bugs.br_status s ON s.group_id = fr.group_id + INNER JOIN bugs.br_user_updates lu ON lu.group_id = fr.group_id + INNER JOIN bugs.events lue ON lue.event_id = lu.last_update_id + INNER JOIN bugs.br_submitters lus ON lus.submitter_id = lue.submitter_id; + + + + +-- +-- Main view for administrators +-- + +CREATE VIEW bugs.br_admin_view + AS SELECT a.id AS administrator_id , mv.group_id , + ire.event_id AS bug_report_id , mv.visible , mv.status , ire.t AS posted , ir.title AS title , + isb.is_admin AS initial_submitter_admin , isb.name AS initial_submitter_name , isb.user_id AS initial_submitter_uid , + mv.last_update , mv.last_submitter_admin , mv.last_submitter_name , mv.last_submitter_uid , + ( CASE + WHEN mv.status NOT IN ('PENDING','OPEN') THEN FALSE + WHEN avs.last_view IS NULL THEN TRUE + ELSE ( avs.last_view < mv.last_update ) + END ) AS updated , + ( bg.bug_report_id IS NOT NULL ) AS own_report + FROM admin.administrators a + CROSS JOIN bugs.br_main_view mv + LEFT OUTER JOIN bugs.admin_view_status avs + ON avs.admin_id = a.id AND avs.group_id = mv.group_id + INNER JOIN bugs.br_first_report fr ON fr.group_id = mv.group_id + LEFT OUTER JOIN bugs.admin_submitters asb ON asb.admin_id = a.id + LEFT OUTER JOIN bugs.br_first_submitter_report bg + ON bg.group_id = mv.group_id AND bg.initial_submitter_id = asb.submitter_id + INNER JOIN bugs.events ire ON ire.event_id = ( CASE + WHEN bg.bug_report_id IS NULL THEN fr.bug_report_id + ELSE bg.bug_report_id + END ) + INNER JOIN bugs.initial_report_events ir ON ir.event_id = ire.event_id + INNER JOIN bugs.br_submitters isb ON isb.submitter_id = ire.submitter_id; + +GRANT SELECT ON bugs.br_admin_view TO :dbuser; + + +-- +-- Main view for users +-- + +CREATE VIEW bugs.br_user_view + AS SELECT e.name_id AS empire_id , mv.group_id , + ire.event_id AS bug_report_id , mv.visible , mv.status , ire.t AS posted , ir.title AS title , + isb.is_admin AS initial_submitter_admin , isb.name AS initial_submitter_name , isb.user_id AS initial_submitter_uid , + mv.last_update , mv.last_submitter_admin , mv.last_submitter_name , mv.last_submitter_uid , + ( CASE + WHEN uvs.last_view IS NULL THEN FALSE + ELSE ( uvs.last_view < mv.last_update ) + END ) AS updated , + ( bg.bug_report_id IS NOT NULL ) AS own_report + FROM emp.empires e + INNER JOIN naming.empire_names en ON en.id = e.name_id + CROSS JOIN bugs.br_main_user_view mv + LEFT OUTER JOIN bugs.user_view_status uvs + ON uvs.user_id = en.owner_id AND uvs.group_id = mv.group_id + INNER JOIN bugs.br_first_report fr ON fr.group_id = mv.group_id + LEFT OUTER JOIN bugs.user_submitters usb ON usb.account_id = en.owner_id + LEFT OUTER JOIN bugs.br_first_submitter_report bg + ON bg.group_id = mv.group_id AND bg.initial_submitter_id = usb.submitter_id + INNER JOIN bugs.events ire ON ire.event_id = ( CASE + WHEN bg.bug_report_id IS NULL THEN fr.bug_report_id + ELSE bg.bug_report_id + END ) + INNER JOIN bugs.initial_report_events ir ON ir.event_id = ire.event_id + INNER JOIN bugs.br_submitters isb ON isb.submitter_id = ire.submitter_id + LEFT OUTER JOIN bugs.br_group_submitters gs + ON gs.submitter_id = usb.submitter_id AND gs.group_id = mv.group_id + WHERE gs.submitter_id IS NOT NULL OR ( mv.visible AND mv.status <> 'PENDING' ); + +GRANT SELECT ON bugs.br_user_view TO :dbuser; + + +-- +-- Bug events view +-- + +CREATE VIEW bugs.br_events + AS SELECT ir.event_id AS bug_report_id , + evt.event_id AS event_id , evt.e_type AS event_type , evt.t AS event_timestamp , + es.name AS submitter_name , es.is_admin AS submitter_admin , + ( CASE WHEN es.is_admin THEN asb.admin_id ELSE usb.account_id END ) AS submitter_uid , + tir.title AS title , + ( CASE WHEN evt.e_type = 'INIT' THEN tir.description ELSE tc.comment END ) AS contents , + tm.initial_post_id AS merged_report_id , + ts.status AS status , + ( CASE + WHEN evt.e_type = 'COMMENT' THEN tc.visible + WHEN evt.e_type = 'INIT' THEN ( asd IS NOT NULL ) + ELSE tv.visible + END ) AS visible + FROM bugs.initial_report_events ir + INNER JOIN bugs.events ire ON ire.event_id = ir.event_id + INNER JOIN bugs.events evt ON evt.group_id = ire.group_id + INNER JOIN bugs.submitters es ON es.submitter_id = evt.submitter_id + LEFT OUTER JOIN bugs.admin_submitters asb ON asb.submitter_id = es.submitter_id + LEFT OUTER JOIN bugs.user_submitters usb ON usb.submitter_id = es.submitter_id + LEFT OUTER JOIN bugs.initial_report_events tir ON tir.event_id = evt.event_id + LEFT OUTER JOIN bugs.account_status_data asd ON asd.event_id = tir.event_id + LEFT OUTER JOIN bugs.comment_events tc ON tc.event_id = evt.event_id + LEFT OUTER JOIN bugs.merge_events tm ON tm.event_id = evt.event_id + LEFT OUTER JOIN bugs.status_change_events ts ON ts.event_id = evt.event_id + LEFT OUTER JOIN bugs.visibility_events tv ON tv.event_id = evt.event_id + ORDER BY evt.t; + +GRANT SELECT ON bugs.br_events TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- FUNCTIONS THAT HANDLE PLAYER ACCESS TO BUG REPORTS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Posts a new bug report, including additional data +-- +-- Parameters: +-- e_id Empire identifier +-- r_ttl Report title +-- r_desc Bug description +-- e_data Extended data to associate with the post +-- +-- Returns: +-- br_id The bug report's identifier +-- bg_id The bug report's group +-- + +CREATE OR REPLACE FUNCTION bugs.post_player_report( e_id INT , r_ttl TEXT , r_desc TEXT , e_data TEXT , OUT br_id BIGINT , OUT bg_id BIGINT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +BEGIN + SELECT INTO br_id , bg_id * FROM bugs.post_report( FALSE , e_id , r_ttl , r_desc ); + IF e_data <> '' + THEN + INSERT INTO bugs.account_status_data( event_id , account_status ) + VALUES ( br_id , e_data ); + END IF; + INSERT INTO bugs.user_view_status ( group_id , user_id ) + SELECT bg_id , n.owner_id + FROM naming.empire_names n + WHERE n.id = e_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.post_player_report( INT , TEXT , TEXT , TEXT ) TO :dbuser; + + + +-- +-- Posts a comment on an existing bug report +-- +-- Parameters: +-- e_id Empire identifier +-- br_id Bug report identifier +-- c_txt Comment to post +-- + +CREATE OR REPLACE FUNCTION bugs.post_player_comment( e_id INT , br_id BIGINT , c_txt TEXT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + sub_id BIGINT; + grp_id BIGINT; + cmt_id BIGINT; + oe_id INT; + obr_id BIGINT; +BEGIN + -- Get submitter + sub_id := bugs.get_user_submitter( e_id ); + IF sub_id IS NULL + THEN + RETURN; + END IF; + + -- Is submitter associated with this bug report? + SELECT INTO grp_id group_id + FROM bugs.br_groups + INNER JOIN bugs.br_group_submitters USING (group_id) + INNER JOIN bugs.br_status USING (group_id) + WHERE bug_report_id = br_id + AND ( status = 'PENDING' AND initial_submitter_id = sub_id + OR status = 'OPEN' AND submitter_id = sub_id ); + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Insert comment + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( grp_id , sub_id , 'COMMENT' ) + RETURNING event_id INTO cmt_id; + INSERT INTO bugs.comment_events ( event_id , comment , visible ) + VALUES ( cmt_id , c_txt , FALSE ); + + -- Update view status + UPDATE bugs.user_view_status v SET last_view = now( ) + FROM naming.empire_names en + WHERE en.id = e_id AND v.user_id = en.owner_id AND v.group_id = grp_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.post_player_comment( INT , BIGINT , TEXT ) TO :dbuser; + + + +-- +-- Reads a bug report +-- +-- Parameters: +-- e_id Empire identifier +-- br_id Bug report to read +-- +-- Returns: +-- The bug report as descibed by bugs.br_user_view +-- + +CREATE OR REPLACE FUNCTION bugs.read_player_report( e_id INT , br_id BIGINT ) + RETURNS SETOF bugs.br_user_view + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + rec bugs.br_user_view; +BEGIN + SELECT INTO rec mv.* FROM bugs.br_user_view mv + INNER JOIN bugs.br_groups bg USING ( group_id ) + WHERE mv.empire_id = e_id AND bg.bug_report_id = br_id; + IF FOUND + THEN + LOOP + UPDATE bugs.user_view_status vs SET last_view = now( ) + FROM bugs.br_groups bg , naming.empire_names en + WHERE bg.bug_report_id = br_id AND en.id = e_id + AND vs.group_id = bg.group_id AND vs.user_id = en.owner_id; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO bugs.user_view_status ( group_id , user_id ) + SELECT bg.group_id , en.owner_id + FROM bugs.br_groups bg , naming.empire_names en + WHERE bug_report_id = br_id AND en.id = e_id; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + RETURN NEXT rec; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.read_player_report( INT , BIGINT ) TO :dbuser; + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- FUNCTIONS THAT HANDLE ADMIN ACCESS TO BUG REPORTS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + + +-- +-- Posts a new bug report +-- +-- Parameters: +-- a_id Admin identifier +-- r_ttl Report title +-- r_desc Bug description +-- pub Whether the bug report is to be made public +-- +-- Returns: +-- br_id The bug report's identifier +-- bg_id The bug report's group +-- + +CREATE OR REPLACE FUNCTION bugs.post_admin_report( a_id INT , r_ttl TEXT , r_desc TEXT , pub BOOLEAN , OUT br_id BIGINT , OUT bg_id BIGINT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + sub_id BIGINT; + e_id BIGINT; +BEGIN + -- Create the report + SELECT INTO br_id , bg_id * FROM bugs.post_report( TRUE , a_id , r_ttl , r_desc ); + SELECT INTO sub_id submitter_id FROM bugs.events WHERE event_id = br_id; + + -- Mark the report as "OPEN" + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( bg_id , sub_id , 'STATUS' ) + RETURNING event_id INTO e_id; + INSERT INTO bugs.status_change_events ( event_id , status ) + VALUES ( e_id , 'OPEN' ); + + -- Mark the report as visible if required + IF pub + THEN + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( bg_id , sub_id , 'VISIBILITY' ) + RETURNING event_id INTO e_id; + INSERT INTO bugs.visibility_events ( event_id , visible ) + VALUES ( e_id , TRUE ); + END IF; + + -- Mark the report as read by the reporter + INSERT INTO bugs.admin_view_status ( group_id , admin_id ) + VALUES ( bg_id , a_id ); + + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Posted bug report #' || br_id || ': ' || r_ttl ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.post_admin_report( INT , TEXT , TEXT , BOOLEAN ) TO :dbuser; + + + +-- +-- Posts a comment on an existing bug report +-- +-- Parameters: +-- a_id Admin identifier +-- br_id Bug report identifier +-- c_txt Comment to post +-- pub Whether the comment should be made public or not +-- + +CREATE OR REPLACE FUNCTION bugs.post_admin_comment( a_id INT , br_id BIGINT , c_txt TEXT , pub BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + sub_id BIGINT; + grp_id BIGINT; + cmt_id BIGINT; +BEGIN + -- Get submitter and group + sub_id := bugs.goc_admin_submitter( a_id ); + SELECT INTO grp_id group_id FROM bugs.br_groups WHERE bug_report_id = br_id; + + -- If the message is public, notify users + IF pub + THEN + PERFORM bugs.update_notification( br_id , sub_id ); + END IF; + + -- Insert comment + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( grp_id , sub_id , 'COMMENT' ) + RETURNING event_id INTO cmt_id; + INSERT INTO bugs.comment_events ( event_id , comment , visible ) + VALUES ( cmt_id , c_txt , pub ); + + -- Update view status + UPDATE bugs.admin_view_status SET last_view = now( ) + WHERE admin_id = a_id AND group_id = grp_id; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.post_admin_comment( INT , BIGINT , TEXT , BOOLEAN ) TO :dbuser; + + + +-- +-- Reads a bug report +-- +-- Parameters: +-- a_id Admin identifier +-- br_id Bug report to read +-- +-- Returns: +-- The bug report as descibed by bugs.br_admin_view +-- + +CREATE OR REPLACE FUNCTION bugs.read_admin_report( a_id INT , br_id BIGINT ) + RETURNS SETOF bugs.br_admin_view + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + rec bugs.br_admin_view; +BEGIN + SELECT INTO rec mv.* FROM bugs.br_admin_view mv + INNER JOIN bugs.br_groups bg USING ( group_id ) + WHERE mv.administrator_id = a_id AND bg.bug_report_id = br_id; + IF FOUND + THEN + LOOP + UPDATE bugs.admin_view_status vs SET last_view = now( ) + FROM bugs.br_groups bg + WHERE bg.bug_report_id = br_id AND vs.group_id = bg.group_id + AND vs.admin_id = a_id; + EXIT WHEN FOUND; + + BEGIN + INSERT INTO bugs.admin_view_status ( group_id , admin_id ) + SELECT group_id , a_id FROM bugs.br_groups + WHERE bug_report_id = br_id; + EXIT; + EXCEPTION + WHEN unique_violation THEN + -- Do nothing + END; + END LOOP; + RETURN NEXT rec; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.read_admin_report( INT , BIGINT ) TO :dbuser; + + + +-- +-- Make a comment visible +-- +-- Parameters: +-- a_id Admin identifier +-- cmt_id Comment identifier +-- + +CREATE OR REPLACE FUNCTION bugs.show_comment( a_id INT , cmt_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + s_admin BOOLEAN; + s_name TEXT; + br_id BIGINT; + sub_id BIGINT; + c_text TEXT; + grp_id BIGINT; + evt_id BIGINT; +BEGIN + SELECT INTO s_admin , s_name , br_id , sub_id , c_text , grp_id + is_admin , name , bug_report_id , submitter_id , comment , group_id + FROM bugs.events e + INNER JOIN bugs.comment_events c USING ( event_id ) + INNER JOIN bugs.submitters s USING ( submitter_id ) + INNER JOIN bugs.br_first_report fr USING ( group_id ) + WHERE event_id = cmt_id AND NOT visible + FOR UPDATE OF e , c , s; + + IF FOUND + THEN + PERFORM bugs.update_notification( br_id , sub_id ); + + -- Delete old version + DELETE FROM bugs.comment_events WHERE event_id = cmt_id; + DELETE FROM bugs.events WHERE event_id = cmt_id; + + -- Re-insert comment + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( grp_id , sub_id , 'COMMENT' ) + RETURNING event_id INTO evt_id; + INSERT INTO bugs.comment_events ( event_id , comment , visible ) + VALUES ( evt_id , c_text , TRUE ); + + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Validated bug comment #' || cmt_id + || ' posted by ' || ( CASE WHEN s_admin THEN 'administrator' ELSE 'empire' END ) + || ' ' || s_name ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.show_comment( INT , BIGINT ) TO :dbuser; + + + +-- +-- Deletes a comment +-- +-- Parameters: +-- a_id Admin identifier +-- cmt_id Comment identifier +-- + +CREATE OR REPLACE FUNCTION bugs.delete_comment( a_id INT , cmt_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + s_admin BOOLEAN; + s_name TEXT; +BEGIN + SELECT INTO s_admin , s_name is_admin , name + FROM bugs.events + INNER JOIN bugs.comment_events USING ( event_id ) + INNER JOIN bugs.submitters USING ( submitter_id ) + WHERE event_id = cmt_id AND NOT visible + FOR UPDATE; + IF FOUND + THEN + DELETE FROM bugs.comment_events WHERE event_id = cmt_id; + DELETE FROM bugs.events WHERE event_id = cmt_id; + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Deleted bug comment #' || cmt_id + || ' posted by ' || ( CASE WHEN s_admin THEN 'administrator' ELSE 'empire' END ) + || ' ' || s_name ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.delete_comment( INT , BIGINT ) TO :dbuser; + + + +-- +-- Validates a bug report +-- +-- Parameters: +-- a_id Admin identifier +-- br_id Report identifier +-- n_stat New status +-- is_pub Whether the report is to be made public +-- g_creds Credits to grand (0: none, 1: small amount, 2: medium, 3: lots) +-- keep_snap Whether the snapshot of the empire should be kept +-- + +CREATE OR REPLACE FUNCTION bugs.validate_report( a_id INT , br_id BIGINT , n_stat bug_status_type , is_pub BOOLEAN , g_creds INT , keep_snap BOOLEAN ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + grp_id BIGINT; + evt_id BIGINT; + sub_id BIGINT; + u_id INT; + rgc INT := 0; +BEGIN + -- Find and lock the record + SELECT INTO grp_id evt.group_id + FROM bugs.initial_report_events ire + INNER JOIN bugs.events evt ON ire.event_id = evt.event_id + INNER JOIN bugs.groups bg ON bg.group_id = evt.group_id + LEFT OUTER JOIN bugs.events oe ON oe.group_id = evt.group_id AND oe.e_type = 'STATUS' + WHERE oe.group_id IS NULL AND ire.event_id = br_id + FOR UPDATE OF ire , evt , bg; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Send update notifications + sub_id := bugs.goc_admin_submitter( a_id ); + PERFORM bugs.update_notification( br_id , sub_id ); + + -- Set new status + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( grp_id , sub_id , 'STATUS' ) + RETURNING event_id INTO evt_id; + INSERT INTO bugs.status_change_events ( event_id , status ) + VALUES ( evt_id , n_stat ); + + -- Set visibility + IF is_pub + THEN + INSERT INTO bugs.events( group_id , submitter_id , e_type ) + VALUES ( grp_id , sub_id , 'VISIBILITY' ) + RETURNING event_id INTO evt_id; + INSERT INTO bugs.visibility_events ( event_id , visible ) + VALUES ( evt_id , is_pub ); + END IF; + + -- Grant credits, if requested and possible + IF g_creds > 0 + THEN + SELECT INTO u_id account_id + FROM bugs.events + INNER JOIN bugs.user_submitters USING (submitter_id) + WHERE event_id = br_id; + IF FOUND + THEN + rgc := floor( CASE g_creds + WHEN 1 THEN sys.get_constant( 'bugtracker.lowCredits') + WHEN 2 THEN sys.get_constant( 'bugtracker.mediumCredits') + ELSE sys.get_constant( 'bugtracker.highCredits') + END ); + UPDATE users.credentials + SET credits = credits + g_creds + WHERE address_id = u_id; + END IF; + END IF; + + -- Remove snapshot data + IF NOT keep_snap + THEN + DELETE FROM bugs.account_status_data WHERE event_id = br_id; + END IF; + + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Validation of bug report #' || br_id + || ': status set to ' || n_stat || ', visibility ' || ( CASE WHEN is_pub THEN 'public' ELSE 'hidden' END ) + || ', ' || rgc || ' credit(s) granted, snapshot ' || (CASE WHEN keep_snap THEN 'kept' ELSE 'deleted' END ) || '.' ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.validate_report( INT , BIGINT , bug_status_type , BOOLEAN , INT , BOOLEAN ) TO :dbuser; + + + +-- +-- Sets a bug report's status +-- +-- Parameters: +-- a_id Admin identifier +-- br_id Report identifier +-- n_stat New status +-- + +CREATE OR REPLACE FUNCTION bugs.set_report_status( a_id INT , br_id BIGINT , n_stat bug_status_type ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + grp_id BIGINT; + evt_id BIGINT; + sub_id BIGINT; +BEGIN + -- Find and lock the record + SELECT INTO grp_id evt.group_id + FROM bugs.initial_report_events ire + INNER JOIN bugs.events evt ON ire.event_id = evt.event_id + INNER JOIN bugs.groups bg ON bg.group_id = evt.group_id + WHERE ire.event_id = br_id + FOR UPDATE OF ire , evt , bg; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Do not add status change events if the status is already the same + PERFORM status FROM bugs.br_main_view + WHERE group_id = grp_id AND status <> n_stat::TEXT; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Set new status + sub_id := bugs.goc_admin_submitter( a_id ); + PERFORM bugs.update_notification( br_id , sub_id ); + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( grp_id , sub_id , 'STATUS' ) + RETURNING event_id INTO evt_id; + INSERT INTO bugs.status_change_events ( event_id , status ) + VALUES ( evt_id , n_stat ); + + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Set status of bug report #' || br_id || ' to ' || n_stat ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.set_report_status( INT , BIGINT , bug_status_type ) TO :dbuser; + + + +-- +-- Changes a bug report's visibility +-- +-- Parameters: +-- a_id Admin identifier +-- br_id Report identifier +-- + +CREATE OR REPLACE FUNCTION bugs.toggle_report_visibility( a_id INT , br_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + grp_id BIGINT; + evt_id BIGINT; + sub_id BIGINT; + c_vis BOOLEAN; +BEGIN + -- Find and lock the record + SELECT INTO grp_id evt.group_id + FROM bugs.initial_report_events ire + INNER JOIN bugs.events evt ON ire.event_id = evt.event_id + INNER JOIN bugs.groups bg ON bg.group_id = evt.group_id + WHERE ire.event_id = br_id + FOR UPDATE OF ire , evt , bg; + IF NOT FOUND + THEN + RETURN; + END IF; + + -- Get the report's current visibility + SELECT INTO c_vis visible FROM bugs.br_main_view WHERE group_id = grp_id; + + -- Set new visibility + sub_id := bugs.goc_admin_submitter( a_id ); + PERFORM bugs.update_notification( br_id , sub_id ); + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( grp_id , sub_id , 'VISIBILITY' ) + RETURNING event_id INTO evt_id; + INSERT INTO bugs.visibility_events ( event_id , visible ) + VALUES ( evt_id , NOT c_vis ); + + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Bug report #' || br_id || ' is now ' + ||( CASE WHEN c_vis THEN 'hidden' ELSE 'public' END ) ); +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.toggle_report_visibility( INT , BIGINT ) TO :dbuser; + + + +-- +-- Merges two bug reports +-- +-- Parameters: +-- a_id Administrator identifier +-- br1_id First bug report +-- br2_id Second bug report +-- +-- Returns: +-- err_code Error code: +-- 0 no error +-- 1 bug report not found +-- 2 bug reports already merged +-- 3 incorrect status (both reports should be OPEN) +-- + +CREATE OR REPLACE FUNCTION bugs.merge_reports( a_id INT , br1_id BIGINT , br2_id BIGINT , OUT err_code INT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + grp1_id BIGINT; + grp2_id BIGINT; + grp1_s TEXT; + grp2_s TEXT; + evt_id BIGINT; + sub_id BIGINT; +BEGIN + -- Get group identifiers and statuses + SELECT INTO grp1_id , grp1_s g.group_id , sv.status + FROM bugs.initial_report_events ire + INNER JOIN bugs.events evt USING (event_id) + INNER JOIN bugs.groups g USING ( group_id ) + INNER JOIN bugs.br_status sv USING ( group_id ) + WHERE ire.event_id = br1_id + FOR UPDATE OF ire , evt , g; + IF NOT FOUND + THEN + err_code := 1; + RETURN; + END IF; + + SELECT INTO grp2_id , grp2_s g.group_id , sv.status + FROM bugs.initial_report_events ire + INNER JOIN bugs.events evt USING (event_id) + INNER JOIN bugs.groups g USING ( group_id ) + INNER JOIN bugs.br_status sv USING ( group_id ) + WHERE ire.event_id = br2_id + FOR UPDATE OF ire , evt , g; + IF NOT FOUND + THEN + err_code := 1; + RETURN; + ELSEIF grp1_id = grp2_id + THEN + err_code := 2; + RETURN; + ELSEIF grp1_s <> 'OPEN' OR grp2_s <> 'OPEN' + THEN + err_code := 3; + RETURN; + END IF; + + -- Send update notification + sub_id := bugs.goc_admin_submitter( a_id ); + PERFORM bugs.update_notification( br1_id , br2_id , sub_id ); + + -- Move events + UPDATE bugs.events SET group_id = grp2_id + WHERE group_id = grp1_id; + + -- Prepare update of user view status + CREATE TEMPORARY TABLE vs_move( + user_id INT , + last_view TIMESTAMP WITHOUT TIME ZONE + ) ON COMMIT DROP; + INSERT INTO vs_move + SELECT user_id , max( last_view ) FROM bugs.user_view_status + WHERE group_id = grp1_id OR group_id = grp2_id + GROUP BY user_id; + + -- Add merge event + INSERT INTO bugs.events ( group_id , submitter_id , e_type ) + VALUES ( grp2_id , sub_id , 'MERGE' ) + RETURNING event_id INTO evt_id; + INSERT INTO bugs.merge_events ( event_id , initial_post_id ) + VALUES ( evt_id , br1_id ); + + -- Update user view status, delete old group + DELETE FROM bugs.user_view_status WHERE group_id = grp1_id OR group_id = grp2_id; + INSERT INTO bugs.user_view_status( group_id , user_id , last_view ) + SELECT grp2_id , user_id , last_view FROM vs_move; + DELETE FROM bugs.groups WHERE group_id = grp1_id; + + PERFORM admin.write_log( a_id , 'INFO'::log_level , 'Merged bug report #' || br1_id + || ' into report #' || br2_id ); + err_code := 0; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION bugs.merge_reports( INT , BIGINT , BIGINT ) TO :dbuser; + + + + +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- VIEWS USED TO GENERATE XML DUMPS -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- +-- --------------------------------------------------------------------------------------------------------------------------------------------------------------- -- + +CREATE VIEW bugs.dump_main_view + AS SELECT ss.current_tick , ss.next_tick , + u.id AS account_id , u.address AS account_address , u.game_credits , + u.status AS account_status , u.language AS account_language , + e.name_id AS empire_id , u.current_empire AS empire_name , e.cash AS cash , + a.id AS alliance_id , a.tag AS alliance_tag , am.is_pending AS alliance_pending + FROM emp.empires e + INNER JOIN admin.users_list u ON u.current_empire_id = e.name_id + INNER JOIN sys.status ss ON TRUE + LEFT OUTER JOIN emp.alliance_members am ON am.empire_id = e.name_id + LEFT OUTER JOIN emp.alliances a ON a.id = am.alliance_id; + +GRANT SELECT ON bugs.dump_main_view TO :dbuser; + + +CREATE VIEW bugs.dump_research_view + AS SELECT et.empire_id , et.line_id AS line_id , et.level AS level , + tst.name AS name , et.accumulated AS accumulated + FROM emp.technologies et + LEFT OUTER JOIN tech.levels tlv ON tlv.line_id = et.line_id AND tlv.level = et.level + LEFT OUTER JOIN defs.strings tst ON tst.id = tlv.name_id; + +GRANT SELECT ON bugs.dump_research_view TO :dbuser; + + +CREATE VIEW bugs.dump_planets_view + AS SELECT ep.empire_id , ep.planet_id , p.population , + ( ph.current / p.population )::REAL AS current_happiness , ph.target AS target_happiness , + cq.money AS civ_money , cq.work AS civ_work , + mq.money AS mil_money , mq.work AS mil_work + FROM emp.planets ep + INNER JOIN verse.planets p ON p.name_id = ep.planet_id + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.bld_queues cq ON cq.planet_id = p.name_id + INNER JOIN verse.mil_queues mq ON mq.planet_id = p.name_id + ORDER BY ep.planet_id; + +GRANT SELECT ON bugs.dump_planets_view TO :dbuser; + + +CREATE VIEW bugs.dump_queues_view + AS SELECT ep.empire_id , ep.planet_id , FALSE AS military , q.queue_order , + q.building_id AS item_id , qin.name AS item_name , + q.destroy , q.amount + FROM emp.planets ep + INNER JOIN verse.bld_items q ON q.queue_id = ep.planet_id + INNER JOIN defs.strings qin ON qin.id = q.building_id + UNION ALL SELECT ep.empire_id , ep.planet_id , TRUE AS military , q.queue_order , + q.ship_id AS item_id , qin.name AS item_name , FALSE AS destroy , q.amount + FROM emp.planets ep + INNER JOIN verse.mil_items q ON q.queue_id = ep.planet_id + INNER JOIN defs.strings qin ON qin.id = q.ship_id; + +GRANT SELECT ON bugs.dump_queues_view TO :dbuser; + + +CREATE VIEW bugs.dump_buildings_view + AS SELECT ep.empire_id , ep.planet_id , b.building_id , bn.name AS building_name , + b.amount , b.damage + FROM emp.planets ep + INNER JOIN verse.planet_buildings b USING( planet_id ) + INNER JOIN defs.strings bn ON bn.id = b.building_id + WHERE b.amount > 0 + ORDER BY building_id; + +GRANT SELECT ON bugs.dump_buildings_view TO :dbuser; + + +CREATE VIEW bugs.dump_fleets_view + AS SELECT f.owner_id AS empire_id , f.id AS fleet_id , f.name AS fleet_name , + f.status , f.attacking , f.location_id , fln.name AS location_name , + fm.source_id , fsn.name AS source_name , fm.time_left , fm.state_time_left , + fmis.ref_point_id , rpn.name AS ref_point_name , fmis.outwards , fmis.past_ref_point , + fmos.start_x , fmos.start_y + FROM fleets.fleets f + INNER JOIN naming.map_names fln ON fln.id = f.location_id + LEFT OUTER JOIN fleets.movements fm ON fm.fleet_id = f.id + LEFT OUTER JOIN naming.map_names fsn ON fsn.id = fm.source_id + LEFT OUTER JOIN fleets.ms_system fmis ON fmis.movement_id = f.id + LEFT OUTER JOIN naming.map_names rpn ON rpn.id = fmis.ref_point_id + LEFT OUTER JOIN fleets.ms_space fmos ON fmos.movement_id = f.id + ORDER BY f.location_id , f.id; + +GRANT SELECT ON bugs.dump_fleets_view TO :dbuser; + + +CREATE VIEW bugs.dump_ships_view + AS SELECT f.owner_id AS empire_id , s.fleet_id , s.ship_id , sn.name AS ship_name , + s.amount , s.damage + FROM fleets.fleets f + INNER JOIN fleets.ships s ON s.fleet_id = f.id + INNER JOIN defs.strings sn ON sn.id = s.ship_id + ORDER BY s.ship_id; + +GRANT SELECT ON bugs.dump_ships_view TO :dbuser; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/210-admin-overview.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/210-admin-overview.sql new file mode 100644 index 0000000..f62dcef --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/functions/210-admin-overview.sql @@ -0,0 +1,64 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Views used to generate the administration overview +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + +CREATE VIEW admin.ov_new_messages + AS SELECT admin_id , count(*) AS new_messages + FROM msgs.admin_delivery + WHERE status = 'UNREAD' + GROUP BY admin_id; + + +CREATE VIEW admin.ov_pending_names + AS SELECT count(*) AS pending_names + FROM naming.changed_map_names + LEFT OUTER JOIN naming.validated_map_names USING (name_id) + WHERE validated_at IS NULL; + + +CREATE VIEW admin.ov_pending_bans + AS SELECT count(*) AS pending_bans + FROM admin.active_ban_requests + WHERE NOT validated; + + +CREATE VIEW admin.ov_pending_bugs + AS SELECT count(*) AS pending_bugs + FROM bugs.br_main_view + WHERE status = 'PENDING'; + + +CREATE VIEW admin.ov_open_bugs + AS SELECT count(*) AS open_bugs + FROM bugs.br_main_view + WHERE status = 'OPEN'; + + +CREATE VIEW admin.ov_updated_bugs + AS SELECT administrator_id , count(*) AS updated_bugs + FROM bugs.br_admin_view + WHERE updated + GROUP BY administrator_id; + + +CREATE VIEW admin.overview + AS SELECT a.id AS admin_id , + ( CASE WHEN nm IS NULL THEN 0 ELSE nm.new_messages END )::BIGINT AS new_messages , + pn.pending_names , pb.pending_bans , pbg.pending_bugs , ob.open_bugs , + ( CASE WHEN ub IS NULL THEN 0 ELSE ub.updated_bugs END )::BIGINT AS updated_bugs + FROM admin.administrators a + LEFT OUTER JOIN admin.ov_new_messages nm ON nm.admin_id = a.id + INNER JOIN admin.ov_pending_names pn ON TRUE + INNER JOIN admin.ov_pending_bans pb ON TRUE + INNER JOIN admin.ov_pending_bugs pbg ON TRUE + INNER JOIN admin.ov_open_bugs ob ON TRUE + LEFT OUTER JOIN admin.ov_updated_bugs ub ON ub.administrator_id = a.id + WHERE a.privileges <> 0; + +GRANT SELECT ON admin.overview TO :dbuser; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/000-updates-ctrl.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/000-updates-ctrl.sql new file mode 100644 index 0000000..9133bf8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/000-updates-ctrl.sql @@ -0,0 +1,172 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - control functions +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + +-- +-- Start a tick +-- + +CREATE OR REPLACE FUNCTION sys.start_tick( OUT tick_id BIGINT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + n_tick BIGINT; + c_tick BIGINT; +BEGIN + -- Get next / current tick + SELECT INTO n_tick , c_tick next_tick , current_tick + FROM sys.status + WHERE maintenance_start IS NULL + FOR UPDATE; + IF NOT FOUND OR c_tick IS NOT NULL THEN + tick_id := NULL; + RETURN; + END IF; + + -- Prepare game updates + UPDATE sys.updates SET last_tick = n_tick , status = 'FUTURE' + WHERE last_tick < n_tick; + + -- Update system status + UPDATE sys.status SET current_tick = n_tick , next_tick = n_tick + 1; + + tick_id := n_tick; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.start_tick( ) TO :dbuser; + + + +-- +-- Marks a tick as completed +-- + +CREATE OR REPLACE FUNCTION sys.end_tick( IN tick_id BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +BEGIN + UPDATE events.events SET status = 'READY' + WHERE status = 'TICK' AND tick = tick_id; + UPDATE sys.status SET current_tick = NULL; + PERFORM msgs.deliver_internal( ); +END; +$$ LANGUAGE plpgsql; + + + +-- +-- Check if a tick got "stuck" +-- + +CREATE OR REPLACE FUNCTION sys.check_stuck_tick( OUT tick_id BIGINT ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + c_tick BIGINT; + u_count INT; +BEGIN + -- Get next / current tick + SELECT INTO c_tick current_tick + FROM sys.status + WHERE maintenance_start IS NULL + FOR UPDATE; + IF NOT FOUND OR c_tick IS NULL THEN + tick_id := NULL; + RETURN; + END IF; + + -- Are there any updates left? + SELECT INTO u_count count(*) FROM sys.updates + WHERE status = 'FUTURE' AND last_tick = c_tick; + IF u_count = 0 THEN + PERFORM sys.end_tick( c_tick ); + tick_id := NULL; + ELSE + tick_id := c_tick; + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.check_stuck_tick( ) TO :dbuser; + + + +-- +-- Process game updates +-- +-- Parameters: +-- c_tick Current tick +-- +-- Returns: +-- TRUE if the function must be called again, FALSE otherwise +-- + +CREATE OR REPLACE FUNCTION sys.process_updates( IN c_tick BIGINT , OUT has_more BOOLEAN ) + STRICT VOLATILE + SECURITY DEFINER + AS $$ +DECLARE + b_size INT; + p_utype update_type; + utype update_type; + uid BIGINT; +BEGIN + b_size := sys.get_constant( 'game.batchSize' ); + p_utype := NULL; + + -- Mark at most b_size entries as being updated + FOR uid , utype IN SELECT id , gu_type FROM sys.updates + WHERE last_tick = c_tick AND status = 'FUTURE' + ORDER BY gu_type LIMIT b_size + LOOP + IF p_utype IS NULL THEN + p_utype := utype; + END IF; + EXIT WHEN utype <> p_utype; + UPDATE sys.updates SET status = 'PROCESSING' WHERE id = uid; + END LOOP; + + has_more := p_utype IS NOT NULL; + IF has_more THEN + -- Execute actual updates + EXECUTE 'SELECT sys.process_' || lower( p_utype::TEXT ) || '_updates( $1 )' + USING c_tick; + UPDATE sys.updates SET status = 'PROCESSED' + WHERE status = 'PROCESSING' AND last_tick = c_tick; + ELSE + -- If nothing was found, we're done + PERFORM sys.end_tick( c_tick ); + END IF; +END; +$$ LANGUAGE plpgsql; + +GRANT EXECUTE ON FUNCTION sys.process_updates( BIGINT ) TO :dbuser; + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/010-empire-money.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/010-empire-money.sql new file mode 100644 index 0000000..a0bb8b1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/010-empire-money.sql @@ -0,0 +1,81 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - empire money +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_empire_money_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + c_cash REAL; + c_debt REAL; +BEGIN + -- Lock empires for update + PERFORM e.name_id FROM sys.updates su + INNER JOIN emp.updates eu + ON eu.update_id = su.id + INNER JOIN emp.empires e + ON eu.empire_id = e.name_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'EMPIRE_MONEY' + FOR UPDATE OF e; + + -- Select all money-related data from empires being updated + FOR rec IN SELECT e.name_id AS id , e.cash AS cash , e.debt AS debt , + ( pov.planet_income - pov.planet_upkeep ) AS p_money , + fov.fleet_upkeep AS f_money , ( v.status = 'PROCESSED' ) AS on_vacation + FROM sys.updates su + INNER JOIN emp.updates eu ON eu.update_id = su.id + INNER JOIN emp.empires e ON eu.empire_id = e.name_id + INNER JOIN emp.fleets_overview fov ON fov.empire = e.name_id + INNER JOIN emp.planets_overview pov ON pov.empire = e.name_id + INNER JOIN naming.empire_names en ON en.id = e.name_id + LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'EMPIRE_MONEY' + LOOP + -- Compute new cash reserve + c_cash := 0; + IF rec.p_money IS NOT NULL THEN + c_cash := c_cash + rec.p_money; + END IF; + IF rec.f_money IS NOT NULL THEN + c_cash := c_cash - rec.f_money; + END IF; + + -- Effects of vacation mode + IF rec.on_vacation + THEN + c_cash := c_cash / sys.get_constant( 'vacation.cashDivider' ); + END IF; + + -- Handle debt + c_cash := rec.cash + c_cash / 1440.0; + IF c_cash < 0 THEN + c_debt := -c_cash; + c_cash := 0; + ELSE + c_debt := 0; + END IF; + + IF rec.debt > 0 AND c_debt = 0 + THEN + PERFORM events.debt_event( rec.id , FALSE ); + ELSEIF rec.debt = 0 AND c_debt > 0 + THEN + PERFORM events.debt_event( rec.id , TRUE ); + END IF; + + -- Update empire + UPDATE emp.empires SET cash = c_cash , debt = c_debt + WHERE name_id = rec.id; + END LOOP; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/020-empire-research.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/020-empire-research.sql new file mode 100644 index 0000000..d9e3cfe --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/020-empire-research.sql @@ -0,0 +1,86 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - empire research +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_empire_research_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + r_points REAL; + tu_rec RECORD; +BEGIN + -- Lock empires for update and planets for share + PERFORM e.name_id FROM sys.updates su + INNER JOIN emp.updates eu ON eu.update_id = su.id + INNER JOIN emp.empires e ON eu.empire_id = e.name_id + INNER JOIN emp.planets ep ON ep.empire_id = e.name_id + INNER JOIN verse.planets p ON p.name_id = ep.planet_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'EMPIRE_RESEARCH' + FOR UPDATE OF e + FOR SHARE OF ep , p; + + -- Process empires + FOR rec IN SELECT e.name_id AS id , ( v.status = 'PROCESSED' ) AS on_vacation , + sum( p.population ) AS population + FROM sys.updates su + INNER JOIN emp.updates eu ON eu.update_id = su.id + INNER JOIN emp.empires e ON eu.empire_id = e.name_id + INNER JOIN emp.planets ep ON ep.empire_id = e.name_id + INNER JOIN verse.planets p ON p.name_id = ep.planet_id + INNER JOIN naming.empire_names en ON en.id = e.name_id + LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'EMPIRE_RESEARCH' + GROUP BY e.name_id , v.status + LOOP + -- Insert any missing tech line + INSERT INTO emp.technologies ( empire_id , line_id ) + SELECT rec.id , l.name_id + FROM tech.lines l + LEFT OUTER JOIN emp.technologies t + ON t.line_id = l.name_id AND t.empire_id = rec.id + WHERE t.empire_id IS NULL; + + -- Compute research output + r_points := rec.population * sys.get_constant( 'game.work.rpPerPopUnit' ) / 1440.0; + IF rec.on_vacation + THEN + r_points := r_points / sys.get_constant( 'vacation.researchDivider' ); + END IF; + + -- Update technologies where: + -- 1) the level actually exists and + -- 2) accumulated points haven't reach the level's + FOR tu_rec IN SELECT t.line_id AS line_id , t.accumulated AS accumulated , + l.points AS points , ( l.points - t.accumulated ) AS diff , + l.id AS level_id + FROM emp.technologies t + INNER JOIN tech.levels l ON l.line_id = t.line_id + AND l.level = t.level AND t.accumulated < l.points + WHERE t.empire_id = rec.id + FOR UPDATE OF t + LOOP + UPDATE emp.technologies t SET accumulated = ( CASE + WHEN tu_rec.diff <= r_points THEN tu_rec.points + ELSE tu_rec.accumulated + r_points + END ) + WHERE t.line_id = tu_rec.line_id AND t.empire_id = rec.id; + + -- Send message + IF tu_rec.diff <= r_points + THEN + PERFORM events.tech_ready_event( rec.id , tu_rec.level_id ); + END IF; + END LOOP; + END LOOP; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/025-empire-debt.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/025-empire-debt.sql new file mode 100644 index 0000000..7bcaa9f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/025-empire-debt.sql @@ -0,0 +1,62 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - damage fleets and buildings when an +-- empire is out of cash and has too much upkeep +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + + +CREATE OR REPLACE FUNCTION sys.process_empire_debt_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + fleet_dr REAL; + bld_dr REAL; + empire INT; + debt REAL; + upkeep REAL; +BEGIN + fleet_dr := sys.get_constant( 'game.debt.fleet'); + bld_dr := sys.get_constant( 'game.debt.buildings'); + + FOR empire, debt IN SELECT e.name_id AS id , e.debt + FROM sys.updates su + INNER JOIN emp.updates eu ON eu.update_id = su.id + INNER JOIN emp.empires e ON eu.empire_id = e.name_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'EMPIRE_DEBT' AND e.debt > 0 + FOR UPDATE + LOOP + PERFORM sys.write_log( 'EmpireDebt' , 'DEBUG'::log_level , 'Handling debt for empire #' + || empire || ' (at tick: ' || debt || '; daily: ' || ( debt * 1440 ) || ')' ); + debt := debt * 1440.0; + + -- Does the empire own fleets? + SELECT INTO upkeep sum( d.upkeep * s.amount ) + FROM fleets.fleets f + INNER JOIN fleets.ships s ON s.fleet_id = f.id + INNER JOIN tech.buildables d ON d.name_id = s.ship_id + WHERE f.owner_id = empire; + IF upkeep IS NOT NULL + THEN + PERFORM fleets.handle_debt( empire , upkeep , ( CASE WHEN debt > upkeep THEN upkeep ELSE debt END ) , fleet_dr ); + debt := debt - upkeep; + CONTINUE WHEN debt <= 0; + END IF; + + -- Does the empire have buildings? + SELECT INTO upkeep sum( d.upkeep * b.amount ) + FROM emp.planets ep + INNER JOIN verse.planet_buildings b ON b.planet_id = ep.planet_id + INNER JOIN tech.buildables d ON d.name_id = b.building_id + WHERE ep.empire_id = empire; + CONTINUE WHEN NOT FOUND OR upkeep = 0; + PERFORM verse.handle_debt( empire , upkeep , debt , bld_dr ); + END LOOP; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/030-fleet-arrivals.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/030-fleet-arrivals.sql new file mode 100644 index 0000000..c9dd59e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/030-fleet-arrivals.sql @@ -0,0 +1,148 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - fleet arrivals +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_fleet_arrivals_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + lstat BOOLEAN; + f_ids BIGINT[]; +BEGIN + -- Lock all records + PERFORM f.id FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN fleets.fleets f ON f.location_id = p.name_id + INNER JOIN fleets.movements fm ON fm.fleet_id = f.id + INNER JOIN emp.empires e ON e.name_id = f.owner_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_ARRIVALS' + AND f.status = 'AVAILABLE' AND fm.time_left = 1 + FOR UPDATE; + + -- Update attack status according to planet owners and enemy lists + FOR rec IN SELECT ep.empire_id AS planet_owner , p.name_id AS planet , + f.owner_id AS fleet_owner , ( v.status = 'PROCESSED' AND b.id IS NULL ) AS on_vacation , + bool_or( f.attacking ) AS attacking + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN fleets.fleets f ON f.location_id = p.name_id + INNER JOIN fleets.movements fm ON fm.fleet_id = f.id + LEFT OUTER JOIN emp.planets ep ON ep.planet_id = p.name_id + LEFT OUTER JOIN naming.empire_names en ON en.id = ep.empire_id + LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id + LEFT OUTER JOIN battles.battles b + ON b.location_id = p.name_id AND b.last_tick IS NULL + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_ARRIVALS' + AND f.status = 'AVAILABLE' AND fm.time_left = 1 + GROUP BY p.name_id , ep.empire_id , f.owner_id , v.status , b.id + LOOP + -- Fleets owned by the planet's owner are never attacking, same for fleets arriving on + -- planets that are on vacation + IF rec.fleet_owner = rec.planet_owner OR rec.on_vacation THEN + UPDATE fleets.fleets f SET attacking = FALSE + FROM fleets.movements m + WHERE f.status = 'AVAILABLE' AND f.owner_id = rec.fleet_owner + AND f.location_id = rec.planet AND m.fleet_id = f.id AND m.time_left = 1; + CONTINUE; + END IF; + + -- Check enemy lists + PERFORM * FROM emp.enemies + WHERE empire = rec.planet_owner AND enemy = rec.fleet_owner; + IF FOUND + THEN + -- Fleet owner in the planet owner's EL + UPDATE fleets.fleets f SET attacking = TRUE + FROM fleets.movements m + WHERE f.status = 'AVAILABLE' AND f.owner_id = rec.fleet_owner + AND f.location_id = rec.planet AND m.fleet_id = f.id AND m.time_left = 1; + CONTINUE; + END IF; + + -- If one of the arriving fleets is attacking, or if the local fleets are already attacking, + -- then switch all local or arriving fleets to attack + SELECT INTO lstat f.attacking + FROM fleets.fleets f + LEFT OUTER JOIN fleets.movements fm ON fm.fleet_id = f.id + WHERE f.owner_id = rec.fleet_owner AND f.location_id = rec.planet AND fm IS NULL + GROUP BY f.attacking; + IF ( FOUND AND lstat ) OR rec.attacking + THEN + SELECT INTO f_ids array_agg( f.id ) FROM fleets.fleets f + WHERE f.owner_id = rec.fleet_owner AND f.location_id = rec.planet; + PERFORM fleets.set_mode( rec.fleet_owner , f_ids , TRUE ); + CONTINUE; + END IF; + END LOOP; + + -- Prepare fleet arrival events + CREATE TEMPORARY TABLE fleet_arrivals( + loc_id INT , + loc_name VARCHAR(20) , + own_id INT , + own_name VARCHAR(20) , + name VARCHAR(64) , + power BIGINT , + mode BOOLEAN , + src_id INT , + src_name VARCHAR(20) + ); + INSERT INTO fleet_arrivals + SELECT f.location_id , ln.name , f.owner_id , fon.name , + f.name , fs.power , f.attacking , fm.source_id , sn.name + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN fleets.fleets f ON f.location_id = p.name_id + INNER JOIN fleets.movements fm ON fm.fleet_id = f.id + INNER JOIN fleets.stats_view fs ON fs.id = f.id + INNER JOIN naming.empire_names fon ON fon.id = f.owner_id + INNER JOIN naming.map_names ln ON ln.id = f.location_id + INNER JOIN naming.map_names sn ON sn.id = fm.source_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_ARRIVALS' + AND f.status = 'AVAILABLE' AND fm.time_left = 1; + + -- Delete movement records, set redeployment penalties, update battles + FOR rec IN SELECT f.id AS fleet , fs.flight_time AS flight_time , + f.attacking AS attacking , b.id AS battle , + f.location_id AS location + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN fleets.fleets f ON f.location_id = p.name_id + INNER JOIN fleets.movements fm ON fm.fleet_id = f.id + INNER JOIN fleets.stats_view fs ON fs.id = f.id + LEFT OUTER JOIN battles.battles b + ON b.location_id = p.name_id AND b.last_tick IS NULL + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_ARRIVALS' + AND f.status = 'AVAILABLE' AND fm.time_left = 1 + LOOP + DELETE FROM fleets.movements + WHERE fleet_id = rec.fleet; + UPDATE fleets.fleets + SET status = 'REDEPLOYING' , + penalty = 1 + rec.flight_time * ( CASE WHEN rec.attacking THEN 40 ELSE 10 END ) + WHERE id = rec.fleet; + + -- Add fleets to battle (will not be executed if battle is NULL) + PERFORM battles.add_fleet( rec.battle , rec.fleet , FALSE , c_tick ); + END LOOP; + + -- Send fleet arrival events + PERFORM events.commit_fleet_arrivals( c_tick ); +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/040-fleet-movements.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/040-fleet-movements.sql new file mode 100644 index 0000000..184aa0a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/040-fleet-movements.sql @@ -0,0 +1,110 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - fleet movements +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_fleet_movements_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + rpid INT; +BEGIN + -- Lock all records + PERFORM f.id FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN fleets.fleets f ON f.location_id = p.name_id + INNER JOIN fleets.movements fm ON fm.fleet_id = f.id + INNER JOIN emp.empires e ON e.name_id = f.owner_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_MOVEMENTS' + AND f.status = 'AVAILABLE' + FOR UPDATE; + + -- Handle state transitions + FOR rec IN SELECT f.id AS id , max( fsd.flight_time ) AS flight_time , + s.x AS x , s.y AS y , s.id AS sys_id , + isms.ref_point_id AS is_ref_point , isms.outwards AS is_outwards , + isms.past_ref_point AS is_past_ref_point , + rp.system_id AS is_ref_point_system , rp.orbit AS is_ref_point_orbit , + rps.x AS is_ref_point_x , rps.y AS is_ref_point_y + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN verse.systems s ON s.id = p.system_id + INNER JOIN fleets.fleets f ON f.location_id = p.name_id + INNER JOIN fleets.ships fs ON fs.fleet_id = f.id + INNER JOIN tech.ships fsd ON fsd.buildable_id = fs.ship_id + INNER JOIN fleets.movements m ON m.fleet_id = f.id + LEFT OUTER JOIN fleets.ms_system isms ON isms.movement_id = f.id + LEFT OUTER JOIN verse.planets rp ON isms.ref_point_id = rp.name_id + LEFT OUTER JOIN verse.systems rps ON rps.id = rp.system_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_MOVEMENTS' + AND f.status = 'AVAILABLE' AND m.state_time_left = 1 + GROUP BY f.id , s.x , s.y , s.id , isms.ref_point_id , isms.outwards , + isms.past_ref_point , rp.system_id , rp.orbit , rps.x , rps.y + LOOP + IF rec.is_ref_point_orbit IS NOT NULL THEN + IF rec.is_ref_point_orbit = 5 AND rec.is_outwards AND rec.is_past_ref_point THEN + -- Fleet exiting system + INSERT INTO fleets.ms_space ( movement_id , start_x , start_y ) + VALUES ( rec.id , rec.is_ref_point_x , rec.is_ref_point_y ); + DELETE FROM fleets.ms_system WHERE movement_id = rec.id; + UPDATE fleets.movements + SET state_time_left = 1 + fleets.compute_outerspace_duration( + rec.flight_time , rec.is_ref_point_x , rec.is_ref_point_y , rec.x , rec.y ) + WHERE fleet_id = rec.id; + ELSE + -- In-system state change + IF rec.is_past_ref_point THEN + SELECT INTO rpid p.name_id FROM verse.planets p + WHERE p.system_id = rec.is_ref_point_system + AND p.orbit = rec.is_ref_point_orbit + ( CASE WHEN rec.is_outwards THEN 1 ELSE -1 END ); + UPDATE fleets.ms_system + SET past_ref_point = FALSE , ref_point_id = rpid + WHERE movement_id = rec.id; + ELSE + UPDATE fleets.ms_system SET past_ref_point = TRUE + WHERE movement_id = rec.id; + END IF; + UPDATE fleets.movements + SET state_time_left = rec.flight_time + 1 + WHERE fleet_id = rec.id; + END IF; + ELSE + -- Fleet entering system + SELECT INTO rpid p.name_id FROM verse.planets p + WHERE p.system_id = rec.sys_id AND p.orbit = 5; + INSERT INTO fleets.ms_system ( movement_id , ref_point_id , outwards , past_ref_point ) + VALUES ( rec.id , rpid , FALSE , FALSE ); + DELETE FROM fleets.ms_space WHERE movement_id = rec.id; + UPDATE fleets.movements + SET state_time_left = rec.flight_time + 1 + WHERE fleet_id = rec.id; + END IF; + END LOOP; + + -- Decrease movement and state time + UPDATE fleets.movements + SET state_time_left = state_time_left - 1 , + time_left = time_left - 1 + WHERE fleet_id IN ( + SELECT f.id FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN fleets.fleets f ON f.location_id = p.name_id + INNER JOIN fleets.movements fm ON fm.fleet_id = f.id + INNER JOIN emp.empires e ON e.name_id = f.owner_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_MOVEMENTS' + AND f.status = 'AVAILABLE' ); +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/050-fleet-status.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/050-fleet-status.sql new file mode 100644 index 0000000..7249954 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/050-fleet-status.sql @@ -0,0 +1,77 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - fleet status +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_fleet_status_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + mt_id BIGINT; +BEGIN + -- Lock all records + PERFORM f.id FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN fleets.fleets f ON f.location_id = p.name_id + INNER JOIN emp.empires e ON e.name_id = f.owner_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_STATUS' + FOR UPDATE; + + -- Fleet deployments + FOR rec IN SELECT f.id AS fleet , f.owner_id AS owner , f.location_id AS location , + b.id AS battle + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN fleets.fleets f ON f.location_id = vu.planet_id + AND f.status = 'DEPLOYING' AND f.penalty = 1 + INNER JOIN emp.empires e ON e.name_id = f.owner_id + LEFT OUTER JOIN battles.battles b + ON b.location_id = f.location_id AND b.last_tick IS NULL + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_STATUS' + LOOP + -- Add fleet to battle (will be ignored if battle is NULL) + PERFORM battles.add_fleet( rec.battle , rec.fleet , TRUE , c_tick ); + + -- Find the biggest available fleet belonging to that owner + SELECT INTO mt_id f.id + FROM fleets.fleets f + INNER JOIN fleets.ships s ON s.fleet_id = f.id + INNER JOIN tech.ships sd ON sd.buildable_id = s.ship_id + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id + WHERE f.owner_id = rec.owner AND f.location_id = rec.location + AND m.fleet_id IS NULL AND f.status = 'AVAILABLE' + GROUP BY f.id + ORDER BY sum( sd.power * s.amount ) DESC + LIMIT 1; + CONTINUE WHEN NOT FOUND; + + -- Merge fleet + PERFORM fleets.merge_ships( mt_id , rec.fleet ); + DELETE FROM fleets.fleets WHERE id = rec.fleet; + END LOOP; + + -- Fleets that must become available + UPDATE fleets.fleets f SET status = 'AVAILABLE' , penalty = 0 + FROM sys.updates su , verse.updates vu + WHERE vu.update_id = su.id AND f.location_id = vu.planet_id + AND f.penalty = 1 AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_STATUS' AND su.last_tick = c_tick; + + -- Fleets that still have a penalty + UPDATE fleets.fleets f SET penalty = penalty - 1 + FROM sys.updates su , verse.updates vu + WHERE vu.update_id = su.id AND f.location_id = vu.planet_id + AND f.penalty > 1 AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_FLEET_STATUS' AND su.last_tick = c_tick; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/060-planet-battle.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/060-planet-battle.sql new file mode 100644 index 0000000..d944f65 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/060-planet-battle.sql @@ -0,0 +1,181 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - battles (start, main computation, end) +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_battle_start_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + p_id INT; +BEGIN + FOR p_id IN SELECT p.name_id + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON vu.planet_id = p.name_id + LEFT OUTER JOIN battles.battles b + ON b.location_id = p.name_id AND b.last_tick IS NULL + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_BATTLE_START' AND b.location_id IS NULL + FOR UPDATE OF p + LOOP + IF battles.check_start( p_id ) THEN + PERFORM events.battle_start_event( battles.initialise( p_id , c_tick ) ); + END IF; + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + + +CREATE OR REPLACE FUNCTION sys.process_planet_battle_main_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + ttfi INT; + initi REAL; + dbonus REAL; + dmg REAL; + rdmg REAL; + rec RECORD; + a_power BIGINT; + d_power BIGINT; + p_power BIGINT; + bmod REAL; + a_dmg REAL; + d_dmg REAL; +BEGIN + ttfi := floor( sys.get_constant( 'game.battle.timeToFullIntensity' ) )::INT; + initi := sys.get_constant( 'game.battle.initialIntensity' ); + dbonus := sys.get_constant( 'game.battle.defenceBonus'); + dmg := sys.get_constant( 'game.battle.damage' ); + rdmg := sys.get_constant( 'game.battle.randomDamage' ); + + FOR rec IN SELECT b.id AS battle , b.first_tick AS first_tick , + b.location_id AS location , ( ph.current / p.population )::REAL AS happiness + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON vu.planet_id = p.name_id + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN battles.battles b + ON b.location_id = p.name_id AND b.last_tick IS NULL + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_BATTLE_MAIN' + FOR UPDATE OF p , b + LOOP + PERFORM sys.write_log( 'BattleUpdate' , 'DEBUG'::log_level , 'Handling battle #' || rec.battle + || ' at planet #' || rec.location ); + + -- Get stationary defence power + p_power := floor( verse.adjust_production( verse.get_raw_production( rec.location , 'DEF' ) , rec.happiness ) ); + + -- Get fleets power + a_power := battles.get_fleets_power( rec.battle , c_tick , TRUE ); + d_power := battles.get_fleets_power( rec.battle , c_tick , FALSE ); + IF a_power = 0 OR d_power + p_power = 0 + THEN + PERFORM battles.set_defence_power( rec.battle , c_tick , p_power ); + CONTINUE; + END IF; + + PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Attack: ' || a_power + || '; planetary defences: ' || p_power || '; defence: ' || d_power ); + + -- Compute battle intensity + IF c_tick - rec.first_tick < ttfi THEN + bmod := initi + ( 1 - initi ) * ( c_tick - rec.first_tick ) / ttfi; + ELSE + bmod := 1.0; + END IF; + PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Intensity modifier: ' || bmod ); + + -- Compute damage + d_dmg := bmod * ( d_power * ( 1 + dbonus ) + p_power ) * dmg * ( 1 - rdmg + 2.0 * rdmg * random() ); + a_dmg := bmod * a_power * dmg * ( 1 - rdmg + 2.0 * rdmg * random() ); + PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Damage - to defence: ' || a_dmg + || '; to attack: ' || d_dmg ); + + -- Inflict damage + PERFORM battles.inflict_damage( rec.battle , a_dmg , FALSE , c_tick ); + PERFORM battles.inflict_damage( rec.battle , d_dmg , TRUE , c_tick ); + + -- Update defence power + p_power := floor( verse.adjust_production( verse.get_raw_production( rec.location , 'DEF' ) , rec.happiness ) ); + PERFORM battles.set_defence_power( rec.battle , c_tick , p_power ); + END LOOP; +END; +$$ LANGUAGE plpgsql; + + + + +CREATE OR REPLACE FUNCTION sys.process_planet_battle_end_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + n_owner INT; +BEGIN + FOR rec IN SELECT b.id AS battle , b.location_id AS location + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON vu.planet_id = p.name_id + INNER JOIN battles.battles b + ON b.location_id = p.name_id AND b.last_tick IS NULL + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_BATTLE_END' + FOR UPDATE OF p , b + LOOP + IF battles.get_fleets_power( rec.battle , c_tick , TRUE ) = 0 THEN + -- Attack is dead/gone, end the battle + UPDATE battles.battles SET last_tick = c_tick + WHERE id = rec.battle; + PERFORM events.battle_end_event( rec.battle ); + ELSEIF battles.get_fleets_power( rec.battle , c_tick , FALSE ) + battles.get_defence_power( rec.battle , c_tick ) = 0 THEN + -- Defence is dead/gone, transfer planet ownership to biggest fleet owner + n_owner := battles.get_biggest_fleet_owner( rec.battle , c_tick ); + PERFORM events.planet_ochange_events( rec.location , n_owner ); + PERFORM emp.leave_planet( rec.location ); + INSERT INTO emp.planets( planet_id , empire_id ) + VALUES( rec.location , n_owner ); + + -- End the battle + UPDATE battles.battles SET last_tick = c_tick + WHERE id = rec.battle; + PERFORM events.battle_end_event( rec.battle ); + + -- Set fleets in orbit to defence if they're not on the new owner's enemy list + UPDATE fleets.fleets f SET attacking = ( ele.empire IS NOT NULL ) + FROM fleets.fleets f2 + LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f2.id + LEFT OUTER JOIN emp.enemies ele ON ele.enemy = f2.owner_id AND ele.empire = n_owner + WHERE f.id = f2.id AND f.location_id = rec.location AND m.fleet_id IS NULL; + + -- Check if the battle needs to be restarted + IF battles.check_start( rec.location ) THEN + PERFORM events.battle_start_event( battles.initialise( rec.location , c_tick ) ); + END IF; + ELSE + CONTINUE; + END IF; + + -- Mark the end of the battle + INSERT INTO battles.finished_battles_list + SELECT empire, battle, planet, x, y, orbit, name, first_tick, last_tick, last_update + FROM battles.full_battles_list + WHERE battle = rec.battle; + END LOOP; +END; +$$ LANGUAGE plpgsql; + diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/070-planet-abandon.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/070-planet-abandon.sql new file mode 100644 index 0000000..85128b7 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/070-planet-abandon.sql @@ -0,0 +1,48 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - abandon +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_abandon_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + p_id INT; +BEGIN + -- Lock all records + PERFORM p.name_id FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN emp.planets ep ON p.name_id = vu.planet_id + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + INNER JOIN emp.abandon a ON a.planet_id = p.name_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_ABANDON' + FOR UPDATE; + + -- Handle planets where time has run out + FOR p_id IN SELECT p.name_id + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON p.name_id = vu.planet_id + INNER JOIN emp.abandon a ON a.planet_id = p.name_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_ABANDON' AND a.time_left = 1 + LOOP + PERFORM emp.leave_planet( p_id ); + END LOOP; + + -- Update all abandon records + UPDATE emp.abandon a SET time_left = a.time_left - 1 + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_ABANDON' AND a.planet_id = vu.planet_id; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/080-planet-construction.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/080-planet-construction.sql new file mode 100644 index 0000000..37470af --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/080-planet-construction.sql @@ -0,0 +1,217 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - buildings construction and destruction +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_construction_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + wu_per_pop REAL; + dest_work REAL; + dest_rec REAL; + cur_empire INT; + cur_cash REAL; + cur_planet INT; + p_finished BOOLEAN; + cur_wus REAL; + cur_acc_c REAL; + n_found INT; + n_removed INT; + i_work REAL; + i_cost REAL; + can_do REAL; + must_do INT; +BEGIN + -- Get constants + wu_per_pop := sys.get_constant( 'game.work.wuPerPopUnit' ); + dest_work := sys.get_constant( 'game.work.destructionWork' ); + dest_rec := - sys.get_constant( 'game.work.destructionRecovery' ); + + -- Enter update loop + cur_empire := NULL; + cur_planet := NULL; + FOR rec IN SELECT p.name_id AS id , p.population AS pop , + ( ph.current / p.population )::REAL AS happiness , + e.name_id AS owner , e.cash AS cash , + q.money AS acc_cash , q.work AS acc_work , + qi.queue_order AS qorder , qi.amount AS amount , + qi.destroy AS destroy , qi.building_id AS building , + b.work AS req_work , b.cost AS req_cost + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON vu.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.bld_queues q ON q.planet_id = p.name_id + INNER JOIN verse.bld_items qi ON qi.queue_id = q.planet_id + INNER JOIN tech.buildables b ON b.name_id = qi.building_id + INNER JOIN naming.empire_names en ON en.id = e.name_id + LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_CONSTRUCTION' + AND ( v.account_id IS NULL OR v.status <> 'PROCESSED' ) + ORDER BY e.name_id , p.name_id , qi.queue_order + FOR UPDATE OF p , e , q , qi + LOOP + -- Update accumulated work and money for the previous planet + IF cur_planet IS NOT NULL AND cur_planet <> rec.id THEN + IF n_found = n_removed THEN + cur_wus := 0; + cur_acc_c := 0; + PERFORM events.empty_queue_events( cur_empire , cur_planet , FALSE , c_tick ); + END IF; + + UPDATE verse.bld_queues + SET money = cur_acc_c , work = cur_wus + WHERE planet_id = cur_planet; + cur_cash := cur_cash - cur_acc_c; + + IF cur_cash < 0 THEN + cur_cash := 0; + END IF; + + cur_planet := NULL; + END IF; + + -- Update cash of the previous empire + IF cur_empire IS NOT NULL AND cur_empire <> rec.owner + THEN + UPDATE emp.empires SET cash = cur_cash + WHERE name_id = cur_empire; + cur_empire := NULL; + END IF; + + -- If this is the first record or if the empire changed... + IF cur_empire IS NULL THEN + cur_empire := rec.owner; + cur_cash := rec.cash; + END IF; + + -- If this is the first record or if the planet changed... + IF cur_planet IS NULL THEN + cur_planet := rec.id; + cur_cash := cur_cash + rec.acc_cash; + cur_wus := rec.acc_work + verse.adjust_production( + ( rec.pop * wu_per_pop )::REAL , + rec.happiness + ); + n_found := 1; + n_removed := 0; + cur_acc_c := 0; + p_finished := FALSE; + ELSE + n_found := n_found + 1; + END IF; + + -- If we're done updating this planet but there were more items... + IF p_finished THEN + IF n_removed > 0 THEN + UPDATE verse.bld_items + SET queue_order = rec.qorder - n_removed + WHERE queue_order = rec.qorder AND queue_id = rec.id; + END IF; + CONTINUE; + END IF; + + -- Compute the actual cost and required work of the item + i_cost := rec.req_cost * ( CASE WHEN rec.destroy THEN dest_rec ELSE 1.0 END ); + i_work := rec.req_work * ( CASE WHEN rec.destroy THEN dest_work ELSE 1.0 END ); + + -- Compute how many items can be completed + can_do := cur_wus / i_work; + IF i_cost > 0 AND cur_cash / i_cost < can_do THEN + can_do := cur_cash / i_cost; + cur_wus := i_work * can_do; + END IF; + + -- If we can't build anything at this point... + IF can_do < 1 THEN + -- Set accumulated cash + IF i_cost > 0 THEN + cur_acc_c := can_do * i_cost; + END IF; + + -- Still update queue item if some items were removed + IF n_removed > 0 THEN + UPDATE verse.bld_items + SET queue_order = rec.qorder - n_removed + WHERE queue_order = rec.qorder AND queue_id = rec.id; + END IF; + + -- Done with this planet + p_finished := TRUE; + CONTINUE; + END IF; + + -- Compute how many actual items can be built + must_do := floor( can_do ); + IF must_do >= rec.amount THEN + must_do := rec.amount; + can_do := 0; + n_removed := n_removed + 1; + END IF; + + -- Handle construction / destruction + IF rec.destroy THEN + must_do := verse.do_destroy_buildings( rec.id , rec.building , must_do ); + PERFORM battles.remove_buildings( rec.id , rec.building , must_do , FALSE , c_tick + 1 ); + ELSE + PERFORM verse.do_construct_buildings( rec.id , rec.building , must_do ); + PERFORM battles.add_buildings( rec.id , rec.building , must_do , c_tick + 1 ); + END IF; + cur_cash := cur_cash - must_do * i_cost; + cur_wus := cur_wus - must_do * i_work; + + -- Check whether we're done with this queue + IF rec.qorder < n_removed THEN + -- Delete queue item + DELETE FROM verse.bld_items + WHERE queue_order = rec.qorder AND queue_id = rec.id; + ELSE + -- Update queue item + UPDATE verse.bld_items + SET queue_order = queue_order - n_removed , + amount = amount - floor( can_do ) + WHERE queue_order = rec.qorder AND queue_id = rec.id; + + -- Set accumulated cash + IF i_cost > 0 THEN + cur_acc_c := ( can_do - floor( can_do ) ) * i_cost; + END IF; + + p_finished := TRUE; + END IF; + END LOOP; + + -- If a planet was being procesed, update it and the empire + IF cur_planet IS NOT NULL THEN + IF n_found = n_removed THEN + cur_wus := 0; + cur_acc_c := 0; + PERFORM events.empty_queue_events( cur_empire , cur_planet , FALSE , c_tick ); + END IF; + + UPDATE verse.bld_queues + SET money = cur_acc_c , work = cur_wus + WHERE planet_id = cur_planet; + cur_cash := cur_cash - cur_acc_c; + + IF cur_cash < 0 THEN + cur_cash := 0; + END IF; + + UPDATE emp.empires SET cash = cur_cash + WHERE name_id = cur_empire; + cur_empire := NULL; + END IF; +END; +$$ LANGUAGE plpgsql; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/090-planet-military.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/090-planet-military.sql new file mode 100644 index 0000000..f3c250a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/090-planet-military.sql @@ -0,0 +1,227 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - ship construction +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_military_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + cur_empire INT; + cur_cash REAL; + cur_planet INT; + p_finished BOOLEAN; + cur_wus REAL; + cur_acc_c REAL; + n_found INT; + n_removed INT; + can_do REAL; + must_do INT; + fl_id BIGINT; +BEGIN + -- Create temporary table for built ships + CREATE TEMPORARY TABLE blt_ships( + location INT , + owner INT , + ship INT , + amount INT + ); + + -- Enter update loop + cur_empire := NULL; + cur_planet := NULL; + FOR rec IN SELECT p.name_id AS id , + ( ph.current / p.population )::REAL AS happiness , + e.name_id AS owner , e.cash AS cash , + q.money AS acc_cash , q.work AS acc_work , + qi.queue_order AS qorder , qi.amount AS amount , + qi.ship_id AS ship , s.work AS req_work , s.cost AS req_cost + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON vu.planet_id = p.name_id + INNER JOIN emp.planets ep ON ep.planet_id = p.name_id + INNER JOIN emp.empires e ON e.name_id = ep.empire_id + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.mil_queues q ON q.planet_id = p.name_id + INNER JOIN verse.mil_items qi ON qi.queue_id = q.planet_id + INNER JOIN tech.buildables s ON s.name_id = qi.ship_id + INNER JOIN naming.empire_names en ON en.id = e.name_id + LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_MILITARY' + AND ( v.account_id IS NULL OR v.status <> 'PROCESSED' ) + ORDER BY e.name_id , p.name_id , qi.queue_order + FOR UPDATE OF p , e , q , qi + LOOP + -- Update accumulated work and money for the previous planet + IF cur_planet IS NOT NULL AND cur_planet <> rec.id THEN + IF n_found = n_removed THEN + cur_wus := 0; + cur_acc_c := 0; + PERFORM events.empty_queue_events( cur_empire , cur_planet , TRUE , c_tick ); + END IF; + + UPDATE verse.mil_queues + SET money = cur_acc_c , work = cur_wus + WHERE planet_id = cur_planet; + cur_cash := cur_cash - cur_acc_c; + + IF cur_cash < 0 THEN + cur_cash := 0; + END IF; + + cur_planet := NULL; + END IF; + + -- Update cash of the previous empire + IF cur_empire IS NOT NULL AND cur_empire <> rec.owner + THEN + UPDATE emp.empires SET cash = cur_cash + WHERE name_id = cur_empire; + cur_empire := NULL; + END IF; + + -- If this is the first record or if the empire changed... + IF cur_empire IS NULL THEN + cur_empire := rec.owner; + cur_cash := rec.cash; + END IF; + + -- If this is the first record or if the planet changed... + IF cur_planet IS NULL THEN + cur_planet := rec.id; + cur_cash := cur_cash + rec.acc_cash; + cur_wus := rec.acc_work + verse.adjust_production( + verse.get_raw_production( rec.id , 'WORK' ) , + rec.happiness + ); + n_found := 1; + n_removed := 0; + cur_acc_c := 0; + p_finished := FALSE; + ELSE + n_found := n_found + 1; + END IF; + + -- If we're done updating this planet but there were more items... + IF p_finished THEN + IF n_removed > 0 THEN + UPDATE verse.mil_items + SET queue_order = rec.qorder - n_removed + WHERE queue_order = rec.qorder AND queue_id = rec.id; + END IF; + CONTINUE; + END IF; + + -- Compute how many items can be completed + can_do := cur_wus / rec.req_work; + IF cur_cash / rec.req_cost < can_do THEN + can_do := cur_cash / rec.req_cost; + cur_wus := rec.req_work * can_do; + END IF; + + -- If we can't build anything at this point... + IF can_do < 1 THEN + -- Set accumulated cash + cur_acc_c := can_do * rec.req_cost; + + -- Still update queue item if some items were removed + IF n_removed > 0 THEN + UPDATE verse.mil_items + SET queue_order = rec.qorder - n_removed + WHERE queue_order = rec.qorder AND queue_id = rec.id; + END IF; + + -- Done with this planet + p_finished := TRUE; + CONTINUE; + END IF; + + -- Compute how many actual items can be built + must_do := floor( can_do ); + IF must_do >= rec.amount THEN + must_do := rec.amount; + can_do := 0; + n_removed := n_removed + 1; + END IF; + + -- Handle construction + INSERT INTO blt_ships( location , owner , ship , amount) + VALUES ( rec.id , rec.owner , rec.ship , must_do ); + cur_cash := cur_cash - must_do * rec.req_cost; + cur_wus := cur_wus - must_do * rec.req_work; + + -- Check whether we're done with this queue + IF rec.qorder < n_removed THEN + -- Delete queue item + DELETE FROM verse.mil_items + WHERE queue_order = rec.qorder AND queue_id = rec.id; + ELSE + -- Update queue item + UPDATE verse.mil_items + SET queue_order = queue_order - n_removed , + amount = amount - must_do + WHERE queue_order = rec.qorder AND queue_id = rec.id; + + -- Set accumulated cash + cur_acc_c := ( can_do - floor( can_do ) ) * rec.req_cost; + + p_finished := TRUE; + END IF; + END LOOP; + + -- If a planet was being procesed, update it and the empire + IF cur_planet IS NOT NULL THEN + IF n_found = n_removed THEN + cur_wus := 0; + cur_acc_c := 0; + PERFORM events.empty_queue_events( cur_empire , cur_planet , TRUE , c_tick ); + END IF; + + UPDATE verse.mil_queues + SET money = cur_acc_c , work = cur_wus + WHERE planet_id = cur_planet; + cur_cash := cur_cash - cur_acc_c; + + IF cur_cash < 0 THEN + cur_cash := 0; + END IF; + + UPDATE emp.empires SET cash = cur_cash + WHERE name_id = cur_empire; + cur_empire := NULL; + END IF; + + -- Spawn fleets + FOR cur_planet , cur_empire IN SELECT DISTINCT location , owner FROM blt_ships + LOOP + -- Get fleet's flight time + SELECT INTO must_do MAX( s.flight_time ) + FROM blt_ships b + INNER JOIN tech.ships s ON s.buildable_id = b.ship + WHERE b.location = cur_planet AND b.owner = cur_empire; + + -- Insert the fleet + INSERT INTO fleets.fleets (owner_id, location_id , attacking , status , penalty ) + VALUES ( cur_empire , cur_planet , FALSE , 'DEPLOYING' , must_do * 2 ) + RETURNING id INTO fl_id; + + -- Insert ships + INSERT INTO fleets.ships ( fleet_id , ship_id , amount , damage ) + SELECT fl_id , b.ship , sum( b.amount ) , 0 + FROM blt_ships b + WHERE b.location = cur_planet AND b.owner = cur_empire + GROUP BY b.ship; + END LOOP; + + -- Destroy temporary table + DROP TABLE blt_ships; +END; +$$ LANGUAGE plpgsql; diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/100-planet-population.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/100-planet-population.sql new file mode 100644 index 0000000..2a805f8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/100-planet-population.sql @@ -0,0 +1,104 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - population growth and happiness +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_population_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + rel_ch REAL; + abs_ch REAL; + g_fact REAL; + gf_inc REAL; + n_happ REAL; + t_happ REAL; + temp REAL; + growth REAL; + workers REAL; + str_thr REAL; +BEGIN + -- Get constants + rel_ch := sys.get_constant( 'game.happiness.relativeChange' ); + abs_ch := sys.get_constant( 'game.happiness.maxAbsoluteChange' ); + g_fact := sys.get_constant( 'game.growthFactor' ); + gf_inc := sys.get_constant( 'game.growthFactor.rCentre' ); + str_thr := sys.get_constant( 'game.happiness.strike' ); + + -- Process planets + FOR rec IN SELECT p.name_id AS id , p.population AS pop , + ph.target AS target , ph.current AS happy_pop , + ( ph.current / p.population )::REAL AS current + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON vu.planet_id = p.name_id + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_POPULATION' + FOR UPDATE OF p, ph + LOOP + IF round( rec.target / rel_ch ) = round( rec.current / rel_ch ) THEN + -- Happiness does not change + n_happ := rec.current; + ELSE + -- Compute new happiness + temp := rec.pop * rel_ch; + IF temp > abs_ch THEN + temp := abs_ch; + ELSEIF temp < 1 THEN + temp := 1; + END IF; + + IF rec.target < rec.current THEN + temp := - temp; + END IF; + + n_happ := ( rec.happy_pop + temp ) / rec.pop; + END IF; + + -- Compute population growth + temp := verse.adjust_production( verse.get_raw_production( rec.id , 'POP' ) , n_happ ); + growth := ( g_fact + temp * gf_inc ) * n_happ / 1440.0; + + -- Get workers + SELECT INTO workers SUM( b.amount * d.workers ) + FROM verse.planet_buildings b + INNER JOIN tech.buildings d + ON d.buildable_id = b.building_id + WHERE b.planet_id = rec.id; + IF workers IS NULL THEN + workers := 0; + END IF; + + -- Compute new target happiness + t_happ := verse.compute_happiness( rec.pop + growth , workers , + verse.adjust_production( verse.get_raw_production( rec.id , 'DEF' ) , n_happ ) , + emp.get_size( rec.id ) + ); + + -- Update planet and happiness records + UPDATE verse.planet_happiness + SET current = ( rec.pop + growth ) * n_happ , target = t_happ + WHERE planet_id = rec.id; + UPDATE verse.planets + SET population = rec.pop + growth + WHERE name_id = rec.id; + + -- Send strike begin/end messages + IF n_happ < str_thr AND rec.current >= str_thr + THEN + PERFORM events.strike_event( rec.id , TRUE ); + ELSEIF n_happ >= str_thr AND rec.current < str_thr + THEN + PERFORM events.strike_event( rec.id , FALSE ); + END IF; + END LOOP; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/110-planet-money.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/110-planet-money.sql new file mode 100644 index 0000000..cbcc432 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/parts/updates/110-planet-money.sql @@ -0,0 +1,45 @@ +-- LegacyWorlds Beta 6 +-- PostgreSQL database scripts +-- +-- Game updates - planet income and upkeep +-- +-- Copyright(C) 2004-2010, DeepClone Development +-- -------------------------------------------------------- + + +CREATE OR REPLACE FUNCTION sys.process_planet_money_updates( c_tick BIGINT ) + RETURNS VOID + STRICT VOLATILE + SECURITY INVOKER + AS $$ +DECLARE + rec RECORD; + incme REAL; +BEGIN + FOR rec IN SELECT p.name_id AS id , p.population AS pop , + ( ph.current / p.population )::REAL AS happiness , + ( ea.planet_id IS NULL ) AS produces_income + FROM sys.updates su + INNER JOIN verse.updates vu ON vu.update_id = su.id + INNER JOIN verse.planets p ON vu.planet_id = p.name_id + INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id + INNER JOIN verse.planet_money pm ON pm.planet_id = p.name_id + LEFT OUTER JOIN emp.abandon ea ON ea.planet_id = p.name_id + WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' + AND su.gu_type = 'PLANET_MONEY' + FOR UPDATE OF p, pm + LOOP + IF rec.produces_income THEN + incme := verse.compute_income( rec.pop , rec.happiness , + verse.get_raw_production( rec.id , 'CASH' ) + ); + ELSE + incme := 0; + END IF; + UPDATE verse.planet_money + SET income = incme , + upkeep = verse.get_planet_upkeep( rec.id ) + WHERE planet_id = rec.id; + END LOOP; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/db-structure/test-mode.sql b/legacyworlds-server/legacyworlds-server-data/db-structure/test-mode.sql new file mode 100644 index 0000000..777b268 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/db-structure/test-mode.sql @@ -0,0 +1,7 @@ +INSERT INTO admin.administrators (appear_as, pass_md5 , pass_sha1, privileges) + VALUES ( 'Test' , '...' , '...' , 0 ); +SELECT sys.set_constant( 'game.growthFactor' , 200 , 1 ); +SELECT sys.set_constant( 'game.battle.damage' , 0.05 , 1 ); +SELECT sys.set_constant( 'game.battle.timeToFullIntensity' , 5 , 1 ); +SELECT sys.set_constant( 'map.names.minDelay' , 1 , 1 ); +SELECT sys.set_constant( 'game.work.wuPerPopUnit' , 0.5 , 1 ); diff --git a/legacyworlds-server/legacyworlds-server-data/pom.xml b/legacyworlds-server/legacyworlds-server-data/pom.xml new file mode 100644 index 0000000..a84f721 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + legacyworlds-server + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-data + Legacy Worlds server data + 5.99.1 + This package contains all data access classes for the Legacy Worlds server. + + + + com.deepclone.lw + legacyworlds-session + ${project.version} + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/Account.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/Account.java new file mode 100644 index 0000000..dfb1648 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/Account.java @@ -0,0 +1,251 @@ +package com.deepclone.lw.sqld.accounts; + + +import java.sql.Timestamp; + +import com.deepclone.lw.cmd.admin.users.AccountStatus; + + + +public class Account +{ + + private int id; + + private String address; + + private String language; + + private String passMd5; + + private String passSha1; + + private int gameCredits; + + private AccountStatus status; + + private String validationToken; + + private String pwdRecoveryToken; + + private String addressChangeToken; + + private String newAddress; + + private Integer vacationCredits; + + private Integer vacationTime; + + private Timestamp vacationStart; + + private Timestamp inactivityStart; + + private String inactivityReason; + + private Integer banRequestId; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getAddress( ) + { + return address; + } + + + public void setAddress( String address ) + { + this.address = address; + } + + + public String getLanguage( ) + { + return language; + } + + + public void setLanguage( String language ) + { + this.language = language; + } + + + public String getPassMd5( ) + { + return passMd5; + } + + + public void setPassMd5( String passMd5 ) + { + this.passMd5 = passMd5; + } + + + public String getPassSha1( ) + { + return passSha1; + } + + + public void setPassSha1( String passSha1 ) + { + this.passSha1 = passSha1; + } + + + public int getGameCredits( ) + { + return gameCredits; + } + + + public void setGameCredits( int gameCredits ) + { + this.gameCredits = gameCredits; + } + + + public AccountStatus getStatus( ) + { + return status; + } + + + public void setStatus( AccountStatus status ) + { + this.status = status; + } + + + public String getValidationToken( ) + { + return validationToken; + } + + + public void setValidationToken( String validationToken ) + { + this.validationToken = validationToken; + } + + + public String getPwdRecoveryToken( ) + { + return pwdRecoveryToken; + } + + + public void setPwdRecoveryToken( String pwdRecoveryToken ) + { + this.pwdRecoveryToken = pwdRecoveryToken; + } + + + public String getAddressChangeToken( ) + { + return addressChangeToken; + } + + + public void setAddressChangeToken( String addressChangeToken ) + { + this.addressChangeToken = addressChangeToken; + } + + + public String getNewAddress( ) + { + return newAddress; + } + + + public void setNewAddress( String newAddress ) + { + this.newAddress = newAddress; + } + + + public Integer getVacationCredits( ) + { + return vacationCredits; + } + + + public void setVacationCredits( Integer vacationCredits ) + { + this.vacationCredits = vacationCredits; + } + + + public Integer getVacationTime( ) + { + return vacationTime; + } + + + public void setVacationTime( Integer vacationTime ) + { + this.vacationTime = vacationTime; + } + + + public Timestamp getVacationStart( ) + { + return vacationStart; + } + + + public void setVacationStart( Timestamp vacationStart ) + { + this.vacationStart = vacationStart; + } + + + public Timestamp getInactivityStart( ) + { + return inactivityStart; + } + + + public void setInactivityStart( Timestamp inactivityStart ) + { + this.inactivityStart = inactivityStart; + } + + + public String getInactivityReason( ) + { + return inactivityReason; + } + + + public void setInactivityReason( String inactivityReason ) + { + this.inactivityReason = inactivityReason; + } + + + public Integer getBanRequestId( ) + { + return banRequestId; + } + + + public void setBanRequestId( Integer banRequestId ) + { + this.banRequestId = banRequestId; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/AccountOperationResult.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/AccountOperationResult.java new file mode 100644 index 0000000..8300024 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/AccountOperationResult.java @@ -0,0 +1,35 @@ +package com.deepclone.lw.sqld.accounts; + + +public class AccountOperationResult +{ + + private Account account; + + private int errorCode; + + + public Account getAccount( ) + { + return account; + } + + + public void setAccount( Account account ) + { + this.account = account; + } + + + public int getErrorCode( ) + { + return errorCode; + } + + + public void setErrorCode( int errorCode ) + { + this.errorCode = errorCode; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/QuittingAccount.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/QuittingAccount.java new file mode 100644 index 0000000..b179c6b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/QuittingAccount.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.sqld.accounts; + + +public class QuittingAccount +{ + + private int id; + private String address; + private String language; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getAddress( ) + { + return address; + } + + + public void setAddress( String address ) + { + this.address = address; + } + + + public String getLanguage( ) + { + return language; + } + + + public void setLanguage( String language ) + { + this.language = language; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/ValidationResult.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/ValidationResult.java new file mode 100644 index 0000000..25e63b3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/accounts/ValidationResult.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.sqld.accounts; + + +public class ValidationResult +{ + private int accountError; + private int empireError; + private int planetError; + + + public int getAccountError( ) + { + return accountError; + } + + + public void setAccountError( int accountError ) + { + this.accountError = accountError; + } + + + public int getEmpireError( ) + { + return empireError; + } + + + public void setEmpireError( int empireError ) + { + this.empireError = empireError; + } + + + public int getPlanetError( ) + { + return planetError; + } + + + public void setPlanetError( int planetError ) + { + this.planetError = planetError; + } + + + public boolean isError( ) + { + return ( this.planetError != 0 || this.empireError != 0 || this.accountError != 0 ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/admin/AdminConnection.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/admin/AdminConnection.java new file mode 100644 index 0000000..17690cd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/admin/AdminConnection.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.sqld.admin; + + +public enum AdminConnection { + + SUCCESS , + PASSWORD , + INACTIVE + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/admin/AdminRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/admin/AdminRecord.java new file mode 100644 index 0000000..b21e7c9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/admin/AdminRecord.java @@ -0,0 +1,126 @@ +package com.deepclone.lw.sqld.admin; + + +public class AdminRecord +{ + + private int id; + private String name; + private int privileges; + private boolean active; + + private Integer account; + private String address; + private String pSha1; + private String pMd5; + private Boolean passChangeRequired; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public int getPrivileges( ) + { + return privileges; + } + + + public void setPrivileges( int privileges ) + { + this.privileges = privileges; + } + + + public boolean isActive( ) + { + return active; + } + + + public void setActive( boolean active ) + { + this.active = active; + } + + + public Integer getAccount( ) + { + return account; + } + + + public void setAccount( Integer account ) + { + this.account = account; + } + + + public String getAddress( ) + { + return address; + } + + + public void setAddress( String address ) + { + this.address = address; + } + + + public String getpSha1( ) + { + return pSha1; + } + + + public void setpSha1( String pSha1 ) + { + this.pSha1 = pSha1; + } + + + public String getpMd5( ) + { + return pMd5; + } + + + public void setpMd5( String pMd5 ) + { + this.pMd5 = pMd5; + } + + + public Boolean getPassChangeRequired( ) + { + return passChangeRequired; + } + + + public void setPassChangeRequired( Boolean passChangeRequired ) + { + this.passChangeRequired = passChangeRequired; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/AllianceMembership.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/AllianceMembership.java new file mode 100644 index 0000000..164831c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/AllianceMembership.java @@ -0,0 +1,35 @@ +package com.deepclone.lw.sqld.game; + + +public class AllianceMembership +{ + + private int allianceId; + + private boolean pending; + + + public int getAllianceId( ) + { + return allianceId; + } + + + public void setAllianceId( int allianceId ) + { + this.allianceId = allianceId; + } + + + public boolean isPending( ) + { + return pending; + } + + + public void setPending( boolean pending ) + { + this.pending = pending; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/BuildingOutputType.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/BuildingOutputType.java new file mode 100644 index 0000000..1301ef0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/BuildingOutputType.java @@ -0,0 +1,11 @@ +package com.deepclone.lw.sqld.game; + + +public enum BuildingOutputType { + + WORK , + CASH , + DEF , + POP + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/EmpireTechLine.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/EmpireTechLine.java new file mode 100644 index 0000000..7ab9d68 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/EmpireTechLine.java @@ -0,0 +1,66 @@ +package com.deepclone.lw.sqld.game; + + +import java.util.LinkedList; +import java.util.List; + + + +public class EmpireTechLine +{ + private int id; + + private String name; + + private String description; + + private List< EmpireTechnology > technologies = new LinkedList< EmpireTechnology >( ); + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getDescription( ) + { + return description; + } + + + public void setDescription( String description ) + { + this.description = description; + } + + + public List< EmpireTechnology > getTechnologies( ) + { + return technologies; + } + + + public void addTechnology( EmpireTechnology eTech ) + { + this.technologies.add( eTech ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/EmpireTechnology.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/EmpireTechnology.java new file mode 100644 index 0000000..b36d4dd --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/EmpireTechnology.java @@ -0,0 +1,90 @@ +package com.deepclone.lw.sqld.game; + + +public class EmpireTechnology +{ + private int line; + + private String name; + + private String description; + + private boolean implemented; + + private int progress; + + private int cost; + + + public int getLine( ) + { + return line; + } + + + public void setLine( int line ) + { + this.line = line; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getDescription( ) + { + return description; + } + + + public void setDescription( String description ) + { + this.description = description; + } + + + public boolean isImplemented( ) + { + return implemented; + } + + + public void setImplemented( boolean implemented ) + { + this.implemented = implemented; + } + + + public int getProgress( ) + { + return progress; + } + + + public void setProgress( int progress ) + { + this.progress = progress; + } + + + public int getCost( ) + { + return cost; + } + + + public void setCost( int cost ) + { + this.cost = cost; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/GeneralInformation.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/GeneralInformation.java new file mode 100644 index 0000000..82b7270 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/GeneralInformation.java @@ -0,0 +1,66 @@ +package com.deepclone.lw.sqld.game; + + +public class GeneralInformation +{ + + private Character status; + + private String name; + + private String tag; + + private long cash; + + private long nextTick; + + private int accountId; + + + public GeneralInformation( Character status , String name , String tag , long cash , long nextTick , int accountId ) + { + this.status = status; + this.name = name; + this.tag = tag; + this.cash = cash; + this.nextTick = nextTick; + this.accountId = accountId; + } + + + public Character getStatus( ) + { + return status; + } + + + public String getName( ) + { + return name; + } + + + public String getTag( ) + { + return tag; + } + + + public long getCash( ) + { + return cash; + } + + + public long getNextTick( ) + { + return nextTick; + } + + + public int getAccountId( ) + { + return accountId; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/MapData.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/MapData.java new file mode 100644 index 0000000..49bbf48 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/MapData.java @@ -0,0 +1,119 @@ +package com.deepclone.lw.sqld.game; + + +public class MapData +{ + + private int x; + + private int y; + + private int orbit; + + private int id; + + private int picture; + + private String name; + + private String tag; + + private String display; + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public int getPicture( ) + { + return picture; + } + + + public void setPicture( int picture ) + { + this.picture = picture; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getTag( ) + { + return tag; + } + + + public void setTag( String tag ) + { + this.tag = tag; + } + + + public String getDisplay( ) + { + return display; + } + + + public void setDisplay( String display ) + { + this.display = display; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/PlanetData.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/PlanetData.java new file mode 100644 index 0000000..1b47231 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/PlanetData.java @@ -0,0 +1,293 @@ +package com.deepclone.lw.sqld.game; + + +public final class PlanetData +{ + public static enum AccessType { + BASIC , + PRESENT , + OWNER + } + + public static class Basic + { + private AccessType access; + private int x; + private int y; + private int orbit; + private int picture; + private String name; + private String tag; + + + public AccessType getAccess( ) + { + return access; + } + + + public void setAccess( AccessType access ) + { + this.access = access; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public int getPicture( ) + { + return picture; + } + + + public void setPicture( int picture ) + { + this.picture = picture; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getTag( ) + { + return tag; + } + + + public void setTag( String tag ) + { + this.tag = tag; + } + + } + + public static class Orbital + { + private long population; + private long defence; + private long ownPower; + private long friendlyPower; + private long hostilePower; + private Long battle; + + + public long getPopulation( ) + { + return population; + } + + + public void setPopulation( long population ) + { + this.population = population; + } + + + public long getDefence( ) + { + return defence; + } + + + public void setDefence( long defence ) + { + this.defence = defence; + } + + + public long getOwnPower( ) + { + return ownPower; + } + + + public void setOwnPower( Long ownPower ) + { + this.ownPower = ( ownPower == null ) ? 0 : ownPower.longValue( ); + } + + + public long getFriendlyPower( ) + { + return friendlyPower; + } + + + public void setFriendlyPower( Long friendlyPower ) + { + this.friendlyPower = ( friendlyPower == null ) ? 0 : friendlyPower.longValue( ); + } + + + public long getHostilePower( ) + { + return hostilePower; + } + + + public void setHostilePower( Long hostilePower ) + { + this.hostilePower = ( hostilePower == null ) ? 0 : hostilePower.longValue( ); + } + + + public Long getBattle( ) + { + return battle; + } + + + public void setBattle( Long battle ) + { + this.battle = battle; + } + + } + + public static class Owner + { + private int happiness; + private int hChange; + private long income; + private long upkeep; + private boolean renamePossible; + private boolean abandonPossible; + private Integer abandonTime; + + + public int getHappiness( ) + { + return happiness; + } + + + public void setHappiness( int happiness ) + { + this.happiness = happiness; + } + + + public int gethChange( ) + { + return hChange; + } + + + public void sethChange( int hChange ) + { + this.hChange = hChange; + } + + + public long getIncome( ) + { + return income; + } + + + public void setIncome( long income ) + { + this.income = income; + } + + + public long getUpkeep( ) + { + return upkeep; + } + + + public void setUpkeep( long upkeep ) + { + this.upkeep = upkeep; + } + + + public boolean isRenamePossible( ) + { + return renamePossible; + } + + + public void setRenamePossible( boolean renamePossible ) + { + this.renamePossible = renamePossible; + } + + + public boolean isAbandonPossible( ) + { + return abandonPossible; + } + + + public void setAbandonPossible( boolean abandonPossible ) + { + this.abandonPossible = abandonPossible; + } + + + public Integer getAbandonTime( ) + { + return abandonTime; + } + + + public void setAbandonTime( Integer abandonTime ) + { + this.abandonTime = abandonTime; + } + + } + + + private PlanetData( ) + { + // EMPTY + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawFleetOwner.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawFleetOwner.java new file mode 100644 index 0000000..1c35cb6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawFleetOwner.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.sqld.game; + + +public class RawFleetOwner +{ + + private int location; + private int id; + private String name; + private String relation; + + + public int getLocation( ) + { + return location; + } + + + public void setLocation( int location ) + { + this.location = location; + } + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getRelation( ) + { + return relation; + } + + + public void setRelation( String relation ) + { + this.relation = relation; + } +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawFleetShip.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawFleetShip.java new file mode 100644 index 0000000..d9acbf2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawFleetShip.java @@ -0,0 +1,73 @@ +package com.deepclone.lw.sqld.game; + + +public class RawFleetShip +{ + + private long fleet; + private int shipType; + private int amount; + private int power; + private String name; + + + public long getFleet( ) + { + return fleet; + } + + + public void setFleet( long fleet ) + { + this.fleet = fleet; + } + + + public int getShipType( ) + { + return shipType; + } + + + public void setShipType( int shipType ) + { + this.shipType = shipType; + } + + + public int getAmount( ) + { + return amount; + } + + + public void setAmount( int amount ) + { + this.amount = amount; + } + + + public int getPower( ) + { + return power; + } + + + public void setPower( int power ) + { + this.power = power; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawStaticFleet.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawStaticFleet.java new file mode 100644 index 0000000..552ea22 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/RawStaticFleet.java @@ -0,0 +1,111 @@ +package com.deepclone.lw.sqld.game; + + +public class RawStaticFleet +{ + private int owner; + private int location; + private long id; + private String name; + private String status; + private int penalty; + private long power; + private int flightTime; + + + public int getOwner( ) + { + return owner; + } + + + public void setOwner( int owner ) + { + this.owner = owner; + } + + + public int getLocation( ) + { + return location; + } + + + public void setLocation( int location ) + { + this.location = location; + } + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getStatus( ) + { + return status; + } + + + public void setStatus( String status ) + { + this.status = status; + } + + + public int getPenalty( ) + { + return penalty; + } + + + public void setPenalty( int penalty ) + { + this.penalty = penalty; + } + + + public long getPower( ) + { + return power; + } + + + public void setPower( long power ) + { + this.power = power; + } + + + public int getFlightTime( ) + { + return flightTime; + } + + + public void setFlightTime( int flightTime ) + { + this.flightTime = flightTime; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/BattleListRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/BattleListRecord.java new file mode 100644 index 0000000..f17049a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/BattleListRecord.java @@ -0,0 +1,137 @@ +package com.deepclone.lw.sqld.game.battle; + + +public class BattleListRecord +{ + private long battle; + private int planetId; + private int x; + private int y; + private int orbit; + private String name; + private long firstTick; + private Long lastTick; + private boolean finished; + private long lastUpdate; + + + public long getBattle( ) + { + return battle; + } + + + public void setBattle( long battle ) + { + this.battle = battle; + } + + + public int getPlanetId( ) + { + return planetId; + } + + + public void setPlanetId( int planetId ) + { + this.planetId = planetId; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public long getFirstTick( ) + { + return firstTick; + } + + + public void setFirstTick( long firstTick ) + { + this.firstTick = firstTick; + } + + + public Long getLastTick( ) + { + return lastTick; + } + + + public void setLastTick( Long lastTick ) + { + this.lastTick = lastTick; + } + + + public boolean isFinished( ) + { + return finished; + } + + + public void setFinished( boolean finished ) + { + this.finished = finished; + } + + + public long getLastUpdate( ) + { + return lastUpdate; + } + + + public void setLastUpdate( long lastUpdate ) + { + this.lastUpdate = lastUpdate; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/BuildingHistoryRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/BuildingHistoryRecord.java new file mode 100644 index 0000000..dae7ba4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/BuildingHistoryRecord.java @@ -0,0 +1,73 @@ +package com.deepclone.lw.sqld.game.battle; + + +public class BuildingHistoryRecord +{ + + private long tick; + private String nature; + private long current; + private long lost; + private long power; + + + public long getTick( ) + { + return tick; + } + + + public void setTick( long tick ) + { + this.tick = tick; + } + + + public String getNature( ) + { + return nature; + } + + + public void setNature( String nature ) + { + this.nature = nature; + } + + + public long getCurrent( ) + { + return current; + } + + + public void setCurrent( long current ) + { + this.current = current; + } + + + public long getLost( ) + { + return lost; + } + + + public void setLost( long lost ) + { + this.lost = lost; + } + + + public long getPower( ) + { + return power; + } + + + public void setPower( long power ) + { + this.power = power; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EmpireBattleRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EmpireBattleRecord.java new file mode 100644 index 0000000..57e5730 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EmpireBattleRecord.java @@ -0,0 +1,138 @@ +package com.deepclone.lw.sqld.game.battle; + + +public class EmpireBattleRecord +{ + + private long battleId; + private int empireId; + private long protagonistId; + private long firstTick; + private Long lastTick; + private String planetName; + private int planetId; + private int x; + private int y; + private int orbit; + + + public long getBattleId( ) + { + return battleId; + } + + + public void setBattleId( long battleId ) + { + this.battleId = battleId; + } + + + public int getEmpireId( ) + { + return empireId; + } + + + public void setEmpireId( int empireId ) + { + this.empireId = empireId; + } + + + public long getProtagonistId( ) + { + return protagonistId; + } + + + public void setProtagonistId( long protagonistId ) + { + this.protagonistId = protagonistId; + } + + + public long getFirstTick( ) + { + return firstTick; + } + + + public void setFirstTick( long firstTick ) + { + this.firstTick = firstTick; + } + + + public Long getLastTick( ) + { + return lastTick; + } + + + public void setLastTick( Long lastTick ) + { + this.lastTick = lastTick; + } + + + public String getPlanetName( ) + { + return planetName; + } + + + public void setPlanetName( String planetName ) + { + this.planetName = planetName; + } + + + public int getPlanetId( ) + { + return planetId; + } + + + public void setPlanetId( int planetId ) + { + this.planetId = planetId; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EventItemRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EventItemRecord.java new file mode 100644 index 0000000..913d0e3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EventItemRecord.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.sqld.game.battle; + + +public class EventItemRecord +{ + private boolean planetEvent; + private long eventId; + private String nature; + private int amount; + + + public boolean isPlanetEvent( ) + { + return planetEvent; + } + + + public void setPlanetEvent( boolean planetEvent ) + { + this.planetEvent = planetEvent; + } + + + public long getEventId( ) + { + return eventId; + } + + + public void setEventId( long eventId ) + { + this.eventId = eventId; + } + + + public String getNature( ) + { + return nature; + } + + + public void setNature( String nature ) + { + this.nature = nature; + } + + + public int getAmount( ) + { + return amount; + } + + + public void setAmount( int amount ) + { + this.amount = amount; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EventRecord.java new file mode 100644 index 0000000..a6fe677 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/EventRecord.java @@ -0,0 +1,86 @@ +package com.deepclone.lw.sqld.game.battle; + + +public class EventRecord +{ + + private long tick; + private String eventType; + private boolean planet; + private Long eventId; + private String name; + private Boolean attack; + + + public long getTick( ) + { + return tick; + } + + + public void setTick( long tick ) + { + this.tick = tick; + } + + + public String getEventType( ) + { + return eventType; + } + + + public void setEventType( String eventType ) + { + this.eventType = eventType; + } + + + public boolean isPlanet( ) + { + return planet; + } + + + public void setPlanet( boolean planet ) + { + this.planet = planet; + } + + + public Long getEventId( ) + { + return eventId; + } + + + public void setEventId( Long eventId ) + { + this.eventId = eventId; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public Boolean getAttack( ) + { + return attack; + } + + + public void setAttack( Boolean attack ) + { + this.attack = attack; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/PresenceRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/PresenceRecord.java new file mode 100644 index 0000000..863864e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/PresenceRecord.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.sqld.game.battle; + + +public class PresenceRecord +{ + private long tick; + private boolean present; + private boolean isPlanetOwner; + + + public long getTick( ) + { + return tick; + } + + + public void setTick( long tick ) + { + this.tick = tick; + } + + + public boolean isPresent( ) + { + return present; + } + + + public void setPresent( boolean present ) + { + this.present = present; + } + + + public boolean isPlanetOwner( ) + { + return isPlanetOwner; + } + + + public void setPlanetOwner( boolean isPlanetOwner ) + { + this.isPlanetOwner = isPlanetOwner; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/ProtagonistRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/ProtagonistRecord.java new file mode 100644 index 0000000..b9656db --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/ProtagonistRecord.java @@ -0,0 +1,73 @@ +package com.deepclone.lw.sqld.game.battle; + + +public class ProtagonistRecord +{ + + private long tick; + private long protagonistId; + private Long empireId; + private String name; + private boolean attacking; + + + public long getTick( ) + { + return tick; + } + + + public void setTick( long tick ) + { + this.tick = tick; + } + + + public long getProtagonistId( ) + { + return protagonistId; + } + + + public void setProtagonistId( long protagonistId ) + { + this.protagonistId = protagonistId; + } + + + public Long getEmpireId( ) + { + return empireId; + } + + + public void setEmpireId( Long empireId ) + { + this.empireId = empireId; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public boolean isAttacking( ) + { + return attacking; + } + + + public void setAttacking( boolean status ) + { + this.attacking = status; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/ShipHistoryRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/ShipHistoryRecord.java new file mode 100644 index 0000000..f66d11f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/game/battle/ShipHistoryRecord.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.sqld.game.battle; + + +public class ShipHistoryRecord + extends BuildingHistoryRecord +{ + private long protagonist; + + + public long getProtagonist( ) + { + return protagonist; + } + + + public void setProtagonist( long protagonist ) + { + this.protagonist = protagonist; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/i18n/Translation.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/i18n/Translation.java new file mode 100644 index 0000000..f063d78 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/i18n/Translation.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.sqld.i18n; + + +public class Translation +{ + + private String languageId; + private String languageName; + private String stringId; + private String translation; + + + public String getLanguageId( ) + { + return languageId; + } + + + public void setLanguageId( String languageId ) + { + this.languageId = languageId; + } + + + public String getLanguageName( ) + { + return languageName; + } + + + public void setLanguageName( String languageName ) + { + this.languageName = languageName; + } + + + public String getStringId( ) + { + return stringId; + } + + + public void setStringId( String stringId ) + { + this.stringId = stringId; + } + + + public String getTranslation( ) + { + return translation; + } + + + public void setTranslation( String translation ) + { + this.translation = translation; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/AdminEventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/AdminEventRecord.java new file mode 100644 index 0000000..d22ecbf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/AdminEventRecord.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.sqld.msgs; + + +public class AdminEventRecord + extends EventRecord +{ + + private Integer warnings; + private Integer locationId; + private String oldName; + private String newName; + + + public Integer getWarnings( ) + { + return warnings; + } + + + public void setWarnings( Integer warnings ) + { + this.warnings = warnings; + } + + + public Integer getLocationId( ) + { + return locationId; + } + + + public void setLocationId( Integer locationId ) + { + this.locationId = locationId; + } + + + public String getOldName( ) + { + return oldName; + } + + + public void setOldName( String oldName ) + { + this.oldName = oldName; + } + + + public String getNewName( ) + { + return newName; + } + + + public void setNewName( String newName ) + { + this.newName = newName; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/AllianceEventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/AllianceEventRecord.java new file mode 100644 index 0000000..f811077 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/AllianceEventRecord.java @@ -0,0 +1,74 @@ +package com.deepclone.lw.sqld.msgs; + + +public class AllianceEventRecord + extends EventRecord +{ + + private Integer allianceId; + private String allianceTag; + private Integer empireId; + private String empireName; + private Boolean reqResult; + + + public Integer getAllianceId( ) + { + return allianceId; + } + + + public void setAllianceId( Integer allianceId ) + { + this.allianceId = allianceId; + } + + + public String getAllianceTag( ) + { + return allianceTag; + } + + + public void setAllianceTag( String allianceTag ) + { + this.allianceTag = allianceTag; + } + + + public Integer getEmpireId( ) + { + return empireId; + } + + + public void setEmpireId( Integer empireId ) + { + this.empireId = empireId; + } + + + public String getEmpireName( ) + { + return empireName; + } + + + public void setEmpireName( String empireName ) + { + this.empireName = empireName; + } + + + public Boolean getReqResult( ) + { + return reqResult; + } + + + public void setReqResult( Boolean reqResult ) + { + this.reqResult = reqResult; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/BugEventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/BugEventRecord.java new file mode 100644 index 0000000..d990cf5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/BugEventRecord.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.sqld.msgs; + + +public class BugEventRecord + extends EventRecord +{ + + private long reportId; + private String submitter; + private boolean admin; + + + public long getReportId( ) + { + return reportId; + } + + + public void setReportId( long reportId ) + { + this.reportId = reportId; + } + + + public String getSubmitter( ) + { + return submitter; + } + + + public void setSubmitter( String submitter ) + { + this.submitter = submitter; + } + + + public boolean isAdmin( ) + { + return admin; + } + + + public void setAdmin( boolean admin ) + { + this.admin = admin; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EmpireEventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EmpireEventRecord.java new file mode 100644 index 0000000..793074e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EmpireEventRecord.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.sqld.msgs; + + +public class EmpireEventRecord + extends EventRecord +{ + private String tech; + + + public String getTech( ) + { + return tech; + } + + + public void setTech( String tech ) + { + this.tech = tech; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventRecord.java new file mode 100644 index 0000000..0fdd891 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventRecord.java @@ -0,0 +1,40 @@ +package com.deepclone.lw.sqld.msgs; + + +public abstract class EventRecord + extends MessageDataRecord +{ + private EventType type; + private int subType; + + + public EventRecord( ) + { + super( true ); + } + + + public EventType getType( ) + { + return type; + } + + + public void setType( EventType type ) + { + this.type = type; + } + + + public int getSubType( ) + { + return subType; + } + + + public void setSubType( int subType ) + { + this.subType = subType; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventType.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventType.java new file mode 100644 index 0000000..e8f14f8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventType.java @@ -0,0 +1,12 @@ +package com.deepclone.lw.sqld.msgs; + + +public enum EventType { + QUEUE , + EMPIRE , + FLEETS , + ALLIANCE , + PLANET , + ADMIN , + BUGS +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventTypeRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventTypeRecord.java new file mode 100644 index 0000000..f9f6a45 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/EventTypeRecord.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.sqld.msgs; + + +public class EventTypeRecord +{ + private long id; + private EventType type; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public EventType getType( ) + { + return type; + } + + + public void setType( EventType type ) + { + this.type = type; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FleetEventFleet.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FleetEventFleet.java new file mode 100644 index 0000000..823ee42 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FleetEventFleet.java @@ -0,0 +1,112 @@ +package com.deepclone.lw.sqld.msgs; + + +public class FleetEventFleet +{ + + private long eventId; + private Integer ownerId; + private String ownerName; + private String fleetName; + private long fleetPower; + private Boolean status; + private Integer sourceId; + private String sourceName; + + + public long getEventId( ) + { + return eventId; + } + + + public void setEventId( long eventId ) + { + this.eventId = eventId; + } + + + public Integer getOwnerId( ) + { + return ownerId; + } + + + public void setOwnerId( Integer ownerId ) + { + this.ownerId = ownerId; + } + + + public String getOwnerName( ) + { + return ownerName; + } + + + public void setOwnerName( String ownerName ) + { + this.ownerName = ownerName; + } + + + public String getFleetName( ) + { + return fleetName; + } + + + public void setFleetName( String fleetName ) + { + this.fleetName = fleetName; + } + + + public long getFleetPower( ) + { + return fleetPower; + } + + + public void setFleetPower( long fleetPower ) + { + this.fleetPower = fleetPower; + } + + + public Boolean getStatus( ) + { + return status; + } + + + public void setStatus( Boolean status ) + { + this.status = status; + } + + + public Integer getSourceId( ) + { + return sourceId; + } + + + public void setSourceId( Integer sourceId ) + { + this.sourceId = sourceId; + } + + + public String getSourceName( ) + { + return sourceName; + } + + + public void setSourceName( String sourceName ) + { + this.sourceName = sourceName; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FleetEventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FleetEventRecord.java new file mode 100644 index 0000000..1dbf0ab --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FleetEventRecord.java @@ -0,0 +1,91 @@ +package com.deepclone.lw.sqld.msgs; + + +import java.util.LinkedList; +import java.util.List; + + + +public class FleetEventRecord + extends EventRecord +{ + private int locationId; + private String locationName; + private int x; + private int y; + private int orbit; + private final List< FleetEventFleet > fleets = new LinkedList< FleetEventFleet >( ); + + + public int getLocationId( ) + { + return locationId; + } + + + public void setLocationId( int locationId ) + { + this.locationId = locationId; + } + + + public String getLocationName( ) + { + return locationName; + } + + + public void setLocationName( String locationName ) + { + this.locationName = locationName; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public List< FleetEventFleet > getFleets( ) + { + return fleets; + } + + + public void addFleet( FleetEventFleet fleet ) + { + this.fleets.add( fleet ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FormatType.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FormatType.java new file mode 100644 index 0000000..0611500 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/FormatType.java @@ -0,0 +1,86 @@ +package com.deepclone.lw.sqld.msgs; + + +public class FormatType +{ + private final boolean internal; + private final EventType eType; + private final int eSubType; + + + public FormatType( ) + { + this.internal = false; + this.eType = null; + this.eSubType = 0; + } + + + public FormatType( EventType eType , int eSubType ) + { + this.internal = true; + this.eType = eType; + this.eSubType = eSubType; + } + + + public boolean isInternal( ) + { + return internal; + } + + + public EventType getType( ) + { + return eType; + } + + + public int getSubType( ) + { + return eSubType; + } + + + @Override + public int hashCode( ) + { + final int prime = 31; + int result = 1; + result = prime * result + eSubType; + result = prime * result + ( ( eType == null ) ? 0 : eType.hashCode( ) ); + result = prime * result + ( internal ? 1231 : 1237 ); + return result; + } + + + @Override + public boolean equals( Object obj ) + { + if ( this == obj ) + return true; + if ( obj == null ) + return false; + if ( getClass( ) != obj.getClass( ) ) + return false; + FormatType other = (FormatType) obj; + if ( eSubType != other.eSubType ) + return false; + if ( eType == null ) { + if ( other.eType != null ) + return false; + } else if ( !eType.equals( other.eType ) ) + return false; + if ( internal != other.internal ) + return false; + return true; + } + + + @Override + public String toString( ) + { + return "[internal=" + internal + ", eType=" + eType + ", eSubType=" + eSubType + "]"; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/InboxRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/InboxRecord.java new file mode 100644 index 0000000..1356702 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/InboxRecord.java @@ -0,0 +1,157 @@ +package com.deepclone.lw.sqld.msgs; + + +import java.sql.Timestamp; + + + +public class InboxRecord +{ + private long id; + private boolean read; + private boolean internal; + private Timestamp received; + + private String senderType; + private Integer senderId; + private String senderName; + + private String receiverType; + private int receiverId; + private String receiverName; + + private long contentId; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public boolean isRead( ) + { + return read; + } + + + public void setRead( boolean read ) + { + this.read = read; + } + + + public boolean isInternal( ) + { + return internal; + } + + + public void setInternal( boolean internal ) + { + this.internal = internal; + } + + + public Timestamp getReceived( ) + { + return received; + } + + + public void setReceived( Timestamp received ) + { + this.received = received; + } + + + public String getSenderType( ) + { + return senderType; + } + + + public void setSenderType( String senderType ) + { + this.senderType = senderType; + } + + + public Integer getSenderId( ) + { + return senderId; + } + + + public void setSenderId( Integer senderId ) + { + this.senderId = senderId; + } + + + public String getSenderName( ) + { + return senderName; + } + + + public void setSenderName( String senderName ) + { + this.senderName = senderName; + } + + + public String getReceiverType( ) + { + return receiverType; + } + + + public void setReceiverType( String receiverType ) + { + this.receiverType = receiverType; + } + + + public int getReceiverId( ) + { + return receiverId; + } + + + public void setReceiverId( int receiverId ) + { + this.receiverId = receiverId; + } + + + public String getReceiverName( ) + { + return receiverName; + } + + + public void setReceiverName( String receiverName ) + { + this.receiverName = receiverName; + } + + + public long getContentId( ) + { + return contentId; + } + + + public void setContentId( long contentId ) + { + this.contentId = contentId; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/MessageDataRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/MessageDataRecord.java new file mode 100644 index 0000000..ccfd86e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/MessageDataRecord.java @@ -0,0 +1,63 @@ +package com.deepclone.lw.sqld.msgs; + + +import java.sql.Timestamp; + + + +public abstract class MessageDataRecord +{ + private final boolean internal; + private long id; + private Timestamp timestamp; + private long tick; + + + protected MessageDataRecord( boolean internal ) + { + this.internal = internal; + } + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public Timestamp getTimestamp( ) + { + return timestamp; + } + + + public void setTimestamp( Timestamp timestamp ) + { + this.timestamp = timestamp; + } + + + public long getTick( ) + { + return tick; + } + + + public void setTick( long tick ) + { + this.tick = tick; + } + + + public boolean isInternal( ) + { + return internal; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/NotificationsRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/NotificationsRecord.java new file mode 100644 index 0000000..9471995 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/NotificationsRecord.java @@ -0,0 +1,154 @@ +package com.deepclone.lw.sqld.msgs; + + +public class NotificationsRecord +{ + + private int id; + private String name; + private String language; + private String address; + + private String onPrivate; + private String onAlliance; + private String onInternal; + private String onAdmin; + + private Long lastUnmailed; + private Long lastUnrecaped; + + private boolean canNotify; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getLanguage( ) + { + return language; + } + + + public void setLanguage( String language ) + { + this.language = language; + } + + + public String getAddress( ) + { + return address; + } + + + public void setAddress( String address ) + { + this.address = address; + } + + + public String getOnPrivate( ) + { + return onPrivate; + } + + + public void setOnPrivate( String onPrivate ) + { + this.onPrivate = onPrivate; + } + + + public String getOnAlliance( ) + { + return onAlliance; + } + + + public void setOnAlliance( String onAlliance ) + { + this.onAlliance = onAlliance; + } + + + public String getOnInternal( ) + { + return onInternal; + } + + + public void setOnInternal( String onInternal ) + { + this.onInternal = onInternal; + } + + + public String getOnAdmin( ) + { + return onAdmin; + } + + + public void setOnAdmin( String onAdmin ) + { + this.onAdmin = onAdmin; + } + + + public Long getLastUnmailed( ) + { + return lastUnmailed; + } + + + public void setLastUnmailed( Long lastUnmailed ) + { + this.lastUnmailed = lastUnmailed; + } + + + public Long getLastUnrecaped( ) + { + return lastUnrecaped; + } + + + public void setLastUnrecaped( Long lastUnrecaped ) + { + this.lastUnrecaped = lastUnrecaped; + } + + + public boolean isCanNotify( ) + { + return canNotify; + } + + + public void setCanNotify( boolean canNotify ) + { + this.canNotify = canNotify; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/PlanetEventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/PlanetEventRecord.java new file mode 100644 index 0000000..148bd3a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/PlanetEventRecord.java @@ -0,0 +1,112 @@ +package com.deepclone.lw.sqld.msgs; + + +public class PlanetEventRecord + extends EventRecord +{ + private int locationId; + private String locationName; + private int x; + private int y; + private int orbit; + private Integer empireId; + private String empireName; + private Long battleId; + + + public int getLocationId( ) + { + return locationId; + } + + + public void setLocationId( int locationId ) + { + this.locationId = locationId; + } + + + public String getLocationName( ) + { + return locationName; + } + + + public void setLocationName( String locationName ) + { + this.locationName = locationName; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public Integer getEmpireId( ) + { + return empireId; + } + + + public void setEmpireId( Integer empireId ) + { + this.empireId = empireId; + } + + + public String getEmpireName( ) + { + return empireName; + } + + + public void setEmpireName( String empireName ) + { + this.empireName = empireName; + } + + + public Long getBattleId( ) + { + return battleId; + } + + + public void setBattleId( Long battleId ) + { + this.battleId = battleId; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/QueueEventLocation.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/QueueEventLocation.java new file mode 100644 index 0000000..54fa287 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/QueueEventLocation.java @@ -0,0 +1,86 @@ +package com.deepclone.lw.sqld.msgs; + + +public class QueueEventLocation +{ + + private long eventId; + private int locationId; + private String locationName; + private int x; + private int y; + private int orbit; + + + public long getEventId( ) + { + return eventId; + } + + + public void setEventId( long eventId ) + { + this.eventId = eventId; + } + + + public int getLocationId( ) + { + return locationId; + } + + + public void setLocationId( int locationId ) + { + this.locationId = locationId; + } + + + public String getLocationName( ) + { + return locationName; + } + + + public void setLocationName( String locationName ) + { + this.locationName = locationName; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/QueueEventRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/QueueEventRecord.java new file mode 100644 index 0000000..d91b407 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/QueueEventRecord.java @@ -0,0 +1,26 @@ +package com.deepclone.lw.sqld.msgs; + + +import java.util.LinkedList; +import java.util.List; + + + +public class QueueEventRecord + extends EventRecord +{ + + private final List< QueueEventLocation > locations = new LinkedList< QueueEventLocation >( ); + + + public List< QueueEventLocation > getLocations( ) + { + return locations; + } + + + public void addLocation( QueueEventLocation eventLocation ) + { + this.locations.add( eventLocation ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/TextMessageRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/TextMessageRecord.java new file mode 100644 index 0000000..a1dc5b8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/msgs/TextMessageRecord.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.sqld.msgs; + + +public class TextMessageRecord + extends MessageDataRecord +{ + + private String subject; + private String text; + + + public TextMessageRecord( ) + { + super( false ); + } + + + public String getSubject( ) + { + return subject; + } + + + public void setSubject( String subject ) + { + this.subject = subject; + } + + + public String getText( ) + { + return text; + } + + + public void setText( String text ) + { + this.text = text; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/Constant.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/Constant.java new file mode 100644 index 0000000..971b5ef --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/Constant.java @@ -0,0 +1,111 @@ +package com.deepclone.lw.sqld.sys; + + +public class Constant +{ + /** The constant's category */ + private String category; + + /** The constant's internal name */ + private String name; + + /** A description of the constant to be used on the administrative interface */ + private String description; + + /** The minimal value of the constant (may be omitted) */ + private Double minValue; + + /** The maximal value of the constant (may be omitted) */ + private Double maxValue; + + /** The constant's current value */ + private double value; + + + public String getCategory( ) + { + return category; + } + + + public void setCategory( String category ) + { + this.category = category; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getDescription( ) + { + return description; + } + + + public void setDescription( String description ) + { + this.description = description; + } + + + public Double getMinValue( ) + { + return minValue; + } + + + public void setMinValue( Double minValue ) + { + + this.minValue = minValue; + } + + + public void setMinValue( Float minValue ) + { + + this.minValue = ( minValue == null ? null : minValue.doubleValue( ) ); + } + + + public Double getMaxValue( ) + { + return maxValue; + } + + + public void setMaxValue( Double maxValue ) + { + this.maxValue = maxValue; + } + + + public void setMaxValue( Float maxValue ) + { + + this.maxValue = ( maxValue == null ? null : maxValue.doubleValue( ) ); + } + + + public double getValue( ) + { + return value; + } + + + public void setValue( double value ) + { + this.value = value; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/ExceptionLog.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/ExceptionLog.java new file mode 100644 index 0000000..a55df83 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/ExceptionLog.java @@ -0,0 +1,75 @@ +package com.deepclone.lw.sqld.sys; + + +import java.util.LinkedList; +import java.util.List; + + + +public class ExceptionLog +{ + + private Long id; + + private Integer order; + + private String className; + + private String message; + + private List< StackTraceLog > stack = new LinkedList< StackTraceLog >( ); + + + public ExceptionLog( SystemLogEntry logEntry, String className , String message ) + { + this.className = className; + this.message = message; + logEntry.addException( this ); + } + + + public ExceptionLog( Long id , Integer order , String className , String message ) + { + this.id = id; + this.order = order; + this.className = className; + this.message = message; + } + + + public Long getId( ) + { + return id; + } + + + public Integer getOrder( ) + { + return order; + } + + + public String getClassName( ) + { + return className; + } + + + public String getMessage( ) + { + return message; + } + + + public List< StackTraceLog > getStack( ) + { + return stack; + } + + + public void addStackTrace( StackTraceLog stackTraceLog ) + { + this.stack.add( stackTraceLog ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/StackTraceLog.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/StackTraceLog.java new file mode 100644 index 0000000..743e6eb --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/StackTraceLog.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.sqld.sys; + + +public class StackTraceLog +{ + private Long excId; + + private Integer order; + + private String location; + + private String fileName; + + private Integer line; + + + public StackTraceLog( ExceptionLog eLog , String location , String fileName , Integer line ) + { + this.location = location; + this.fileName = fileName; + this.line = line; + eLog.addStackTrace( this ); + } + + + public StackTraceLog( Long excId , Integer order , String location , String fileName , Integer line ) + { + this.excId = excId; + this.order = order; + this.location = location; + this.fileName = fileName; + this.line = line; + } + + + public Long getExcId( ) + { + return excId; + } + + + public Integer getOrder( ) + { + return order; + } + + + public String getLocation( ) + { + return location; + } + + + public String getFileName( ) + { + return fileName; + } + + + public Integer getLine( ) + { + return line; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/Status.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/Status.java new file mode 100644 index 0000000..9144503 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/Status.java @@ -0,0 +1,135 @@ +package com.deepclone.lw.sqld.sys; + + +import java.sql.Timestamp; + + + +/** + * Single-entry system status "table". + * + * @author tseeker + */ +public class Status +{ + /** Identifier of the next tick */ + private long nextTickIdentifier; + + /** Identifier of the current tick, if one is running */ + private Long currentTick; + + /** If the game is under maintenance, timestamp at which maintenance was initiated */ + private Timestamp maintenanceStart; + + /** If the game is under maintenance, timestamp at which maintenance is supposed to end */ + private Timestamp maintenanceEnd; + + /** If the game is under maintenance, text to display as the reason for maintenance */ + private String maintenanceReason; + + /** Timestamp at which errors were last checked */ + private Timestamp lastErrorCheck; + + /** Timestamp at which the last administration recap email was sent */ + private Timestamp lastAdminRecap; + + /** Timestamp at which the last messages recap email was sent */ + private Timestamp lastMsgRecap; + + + public Long getNextTickIdentifier( ) + { + return nextTickIdentifier; + } + + + public void setNextTickIdentifier( long nextTickIdentifier ) + { + this.nextTickIdentifier = nextTickIdentifier; + } + + + public Long getCurrentTick( ) + { + return currentTick; + } + + + public void setCurrentTick( Long currentTick ) + { + this.currentTick = currentTick; + } + + + public Timestamp getMaintenanceStart( ) + { + return maintenanceStart; + } + + + public void setMaintenanceStart( Timestamp maintenanceStart ) + { + this.maintenanceStart = maintenanceStart; + } + + + public Timestamp getMaintenanceEnd( ) + { + return maintenanceEnd; + } + + + public void setMaintenanceEnd( Timestamp maintenanceEnd ) + { + this.maintenanceEnd = maintenanceEnd; + } + + + public String getMaintenanceReason( ) + { + return maintenanceReason; + } + + + public void setMaintenanceReason( String maintenanceReason ) + { + this.maintenanceReason = maintenanceReason; + } + + + public Timestamp getLastErrorCheck( ) + { + return lastErrorCheck; + } + + + public void setLastErrorCheck( Timestamp lastErrorCheck ) + { + this.lastErrorCheck = lastErrorCheck; + } + + + public Timestamp getLastAdminRecap( ) + { + return lastAdminRecap; + } + + + public void setLastAdminRecap( Timestamp lastAdminRecap ) + { + this.lastAdminRecap = lastAdminRecap; + } + + + public Timestamp getLastMsgRecap( ) + { + return lastMsgRecap; + } + + + public void setLastMsgRecap( Timestamp lastMsgRecap ) + { + this.lastMsgRecap = lastMsgRecap; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/SystemLogEntry.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/SystemLogEntry.java new file mode 100644 index 0000000..e599093 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/SystemLogEntry.java @@ -0,0 +1,93 @@ +package com.deepclone.lw.sqld.sys; + + +import java.sql.Timestamp; +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.admin.logs.LogLevel; + + + +/** + * This class represents entries in the system log. + * + * @author tseeker + */ +public class SystemLogEntry +{ + + private Long id; + + private Timestamp timestamp; + + private LogLevel level; + + private String component; + + private String message; + + private List< ExceptionLog > exception; + + + public SystemLogEntry( LogLevel level , String component , String message ) + { + this.level = level; + this.component = component; + this.message = message; + this.exception = new LinkedList< ExceptionLog >( ); + } + + + public SystemLogEntry( Long id , Timestamp timestamp , LogLevel level , String component , String message ) + { + this.id = id; + this.timestamp = timestamp; + this.level = level; + this.component = component; + this.message = message; + } + + + public Long getId( ) + { + return id; + } + + + public Timestamp getTimestamp( ) + { + return timestamp; + } + + + public LogLevel getLevel( ) + { + return level; + } + + + public String getComponent( ) + { + return component; + } + + + public String getMessage( ) + { + return message; + } + + + public List< ExceptionLog > getException( ) + { + return exception; + } + + + public void addException( ExceptionLog exceptionLog ) + { + this.exception.add( exceptionLog ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/TickerTaskRecord.java b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/TickerTaskRecord.java new file mode 100644 index 0000000..cce8086 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/java/com/deepclone/lw/sqld/sys/TickerTaskRecord.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.sqld.sys; + + +import java.sql.Timestamp; + + + +public class TickerTaskRecord +{ + + private int id; + private String name; + private String status; + private Timestamp timestamp; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getStatus( ) + { + return status; + } + + + public void setStatus( String status ) + { + this.status = status; + } + + + public Timestamp getTimestamp( ) + { + return timestamp; + } + + + public void setTimestamp( Timestamp timestamp ) + { + this.timestamp = timestamp; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-data/src/main/resources/configuration/transaction-bean.xml b/legacyworlds-server/legacyworlds-server-data/src/main/resources/configuration/transaction-bean.xml new file mode 100644 index 0000000..6cf7b29 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-data/src/main/resources/configuration/transaction-bean.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-interfaces/.classpath b/legacyworlds-server/legacyworlds-server-interfaces/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-interfaces/.project b/legacyworlds-server/legacyworlds-server-interfaces/.project new file mode 100644 index 0000000..25a4794 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-interfaces + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-interfaces/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-interfaces/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..847aea3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 09 10:20:04 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-interfaces/pom.xml b/legacyworlds-server/legacyworlds-server-interfaces/pom.xml new file mode 100644 index 0000000..1a0f426 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/pom.xml @@ -0,0 +1,29 @@ + + 4.0.0 + + legacyworlds-server + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-interfaces + 5.99.1 + + Legacy Worlds server interfaces + This package contains interfaces for all beans provided by the various server components. + + + + com.deepclone.lw + legacyworlds-server-data + ${project.version} + + + com.deepclone.lw + legacyworlds-server-utils + ${project.version} + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountMailException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountMailException.java new file mode 100644 index 0000000..2bbffee --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountMailException.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.interfaces.acm; + + +public class AccountMailException + extends Exception +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountManagement.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountManagement.java new file mode 100644 index 0000000..0804324 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountManagement.java @@ -0,0 +1,112 @@ +package com.deepclone.lw.interfaces.acm; + + +import java.net.InetAddress; +import java.util.List; +import java.util.Map; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.users.AccountListEntry; +import com.deepclone.lw.cmd.admin.users.AccountSessionEntry; +import com.deepclone.lw.cmd.admin.users.AccountStatus; +import com.deepclone.lw.cmd.admin.users.AccountViewEntry; +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.cmd.player.account.BanDetailsResponse; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; +import com.deepclone.lw.interfaces.i18n.TranslationException; +import com.deepclone.lw.interfaces.mailer.MailerException; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.sqld.accounts.ValidationResult; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; + + + +public interface AccountManagement +{ + public void createAccount( EmailAddress address , Password password , String language ) + throws AccountMailException , MailerException , TranslationException; + + + public ValidationResult validateAccount( EmailAddress address , String token , String empire , String planet ); + + + public void reactivateAccount( EmailAddress address ) + throws AccountMailException , MailerException; + + + public void requestPasswordRecovery( EmailAddress address ) + throws AccountMailException , MailerException , PasswordRecoveryException; + + + public void recoverPassword( EmailAddress address , String token , Password password ) + throws AccountMailException , PasswordRecoveryException , PasswordProhibitedException; + + + public AccountSession login( EmailAddress address , String challenge , String sha1Hash , String md5Hash , + InetAddress ipAddress , String clientType , String sessionName ); + + + public void logout( long session , SessionTerminationType reason ); + + + public Account restoreSession( long session ); + + + public Account getAccount( EmailAddress address ); + + + public List< String > getEmpireNames( EmailAddress address ); + + + public AccountData getAccountPage( EmailAddress address ); + + + public void setLanguage( EmailAddress address , String language ); + + + public boolean setPassword( EmailAddress address , String challenge , String sha1Hash , String md5Hash , + Password newPassword ) + throws PasswordProhibitedException; + + + public boolean setAddress( EmailAddress address , String challenge , String sha1Auth , String md5Auth , + EmailAddress nAddress ) + throws AccountMailException , MailerException; + + + public void cancelAddressChange( EmailAddress cAddress ); + + + public AccountData confirmAddressChange( EmailAddress cAddress , String code ); + + + public void resetPreferences( EmailAddress address ); + + + public void setPreferences( EmailAddress address , Map< String , String > values ); + + + public void setQuit( EmailAddress address , String reason ); + + + public void cancelQuit( EmailAddress address ); + + + public void toggleVacation( EmailAddress address ); + + + public List< AccountListEntry > listAccounts( AccountStatus status , boolean online ); + + + public AccountViewEntry getAccountView( int id ); + + + public AccountSessionEntry viewSessions( int id ); + + + public void giveCredits( Administrator admin , int id , int credits ); + + + public BanDetailsResponse getBanDetails( EmailAddress address ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountSession.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountSession.java new file mode 100644 index 0000000..f7bd4ba --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/AccountSession.java @@ -0,0 +1,20 @@ +package com.deepclone.lw.interfaces.acm; + + +import com.deepclone.lw.sqld.accounts.Account; + + + +public class AccountSession +{ + public final Account account; + public final long session; + + + public AccountSession( Account account , long session ) + { + this.account = account; + this.session = session; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/EmailChangeException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/EmailChangeException.java new file mode 100644 index 0000000..3bed615 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/EmailChangeException.java @@ -0,0 +1,17 @@ +package com.deepclone.lw.interfaces.acm; + + +public class EmailChangeException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + public final boolean statusProblem; + + + public EmailChangeException( boolean statusProblem ) + { + this.statusProblem = statusProblem; + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/JoinGameException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/JoinGameException.java new file mode 100644 index 0000000..c410c8b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/JoinGameException.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.interfaces.acm; + + +import com.deepclone.lw.interfaces.naming.EmpireNameException; +import com.deepclone.lw.interfaces.naming.MapNameException; + + + +public class JoinGameException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + public final boolean validated; + public final EmpireNameException.Error empireNameError; + public final MapNameException.Error mapNameError; + + + public JoinGameException( boolean validated , EmpireNameException.Error empireNameError , + MapNameException.Error mapNameError ) + { + this.validated = validated; + this.empireNameError = empireNameError; + this.mapNameError = mapNameError; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PasswordProhibitedException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PasswordProhibitedException.java new file mode 100644 index 0000000..0b8fc8e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PasswordProhibitedException.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.interfaces.acm; + + +public class PasswordProhibitedException + extends Exception +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PasswordRecoveryException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PasswordRecoveryException.java new file mode 100644 index 0000000..63c96ee --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PasswordRecoveryException.java @@ -0,0 +1,17 @@ +package com.deepclone.lw.interfaces.acm; + + +public class PasswordRecoveryException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + public final boolean statusProblem; + + + public PasswordRecoveryException( boolean statusProblem ) + { + this.statusProblem = statusProblem; + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PermanentlyDisabledException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PermanentlyDisabledException.java new file mode 100644 index 0000000..09ab753 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/PermanentlyDisabledException.java @@ -0,0 +1,9 @@ +package com.deepclone.lw.interfaces.acm; + +public class PermanentlyDisabledException + extends Exception +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/UserSessionDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/UserSessionDAO.java new file mode 100644 index 0000000..793e78e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/UserSessionDAO.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.interfaces.acm; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.cmd.admin.users.UserSession; + + + +public interface UserSessionDAO +{ + + public long startSession( int id , String sName , String client , String address ); + + + public void endSession( long session , SessionTerminationType termination ); + + + public UserSession getSession( long id ); + + + public boolean isOnline( int id ); + + + public List< UserSession > getSessions( int id ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/UsersDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/UsersDAO.java new file mode 100644 index 0000000..93c8343 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/acm/UsersDAO.java @@ -0,0 +1,107 @@ +package com.deepclone.lw.interfaces.acm; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.users.AccountListEntry; +import com.deepclone.lw.cmd.admin.users.AccountStatus; +import com.deepclone.lw.cmd.admin.users.AccountViewEntry; +import com.deepclone.lw.cmd.player.gdata.account.MailChangeData; +import com.deepclone.lw.sqld.accounts.Account; +import com.deepclone.lw.sqld.accounts.AccountOperationResult; +import com.deepclone.lw.sqld.accounts.QuittingAccount; +import com.deepclone.lw.sqld.accounts.ValidationResult; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; + + + +public interface UsersDAO +{ + + public Account getAccount( EmailAddress address ); + + + public Account getAccount( int id ); + + + public AccountOperationResult createAccount( EmailAddress address , Password password , String language ); + + + public Account reactivateAccount( EmailAddress address ); + + + public void cancelAccountValidation( Account account ); + + + public ValidationResult validateAccount( EmailAddress address , String token , String eName , String pName ); + + + public AccountOperationResult requestPasswordRecovery( EmailAddress address ); + + + public void cancelPasswordRecovery( Account account ); + + + public AccountOperationResult confirmPasswordRecovery( EmailAddress address , String token , Password nPassword ); + + + public MailChangeData getMailChange( int accountId ); + + + public void setLanguage( EmailAddress address , String language ); + + + public boolean setPassword( Account account , Password newPassword ); + + + public int setAddress( Account account , EmailAddress nAddress ); + + + public void cancelAddressChange( Account account ); + + + public int confirmAddressChange( Account account , String code ); + + + public void expireRequests( ); + + + public void setQuit( Account account , String reason ); + + + public void cancelQuit( Account account ); + + + public List< QuittingAccount > processQuits( ); + + + public void enterVacation( Account account ); + + + public void leaveVacation( Account account ); + + + public void processVacations( ); + + + public List< AccountListEntry > listAccounts( AccountStatus status ); + + + public List< AccountListEntry > listOnlineAccounts( AccountStatus status ); + + + public AccountViewEntry viewAccount( int id ); + + + public void giveCredits( int adminId , int accountId , int credits ); + + + public void deleteOldAccounts( ); + + + public List< QuittingAccount > getInactivesToWarn( ); + + + public List< QuittingAccount > getInactivesToDisable( ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/AdminDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/AdminDAO.java new file mode 100644 index 0000000..0e4383a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/AdminDAO.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.interfaces.admin; + + +import java.net.InetAddress; +import java.sql.Timestamp; +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.AdminOverview; +import com.deepclone.lw.sqld.admin.AdminConnection; +import com.deepclone.lw.sqld.admin.AdminRecord; +import com.deepclone.lw.utils.EmailAddress; + + + +public interface AdminDAO +{ + + public AdminRecord getAdmin( int id ); + + + public AdminRecord getAdmin( EmailAddress address ); + + + public AdminRecord getAdmin( String name ); + + + public int createAdmin( String address , String name , int privileges ) + throws AdminDAOException; + + + public void logConnectionAttempt( int id , AdminConnection status , InetAddress address ); + + + public void logDisconnection( int id ); + + + public boolean setPassword( int id , String sha1 , String md5 ); + + + public List< AdminRecord > listAdministrators( ); + + + public boolean resetPassword( int identifier , int superuser ); + + + public boolean setPrivileges( int identifier , int superuser , int privileges ); + + + public AdminOverview getOverview( int id ); + + + public List< AdminOverview > getOverviews( ); + + + public Timestamp isRecapTime( ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/AdminDAOException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/AdminDAOException.java new file mode 100644 index 0000000..916430b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/AdminDAOException.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.interfaces.admin; + + +public class AdminDAOException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + private final int errorCode; + + + public AdminDAOException( int errorCode ) + { + this.errorCode = errorCode; + } + + + public int getErrorCode( ) + { + return errorCode; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/Administration.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/Administration.java new file mode 100644 index 0000000..950e3b2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/Administration.java @@ -0,0 +1,71 @@ +package com.deepclone.lw.interfaces.admin; + + +import java.net.InetAddress; +import java.util.List; +import java.util.Set; + +import com.deepclone.lw.cmd.admin.AdminOverviewResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.BanType; +import com.deepclone.lw.cmd.admin.bans.BansSummaryResponse; +import com.deepclone.lw.cmd.admin.bans.ListBansResponse; +import com.deepclone.lw.cmd.admin.bans.RequestBanResponse; +import com.deepclone.lw.cmd.admin.su.AddAdministratorResponse; +import com.deepclone.lw.interfaces.acm.PasswordProhibitedException; +import com.deepclone.lw.sqld.admin.AdminRecord; +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; + + + +public interface Administration +{ + + public AdminRecord getAdmin( int id ); + + + public AdminRecord login( EmailAddress address , String challenge , String sha1Hash , String md5Hash , + InetAddress ipAddress ); + + + public void logout( int adminId ); + + + public boolean setPassword( int id , String challenge , String sha1Auth , String md5Auth , Password password ) + throws PasswordProhibitedException; + + + public List< AdminRecord > listAdministrators( ); + + + public AddAdministratorResponse createAdmin( Administrator creator , String address , String name , int privileges ); + + + public AdminRecord resetPassword( Administrator admin , int identifier ); + + + public AdminRecord setPrivileges( Administrator admin , int identifier , Set< Privileges > privileges ); + + + public BansSummaryResponse getBansSummary( Administrator admin ); + + + public ListBansResponse getBans( Administrator admin , BanType type ); + + + public RequestBanResponse requestBan( Administrator admin , String user , boolean empire , String reason ); + + + public void rejectBan( Administrator admin , int id , String reason ); + + + public void confirmBan( Administrator admin , int id ); + + + public void liftBan( Administrator admin , int id ); + + + public AdminOverviewResponse getOverview( Administrator admin ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/BanMailData.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/BanMailData.java new file mode 100644 index 0000000..480c452 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/BanMailData.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.interfaces.admin; + + +public class BanMailData +{ + + public final String address; + public final String language; + public final String reason; + + + public BanMailData( String address , String language , String reason ) + { + this.address = address; + this.language = language; + this.reason = reason; + } + + + public BanMailData( String address , String language ) + { + this.address = address; + this.language = language; + this.reason = null; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/BansDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/BansDAO.java new file mode 100644 index 0000000..7e0872f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/BansDAO.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.interfaces.admin; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.bans.BanRequest; +import com.deepclone.lw.cmd.admin.bans.SummaryEntry; +import com.deepclone.lw.cmd.admin.bans.ValidatedBanRequest; +import com.deepclone.lw.utils.EmailAddress; + + + +public interface BansDAO +{ + + public List< SummaryEntry > getSummary( ); + + + public List< BanRequest > getPending( ); + + + public List< BanRequest > getArchived( ); + + + public List< BanRequest > getActive( ); + + + public int requestBan( int administrator , EmailAddress address , String reason ); + + + public int requestBan( int administrator , String empire , String reason ); + + + public void rejectBan( int administrator , int requestId , String reason ); + + + public BanMailData validateBan( int administrator , int requestId ); + + + public BanMailData liftBan( int administrator , int requestId ); + + + public void expireBanRequests( ); + + + public void expireWarnings( ); + + + public boolean finaliseBan( ); + + + public ValidatedBanRequest getActiveBan( EmailAddress address ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/IpBan.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/IpBan.java new file mode 100644 index 0000000..da7af78 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/admin/IpBan.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.interfaces.admin; + + +import java.net.InetAddress; + + + +/** + * This interface is used to check if an IP address is banned. + * + * @author tseeker + */ +public interface IpBan +{ + + /** + * Checks if the InetAddress provided is banned. + * + * @param address + * the IP Address to be checked + * @return a boolean saying whether or not the address is banned. + */ + public boolean isBanned( InetAddress address ); + + + /** + * Increases the ban counter associated with the given address. + * + * @param address + * the IP Address to be added to the counter. + */ + public void increaseBanCounter( InetAddress address ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/AdminBugs.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/AdminBugs.java new file mode 100644 index 0000000..1de3949 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/AdminBugs.java @@ -0,0 +1,45 @@ +package com.deepclone.lw.interfaces.bt; + + +import com.deepclone.lw.cmd.bt.data.*; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.bt.*; + + + +public interface AdminBugs +{ + + public BugsSummaryResponse getSummary( Administrator admin ); + + + public ListBugsResponse getBugs( Administrator admin , BugStatus status , boolean ownOnly , long first , int count ); + + + public ReportBugResponse postReport( Administrator admin , String title , String contents , boolean publicReport ); + + + ViewBugResponse getReport( Administrator admin , long bugId ); + + + public PostCommentResponse postComment( Administrator admin , long bugId , String comment , boolean publicComment ); + + + public void moderateComment( Administrator admin , long commentId , boolean validation ); + + + public void validateReport( Administrator admin , long bugId , BugStatus status , boolean publicReport , int credits, boolean snapshot ); + + + public void setStatus( Administrator admin , long bugId , BugStatus status ); + + + public void toggleVisibility( Administrator admin , long bugId ); + + + public MergeReportsResponse mergeReports( Administrator admin , long id , long mergeId ); + + + public GetSnapshotResponse getSnapshot( Administrator admin , long bugId ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/BugsDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/BugsDAO.java new file mode 100644 index 0000000..9e28012 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/BugsDAO.java @@ -0,0 +1,71 @@ +package com.deepclone.lw.interfaces.bt; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.bt.data.*; + + + +public interface BugsDAO +{ + + public long countReports( int empireId , BugStatus status , boolean ownOnly ); + + + public long countReports( Administrator admin , BugStatus status , boolean ownOnly ); + + + public long countUpdatedReports( Administrator admin ); + + + public List< BugReport > getReports( int empireId , BugStatus status , boolean ownOnly , long first , int count ); + + + public List< BugReport > getReports( Administrator admin , BugStatus status , boolean ownOnly , long first , + int count ); + + + public BugReport getReport( int empireId , long reportId ); + + + public BugReport getReport( Administrator admin , long reportId ); + + + public long postReport( int empireId , String title , String contents , String extra ); + + + public long postReport( Administrator admin , String title , String contents , boolean publicReport ); + + + public void postComment( int empireId , long reportId , String comment ); + + + public void postComment( Administrator admin , long reportId , String comment , boolean publicComment ); + + + public List< BugEvent > getEvents( long bugId ); + + + public void showComment( Administrator admin , long commentId ); + + + public void deleteComment( Administrator admin , long commentId ); + + + public void validateReport( Administrator admin , long bugId , BugStatus status , boolean publicReport , int credits, boolean snapshot ); + + + public void setStatus( Administrator admin , long bugId , BugStatus status ); + + + public void toggleVisibility( Administrator admin , long bugId ); + + + public int mergeReports( Administrator admin , long id , long mergeId ); + + + public String getSnapshot( long bugId ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/EmpireSummary.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/EmpireSummary.java new file mode 100644 index 0000000..bd09629 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/EmpireSummary.java @@ -0,0 +1,9 @@ +package com.deepclone.lw.interfaces.bt; + + +public interface EmpireSummary +{ + + public String getSummary( int empireId ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/PlayerBugs.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/PlayerBugs.java new file mode 100644 index 0000000..a798880 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/bt/PlayerBugs.java @@ -0,0 +1,23 @@ +package com.deepclone.lw.interfaces.bt; + + +import com.deepclone.lw.cmd.bt.data.*; +import com.deepclone.lw.cmd.player.bt.*; + + + +public interface PlayerBugs +{ + + public ListBugsResponse getBugs( int empireId , BugStatus status , boolean ownOnly , long first , int count ); + + + public ReportBugResponse postReport( int empireId , String title , String desc ); + + + ViewBugResponse getReport( int empireId , long bugId ); + + + public PostCommentResponse postComment( int empireId , long reportId , String comment ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/ExtendedLogEntry.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/ExtendedLogEntry.java new file mode 100644 index 0000000..f868a27 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/ExtendedLogEntry.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.interfaces.eventlog; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.logs.ExceptionEntry; +import com.deepclone.lw.cmd.admin.logs.LogEntry; + + + +public class ExtendedLogEntry +{ + + public final LogEntry logEntry; + public final List< ExceptionEntry > exceptions; + + + public ExtendedLogEntry( LogEntry logEntry , List< ExceptionEntry > exceptions ) + { + this.logEntry = logEntry; + this.exceptions = exceptions; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/LogReader.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/LogReader.java new file mode 100644 index 0000000..4ce8e6f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/LogReader.java @@ -0,0 +1,31 @@ +package com.deepclone.lw.interfaces.eventlog; + + +import java.sql.Timestamp; +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.logs.GetEntryResponse; +import com.deepclone.lw.cmd.admin.logs.LogEntry; +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.admin.logs.LogType; +import com.deepclone.lw.cmd.admin.logs.ViewLogResponse; + + + +public interface LogReader +{ + + public ViewLogResponse getLog( Administrator admin , LogType type , long first , int count , LogLevel minLevel , + String component , boolean excOnly ); + + + public GetEntryResponse getEntry( Administrator admin , long id ); + + + public List< ExtendedLogEntry > getErrorEntries( ); + + + public List< LogEntry > getAdminLogSince( Timestamp timestamp ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/LogWriter.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/LogWriter.java new file mode 100644 index 0000000..49fe2f1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/LogWriter.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.interfaces.eventlog; + + +import java.util.List; + +import com.deepclone.lw.sqld.sys.SystemLogEntry; + + + +/** + * This interface is used by the server's log writer bean. It implements an asynchronous log writer + * that uses the database to store log entries. + * + * @author tseeker + */ +public interface LogWriter +{ + + /** + * Adds a list of log entries to the queue of messages to write. + * + * @param entries + * the entries to write + */ + public void addEntries( List< SystemLogEntry > entries ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/Logger.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/Logger.java new file mode 100644 index 0000000..ee98a90 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/Logger.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.interfaces.eventlog; + + +/** + * This interface is used by the server's in-base logger. + * + * @author tseeker + */ +public interface Logger +{ + + /** + * Creates a logger for system actions, using the specified string as the component's name. + * + * @param component + * the name of the component producing log entries + * @return a {@link SystemLogger} for the specified component + */ + public SystemLogger getSystemLogger( String component ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/SystemLogger.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/SystemLogger.java new file mode 100644 index 0000000..fdfe44c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/eventlog/SystemLogger.java @@ -0,0 +1,49 @@ +package com.deepclone.lw.interfaces.eventlog; + + +import com.deepclone.lw.cmd.admin.logs.LogLevel; + + + +/** + * A SystemLogger is capable of writing basic, system-related entries to the database. + * + * @author tseeker + */ +public interface SystemLogger +{ + + /** + * Writes a log entry. + * + * @param level + * the entry's log level + * @param message + * the text of the log entry + * @return the logger + */ + public SystemLogger log( LogLevel level , String message ); + + + /** + * Writes a log entry and an associated exception + * + * @param level + * the entry's log level + * @param message + * the text of the log entry + * @param exception + * the exception to associate to the log entry + * @return the logger + */ + public SystemLogger log( LogLevel level , String message , Throwable exception ); + + + /** + * Flushes a logger's entries to the main logger bean. + * + * @return the logger + */ + public SystemLogger flush( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/AllianceDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/AllianceDAO.java new file mode 100644 index 0000000..2a48bf0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/AllianceDAO.java @@ -0,0 +1,49 @@ +package com.deepclone.lw.interfaces.game; + + +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceLeaderData; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceMemberData; +import com.deepclone.lw.cmd.player.gdata.alliance.PublicAllianceInformation; +import com.deepclone.lw.sqld.game.AllianceMembership; + + + +public interface AllianceDAO +{ + + public AllianceMembership getAlliance( int empireId ); + + + public Integer findAlliance( String tag ); + + + public Integer createAlliance( int empireId , String tag , String name ); + + + public PublicAllianceInformation getPublicInformation( int allianceId ); + + + public AllianceMemberData getMemberData( int allianceId ); + + + public AllianceLeaderData getLeaderData( int allianceId ); + + + public boolean requestJoin( int empireId , int allianceId ); + + + public void cancelJoin( int empireId ); + + + public void leave( int empireId ); + + + public void transferLeadership( int empireId , int toMember ); + + + public void manageRequests( int empireId , boolean accept , int[] members ); + + + public void kick( int empireId , int[] members ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/AllianceManagement.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/AllianceManagement.java new file mode 100644 index 0000000..e4841cf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/AllianceManagement.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.interfaces.game; + + +import com.deepclone.lw.cmd.player.alliances.AllianceStatusResponse; + + + +public interface AllianceManagement +{ + + public AllianceStatusResponse getView( int empireId ); + + + public AllianceStatusResponse getInformation( int empireId , String tag ); + + + public AllianceStatusResponse create( int empireId , String tag , String name ); + + + public AllianceStatusResponse requestJoin( int empireId , String tag ); + + + public AllianceStatusResponse cancelJoin( int empireId ); + + + public AllianceStatusResponse leave( int empireId ); + + + public AllianceStatusResponse transferLeadership( int empireId , int toMember ); + + + public AllianceStatusResponse manageRequests( int empireId , boolean accept , int[] members ); + + + public AllianceStatusResponse kick( int empireId , int[] members ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattleViewer.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattleViewer.java new file mode 100644 index 0000000..13e89d6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattleViewer.java @@ -0,0 +1,19 @@ +package com.deepclone.lw.interfaces.game; + + +import com.deepclone.lw.cmd.player.battles.GetBattleResponse; +import com.deepclone.lw.cmd.player.battles.ListBattlesResponse; + + + +public interface BattleViewer +{ + public GetBattleResponse getBattle( int empireId , long battleId ); + + + public GetBattleResponse getBattle( int empireId , long battleId , long tick ); + + + public ListBattlesResponse getBattles( int empireId , int page ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattlesCache.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattlesCache.java new file mode 100644 index 0000000..a7144ff --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattlesCache.java @@ -0,0 +1,8 @@ +package com.deepclone.lw.interfaces.game; + + +public interface BattlesCache + extends BattlesDAO +{ + // EMPTY +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattlesDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattlesDAO.java new file mode 100644 index 0000000..c45522b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/BattlesDAO.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.interfaces.game; + + +import java.util.List; +import java.util.Map; + +import com.deepclone.lw.sqld.game.battle.*; + + + +public interface BattlesDAO +{ + + public EmpireBattleRecord getBattleRecord( int empireId , long battleId ); + + + public List< PresenceRecord > getPresence( EmpireBattleRecord record ); + + + public List< EventRecord > getEvents( EmpireBattleRecord record ); + + + public Map< Boolean , Map< Long , List< EventItemRecord >>> getEventItems( EmpireBattleRecord record ); + + + public Map< Long , Map< Long , ProtagonistRecord >> getProtagonists( EmpireBattleRecord record ); + + + public Map< Long , List< BuildingHistoryRecord >> getBuildingsHistory( EmpireBattleRecord record ); + + + public Map< Long , Map< Long , List< ShipHistoryRecord >>> getShipsHistory( EmpireBattleRecord record ); + + + List< BattleListRecord > getBattles( int empireId ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/EmpireDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/EmpireDAO.java new file mode 100644 index 0000000..59342d4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/EmpireDAO.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.interfaces.game; + + +import java.util.List; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.PlanetListData; +import com.deepclone.lw.cmd.player.gdata.empire.OverviewData; +import com.deepclone.lw.sqld.game.EmpireTechLine; +import com.deepclone.lw.sqld.game.GeneralInformation; + + + +public interface EmpireDAO +{ + + public GeneralInformation getInformation( int empireId ); + + + public List< NameIdPair > getPlanets( int empireId ); + + + public OverviewData getOverview( int empireId ); + + + public List< EmpireTechLine > getTechnology( int empireId ); + + + public void implementTechnology( int empireId , int lineId ); + + + public List< PlanetListData > getPlanetList( int empireId ); + + + public List< NameIdPair > getEnemies( int empireId , boolean alliances ); + + + public ObjectNameError addEnemy( int empireId , boolean alliance , String name ); + + + public void removeEnemies( int empireId , boolean alliance , int[] ids ); + + + public int getNewPlanet( int empireId , String name ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/EmpireManagement.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/EmpireManagement.java new file mode 100644 index 0000000..eb92be9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/EmpireManagement.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.interfaces.game; + + +import com.deepclone.lw.cmd.player.GetNewPlanetResponse; +import com.deepclone.lw.cmd.player.ListPlanetsResponse; +import com.deepclone.lw.cmd.player.EmpireResponse; +import com.deepclone.lw.cmd.player.elist.EnemyListResponse; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.utils.EmailAddress; + + + +public interface EmpireManagement +{ + + public Integer getEmpireId( EmailAddress address ); + + + public GamePageData getGeneralInformation( int empireId ); + + + public EmpireResponse getOverview( int empireId ); + + + public EmpireResponse implementTechnology( int empireId , int techId ); + + + public ListPlanetsResponse getPlanetList( int empireId ); + + + public EnemyListResponse getEnemyLists( int empireId ); + + + public EnemyListResponse addEnemy( int empireId , boolean alliance , String name ); + + + public EnemyListResponse removeEnemies( int empireId , boolean alliance , int[] ids ); + + + public GetNewPlanetResponse getNewPlanet( int empireId , String name ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/FleetManagement.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/FleetManagement.java new file mode 100644 index 0000000..58bd19d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/FleetManagement.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.interfaces.game; + + +import java.util.Map; + +import com.deepclone.lw.cmd.player.fleets.MultiFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.SplitFleetResponse; +import com.deepclone.lw.cmd.player.fleets.ViewFleetsResponse; + + + +public interface FleetManagement +{ + + public ViewFleetsResponse getFleets( int empireId ); + + + public MultiFleetsResponse move( int empireId , long[] fleets , String destination , boolean attack ); + + + public MultiFleetsResponse setMode( int empireId , long[] fleets , boolean attack , boolean doIt ); + + + public MultiFleetsResponse rename( int empireId , long[] fleets , String name ); + + + public MultiFleetsResponse merge( int empireId , long[] fleets ); + + + public SplitFleetResponse split( int empireId , long fleetId , Map< Integer , Integer > ships , int nFleets , + String name , boolean simulate ); + + + public MultiFleetsResponse disband( int empireId , long[] fleets , boolean doIt ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/FleetsDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/FleetsDAO.java new file mode 100644 index 0000000..bf150b0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/FleetsDAO.java @@ -0,0 +1,50 @@ +package com.deepclone.lw.interfaces.game; + + +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.fleets.FleetsView; +import com.deepclone.lw.cmd.player.gdata.fleets.ShortFleetView; +import com.deepclone.lw.cmd.player.gdata.fleets.SplitShips; + + + +public interface FleetsDAO +{ + + public FleetsView getFleets( int empireId ); + + + public List< ShortFleetView > getShortFleets( int empireId , long[] fleets , boolean needsAvailable ); + + + public ShortFleetView getShortFleet( int empireId , long fleetId ); + + + public boolean move( int empireId , long[] fleets , String destination ); + + + public void setMode( int empireId , long[] fleets , boolean attack ); + + + public void rename( int empireId , long[] fleets , String name ); + + + public void merge( int empireId , long[] fleets ); + + + public void disband( int empireId , long[] fleets ); + + + public List< SplitShips > getShips( int empireId , long fleetId ); + + + public boolean initSplit( long fleetId , int nFleets , String name ); + + + public void setSplitShips( int shipType , int amount ); + + + public boolean executeSplit( boolean simulate ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/MapViewParameters.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/MapViewParameters.java new file mode 100644 index 0000000..3f32b91 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/MapViewParameters.java @@ -0,0 +1,23 @@ +package com.deepclone.lw.interfaces.game; + + +import com.deepclone.lw.cmd.player.gdata.MapSize; + + + +public class MapViewParameters +{ + + public final int x; + public final int y; + public final MapSize size; + + + public MapViewParameters( int x , int y , MapSize size ) + { + this.x = x; + this.y = y; + this.size = size; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/MapViewer.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/MapViewer.java new file mode 100644 index 0000000..282fb95 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/MapViewer.java @@ -0,0 +1,17 @@ +package com.deepclone.lw.interfaces.game; + + +import com.deepclone.lw.cmd.player.gdata.map.MapSystemData; +import com.deepclone.lw.utils.EmailAddress; + + + +public interface MapViewer +{ + + public MapViewParameters getDefaults( EmailAddress address ); + + + public MapSystemData[][] getMapView( int empireId , MapViewParameters parameters ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/PlanetDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/PlanetDAO.java new file mode 100644 index 0000000..b5f1d88 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/PlanetDAO.java @@ -0,0 +1,58 @@ +package com.deepclone.lw.interfaces.game; + + +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.planets.BuildableBuildingData; +import com.deepclone.lw.cmd.player.gdata.planets.BuildableShipData; +import com.deepclone.lw.cmd.player.gdata.planets.BuildingData; +import com.deepclone.lw.cmd.player.gdata.planets.QueueData; +import com.deepclone.lw.sqld.game.PlanetData; + + + +public interface PlanetDAO +{ + + public PlanetData.Basic getBasicInformation( int empireId , int planetId ); + + + public PlanetData.Orbital getOrbitalInformation( int empireId , int planetId ); + + + public PlanetData.Owner getOwnerInformation( int empireId , int planetId ); + + + public List< BuildingData > getBuildings( int empireId , int planetId , boolean isOwner ); + + + public QueueData getConstructionQueue( int planetId ); + + + public QueueData getMilitaryQueue( int planetId ); + + + public List< BuildableBuildingData > getAvailableBuildings( int planetId ); + + + public List< BuildableShipData > getAvailableShips( int planetId ); + + + public void flushQueue( int planetId , boolean military ); + + + public void addToMilitaryQueue( int planetId , int sType , int amount ); + + + public void constructBuildings( int planetId , int bType , int amount ); + + + public boolean destroyBuildings( int planetId , int bType , int amount ); + + + public Integer abandon( int planetId ); + + + public void cancelAbandon( int planetId ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/PlanetsManagement.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/PlanetsManagement.java new file mode 100644 index 0000000..d207a66 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/PlanetsManagement.java @@ -0,0 +1,31 @@ +package com.deepclone.lw.interfaces.game; + + +import com.deepclone.lw.cmd.player.planets.ViewPlanetResponse; + + + +public interface PlanetsManagement +{ + + public ViewPlanetResponse viewPlanet( int empireId , int planetId ); + + + public ViewPlanetResponse renamePlanet( int empireId , int planetId , String name ); + + + public ViewPlanetResponse flushQueue( int empireId , int planetId , boolean military ); + + + public ViewPlanetResponse addToMilitaryQueue( int empireId , int planetId , int sType , int amount ); + + + public ViewPlanetResponse addToCivilianQueue( int empireId , int planetId , int bType , boolean destroy , int amount ); + + + public ViewPlanetResponse abandon( int empireId , int planetId ); + + + public ViewPlanetResponse cancelAbandon( int empireId , int planetId ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/UniverseDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/UniverseDAO.java new file mode 100644 index 0000000..70af7e5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/UniverseDAO.java @@ -0,0 +1,18 @@ +package com.deepclone.lw.interfaces.game; + + +import java.util.List; + +import com.deepclone.lw.sqld.game.MapData; + + + +public interface UniverseDAO +{ + + public void generate( ); + + + public List< MapData > getMap( int empireId , int minX , int minY , int maxX , int maxY ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/UpdatesDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/UpdatesDAO.java new file mode 100644 index 0000000..86736b4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/UpdatesDAO.java @@ -0,0 +1,7 @@ +package com.deepclone.lw.interfaces.game; + + +public interface UpdatesDAO +{ + public boolean processUpdates( long tickId ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/DuplicateLanguageException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/DuplicateLanguageException.java new file mode 100644 index 0000000..ad65f8d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/DuplicateLanguageException.java @@ -0,0 +1,22 @@ +package com.deepclone.lw.interfaces.i18n; + + +/** + * This exception is thrown by the administration session object if the creation of a language is + * requested using an identifier that is already present in the database. + * + * @author tseeker + */ +public class DuplicateLanguageException + extends I18NException +{ + + private static final long serialVersionUID = 1L; + + + public DuplicateLanguageException( String message ) + { + super( message ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/DuplicateStringException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/DuplicateStringException.java new file mode 100644 index 0000000..e113498 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/DuplicateStringException.java @@ -0,0 +1,22 @@ +package com.deepclone.lw.interfaces.i18n; + + +/** + * This exception is thrown by the administration session object when the creation of a string is + * requested and the new string's identifier is already in use. + * + * @author tseeker + */ +public class DuplicateStringException + extends I18NException +{ + + private static final long serialVersionUID = 1L; + + + public DuplicateStringException( String message ) + { + super( message ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NAdministration.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NAdministration.java new file mode 100644 index 0000000..e5be52a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NAdministration.java @@ -0,0 +1,143 @@ +package com.deepclone.lw.interfaces.i18n; + + +import java.util.Map; +import java.util.Set; + + + +/** + * Translations database administration session + * + * This interface defines the various methods allowing an administrator to make changes to the + * translations database. + * + * @author tseeker + */ +public interface I18NAdministration +{ + + /** + * @return the set of all languages identifiers, including languages that are not 100% supported + */ + public Set< String > getLanguages( ); + + + /** + * Obtains the name of a language + * + * @param language + * the language's identifier + * @return the language's name + * @throws UnknownLanguageException + * if the language does not exist + */ + public String getLanguageName( String language ) + throws UnknownLanguageException; + + + /** + * Returns the ratio of translated strings in a language relative to the total amount of string + * definitions. + * + * @param language + * the language's identifier + * @return the language's support ratio + * @throws UnknownLanguageException + * if the language does not exist + */ + public double getLanguageSupport( String language ) + throws UnknownLanguageException; + + + /** + * Adds a new, totally unsupported language. + * + * @param language + * the new language's identifier + * @param name + * the name of the new language + * @throws DuplicateLanguageException + * if the language identifier is already in use + */ + public void createLanguage( String language , String name ) + throws DuplicateLanguageException; + + + /** + * Updates a language's name + * + * @param language + * the language's identifier + * @param name + * the new name of the language + * @throws UnknownLanguageException + * if the language does not exist + */ + public void setLanguageName( String language , String name ) + throws UnknownLanguageException; + + + /** + * @return the set of all string identifiers + */ + public Set< String > getStrings( ); + + + /** + * Accesses a string's translation. + * + * @param language + * the language identifier + * @param string + * the string identifier + * @return the translation for the specified string in the specified language, or null if the + * string has not been translated in this language + * @throws UnknownStringException + * if the string identifier is invalid + * @throws UnknownLanguageException + * if the language does not exist + */ + public String getTranslation( String language , String string ) + throws UnknownStringException , UnknownLanguageException; + + + /** + * Modifies or creates a string's translation in a given language + * + * @param language + * the language identifier + * @param string + * the string identifier + * @param translation + * the new translated string + * @return true if the string was created, false if it was updated + * @throws UnknownStringException + * if the string identifier is invalid + * @throws UnknownLanguageException + * if the language does not exist + */ + public boolean updateTranslation( String language , String string , String translation ) + throws UnknownStringException , UnknownLanguageException; + + + /** + * Creates a new string and adds some of its translations. For this method to work as expected, + * no 100% supported language must become unsupported. + * + * @param string + * the new string's identifier + * @param translations + * a map whose keys are language identifiers and whose values are translations. + * @throws DuplicateStringException + * if the new string's identifier already exists + * @throws UnknownLanguageException + * if one of the languages does not exist + * @throws InvalidUpdateException + * if the creation of the string would cause one or more of the currently supported + * languages to become unsupported + */ + public void createString( String string , Map< String , String > translations ) + throws DuplicateStringException , UnknownLanguageException , InvalidUpdateException; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NException.java new file mode 100644 index 0000000..95cbb02 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NException.java @@ -0,0 +1,22 @@ +package com.deepclone.lw.interfaces.i18n; + + +/** + * Base class for all I18N-related exception, including both translation exceptions and + * administration exceptions. + * + * @author tseeker + */ +public abstract class I18NException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + + public I18NException( String message ) + { + super( message ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NManager.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NManager.java new file mode 100644 index 0000000..3895022 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/I18NManager.java @@ -0,0 +1,30 @@ +package com.deepclone.lw.interfaces.i18n; + + + + +/** + * The I18NManager interface is used to access the main I18N management bean. + * + * @author tseeker + */ +public interface I18NManager +{ + + /** + * Creates an administration session for an administrator. + * + * @param administrator + * the administrator editing the I18N database + * @return the administration session instance + */ + public I18NAdministration getAdminSession( int administrator ); + + + /** + * Reloads all translations from the database. This should only be used if manual modifications + * are made to the DB for some reason. + */ + public void reload( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/InvalidUpdateException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/InvalidUpdateException.java new file mode 100644 index 0000000..9f00be1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/InvalidUpdateException.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.interfaces.i18n; + + +import java.util.HashSet; +import java.util.Set; + + + +/** + * This exception is thrown by administration session objects when the creation of a new string + * would make previously supported languages unsupported. + * + * @author tseeker + */ +public class InvalidUpdateException + extends I18NException +{ + + private static final long serialVersionUID = 1L; + private Set< String > downgradedLanguages; + + + public InvalidUpdateException( Set< String > languages ) + { + super( "would downgrade the following languages: " + languages.toString( ) ); + this.downgradedLanguages = new HashSet< String >( languages ); + } + + + /** + * @return the set of identifiers for languages that would have become unsupported + */ + public Set< String > getDowngradedLanguages( ) + { + return new HashSet< String >( this.downgradedLanguages ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/TranslationException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/TranslationException.java new file mode 100644 index 0000000..41b991f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/TranslationException.java @@ -0,0 +1,22 @@ +package com.deepclone.lw.interfaces.i18n; + + +/** + * Base class for exceptions that can be thrown by both the administration interface and the + * translator bean. + * + * @author tseeker + */ +public abstract class TranslationException + extends I18NException +{ + + private static final long serialVersionUID = 1L; + + + public TranslationException( String message ) + { + super( message ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/Translator.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/Translator.java new file mode 100644 index 0000000..9c5eb39 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/Translator.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.interfaces.i18n; + + +import java.util.Set; + + + +/** + * Translator service interface + * + * This interface defines the methods available on the Translator service. One such service should + * be present on all nodes. All Translator service instances are managed by the I18NManager service, + * which is shared between nodes and notifies Translator instances of database updates. + * + * @author tseeker + * + */ +public interface Translator +{ + + /** + * @return the list of supported languages + */ + public Set< String > getSupportedLanguages( ); + + + /** + * Checks if a language is supported. + * + * @param language + * the identifier of the language + * @return true if the language is present and fully supported, false otherwise. + */ + public boolean isLanguageSupported( String language ); + + + /** + * Returns the plain text name of a language from its identifier. + * + * @param language + * the identifier of the language + * @return the name of the language + * @throws UnknownLanguageException + * if the specified language does not exist + */ + public String getLanguageName( String language ) + throws UnknownLanguageException;; + + + /** + * Translates a string specified using its identifier. + * + * @param language + * the identifier of the language to translate to + * @param string + * the identifier of the string to translate + * @return the string's translation + * @throws UnknownStringException + * if the string is unknown + * @throws UnknownLanguageException + * if the language does not exist or is not supported + */ + public String translate( String language , String string ) + throws UnknownStringException , UnknownLanguageException; +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/UnknownLanguageException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/UnknownLanguageException.java new file mode 100644 index 0000000..8deca86 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/UnknownLanguageException.java @@ -0,0 +1,29 @@ +package com.deepclone.lw.interfaces.i18n; + + +/** + * This exception is thrown when a language does not exist in the database or, in the case of the + * translator bean, if the language isn't fully supported. + * + * @author tseeker + */ +public final class UnknownLanguageException + extends TranslationException +{ + private static final long serialVersionUID = 1L; + + private String language; + + + public UnknownLanguageException( String language ) + { + super( "the requested language '" + language + "' could not be found" ); + this.language = language; + } + + + public String getLanguage( ) + { + return this.language; + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/UnknownStringException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/UnknownStringException.java new file mode 100644 index 0000000..e382634 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/i18n/UnknownStringException.java @@ -0,0 +1,30 @@ +package com.deepclone.lw.interfaces.i18n; + + +/** + * This exception is thrown when a string identifier does not exist in the database. + * + * @author tseeker + */ +public final class UnknownStringException + extends TranslationException +{ + + private static final long serialVersionUID = 1L; + + private String string; + + + public UnknownStringException( String string ) + { + super( "the requested i18n string '" + string + "' could not be found" ); + this.string = string; + } + + + public String getString( ) + { + return this.string; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/AlreadySentException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/AlreadySentException.java new file mode 100644 index 0000000..9aa8c44 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/AlreadySentException.java @@ -0,0 +1,15 @@ +package com.deepclone.lw.interfaces.mailer; + + +/** + * This exception is thrown when a message is sent twice. + * + * @author tseeker + */ +public class AlreadySentException + extends MailerException +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MailData.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MailData.java new file mode 100644 index 0000000..89fd956 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MailData.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.interfaces.mailer; + + +/** + * A MailData instance allows an email to be prepared by substituting fields in the message template + * then sent either synchronously or asynchronously. + * + * @author tseeker + */ +public interface MailData +{ + + /** + * Sets the value of a template field + * + * @param identifier + * the field's identifier + * @param value + * the value with which the field is to be replaced + * @throws IllegalArgumentException + * if the identifier does not correspond to a field, if the value is null or if the + * field had already been set. + */ + public void setData( String identifier , Object value ) + throws IllegalArgumentException; + + + /** + * Sends the message immediately, returning only after it has been sent. + * + * @throws AlreadySentException + * if the message had already been sent + * @throws MissingDataException + * if some of the template fields have not been set + * @throws NotSentException + * if the mail could not be sent + */ + public void sendNow( ) + throws AlreadySentException , MissingDataException , NotSentException; + + + /** + * Queue the message so that it may be sent asynchronously. + * + * @throws AlreadySentException + * if the message had already been sent + * @throws MissingDataException + * if some of the template fields have not been set + */ + public void queue( ) + throws AlreadySentException , MissingDataException; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/Mailer.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/Mailer.java new file mode 100644 index 0000000..270b00e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/Mailer.java @@ -0,0 +1,35 @@ +package com.deepclone.lw.interfaces.mailer; + + +import com.deepclone.lw.interfaces.i18n.TranslationException; + + + +/** + * Mailer bean interface + * + * This interface is meant to be implemented by the server's mailer bean. + * + * @author tseeker + */ +public interface Mailer +{ + + /** + * This method generates a MailData instance from a template found in the internationalisation + * database. + * + * @param language + * the language identifier + * @param contentsDef + * the string identifier for the mail's template + * @param target + * the address to which the mail is to be sent + * @return the mail data instance + * @throws TranslationException + * when retrieving the template from the database fails + */ + public MailData createMail( String language , String contentsDef , String target ) + throws TranslationException; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MailerException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MailerException.java new file mode 100644 index 0000000..80387a5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MailerException.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.interfaces.mailer; + + +/** + * Base class for the mailer bean's exceptions + * + * @author tseeker + */ +public abstract class MailerException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + + public MailerException( ) + { + super( ); + } + + + public MailerException( String message ) + { + super( message ); + } + + + public MailerException( Throwable cause ) + { + super( cause ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MissingDataException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MissingDataException.java new file mode 100644 index 0000000..af04d53 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/MissingDataException.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.interfaces.mailer; + + +/** + * This exception is thrown when a template field has not been assigned a value. + * + * @author tseeker + */ +public class MissingDataException + extends MailerException +{ + + private static final long serialVersionUID = 1L; + + + public MissingDataException( String fieldName ) + { + super( fieldName ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/NotSentException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/NotSentException.java new file mode 100644 index 0000000..01215af --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/mailer/NotSentException.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.interfaces.mailer; + + +/** + * This exception is thrown when an email could not be sent. + * + * @author tseeker + */ +public class NotSentException + extends MailerException +{ + + private static final long serialVersionUID = 1L; + + + public NotSentException( Throwable cause ) + { + super( cause ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/AdminMessages.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/AdminMessages.java new file mode 100644 index 0000000..c48e918 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/AdminMessages.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.interfaces.msg; + + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.admin.msg.*; + + + +public interface AdminMessages +{ + + public GetMessagesResponse getMessages( Administrator admin , boolean inbox ); + + + public ReadMessageResponse getMessage( Administrator admin , boolean inbox , long id ); + + + public void deleteMessages( Administrator admin , boolean inbox , long[] selection ); + + + public void markRead( Administrator admin , long[] selection ); + + + public void markUnread( Administrator admin , long[] selection ); + + + public ComposeMessageResponse prepareBlankMessage( Administrator admin ); + + + public ComposeMessageResponse prepareMessageTo( Administrator admin , MessageType type , int id ); + + + public ComposeMessageResponse sendMessage( Administrator admin , MessageType type , String target , String title , + String contents , boolean simulate ); + + + public ComposeMessageResponse sendReply( Administrator admin , boolean inbox , long replyTo , MessageType type , + String target , String title , String contents , boolean simulate ); + + + public ComposeMessageResponse prepareReply( Administrator admin , boolean inbox , long id ); + + + public void sendSpam( Administrator admin , String title , String body ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/EmpireMessages.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/EmpireMessages.java new file mode 100644 index 0000000..8ae8af9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/EmpireMessages.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.interfaces.msg; + + +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.player.msgs.ComposeMessageResponse; +import com.deepclone.lw.cmd.player.msgs.GetMessagesResponse; +import com.deepclone.lw.cmd.player.msgs.ListTargetsResponse; +import com.deepclone.lw.cmd.player.msgs.ReadMessageResponse; + + + +public interface EmpireMessages +{ + + public GetMessagesResponse getMessages( int empireId , boolean inbox ); + + + public ReadMessageResponse getMessage( int empireId , boolean inbox , long id ); + + + public void deleteMessages( int empireId , boolean inbox , long[] selection ); + + + public void markRead( int empireId , long[] selection ); + + + public void markUnread( int empireId , long[] selection ); + + + public ComposeMessageResponse prepareBlankMessage( int empireId ); + + + public ComposeMessageResponse prepareMessageTo( int empireId , MessageType type , int id ); + + + public ComposeMessageResponse sendMessage( int empireId , MessageType type , String target , String title , + String contents , boolean simulate ); + + + public ComposeMessageResponse sendReply( int empireId , boolean inbox , long replyTo , MessageType type , + String target , String title , String contents , boolean simulate ); + + + public ComposeMessageResponse prepareReply( int empireId , boolean inbox , long id ); + + + public ListTargetsResponse getTargets( int empireId ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageBoxDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageBoxDAO.java new file mode 100644 index 0000000..a2f921b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageBoxDAO.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.interfaces.msg; + + +import java.util.List; + +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.sqld.msgs.InboxRecord; + + + +public interface MessageBoxDAO +{ + + public int sendMessage( boolean admin , int empireId , MessageType type , String target , String title , + String contents , boolean simulate ); + + + public List< InboxRecord > getList( boolean admin , int id , boolean inbox ); + + + public void markRead( boolean admin , int userId , long[] ids ); + + + public void markRead( boolean admin , int userId ); + + + public void markUnread( boolean admin , int userId , long[] ids ); + + + public void markUnread( boolean admin , int userId ); + + + public void delete( boolean admin , int userId , boolean inbox , long[] ids ); + + + public void delete( boolean admin , int userId , boolean inbox ); + + + public void clearCache( ); + + + public void sendSpam( int adminId , String title , String body ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageContentCache.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageContentCache.java new file mode 100644 index 0000000..1612531 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageContentCache.java @@ -0,0 +1,20 @@ +package com.deepclone.lw.interfaces.msg; + + +import java.util.List; +import java.util.Map; + +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +public interface MessageContentCache +{ + + public Map< Long , MessageDataRecord > getContent( List< InboxRecord > messages ); + + + public void clearCache( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageExtractor.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageExtractor.java new file mode 100644 index 0000000..6e88cf1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageExtractor.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.interfaces.msg; + + +public interface MessageExtractor +{ + + public String getSender( ); + + + public String getSubject( ); + + + public String getContents( ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageFormatRegistry.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageFormatRegistry.java new file mode 100644 index 0000000..8e58c82 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageFormatRegistry.java @@ -0,0 +1,16 @@ +package com.deepclone.lw.interfaces.msg; + + +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +public interface MessageFormatRegistry +{ + + public void addFormatter( MessageFormatter formatter ); + + + public MessageFormatter getFormatter( MessageDataRecord contents ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageFormatter.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageFormatter.java new file mode 100644 index 0000000..5c85f14 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageFormatter.java @@ -0,0 +1,18 @@ +package com.deepclone.lw.interfaces.msg; + + +import java.util.Set; + +import com.deepclone.lw.sqld.msgs.FormatType; +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.MessageDataRecord; + + + +public interface MessageFormatter +{ + public Set< FormatType > getFormats( ); + + + public MessageExtractor getExtractor( InboxRecord envelope , MessageDataRecord contents , String language ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageRecordsDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageRecordsDAO.java new file mode 100644 index 0000000..ab64686 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/MessageRecordsDAO.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.interfaces.msg; + + +import java.util.List; + +import com.deepclone.lw.sqld.msgs.*; + + + +public interface MessageRecordsDAO +{ + + public List< TextMessageRecord > getTextMessages( List< Long > ids ); + + + public List< EventTypeRecord > getEventTypes( List< Long > ids ); + + + public List< EventRecord > getEvents( EventType type , List< Long > ids ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/NotificationsDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/NotificationsDAO.java new file mode 100644 index 0000000..1aaad54 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/msg/NotificationsDAO.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.interfaces.msg; + + +import java.util.List; + +import com.deepclone.lw.sqld.msgs.InboxRecord; +import com.deepclone.lw.sqld.msgs.NotificationsRecord; + + + +public interface NotificationsDAO +{ + public boolean isRecapTime( ); + + + public List< NotificationsRecord > getNotificationRecords( boolean instant ); + + + public List< InboxRecord > listMessages( int empireId , long maxId , boolean instant , boolean nPrivate , + boolean nInternal , boolean nAlliance , boolean nAdmin ); + + + public void cleanupMessages( ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/EmpireNameException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/EmpireNameException.java new file mode 100644 index 0000000..d1d2966 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/EmpireNameException.java @@ -0,0 +1,42 @@ +package com.deepclone.lw.interfaces.naming; + + +/** + * Empire/player name manager exception + * + * This exception is used by {@link EmpireNamesDAO} to indicate that something went wrong in the + * name creation or modification code. + * + * @author tseeker + */ +public class EmpireNameException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + /** Possible causes for this exception */ + public static enum Error { + /** Attempting to use a banned name */ + BANNED , + /** Attempting to use a name which already exists in the DB */ + UNAVAILABLE , + } + + /** Actual error code */ + private Error error;; + + + public EmpireNameException( Error error ) + { + super( error.toString( ) ); + this.error = error; + } + + + /** @return the error code for the exception */ + public Error getError( ) + { + return this.error; + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/MapNameException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/MapNameException.java new file mode 100644 index 0000000..dcb5826 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/MapNameException.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.interfaces.naming; + + +/** + * Map object name manager exception + * + * This exception is thrown by {@link MapNamesDAO} to indicate that something went wrong. It + * carries an error code indicating the nature of the problem. + * + * @author tseeker + */ +public class MapNameException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + /** Possible causes for this exception */ + public static enum Error { + /** Attempting to use a banned name */ + BANNED , + /** Attempting to use a name which already exists in the DB */ + UNAVAILABLE , + /** Attempting a rename too early after the previous one */ + TOO_EARLY , + /** Attempting to validate a name that's already been validated */ + VALIDATED , + /** Attempting to validate a name that's never been modified by a player */ + NOT_RENAMED + }; + + /** Actual error code */ + private Error error;; + + + public MapNameException( Error error ) + { + super( error.toString( ) ); + this.error = error; + } + + + /** @return the error code for the exception */ + public Error getError( ) + { + return this.error; + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/NamesManager.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/NamesManager.java new file mode 100644 index 0000000..2adb7d8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/NamesManager.java @@ -0,0 +1,32 @@ +package com.deepclone.lw.interfaces.naming; + + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.naming.GetNamesResponse; +import com.deepclone.lw.cmd.admin.naming.NameType; +import com.deepclone.lw.cmd.admin.naming.NamesSummaryResponse; + + + +public interface NamesManager +{ + public NamesSummaryResponse getSummary( Administrator admin ); + + + public GetNamesResponse getNames( Administrator admin , NameType type ); + + + public void validateMapNames( Administrator admin , int[] ids ); + + + public void allowMapNameChanges( Administrator admin , int[] ids ); + + + public void rejectMapNames( Administrator admin , int[] ids , boolean ban ); + + + public void rejectEmpireNames( Administrator admin , int[] ids , boolean ban ); + + + public void rejectAllianceNames( Administrator admin , int[] ids ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/NamingDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/NamingDAO.java new file mode 100644 index 0000000..efab7a8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/naming/NamingDAO.java @@ -0,0 +1,45 @@ +package com.deepclone.lw.interfaces.naming; + + +import java.util.List; +import java.util.Map; + +import com.deepclone.lw.cmd.admin.naming.Name; +import com.deepclone.lw.cmd.admin.naming.NameType; +import com.deepclone.lw.sqld.accounts.Account; + + + +public interface NamingDAO +{ + + public List< String > getEmpireNames( int id ); + + + public Integer getCurrentEmpire( Account account ); + + + public int renamePlanet( int id , String name ); + + + public Map< NameType , Long > countNames( ); + + + public List< Name > getNames( NameType type ); + + + void validateMapName( int administrator , int name ); + + + public void allowMapNameChange( int administrator , int name ); + + + public void rejectMapName( int administrator , int name , boolean ban ); + + + public void rejectEmpireName( int administrator , int empire , boolean ban ); + + + public void rejectAllianceName( int administrator , int alliance ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/AccountPreferences.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/AccountPreferences.java new file mode 100644 index 0000000..73f5cea --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/AccountPreferences.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.interfaces.prefs; + + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + + + +public class AccountPreferences +{ + + private final Map< String , PreferenceGroup > groups = new HashMap< String , PreferenceGroup >( ); + + private final List< String > groupOrder = new LinkedList< String >( ); + + private final Map< String , String > prefGroups; + + + public AccountPreferences( List< PreferenceGroup > groups , Map< String , String > prefGroups ) + { + for ( PreferenceGroup group : groups ) { + this.groups.put( group.getName( ) , group ); + this.groupOrder.add( group.getName( ) ); + } + this.prefGroups = prefGroups; + } + + + public List< PreferenceGroup > getGroups( ) + { + List< PreferenceGroup > g = new LinkedList< PreferenceGroup >( ); + for ( String gn : groupOrder ) { + g.add( this.groups.get( gn ) ); + } + return g; + } + + + public < T > T getPreference( String name , Class< T > type ) + { + String gn = this.prefGroups.get( name ); + return this.groups.get( gn ).getPreference( name ).getValue( type ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/Preference.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/Preference.java new file mode 100644 index 0000000..36a2f4a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/Preference.java @@ -0,0 +1,75 @@ +package com.deepclone.lw.interfaces.prefs; + + +public class Preference +{ + + private String name; + + private PreferenceGroup group; + + private String displayName; + + private String description; + + private PreferenceType< ? > type; + + private String value; + + + public Preference( String name , PreferenceGroup group , String displayName , String description , + PreferenceType< ? > type , String value ) + { + this.name = name; + this.group = group; + this.displayName = displayName; + this.description = description; + this.type = type; + this.value = value; + this.group.addPreference( this ); + } + + + public String getName( ) + { + return name; + } + + + public PreferenceGroup getGroup( ) + { + return group; + } + + + public String getDisplayName( ) + { + return displayName; + } + + + public String getDescription( ) + { + return description; + } + + + public PreferenceType< ? > getType( ) + { + return type; + } + + + public String getDBValue( ) + { + return this.value; + } + + + @SuppressWarnings( "unchecked" ) + public < T > T getValue( Class< T > type ) + { + return ( (PreferenceType< T >) this.type ).valueOf( this.value , type ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceDefinitionException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceDefinitionException.java new file mode 100644 index 0000000..34c12f8 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceDefinitionException.java @@ -0,0 +1,25 @@ +package com.deepclone.lw.interfaces.prefs; + + +public class PreferenceDefinitionException + extends Exception +{ + + /** Serialisation version identifier */ + private static final long serialVersionUID = 1L; + + public static enum Error { + MISSING_GROUP , + MISSING_DEFINITION , + MISSING_STRING , + INVALID_TYPE + } + + public final Error error; + + + public PreferenceDefinitionException( Error error ) + { + this.error = error; + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceDefinitions.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceDefinitions.java new file mode 100644 index 0000000..aef759d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceDefinitions.java @@ -0,0 +1,71 @@ +package com.deepclone.lw.interfaces.prefs; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.player.gdata.account.PrefCategory; + + + +/** + * Interface for the preference definitions management bean. + * + * @author tseeker + */ +public interface PreferenceDefinitions +{ + + /** + * Registers a group of preferences. + * + * @param name + * programmatic name of the group + * @param displayName + * internationalised string identifier + * @throws PreferenceDefinitionException + * when the display name string doesn't exist (with the + * {@link PreferenceDefinitionException.Error#MISSING_STRING} error code) + * @throws IllegalArgumentException + * if one of the parameters is null + */ + public void registerGroup( String name , String displayName ) + throws PreferenceDefinitionException , IllegalArgumentException; + + + /** + * Registers a new type of user preference. + * + * @param name + * programmatic name of the preference + * @param group + * programmatic name of the group the preference is a part of + * @param displayName + * internationalised string identifier that allows the preference's name to be + * displayed + * @param displayDescription + * internationalised string identifier that allows the preference's description to be + * displayed (may be null) + * @param defaultValue + * default value of the preference + * @throws PreferenceDefinitionException + * when the group doesn't exist (with the + * {@link PreferenceDefinitionException.Error#MISSING_GROUP} error code), when the + * display name or description string doesn't exist (with the + * {@link PreferenceDefinitionException.Error#MISSING_STRING} error code) or if the + * preference already exists but is defined as having a different type (with the + * {@link PreferenceDefinitionException.Error#INVALID_TYPE} error code). + * @throws IllegalArgumentException + * if one of the mandatory arguments is null + */ + public void registerPreference( String name , String group , String displayName , String displayDescription , + Object defaultValue ) + throws PreferenceDefinitionException , IllegalArgumentException; + + + public List< PrefCategory > getDefaults( ); + + + public void setDefault( Administrator admin , String preference , String value ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceGroup.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceGroup.java new file mode 100644 index 0000000..77b7a8b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceGroup.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.interfaces.prefs; + + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + + + +public class PreferenceGroup +{ + + private String name; + + private String display; + + private final List< Preference > definitions = new LinkedList< Preference >( ); + + private final Map< String , Preference > byName = new HashMap< String , Preference >( ); + + + public PreferenceGroup( String name , String display ) + { + this.name = name; + this.display = display; + } + + + public String getName( ) + { + return name; + } + + + public String getDisplay( ) + { + return display; + } + + + public void addPreference( Preference def ) + { + this.definitions.add( def ); + this.byName.put( def.getName( ) , def ); + } + + + public List< Preference > getPreferences( ) + { + return this.definitions; + } + + + public Preference getPreference( String name ) + { + return this.byName.get( name ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceType.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceType.java new file mode 100644 index 0000000..f69ff95 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceType.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.interfaces.prefs; + + +import java.util.Map; + + + +public interface PreferenceType< T > +{ + + public T valueOf( String dbValue , Class< T > type ); + + + public Object valueOf( String inValue ); + + + public String convert( Object value ); + + + public Map< String , String > getChoices( ); + + + public Class< T > getType( ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceTypesRegistry.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceTypesRegistry.java new file mode 100644 index 0000000..9fb635f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferenceTypesRegistry.java @@ -0,0 +1,12 @@ +package com.deepclone.lw.interfaces.prefs; + + +public interface PreferenceTypesRegistry +{ + + public < T > PreferenceType< T > getType( Class< T > jType ); + + + public PreferenceType< ? > getType( String typeName ); + +} \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferencesDAO.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferencesDAO.java new file mode 100644 index 0000000..1f790d5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/prefs/PreferencesDAO.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.interfaces.prefs; + + +import java.util.Map; + +import com.deepclone.lw.sqld.accounts.Account; + + + +/** + * Interface for the account preferences management bean. + * + * @author tseeker + */ +public interface PreferencesDAO +{ + + /** + * Reads all preferences from an account. + * + *

+ * This method reads all preferences associated to an account. The default value is used if a + * preference definition exists but no such preference is set for the account. + * + * @param account + * account whose preferences are to be read. + */ + public AccountPreferences getPreferences( Account account ); + + + public AccountPreferences getPreferences( int accountId ); + + + /** + * Resets an account's preferences. + * + * @param account + * account whose preferences are to be reset + */ + public void resetPreferences( Account account ); + + + void setPreferences( Account account , Map< String , String > values ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/ServerSession.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/ServerSession.java new file mode 100644 index 0000000..5844208 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/ServerSession.java @@ -0,0 +1,104 @@ +package com.deepclone.lw.interfaces.session; + + +import java.net.InetAddress; +import java.util.Date; + +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; + + + +/** + * Server-side session interface. + * + *

+ * This interface provides session type definers (as defined by {@link SessionTypeDefiner}) limited + * access to server-side session data. + * + * @author tseeker + */ +public interface ServerSession +{ + + /** + * @return the session's identifier (may be null when the session is being initialised) + */ + public String getIdentifier( ); + + + /** + * @return the identifier of the client on behalf of which the session was created + */ + public String getClient( ); + + + /** + * @return the IP address of the client on behalf of which the session was created + */ + public InetAddress getAddress( ); + + + /** + * @return the session's current authentication challenge string + */ + public String getChallenge( ); + + + /** + * Sets the session's expiration date + * + * @param date + * new expiration date + */ + public void setExpirationDate( Date date ); + + + /** + * @return the type of session termination or null if the session is not being + * terminated + */ + public SessionTerminationType getTerminationType( ); + + + /** + * Terminates the session. + * + *

+ * This method can be called by session type definers which need to destroy a session. It will + * set the termination type to {@link SessionTerminationType#MANUAL} and call back + * {@link SessionTypeDefiner#terminate(ServerSession)}. + */ + public void terminate( ); + + + /** + * Terminates the session. + * + *

+ * This method can be called by session type definers which need to destroy a session and give a + * specific reason. + */ + public void terminate( SessionTerminationType reason ); + + + /** + * Stores data into the session. + * + * @param key + * key with which the specified value is to be associated + * @param value + * value to be associated with the specified key + */ + public void put( String key , Object value ); + + + /** + * Retrieves data from the session. + * + * @param key + * the key whose associated value is to be returned + * @param type + * expected type of the value + */ + public < T > T get( String key , Class< T > type ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/SessionManager.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/SessionManager.java new file mode 100644 index 0000000..22a2a8c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/SessionManager.java @@ -0,0 +1,34 @@ +package com.deepclone.lw.interfaces.session; + + +import com.deepclone.lw.session.SessionAccessor; + + + +/** + * Session manager interface. + * + *

+ * This interface, implemented by the session management bean, extends the Legacy Worlds + * {@link SessionAccessor} interface and adds a method allowing {@link SessionTypeDefiner} instances + * to be registered. + * + * @author tseeker + */ +public interface SessionManager + extends SessionAccessor +{ + + /** + * Registers a session type definer. + * + *

+ * This method adds support for a session type using the specified session type definer. If a + * session type with the same name already exists, it is replaced. + * + * @param definer + * the session type definer to register. + */ + public void registerSessionType( SessionTypeDefiner definer ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/SessionTypeDefiner.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/SessionTypeDefiner.java new file mode 100644 index 0000000..16147e1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/session/SessionTypeDefiner.java @@ -0,0 +1,125 @@ +package com.deepclone.lw.interfaces.session; + + +import com.deepclone.lw.cmd.admin.users.SessionTerminationType; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionCommandException; +import com.deepclone.lw.session.SessionStateException; + + + +/** + * Interface for session type definers. + * + *

+ * This interface defines methods which allow sessions to be managed. + * + * @author tseeker + */ +public interface SessionTypeDefiner +{ + + /** @return the name of the session type */ + public String getName( ); + + + /** + * Initialises a session. + * + *

+ * This method should initialise the specified session, setting its initial data and expiration + * date. When the method is called by the {@link SessionManager}, the session has no identifier + * - it is only assigned once initialisation has completed. + * + * @param session + * the session to initialise + */ + public void initialise( ServerSession session ); + + + /** + * Determines whether the specified session has undergone authentication. + * + * @param session + * the session whose status is to be determined. + * @return true if the session has undergone authentication or doesn't need to + * authenticate, false if authentication is required + */ + public boolean isAuthenticated( ServerSession session ); + + + /** + * Returns the current state of the session. + * + *

+ * This method returns the current state of an authenticated session. It is useful for session + * definers that implement multi-state sessions, accepting different sets of commands in each + * state. + * + * @param session + * the session whose state is to be determined + * @return the session's state. + */ + public String getState( ServerSession session ); + + + /** + * Authenticates a session. + * + *

+ * This method attempts to authenticate a session, modifying the session's data accordingly if + * successful. + * + * @param session + * the session being authenticated + * @param identifier + * authentication identifier (for example an account's mail address) + * @param sha1Hash + * SHA-1 hash of the challenge response + * @param md5Hash + * MD5 hash of the challenge response + * @throws SessionStateException + * if the session type doesn't support authentication or if the session had already + * undergone authentication. + */ + public void authenticate( ServerSession session , String identifier , String sha1Hash , String md5Hash ) + throws SessionStateException; + + + /** + * Executes a command. + * + *

+ * This method executes the specified command in the session's context, returning the command's + * results. + * + * @param session + * the session whose context is to be used when executing the command + * @param command + * the command to execute + * @return whatever the command execution yields. + * @throws SessionStateException + * if the session type requires authentication and the session is not authenticated. + * @throws SessionCommandException + * if the session type does not support the specified command. + */ + public CommandResponse execute( ServerSession session , Command command ) + throws SessionStateException , SessionCommandException; + + + /** + * Handles session termination. + * + *

+ * This method will execute code specific to a session type when a session is being terminated + * (either through the session type definer itself or for other reasons). + * + * @param session + * the session that's being terminated. + * @param reason + * the reason why the session's being terminated + */ + public void terminate( ServerSession session , SessionTerminationType reason ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantDefinition.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantDefinition.java new file mode 100644 index 0000000..19704ff --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantDefinition.java @@ -0,0 +1,122 @@ +package com.deepclone.lw.interfaces.sys; + + +/** + * This class is used by beans which define constants in order to notify the constants manager of + * their existence and specifics. + * + * @author tseeker + */ +public final class ConstantDefinition +{ + + /** The constant's name, as it is used in the code */ + public final String name; + + /** The human-readable category name used in the administration interface */ + public final String category; + + /** The constant's description used in the administrative interface */ + public final String description; + + /** The optional minimal value */ + public final Double minValue; + + /** The optional maximal value */ + public final Double maxValue; + + /** The constant's default value */ + public final Double defaultValue; + + + /** + * Creates a constant definition with no constraints. + * + * @param name + * the constant's name + * @param category + * the constant's category + * @param description + * the constant's description + * @param value + * the constant's default value + */ + public ConstantDefinition( String name , String category , String description , Double value ) + { + this.name = name; + this.category = category; + this.description = description; + this.defaultValue = value; + this.maxValue = this.minValue = null; + } + + + /** + * Creates a constant definition with a single constraint. + * + * @param name + * the constant's name + * @param category + * the constant's category + * @param description + * the constant's description + * @param value + * the constant's default value + * @param constraint + * a constraint to apply on the constant's definition + * @param isMinimal + * whether the constraint is the minimal or maximal value + * @throws IllegalArgumentException + * if the default value is out of bounds + */ + public ConstantDefinition( String name , String category , String description , Double value , Double constraint , + boolean isMinimal ) + throws IllegalArgumentException + { + if ( isMinimal && value < constraint || !isMinimal && value > constraint ) { + throw new IllegalArgumentException( ); + } + this.name = name; + this.category = category; + this.description = description; + this.defaultValue = value; + this.maxValue = isMinimal ? null : constraint; + this.minValue = isMinimal ? constraint : null; + } + + + /** + * Creates a constant definition with two constraints. + * + * @param name + * the constant's name + * @param category + * the constant's category + * @param description + * the constant's description + * @param value + * the constant's default value + * @param min + * the constant's minimal value + * @param max + * the constant's maximal value + * @throws IllegalArgumentException + * if the minimal is greater than the maximal or if the default value is out of + * bounds + */ + public ConstantDefinition( String name , String category , String description , Double value , Double min , + Double max ) + throws IllegalArgumentException + { + if ( min > max || value < min || value > max ) { + throw new IllegalArgumentException( ); + } + this.name = name; + this.category = category; + this.description = description; + this.defaultValue = value; + this.maxValue = max; + this.minValue = min; + + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsAdministration.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsAdministration.java new file mode 100644 index 0000000..5ec7053 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsAdministration.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.interfaces.sys; + + +import java.util.Collection; +import java.util.Set; + + + +/** + * This is the constants administrative interface, which allows constants to be listed and modified + * by the game's administrators. + * + * @author tseeker + */ +public interface ConstantsAdministration +{ + + /** @return the set of constant categories */ + public Set< String > getCategories( ); + + + /** + * List all constants in a category. The constant definition objects that are returned have the + * constant's current value set as their default value field. + * + * @param category + * the name of the category to list + * @return the list of constants in a given category or an empty list if the category does not + * exist + */ + public Collection< ConstantDefinition > getConstants( String category ); + + + /** + * Modifies a constant and notifies all constant user components of the change. + * + * @param name + * the constant's name + * @param value + * the constant's new value + * @throws UnknownConstantError + * if the name doesn't match any actual constant + * @throws InvalidConstantValue + * if the specified value is out of bounds + */ + public void setConstant( String name , Double value ) + throws UnknownConstantError , InvalidConstantValue; +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsManager.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsManager.java new file mode 100644 index 0000000..825e886 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsManager.java @@ -0,0 +1,63 @@ +package com.deepclone.lw.interfaces.sys; + + +import java.util.Collection; +import java.util.Set; + + + +/** + * The constants management service provides a way for system constants to be accessed from a + * central location. All constants are loaded in main memory, and can be modified through an + * administrative interface. + * + * @author tseeker + * + */ +public interface ConstantsManager +{ + + /** + * Registers a set of constants; if the constants already exist in the database, their + * constraints are updated and their value is only modified if it violates the constraints. If + * they do not exist yet, they are created. + * + * If constants are modified or created, and if there are users registered for these constants, + * they will be notified. + * + * @param definitions + * the set of constant definitions to register + */ + public void registerConstants( Collection< ConstantDefinition > definitions ); + + + /** + * Registers a constants user, which will need to be informed of the constants' changes. If the + * required constants have not been registered yet, the user instance will not be notified. + * + * @param user + * the constants user component to register + * @param constants + * set of constant names the user wants to be informed about + */ + public void registerUser( ConstantsUser user , Set< String > constants ); + + + /** + * Unregisters a constants user. + * + * @param user + * the constants user component to unregister + */ + public void unregisterUser( ConstantsUser user ); + + + /** + * Creates an administrative interface for a specific administrator. + * + * @param admin + * the administrator making changes to the constants. + * @return the administrative interface + */ + public ConstantsAdministration getAdminSession( int admin ); +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsUser.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsUser.java new file mode 100644 index 0000000..c821c63 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/ConstantsUser.java @@ -0,0 +1,32 @@ +package com.deepclone.lw.interfaces.sys; + + +import java.util.Map; + + + +/** + * This interface is implemented by beans which need to access system constants and be informed if + * the constants are modified. + * + * @author tseeker + * + */ +public interface ConstantsUser +{ + + /** + * This method will be called by the constants manager when the constants user registers itself + * or whenever one of the constants needed by the user is modified. + * + * @param initial + * true if the call is being issued after registration, false otherwise + * @param values + * a map that associates updated constant names to their new values + * @throws Exception + * for whatever reasons. + */ + public void setConstants( boolean initial , Map< String , Double > values ) + throws Exception; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/EndAutowiredTransaction.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/EndAutowiredTransaction.java new file mode 100644 index 0000000..fc9bf4e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/EndAutowiredTransaction.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.interfaces.sys; + + +public class EndAutowiredTransaction + extends RuntimeException +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/InvalidConstantValue.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/InvalidConstantValue.java new file mode 100644 index 0000000..22eefab --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/InvalidConstantValue.java @@ -0,0 +1,17 @@ +package com.deepclone.lw.interfaces.sys; + + +/** + * This exception is thrown by the constants administrative interface when an administrator attempts + * to set a constraint that is out of bounds. + * + * @author tseeker + * + */ +public class InvalidConstantValue + extends Exception +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/MaintenanceData.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/MaintenanceData.java new file mode 100644 index 0000000..0199d6f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/MaintenanceData.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.interfaces.sys; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public final class MaintenanceData + implements Serializable +{ + + /** Serialisation version identifier */ + private static final long serialVersionUID = 1L; + + public final Timestamp start; + public final Timestamp end; + public final String reason; + + + public MaintenanceData( Timestamp start , Timestamp end , String reason ) + { + this.start = start; + this.end = end; + this.reason = reason; + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/MaintenanceStatusException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/MaintenanceStatusException.java new file mode 100644 index 0000000..fb4f2a2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/MaintenanceStatusException.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.interfaces.sys; + + +public class MaintenanceStatusException + extends Exception +{ + + /** Serialisation version identifier */ + private static final long serialVersionUID = 1L; + + public final MaintenanceData maintenanceData; + + + public MaintenanceStatusException( ) + { + super( "not under maintenance" ); + this.maintenanceData = null; + } + + + public MaintenanceStatusException( MaintenanceData data ) + { + super( "under maintenance" ); + this.maintenanceData = data; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/SystemStatus.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/SystemStatus.java new file mode 100644 index 0000000..d8cc5d2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/SystemStatus.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.interfaces.sys; + + +public interface SystemStatus +{ + + /** + * Checks whether the system is currently under maintenance. + * + * @return null or maintenance record + */ + public MaintenanceData checkMaintenance( ); + + + /** + * Activates maintenance mode. + */ + public void startMaintenance( int adminId , String reason , int duration ) + throws MaintenanceStatusException; + + + /** + * Updates maintenance mode duration. + */ + public void updateMaintenance( int adminId , int durationFromNow ) + throws MaintenanceStatusException; + + + /** + * Exits maintenance mode. + */ + public void endMaintenance( int adminId ) + throws MaintenanceStatusException; + + + /** + * Starts a new tick. + * + * @return new tick's identifier + */ + public long startTick( ) + throws TickStatusException , MaintenanceStatusException; + + + /** + * Checks if there is a "stuck" tick. + * + * @return current tick's identifier or null if there is no stuck tick + */ + public Long checkStuckTick( ) + throws MaintenanceStatusException; + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/TickStatusException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/TickStatusException.java new file mode 100644 index 0000000..c5d9bd6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/TickStatusException.java @@ -0,0 +1,25 @@ +package com.deepclone.lw.interfaces.sys; + + +public class TickStatusException + extends Exception +{ + /** Serialisation version identifier */ + private static final long serialVersionUID = 1L; + + public final Long tickIdentifier; + + + public TickStatusException( ) + { + super( "no tick in progress" ); + this.tickIdentifier = null; + } + + + public TickStatusException( long id ) + { + super( "tick in progress" ); + this.tickIdentifier = id; + } +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/Ticker.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/Ticker.java new file mode 100644 index 0000000..26b23fa --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/Ticker.java @@ -0,0 +1,78 @@ +package com.deepclone.lw.interfaces.sys; + + +/** + * System task scheduler + * + * This interface provides access to the system task scheduler, which is used for everything that is + * supposed to happen at a regular interval (from log cleaning to ticks). + * + * @author tseeker + */ +public interface Ticker +{ + + /** Task execution frequencies */ + public enum Frequency { + /** Tasks that are meant to be executed every five seconds */ + HIGH , + + /** Tasks that are meant to be executed every thirty seconds */ + MEDIUM , + + /** Tasks that are meant to be executed every minute */ + MINUTE , + + /** Tasks that are meant to be executed every five minutes */ + LOW + } + + + /** + * Registers a new task. + * + * This method may be called to register a new task in the system ticker. The ticker will use a + * weak reference to store the task's execution instance. + * + * @param frequency + * task execution frequency + * @param name + * task name + * @param task + * runnable instance to be executed at the specified frequency + */ + public void registerTask( Ticker.Frequency frequency , String name , Runnable task ); + + + /** + * Pauses the ticker. + * + * This method pauses the ticker. Once the method is called, no new tasks will be started; + * however, the method will wait for any currently running tasks before returning. + * + * @throws IllegalStateException + * if the ticker was already paused + */ + public void pause( ) + throws IllegalStateException; + + + /** + * Restarts the ticker. + * + * This method attempts to restart the ticker after it has been paused. + * + * @throws IllegalStateException + * if the ticker was already running. + */ + public void unpause( ) + throws IllegalStateException; + + + /** + * @return true the ticker is currently running or false if it has + * been paused. + */ + public boolean isActive( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/TickerManager.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/TickerManager.java new file mode 100644 index 0000000..9671b38 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/TickerManager.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.interfaces.sys; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.tick.TickerTaskInfo; + + + +public interface TickerManager +{ + + public List< TickerTaskInfo > getTasks( ); + + + public void startTask( int administrator , int id ); + + + public void stopTask( int administrator , int id ); + + + public void setTaskStart( int administrator , int id , long time ); + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/UnknownConstantError.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/UnknownConstantError.java new file mode 100644 index 0000000..6145b80 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/UnknownConstantError.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.interfaces.sys; + + +/** + * This exception is thrown when a constant name doesn't match an actual constant. + * + * @author tseeker + */ +public class UnknownConstantError + extends Exception +{ + + private static final long serialVersionUID = 1L; + + + public UnknownConstantError( String constant ) + { + super( constant ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/WiringException.java b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/WiringException.java new file mode 100644 index 0000000..42c48e4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/sys/WiringException.java @@ -0,0 +1,16 @@ +package com.deepclone.lw.interfaces.sys; + + +public class WiringException + extends RuntimeException +{ + + private static final long serialVersionUID = 1L; + + + public WiringException( Throwable cause ) + { + super( cause ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/.classpath b/legacyworlds-server/legacyworlds-server-main/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-main/.project b/legacyworlds-server/legacyworlds-server-main/.project new file mode 100644 index 0000000..4fabc51 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-main + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-main/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-main/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..deacd36 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Thu Apr 15 09:16:34 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-main/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-server/legacyworlds-server-main/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..1a8e041 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Thu Apr 15 09:16:34 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-server/legacyworlds-server-main/data-source.xml b/legacyworlds-server/legacyworlds-server-main/data-source.xml new file mode 100644 index 0000000..fccf83f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data-source.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-main/data/addressChangeMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/addressChangeMail-en.txt new file mode 100644 index 0000000..9dfc314 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/addressChangeMail-en.txt @@ -0,0 +1,11 @@ +Legacy Worlds (B6M1) - Address change +Hello, + +You are receiving this message because an user of Legacy Worlds (you, presumably) requested to change his or her address to ${address}. + +Your confirmation code is: ${token} + +If you did not request this, please sent the staff an email at staff@legacyworlds.com. + +Thanks! +The Legacy Worlds staff \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/addressChangeMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/addressChangeMail-fr.txt new file mode 100644 index 0000000..569a8e9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/addressChangeMail-fr.txt @@ -0,0 +1,11 @@ +Legacy Worlds (B6M1) - Changement d'adresse +Bonjour, + +Vous avez reƧu ce message car un utilisateur de Legacy Worlds (vous, probablement) a demandĆ© Ć  ce que son adresse soit changĆ©e pour ${address}. + +Votre code de confirmation est: ${token} + +Si vous n'ĆŖtes pas responsable de cette demande, veuillez contacter notre Ć©quipe par courrier Ć©lectronique (staff@legacyworlds.com). + +Cordialement, +L'Ć©quipe de Legacy Worlds \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/adminErrorMail.txt b/legacyworlds-server/legacyworlds-server-main/data/adminErrorMail.txt new file mode 100644 index 0000000..f577aa2 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/adminErrorMail.txt @@ -0,0 +1,4 @@ +[LWB6-ADMIN] Server errors +Errors have been found in the server's system log. Intervention might be required. + +${contents} diff --git a/legacyworlds-server/legacyworlds-server-main/data/adminRecapMail.txt b/legacyworlds-server/legacyworlds-server-main/data/adminRecapMail.txt new file mode 100644 index 0000000..3d90b25 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/adminRecapMail.txt @@ -0,0 +1,4 @@ +[LWB6-ADMIN] Recap +Here's what happened in the past 12 hours... + +${contents} diff --git a/legacyworlds-server/legacyworlds-server-main/data/banLiftedMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/banLiftedMail-en.txt new file mode 100644 index 0000000..39ceb1d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/banLiftedMail-en.txt @@ -0,0 +1,9 @@ +Legacy Worlds (B6M1) - Ban lifted +Hello, + +The ban on your account has been lifted. + +Please accept our most sincere apologies. + +Best regards, +The Legacy Worlds staff diff --git a/legacyworlds-server/legacyworlds-server-main/data/banLiftedMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/banLiftedMail-fr.txt new file mode 100644 index 0000000..95b003f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/banLiftedMail-fr.txt @@ -0,0 +1,9 @@ +Legacy Worlds (B6M1) - Bannissement levĆ© +Bonjour, + +Le bannissement de votre compte a Ć©tĆ© levĆ©. + +Veuillez accepter nos sincĆØres excuses. + +Cordialement, +L'Ć©quipe de Legacy Worlds diff --git a/legacyworlds-server/legacyworlds-server-main/data/bannedMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/bannedMail-en.txt new file mode 100644 index 0000000..c546f78 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/bannedMail-en.txt @@ -0,0 +1,12 @@ +Legacy Worlds (B6M1) account banned +Hello, + +Your Legacy Worlds account has been banned by the game's administrators for the following reason: + +${reason} + +You have 48h to appeal this ban before your empire is lost. +To do so, please send an e-mail to the staff at staff@legacyworlds.com + +Best regards, +The Legacy Worlds staff diff --git a/legacyworlds-server/legacyworlds-server-main/data/bannedMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/bannedMail-fr.txt new file mode 100644 index 0000000..a2fb65e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/bannedMail-fr.txt @@ -0,0 +1,12 @@ +Legacy Worlds (B6M1) - Compte banni +Bonjour, + +Votre compte Legacy Worlds a Ć©tĆ© banni par les administrateurs du jeu pour la raison suivante : + +${reason} + +Vous avez 48h pour faire appel de ce bannissement avant que votre empire soit perdu. +Pour ce faire, veuillez envoyer un mail Ć  l'Ć©quipe d'administration Ć  l'adresse staff@legacyworlds.com + +Cordialement, +L'Ć©quipe de Legacy Worlds diff --git a/legacyworlds-server/legacyworlds-server-main/data/buildables-test.xml b/legacyworlds-server/legacyworlds-server-main/data/buildables-test.xml new file mode 100644 index 0000000..69bc47a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/buildables-test.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/buildables.xml b/legacyworlds-server/legacyworlds-server-main/data/buildables.xml new file mode 100644 index 0000000..5ba9554 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/buildables.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/buildables.xsd b/legacyworlds-server/legacyworlds-server-main/data/buildables.xsd new file mode 100644 index 0000000..a3e80ab --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/buildables.xsd @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-main/data/i18n-text.xml b/legacyworlds-server/legacyworlds-server-main/data/i18n-text.xml new file mode 100644 index 0000000..c2ef4e9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/i18n-text.xml @@ -0,0 +1,1033 @@ + + + + + + + + + + + + + + + + + + + + +*** +From: ${from} +To: ${to} +Subject: ${subject} + +${text} + + + + + * ${subject} + from ${from} + received ${time} + + + Private messages: + + + Alliance messages: + + + Internal messages: + + + Messages from administrators: + + + + Civilian technologies + + + They're not just your slaves, they're your scientists, poets and workers. Make the poets work first, then use these technologies to increase their productivity! Useless poets. + + + + Universal assemblers + + + You know how it is when you have a thingy-bob that you need to build but you just don't have the right tool. Well, fear no more, Universal Assemblers will solve all your problems! Build anything and everything with these clever machines, they are 1337. + + + Corpse reanimation + + + Tired of workers dying too early? Want a little less perspiration in your corporation? Zombies will work, won't complain and best of all, they can be fed on almost anything! Feed them your enemies! But mostly, use them to increase factory productivity by a rather nice amount. + + + Biological generators + + + For every turret a military commander wants, there is a bigger, stronger turret he wants more. Now you too can have such a turret! It will defend your planet with ease while you venture out into the galaxy, bending it to your will. Available in all good hardware stores. + + + + Military technologies + + + It is only one who is thoroughly acquainted with the evils of war that can thoroughly understand the profitable way of carrying it on. - Sun Tzu + + + + Orbital construction + + + Ships built on the ground must endure the stress of atmospheric flight before they are even able to dominate the vast emptiness of space. Build them in space and they will be sleeker, more powerful and now free of the need for windows. Use your brand new Cruisers to dominate the known universe. + + + Structural reinforcement + + + The power of your Cruisers can be augmented by an improved design! Take advantage of a more structurally sound space vehicle that can bring empires to their knees with its speed and technological grace. + + + Automated space docks + + + Technology has advanced. The ultimate weapon is now available. Claim the awesome power of the Dreadnought and crush your enemies. Ever wanted a tank in space? Well, now you have it. All their base are belong to you. + + + + Ship parts factory + + + A Ship parts factory is a mass production factory for the creation of components used in your space faring vessels. They are essential to any space empire; Properly managed factories produce new vehicles quickly and efficiently. + + + Defence turret + + + Exploration without vigilance is the action of a fool. Turrets are the last line of defence for the planet, super massive weapons capable of destroying orbital vehicles from the ground. They can be placed anywhere, on any building or vacant land in your domain and will defend your planets from attack. + + + Generic assembly line + + + Factories are the backbone of a thriving economy, providing goods and matĆ©riel to buy and sell on the free market. Your brand new Generic assembly lines will enhance your wealth and keep the population employed. Properly managed factories produce many economic benefits for an empire. + + + Reanimation centre + + + People are frail but cheap and robots are hard wearing but expensive. Renew the life of your workers and you can take advantage of a cheap zombie resource, giving you a third option for keeping your empire thriving. + + + Biological turret + + + The perfect union of man and machine, Biological Turrets are a blending of the technological and the biological to provide the ultimate defence for your planets. More powerful and accurate than Turrets, in ground based defence they are unmatched. Keep your people away from them, however, as they tend to hunger for human flesh. + + + + Fighter + + + Give a boy a gun and he will become a man. Give a man a ship and he will dominate planets. A Fighter is a light and fast space superiority weapon that alone is inconspicuous and in vast hordes are terrifying. Transport them around the galaxy and you will have all you desire. + + + Cruiser + + + A Cruiser is a compact yet powerful capital ship. It has space-to-space and space-to-ground weapons, as well as a decent number of cup holders. + + + Battlecruiser + + + A BattleCruiser is a capital ship, faster and sleeker than a cruiser. It is much faster than his smaller sibling but still packs a lot of firepower for your money. A worthy addition for any warlord's fleet. + + + Dreadnought + + + Bring the Dread. The Dreadnought is a large capital ship with awesome power and capabilities, expensive and slow but the ultimate in space domination. + + + + Display preferences + + + Real-life time + + + Selecting this option will cause all durations to be displayed using real-life minutes. + + + Map defaults + + + Map centre (X) + + + The abscissa of the default map centre. + + + Map centre (Y) + + + The ordinates of the default map centre. + + + Map size + + + The default size of the map. + + + E-mail settings + + + Private messages + + + Select the type of e-mail notifications you will get for private messages sent by other empires. + + + Alliance messages + + + Select the type of e-mail notifications you will get for alliance-wise messages. + + + Internal messages + + + Select the type of e-mail notifications you will get for internal game messages. + + + Messages from administrators + + + Select the type of e-mail notifications you will get for messages sent by the game's administrators. + + + + Small (3x3) + + + Medium (5x5) + + + Large (7x7) + + + + No notification + + + Include in daily recap + + + Instant notification + + + + + Ministry of Economy + + + Ministry of War + + + Ministry of Peace + + + Ministry of Research + + + Legacy Worlds staff + + + Bug tracker + + + + + Empty civilian queues + + + Some of your planets have finished constructing or destroying buildings: + + + + Empty civilian queue at ${location} + + + Planet ${location} has finished constructing or destroying buildings. + + + + + Empty military queues + + + Some of your planets have finished constructing ships: + + + + Empty military queue at ${location} + + + Planet ${location} has finished constructing ships. + + + + + Battle started at ${location} + + + {{battle:${battleId} Battle #${battleId}}} has started at ${location}. + + + + Battle ended at ${location} + + + {{battle:${battleId} Battle #${battleId}}} has ended at ${location}. + + + + + The citizens of ${location} are on strike + + + The citizens of ${location} are in a really bad mood and have started leaving their posts... We'd better do something about this. + + + + Situation back to normal on ${location} + + + The citizens of ${location} have resumed working. + + + + + Planet ${location} lost + + + We have lost control of ${location}, which was taken from us by ${taker}. + + + + Planet ${location} abandoned + + + Our forces have completed the evacuation of ${location}; the citizens of this world are left to fend for themselves. + + + + + Planet ${location} conquered + + + We have seized control of planet ${location} from the local (lack of) government. + + + We have seized control of planet ${location} from the clutches of ${owner}. + + + + + ${tech} available + + + A new technology, ${tech}, has been fully researched and is ready to be implemented. + + + Out of money!!!!11111 + + + With all due respect, what the hell were you thinking, Sir?! We are so poor we can't even pay for our fleets and buildings anymore! Some of your ministers are even considering prostituting themselves! + + + Economic situation resolved + + + Good to see that our money problems are over, Sir. Good job. Well, of course it'd been better if these problems had never started... Sir? What are you doing with this handgu- + + + + + Pending alliance request + + + ${empire} is requesting to join the alliance. + + + Alliance request accepted + + + Our request to join ${alliance} has been accepted!. + + + Alliance request rejected + + + Our request to join ${alliance} has been rejected. + + + Leadership change + + + ${leader} has stepped down as the alliance's leader. + + + Kicked! + + + We have been kicked out of ${alliance}. + + + ${empire} kicked + + + ${empire} has been kicked from the alliance. + + + ${empire} has left + + + ${empire} has left the alliance. + + + Alliance disbanded! + + + The leader has left and the alliance was disbanded. + + + + + Fleets have arrived at ${location} + + + The following fleet(s) have arrived at ${location}: + + + Fleets have left orbit at ${location} + + + The following fleet(s) have left orbit at ${location}: + + + Fleets mode change at ${location} + + + The following fleet(s) have changed mode at ${location}: + + + Fleets switched to attack at ${location} + + + Our fleets at ${location} have been forced to attack! + + + our unnamed fleet (power: ${power}) + + + our fleet named ${fleet} (power: ${power}) + + + a friendly, unnamed fleet (power: ${power}) owned by ${owner} + + + a friendly fleet named ${fleet} (power: ${power}) owned by ${owner} + + + a hostile, unnamed fleet (power: ${power}) owned by ${owner} + + + a hostile fleet named ${fleet} (power: ${power}) owned by ${owner} + + + - coming from ${source} + + + an unnamed fleet (power: ${power}) owned by ${owner} + + + a fleet named ${fleet} (power: ${power}) owned by ${owner} + + + : switched to attack + + + : switched to defence + + + + + You currently have ${warnings} warning(s). Please note that, upon reaching 3 warnings, the administration team will consider banning you. + + + Warning - planet name ${oldName} + + + This is an official warning from the Legacy Worlds moderation team. + +One of the planets you own, {{planet:${locationId} ${oldName}}}, had a name that was considered either vulgar, disrespectful or discriminating. + +The planet's name has been changed to ${newName}. + + + Warning - your empire '${oldName}' + + + This is an official warning from the Legacy Worlds moderation team. + +Your empire, ${oldName}, had a name that was considered either vulgar, disrespectful or discriminating. + +It was forcibly renamed to ${newName}. + + + Warning - your alliance '${oldName}' + + + This is an official warning from the Legacy Worlds moderation team. + +Your alliance, ${oldName}, had a name that was considered either vulgar, disrespectful or discriminating. + +It was disbanded. + + + + + Bug report #${id} updated + + + Bug report ${bug} has been updated by administrator ${submitter}. + + + Bug report ${bug} has been updated by the owner of empire ${submitter}. + + + + + + + + + + + + + + + + + + + + + +*** +De : ${from} +ƀ : ${to} +Sujet : ${subject} + +${text} + + + + + * ${subject} + de ${from} + date/heure de rĆ©ception ${time} + + + Messages privĆ©s : + + + Messages d'alliance : + + + Messages internes : + + + Messages des administrateurs : + + + + Technologies civiles + + + Ce ne sont pas uniquement vos esclaves, ce sont vos chercheurs, poĆØtes et ouvriers. Faites travailler d'abord les poĆØtes, puis utilisez ces technologies pour augmenter leur productivitĆ©! PoĆØtes inutiles... + + + + Assembleurs universels + + + Vous savez ce que c'est d'avoir un truc Ć  construire, alors que malheureusement vous ne diposez pas du bon outil. Eh bien, plus de peur : les Assembleurs Universels vont rĆ©soudre tous vos problĆØmes! Construisez tout et n'importe quoi avec ces machines intelligentes, elles sont 1337. + + + RĆ©animation de cadavres + + + FatiguĆ© de ces ouvriers qui passent l'arme Ć  gauche trop tĆ“t? Vous voulez un peu plus de transpiration dans vos ateliers ? Les zombies vont travailler, ne vont pas se plaindre, et encore mieux ils peuvent ĆŖtre nourris avec n'importe quoi - y compris avec vos Ć©nemis! Mais surtout, utilisez les pour augmenter de maniĆØre significative la productivitĆ© de vos usines. + + + GĆ©nĆ©rateurs biologiques + + + Pour chaque tourelle qu'un commandant militaire rĆ©clame, il en est une qu'il dĆ©sire encore plus. Maintenant, vous aussi pouvez avoir de telles tourelles! Elles dĆ©fendront vos planĆØtes avec aisance, pendant que vous vous aventurerez dans la galaxie, la pliant Ć  votre volontĆ©. Disponible chez tous les bons quincaillers. + + + + Technologies militaires + + + Ceux qui ne comprennent pas les dommages que la guerre peut causer n'en comprendront jamais les avantages. - Sun Tzu + + + + Construction orbitale + + + Les vaisseaux construits Ć  la surface doivent subir le stress du vol atmosphĆ©rique avant mĆŖme d'ĆŖtre lancĆ©s Ć  assaut du grand vide interstellaire. Construisez-les dans l'espace et ils seront plus gracieux, plus puissants, et ne nĆ©cessiteront plus de fenĆŖtres. Utilisez vos tout nouveaux croiseurs pour dominer l'univers connu. + + + Consolidation structurelle + + + La puissance de vos croiseurs peut ĆŖtre augmentĆ©e par une conception amĆ©liorĆ©e! Profitez d'un vĆ©hicule Ć  la structure mieux adaptĆ©e Ć  l'espace qui peut mettre des empires Ć  genoux grĆ¢ce Ć  sa vitesse et sa finesse technologique. + + + Docks orbitaux automatisĆ©s + + + La technologie a Ć©voluĆ©. L'arme ultime est maintenant disponible. Revendiquez la puissance Ć©crasante du cuirassĆ© et pulvĆ©risez vos opposants. DĆ©jĆ  rĆŖvĆ© d'un tank de l'espace ? Eh bien, maintenant, vous l'avez. All their base are belong to you. + + + + Fabrique de piĆØces de vaisseaux + + + Une fabrique de piĆØces de vaisseaux est une usine de production de masse pour la crĆ©ation des composants utilisĆ©s dans vos vaisseaux spatiaux. Elles sont essentielles Ć  tout empire spatial ; bien gĆ©rĆ©es, elles produisent de nouveaux vaisseaux rapidement et efficacement. + + + Tourelle dĆ©fensive + + + Explorer sans ĆŖtre sur ses gardes est une statĆ©gie de lunatique. Les tourelles dĆ©fensives sont la derniĆØre ligne de dĆ©fense d'une planĆØte, Ć©normes armes capables de dĆ©truire des vĆ©hicules en orbite depuis le sol. Elles peuvent ĆŖtre placĆ©es n'importe oĆ¹, sur n'importe quel bĆ¢timent ou espace dĆ©gagĆ© de votre domaine, et dĆ©fendront vos planĆØtes contre les attaques. + + + Ligne de production gĆ©nĆ©rique + + + Les usines sont l'Ć©pine dorsale d'une Ć©conomie florissante, fournissant des biens et piĆØces dĆ©tachĆ©es qui peuvent ĆŖtre vendues sur le marchĆ©. Vos Lignes de production gĆ©nĆ©riques flambant neuves vont augmenter votre richesse et conserver votre population dans l'emploi. Des usines bien gĆ©rĆ©es fournissent de nombreux bĆ©nĆ©fices Ć©conomiques Ć  un empire. + + + Centre de rĆ©animation + + + Les humains sont frĆŖles mais peu coĆ»teux et les robots sont endurants mais trĆØs chers. Renouvelez la vie de vos travailleurs et vous pourrez tirer partie d'une ressource de zombies bon marchĆ©, vous permettant d'explorer une troisiĆØme voie pour conserver un empire florissant. + + + Tourelle biologique + + + L'union parfaite de l'homme et de la machine, les tourelles biologiques sont un mĆ©lange du technologique et du biologique pour fournir la dĆ©fense ultime Ć  vos planĆØtes. Plus puissantes et prĆ©cises que les tourelles, au niveau dĆ©fense au sol, elles ne peuvent ĆŖtre surclassĆ©es. Mais gardez votre population Ć  distance, car elles ont tendance Ć  avoir faim de chair humaine! + + + + Chasseur + + + Donnez un pistolet Ć  un adolescent et il deviendra un homme. Donnez un vaisseau Ć  un homme et il dominera des planĆØtes. Un chasseur est un vaisseau lĆ©ger et rapide qui seul reste insignifiant mais en vaste horde peut devenir terrifiant. DĆ©placez les d'un bout Ć  l'autre de la galaxie et vous aurez tout ce que vous dĆ©sirez. + + + Croiseur + + + Un croisseur est un gros vaisseau compact mais puissant. Il dispose d'armes espace-espace et espace-sol, ainsi que d'un bon nombre de porte-gobelets. + + + Croiseur lourd + + + Un croiseur lourd est gros vaisseau plus rapide et plus racĆ© qu'un croiseur. Il est bien plus rapide que son petit frĆØre et embarque toujours assez d'armes pour en avoir pour son argent. Une addition pertinente Ć  la flotte de tout seigneur de guerre. + + + CuirassĆ© + + + Amenez la cuirasse. Le cuirassĆ© est un Ć©norme vaisseau aux performances et Ć  la puissance impressionantes, cher et lent, mais le nec plus ultra de la domination spatiale. + + + + PrĆ©fĆ©rences d'affichage + + + Temps rĆ©el + + + Les durĆ©es seront affichĆ©es en utilisant de "vraies" mesures si cette option est sĆ©lectionnĆ©e. + + + Carte + + + Centre de la carte (X) + + + L'abscisse par dĆ©faut du centre de la carte. + + + Centre de la carte (Y) + + + L'ordonnĆ©e par dĆ©faut du centre de la carte. + + + Taille de la carte + + + La taille par dĆ©faut de la carte. + + + Envoi de courrier Ć©lectronique + + + Messages privĆ©s + + + SĆ©lectionnez le type de notifications par courier Ć©lectronique que vous recevrez lorsque d'autres empires vous envoient des messages privĆ©s. + + + Messages d'alliance + + + SĆ©lectionnez le type de notifications par courier Ć©lectronique que vous recevrez lorsque vous recevez un message d'alliance. + + + Messages internes + + + SĆ©lectionnez le type de notifications par courier Ć©lectronique que vous recevrez lorsque vous recevez un message interne du jeu. + + + Messages des administrateurs + + + SĆ©lectionnez le type de notifications par courier Ć©lectronique que vous recevrez lorsque vous recevez un message des administrateurs du jeu. + + + + Petite (3x3) + + + Moyenne (5x5) + + + Grande (7x7) + + + + Pas de notification + + + Inclure dans le rĆ©capitulatif + + + Notification immĆ©diate + + + + + MinistĆØre de l'Ɖconomie + + + MinistĆØre de la Guerre + + + MinistĆØre de la Paix + + + MinistĆØre de la Recherche + + + L'Ɖquipe de Legacy Worlds + + + Suivi de bugs + + + + + Listes de construction civiles vides + + + Certaines de vos planĆØtes ont fini de construir ou dĆ©truire des bĆ¢timents : + + + + Liste de construction civile sur ${location} + + + La planĆØte ${location} a fini de construire ou dĆ©truire des bĆ¢timents. + + + + + Listes de construction militaires vides + + + Certaines de vos planĆØtes ont fini de construire des vaisseaux : + + + + Liste de construction militaire vide sur ${location} + + + La planĆØte ${location} a fini de construire des vaisseaux. + + + + + Bataille commencĆ©e sur ${location} + + + {{battle:${battleId} La bataille #${battleId}}} a commencĆ© sur ${location}. + + + + Bataille terminĆ©e sur ${location} + + + {{battle:${battleId} La bataille #${battleId}}} s'est terminĆ©e sur ${location}. + + + + + Les habitants de ${location} sont en grĆØve + + + Les habitants de ${location} sont de trĆØs mauvaise humeur et ont commencĆ© Ć  quitter leurs postes... Nous devrions faire quelque chose Ć  ce sujet. + + + + Situation revenue Ć  la normale sur ${location} + + + Les habitants de ${location} sont de retour au travail. + + + + + Perte de la planĆØte ${location} + + + Nous avons perdu le contrĆ“le de ${location}, qui nous a Ć©tĆ© prise par ${taker}. + + + + Abandon de la planĆØte ${location} + + + Nos forces ont terminĆ© l'Ć©vacutation de ${location}; les habitants de ce monde sont livrĆ©s Ć  eux-mĆŖmes. + + + + + ConquĆŖte de la planĆØte${location} + + + Nous avons pris le contrĆ“le de la planĆØte ${location} des mains de l'(absence de) gouvernement local. + + + Nous avons pris le contrĆ“le de la planĆØte ${location} des griffes de ${owner}. + + + + + ${tech} disponible + + + Une nouvelle technologie, ${tech}, a Ć©tĆ© complĆ©tement recherchĆ©e et est prĆŖte Ć  ĆŖtre appliquĆ©e. + + + FauchĆ©!!!!11111 + + + Respectueusement, Ć  quoi vous donc vous avez bien pu penser, Chef?! Nous sommes si pauvres que nous ne pouvons mĆŖme plus payer la maintenance de nos flottes et bĆ¢timents! Certains de vos ministres envisagent mĆŖme de se prostituer! + + + AmĆ©lioration de la situation Ć©conomique + + + C'est bon de voir que nos problĆØmes d'argent sont rĆ©solus, Chef. Bien jouĆ©. Bien sĆ»r, Ƨa aurait Ć©tĆ© mieux si ces problĆØmes n'avaient jamais eu lieu... Chef, qu'est ce que vous faites avec ce pistol- + + + + + Demande d'alliance en attente + + + ${empire} demande Ć  joindre l'alliance. + + + Demande d'alliance acceptĆ©e + + + Notre demande de joindre ${alliance} a Ć©tĆ© acceptĆ©e. + + + Demande d'alliance rejetĆ©e + + + Notre demande de joindre ${alliance} a Ć©tĆ© rejetĆ©e. + + + Changement de direction + + + ${leader} s'est retirĆ© de sa position de dirigeant de l'alliance. + + + ExpulsĆ©! + + + Nous avons Ć©tĆ© expulsĆ©s de ${alliance}. + + + ${empire} expulsĆ© + + + ${empire} a Ć©tĆ© expulsĆ© de l'alliance. + + + DĆ©part de ${empire} + + + ${empire} a quittĆ© alliance. + + + Alliance dissoute! + + + Le dirigeant est parti et l'alliance a Ć©tĆ© dissoute. + + + + + ArrivĆ©e de flottes sur ${location} + + + La(les) flotte(s) suivante(s) est(sont) arrivĆ©e(s) sur ${location}: + + + Des flottes ont quittĆ© l'orbite de ${location} + + + La(les) flotte(s) suivante(s) a(ont) quittĆ© l'orbite de ${location}: + + + Changement de mode de flottes sur ${location} + + + La(les) flotte(s) suivante(s) a(ont) changĆ© de mode sur ${location}: + + + Des flottes sont passĆ©es en attaque sur ${location} + + + Nos flottes sur ${location} ont Ć©tĆ© forcĆ©es d'attaquer! + + + notre flotte sans nom (puissance : ${power}) + + + notre flotte nommĆ©e ${fleet} (puissance : ${power}) + + + une flotte alliĆ©es sans nom (puissance : ${power}) possĆ©dĆ©e par ${owner} + + + une flotte alliĆ©e nommĆ©e ${fleet} (puissance : ${power}) possĆ©dĆ©e par ${owner} + + + une flotte hostile sans nom (puissance : ${power}) possĆ©dĆ©e par ${owner} + + + une flotte hostile nommĆ©e ${fleet} (puissance : ${power}) possĆ©dĆ©e par ${owner} + + + - venant de ${source} + + + une flotte sans nom (puissance : ${power}) possĆ©dĆ©e par ${owner} + + + une flotte nommĆ©e ${fleet} (puissance : ${power}) possĆ©dĆ©e par ${owner} + + + : est passĆ©e en attaque + + + : est passĆ©e en dĆ©fensee + + + + + Vous avez actuellement ${warnings} avertissement(s). Veuillez noter que, lorsque vous atteindrez 3 avertissements, l'Ć©quipe d'administration va envisager votre expulsion. + + + Avertissement - nom de planĆØte ${oldName} + + + Ceci est un avertissement officiel de l'Ć©quipe de modĆ©ration de Legacy Worlds. + +Une des planĆØtes que vous possĆ©dez, {{planet:${locationId} ${oldName}}}, avait un nom qui a Ć©tĆ© considĆ©rĆ© comme vulgaire, irrespectueux ou disciminatoire. + +Le nom de la planĆØte a Ć©tĆ© changĆ© en ${newName}. + + + Avertissement - votre empire '${oldName}' + + + Ceci est un avertissement officiel de l'Ć©quipe de modĆ©ration de Legacy Worlds. + +Votre empire, ${oldName}, avait un nom qui a Ć©tĆ© considĆ©rĆ© comme vulgaire, irrespectueux ou disciminatoire. + +Il a Ć©tĆ© changĆ© de force en ${newName}. + + + Avertissement - votre alliance '${oldName}' + + + Ceci est un avertissement officiel de l'Ć©quipe de modĆ©ration de Legacy Worlds. + +Votre alliance, ${oldName}, avait un nom qui a Ć©tĆ© considĆ©rĆ© comme vulgaire, irrespectueux ou disciminatoire. + +Elle a Ć©tĆ© dissoute. + + + + + Rapport de bug #${id} mis Ć  jour + + + Le rapport de bug ${bug} a Ć©tĆ© mis Ć  jour par l'administrateur ${submitter}. + + + Le rapport de bug ${bug} a Ć©tĆ© mis Ć  jour par le propriĆ©taire de l'empire ${submitter}. + + + + + diff --git a/legacyworlds-server/legacyworlds-server-main/data/i18n-text.xsd b/legacyworlds-server/legacyworlds-server-main/data/i18n-text.xsd new file mode 100644 index 0000000..8f8932d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/i18n-text.xsd @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/inactivityQuitMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/inactivityQuitMail-en.txt new file mode 100644 index 0000000..d628f44 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/inactivityQuitMail-en.txt @@ -0,0 +1,11 @@ +Legacy Worlds (B6M1) - Inactive account closed +Hello, + +This email is being sent to inform you that your account on Legacy Worlds has been disabled. It had been inactive for 28 days. + +You can reactivate your account by logging in to the Legacy Worlds web site using your e-mail address and password. + +We hope to see you again very soon on Legacy Worlds. + +Best regards, +The Legacy Worlds staff diff --git a/legacyworlds-server/legacyworlds-server-main/data/inactivityQuitMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/inactivityQuitMail-fr.txt new file mode 100644 index 0000000..7441c8b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/inactivityQuitMail-fr.txt @@ -0,0 +1,11 @@ +Legacy Worlds (B6M1) - Fermeture de compte inactif +Bonjour, + +Ce message vous a Ć©tĆ© envoyĆ© pour vous prĆ©venir que votre compte sur Legacy Worlds a Ć©tĆ© dĆ©sactivĆ©. Il a Ć©tĆ© inactif pendant 28 jours. + +Vous pourrez rĆ©activer votre compteen vous connectant sur le site Web de Legacy Worlds en utilisant votre adresse e-mail et votre mot de passe. + +Nous espĆ©rons vous revoir un jour sur Legacy Worlds. + +Cordialement, +L'Ć©quipe de Legacy Worlds diff --git a/legacyworlds-server/legacyworlds-server-main/data/inactivityWarningMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/inactivityWarningMail-en.txt new file mode 100644 index 0000000..add97f3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/inactivityWarningMail-en.txt @@ -0,0 +1,9 @@ +Legacy Worlds (B6M1) - Inactivity +Hello, + +This email is being sent to warn you that your account on Legacy Worlds has been inactive for the past three weeks. Unless you connect in the coming week, it will be closed and your empire will be lost. + +We hope to see you again on Legacy Worlds. + +Best regards, +The Legacy Worlds staff diff --git a/legacyworlds-server/legacyworlds-server-main/data/inactivityWarningMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/inactivityWarningMail-fr.txt new file mode 100644 index 0000000..d2e8f27 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/inactivityWarningMail-fr.txt @@ -0,0 +1,9 @@ +Legacy Worlds (B6M1) - InactivitĆ© +Bonjour, + +Ce message vous a Ć©tĆ© envoyĆ© pour vous prĆ©venir que votre compte sur Legacy Worlds a Ć©tĆ© inactif pendant les trois derniĆØres semaines. ƀ moins que vous vous connectiez durant la semaine procahine, il sera fermĆ© et votre empire sera perdu. + +Nous espĆ©rons vous revoir un jour sur Legacy Worlds. + +Cordialement, +L'Ć©quipe de Legacy Worlds diff --git a/legacyworlds-server/legacyworlds-server-main/data/messageMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/messageMail-en.txt new file mode 100644 index 0000000..299b5c3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/messageMail-en.txt @@ -0,0 +1,10 @@ +Legacy Worlds (B6M1) - New messages +Hello ${empire}, + +You have just received new messages in Legacy Worlds. + +${messages} +*** + +You will not receive message notifications for the next hour. +If you want to stop receiving these e-mail messages completely, please log on to Legacy Worlds and modify your e-mail settings from the "Account" page. \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/messageMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/messageMail-fr.txt new file mode 100644 index 0000000..d31af22 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/messageMail-fr.txt @@ -0,0 +1,10 @@ +Legacy Worlds (B6M1) - Nouveaux messages +Bonjour ${empire}, + +Vous venez de recevoir de nouveaux messages sur Legacy Worlds! + +${messages} +*** + +Vous ne recevrez pas de nouvelle notification de message pendant une heure. +Si vous souhaitez ne plus recevoir ces courriers Ć©lectroniques, veuillez vous connecter Ć  Legacy Worlds et modifier vos prĆ©fĆ©rences de notification depuis la page "Compte". \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/passwordRecoveryMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/passwordRecoveryMail-en.txt new file mode 100644 index 0000000..d7cf79b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/passwordRecoveryMail-en.txt @@ -0,0 +1,19 @@ +Legacy Worlds (B6M1) password recovery +Hello, + +You are receiving this message because an user of Legacy Worlds (you, presumably) requested to recover his password. +In order to define a new password for your account, please go to the password recovery page and fill in the following information: +- your e-mail address +- the recovery code provided below +- the new password and its confirmation + +Please note that this recovery code is NOT your new password, and you will only need to use it once. +Moreover this code will be valid during a one hour interval. Don't wait too long! + +Your address is: ${address} +Your recovery code is: ${token} + +If you are having problems performing this operation, please contact a member of our support staff at staff@legacyworlds.com + +Thanks! +The Legacy Worlds staff \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/passwordRecoveryMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/passwordRecoveryMail-fr.txt new file mode 100644 index 0000000..94bc15e --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/passwordRecoveryMail-fr.txt @@ -0,0 +1,19 @@ +Legacy Worlds (B6M1) - RĆ©cupĆ©ration de mot de passe +Bonjour, + +Vous avez reƧu ce message car un utilisateur de Legacy Worlds (vous, probablement) a demandĆ© Ć  rĆ©cupĆ©rer son mot de passe oubliĆ©. +Afin de dĆ©finir un nouveau mot de passe pour votre compte, veuillez vous rendre sur le page de rĆ©cupĆ©ration de mot de passe et saisir : +- votre adresse e-mail +- le code de rĆ©cupĆ©ration fourni ci-dessous +- le nouveau mot de passe et sa confirmation + +Attention, ce code de rĆ©cupĆ©ration n'est PAS votre nouveau mot de passe, vous n'en aurez besoin qu'une seule fois. +De plus, ce code sera valide pendant un intervalle de temps d'une heure. Ne tardez pas trop! + +Votre adresse : ${address} +Votre code de rĆ©cupĆ©ration : ${token} + +Si vous Ć©prouvez des difficultĆ©s pour mener Ć  bien cette opĆ©ration, veuillez contacter notre Ć©quipe par courrier Ć©lectronique: staff@legacyworlds.com + +Cordialement, +L'Ć©quipe de Legacy Worlds \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/quitMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/quitMail-en.txt new file mode 100644 index 0000000..8f379e7 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/quitMail-en.txt @@ -0,0 +1,11 @@ +Legacy Worlds (B6M1) - Account closed +Hello, + +This email is being sent to confirm that your account has been closed as you requested. + +For the next six months, you will be able to reactivate your account by logging in to the Legacy Worlds web site using your address and password. Past this delay, your account will be completely deleted. + +We hope to see you again sometime on Legacy Worlds. + +Best regards, +The Legacy Worlds staff diff --git a/legacyworlds-server/legacyworlds-server-main/data/quitMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/quitMail-fr.txt new file mode 100644 index 0000000..2788e38 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/quitMail-fr.txt @@ -0,0 +1,11 @@ +Legacy Worlds (B6M1) - Compte dĆ©sactivĆ© +Bonjour, + +Cet e-mail vous est envoyĆ© pour confirmer que votre compte a Ć©tĆ© fermĆ© Ć  votre demande. + +Pendant les six mois Ć  venir, vous pourrez le rĆ©activer en vous connectant sur le site Web de Legacy Worlds en utilisant votre adresse e-mail et votre mot de passe. passĆ© ce dĆ©lai, votre compte sera complĆØtement effacĆ©. + +Nous espĆ©rons vous revoir un jour sur Legacy Worlds. + +Cordialement, +L'Ć©quipe de Legacy Worlds \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/reactivationMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/reactivationMail-en.txt new file mode 100644 index 0000000..c0176e0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/reactivationMail-en.txt @@ -0,0 +1,17 @@ +Legacy Worlds (B6M1) - Account reactivation +Hello, + +Thank you for revisiting at Legacy Worlds! +Please note that you reactivated your account for "Beta 6 Milestone 1", a highly experimental, in-progress rewrite of the game. As this game does not include forums at this stage, you might want to register to Legacy Worlds Beta 5 to keep up with the game's news. + +Before we reactivate your account, there's just one more step to complete your request. +You have to connect to the site using your e-mail address and password, then validate your account reactivation using the confirmation code below. +Please note that this confirmation code is NOT your password, and you will only need to use it once. + +Your registration address is: ${address} +Your confirmation code is: ${token} + +If you are having problems reactivating your account, please contact a member of our support staff at staff@legacyworlds.com + +Thanks! +The Legacy Worlds staff \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/reactivationMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/reactivationMail-fr.txt new file mode 100644 index 0000000..3a97e3c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/reactivationMail-fr.txt @@ -0,0 +1,17 @@ +Legacy Worlds (B6M1) - RĆ©activation de votre compte +Bonjour, + +Merci de revenir sur Legacy Worlds! +Veuillez remarquer que vous venez de rĆ©activer un compte sur le jeu "Beta 6 Milestone 1", une rĆ©criture en cours et par consĆ©quent hautement expĆ©rimentale du jeu. Comme cette version ne dispose pas de forums Ć  l'heure actuelle, nous vous suggĆ©rons de vous enregistrer Ć©galement Ć  Legacy Worlds Beta 5 afin de vous tenir au courant des derniĆØres nouvelles. + +Avant que nous rĆ©activions votre compte, il vous reste une derniĆØre Ć©tape Ć  accomplir. +Vous allez devoir vous connecter au site en utilisant votre adresse Ć©lectronique et votre mot de passe, puis valider la rĆ©activation de votre compte en saisissant le code de confirmation ci-dessous. +Attention, ce code n'est PAS votre mot de passe, vous n'en aurez besoin qu'une seule fois. + +Votre adresse d'enregistrement est: ${address} +Votre code de confirmation code est: ${token} + +Si vous Ć©prouvez des difficultĆ©s lors de cette Ć©tape, veuillez contacter notre Ć©quipe par courier Ć©lectronique: staff@legacyworlds.com + +Cordialement, +L'Ć©quipe de Legacy Worlds \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/recapMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/recapMail-en.txt new file mode 100644 index 0000000..c72810f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/recapMail-en.txt @@ -0,0 +1,8 @@ +Legacy Worlds (B6M1) - Today's messages +Hello ${empire}, + +Here is a reminder of the messages you received today. + +${messages} + +If you want to stop receiving these e-mail messages completely, please log on to Legacy Worlds and modify your e-mail settings from the "Account" page. \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/recapMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/recapMail-fr.txt new file mode 100644 index 0000000..641f2d7 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/recapMail-fr.txt @@ -0,0 +1,8 @@ +Legacy Worlds (B6M1) - Messages du jour +Bonjour ${empire}, + +Voici un rĆ©capitulatif des messages que vous avez reƧu aujourd'hui. + +${messages} + +Si vous souhaitez ne plus recevoir ces courriers Ć©lectroniques, veuillez vous connecter Ć  Legacy Worlds et modifier vos prĆ©fĆ©rences de notification depuis la page "Compte". \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/registrationMail-en.txt b/legacyworlds-server/legacyworlds-server-main/data/registrationMail-en.txt new file mode 100644 index 0000000..e91d215 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/registrationMail-en.txt @@ -0,0 +1,17 @@ +Legacy Worlds (B6M1) - Your account +Hello, + +Thank you for registering at Legacy Worlds! +Please note that you registered to "Beta 6 Milestone 1", a highly experimental, in-progress rewrite of the game. As this game does not include forums at this stage, you might want to register to Legacy Worlds Beta 5 to keep up with the game's news. + +Before we activate your account, there's just one more step to complete your registration. +You have to connect to the site using the e-mail address and password you chose, then validate your account using the confirmation code below. +Please note that this confirmation code is NOT your password, and you will only need to use it once. + +Your registration address is: ${address} +Your confirmation code is: ${validationKey} + +If you are having problems signing up, please contact a member of our support staff at staff@legacyworlds.com + +Thanks! +The Legacy Worlds staff \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/registrationMail-fr.txt b/legacyworlds-server/legacyworlds-server-main/data/registrationMail-fr.txt new file mode 100644 index 0000000..a6bc7bf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/registrationMail-fr.txt @@ -0,0 +1,17 @@ +Legacy Worlds (B6M1) - Votre compte +Bonjour, + +Merci de vous ĆŖtre enregistrĆ©(e) sur Legacy Worlds! +Veuillez remarquer que vous venez de crĆ©er un compte sur le jeu "Beta 6 Milestone 1", une rĆ©criture en cours et par consĆ©quent hautement expĆ©rimentale du jeu. Comme cette version ne dispose pas de forums Ć  l'heure actuelle, nous vous suggĆ©rons de vous enregistrer Ć©galement Ć  Legacy Worlds Beta 5 afin de vous tenir au courant des derniĆØres nouvelles. + +Avant que nous activions votre compte, il vous reste une derniĆØre Ć©tape Ć  accomplir. +Vous allez devoir vous connecter au site en utilisant l'adresse Ć©lectronique et le mot de passe que vous avez choisi, puis valider votre compte en saisissant le code de confirmation ci-dessous. +Attention, ce code n'est PAS votre mot de passe, vous n'en aurez besoin qu'une seule fois. + +Votre adresse d'enregistrement est: ${address} +Votre code de confirmation code est: ${validationKey} + +Si vous Ć©prouvez des difficultĆ©s lors de cette Ć©tape, veuillez contacter notre Ć©quipe par courier Ć©lectronique: staff@legacyworlds.com + +Cordialement, +L'Ć©quipe de Legacy Worlds \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/techs-test.xml b/legacyworlds-server/legacyworlds-server-main/data/techs-test.xml new file mode 100644 index 0000000..f2b8f44 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/techs-test.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/techs.xml b/legacyworlds-server/legacyworlds-server-main/data/techs.xml new file mode 100644 index 0000000..aef6fc6 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/techs.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/data/techs.xsd b/legacyworlds-server/legacyworlds-server-main/data/techs.xsd new file mode 100644 index 0000000..84698c3 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/data/techs.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/hibernate.xml b/legacyworlds-server/legacyworlds-server-main/hibernate.xml new file mode 100644 index 0000000..03001ba --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/hibernate.xml @@ -0,0 +1,25 @@ + + + + + + + + + org.hibernate.dialect.HSQLDialect + 0 + true + true + + + + + diff --git a/legacyworlds-server/legacyworlds-server-main/pom.xml b/legacyworlds-server/legacyworlds-server-main/pom.xml new file mode 100644 index 0000000..6774468 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/pom.xml @@ -0,0 +1,127 @@ + + 4.0.0 + + legacyworlds-server + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-main + 5.99.1 + Legacy Worlds server + Server main classes and JAR builder. + + + + legacyworlds-server-beans-accounts + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-bt + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-eventlog + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-i18n + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-mailer + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-naming + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-simple + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-system + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-user + com.deepclone.lw + ${project.version} + + + + com.thoughtworks.xstream + xstream + ${com.thoughtworks.xstream.version} + jar + + + + postgresql + postgresql + 8.4-701.jdbc4 + jar + runtime + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.2 + + + default-jar + package + + jar + + + + + com.deepclone.lw.Main + true + lib + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/lib + false + false + true + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/Main.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/Main.java new file mode 100644 index 0000000..3132a03 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/Main.java @@ -0,0 +1,149 @@ +package com.deepclone.lw; + + +import java.util.Arrays; + +import com.deepclone.lw.cli.CLITool; +import com.deepclone.lw.cli.ToolBase; +import com.deepclone.lw.srv.Server; + + + +public class Main + implements Runnable +{ + private String dataSource = "data-source.xml"; + private int port = 9137; + private int servPort = 9138; + private String tool = null; + private String toolOptions[] = { }; + private ToolBase toolInstance; + + + public Main( String[] args ) + { + this.parseArguments( args ); + + if ( this.tool != null ) { + this.toolInstance = CLITool.create( this.tool ); + } else { + this.toolInstance = new Server( ); + } + + if ( this.toolInstance == null ) { + System.err.println( "tool " + this.tool + " not found" ); + System.exit( -1 ); + } + + this.toolInstance.setMainSettings( this.dataSource , this.port , this.servPort ); + if ( !this.toolInstance.setOptions( this.toolOptions ) ) { + System.err.println( "invalid tool options (" + Arrays.asList( this.toolOptions ) + ")" ); + System.exit( -1 ); + } + } + + + @Override + public void run( ) + { + this.toolInstance.run( ); + System.gc( ); + System.exit( 0 ); + } + + + private void parseArguments( String[] args ) + { + int state = 0; + for ( int i = 0 ; i < args.length ; i++ ) { + switch ( state ) { + case 0: + state = this.parseNextOption( args[ i ] ); + break; + case 1: + this.dataSource = args[ i ]; + state = 0; + break; + case 2: + this.port = this.getPort( args[ i ] ); + state = 0; + break; + case 3: + this.servPort = this.getPort( args[ i ] ); + state = 0; + break; + case 4: + this.tool = args[ i ]; + state = 300; + break; + case 300: + if ( args[ i ].startsWith( "--" ) ) { + i--; + } else if ( !args[ i ].equals( "" ) ) { + this.toolOptions = args[ i ].split( "\\s+" ); + } + state = 0; + break; + } + } + + if ( state % 100 != 0 || this.port == this.servPort ) { + this.printCommandLine( ); + } + } + + + private int parseNextOption( String arg ) + { + if ( "--data-source".equals( arg ) ) { + return 1; + } else if ( "--server-port".equals( arg ) ) { + return 2; + } else if ( "--service-port".equals( arg ) ) { + return 3; + } else if ( "--run-tool".equals( arg ) ) { + return 4; + } + this.printCommandLine( ); + return -1; + } + + + private int getPort( String arg ) + { + int port; + try { + port = Integer.parseInt( arg ); + } catch ( NumberFormatException e ) { + port = 0; + } + if ( port < 1 || port > 65535 ) { + this.printCommandLine( ); + return -1; + } + return port; + } + + + private void printCommandLine( ) + { + System.err.println( "Legacy Worlds beta 6 - Game server and command line tools" ); + System.err.println( ); + System.err.println( " Command line options:" ); + System.err.println( " --data-source Data source configuration file (default: " + + this.dataSource + ")" ); + System.err.println( " --run-tool Command line tool to run (default: none)" ); + System.err.println( " --server-port RMI registry port number (default: " + this.port + ")" ); + System.err.println( " --service-port RMI service port number (default: " + this.servPort + ")" ); + System.err.println( ); + + System.exit( -1 ); + } + + + public static void main( String[] args ) + { + new Main( args ).run( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CLITool.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CLITool.java new file mode 100644 index 0000000..d209760 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CLITool.java @@ -0,0 +1,106 @@ +package com.deepclone.lw.cli; + + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Map; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.remoting.rmi.RmiProxyFactoryBean; + + + +public abstract class CLITool + extends ToolBase +{ + + private String makeRmiUrl( String service ) + { + return "rmi://localhost:" + this.getRmiPort( ) + "/" + service; + } + + + private void addRMIClient( GenericApplicationContext context , String service , String iface ) + { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition( RmiProxyFactoryBean.class ); + builder.setScope( BeanDefinition.SCOPE_PROTOTYPE ); + builder.addPropertyValue( "serviceInterface" , iface ); + builder.addPropertyValue( "serviceUrl" , this.makeRmiUrl( service ) ); + context.registerBeanDefinition( service , builder.getBeanDefinition( ) ); + } + + + protected ApplicationContext createClientContext( String... configurationFiles ) + { + return this.createClientContext( null , configurationFiles ); + } + + + protected ApplicationContext createClientContext( Map< String , String > rmiServices ) + { + return this.createClientContext( rmiServices , (String[]) null ); + } + + + protected ApplicationContext createClientContext( Map< String , String > rmiServices , String... configurationFiles ) + { + if ( rmiServices == null ) { + return new ClassPathXmlApplicationContext( configurationFiles , true ); + } + + GenericApplicationContext context = new GenericApplicationContext( ); + for ( Map.Entry< String , String > rmiService : rmiServices.entrySet( ) ) { + this.addRMIClient( context , rmiService.getKey( ) , rmiService.getValue( ) ); + } + context.refresh( ); + if ( configurationFiles == null ) { + return context; + } + return new ClassPathXmlApplicationContext( configurationFiles , true , context ); + } + + + public static ToolBase create( String tool ) + { + String cName = "com.deepclone.lw.cli." + tool; + Class< ? > toolClass; + Object o; + + try { + toolClass = Class.forName( cName ); + } catch ( ClassNotFoundException e ) { + return null; + } + + try { + o = toolClass.newInstance( ); + } catch ( Exception e ) { + return null; + } + + if ( ! ( o instanceof CLITool ) ) { + return null; + } + + return (ToolBase) o; + } + + + protected static String getLine( ) + { + BufferedReader stdin = new BufferedReader( new InputStreamReader( System.in ) ); + do { + try { + return stdin.readLine( ); + } catch ( IOException e ) { + e.printStackTrace( ); + } + } while ( true ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CreateSuperuser.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CreateSuperuser.java new file mode 100644 index 0000000..4c92d2b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CreateSuperuser.java @@ -0,0 +1,132 @@ +package com.deepclone.lw.cli; + + +import java.sql.Types; +import java.util.Map; + +import javax.sql.DataSource; + +import org.apache.log4j.Logger; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.utils.StoredProc; + + + +public class CreateSuperuser + extends CLITool +{ + private final Logger logger = Logger.getLogger( CreateSuperuser.class ); + + private String address; + private String appearAs; + private TransactionTemplate tTemplate; + private StoredProc fCreateAdmin; + + + private ClassPathXmlApplicationContext getContext( ) + { + // Load data source and Hibernate properties + String[] dataConfig = { + this.getDataSource( ) , + }; + FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( dataConfig ); + ctx.refresh( ); + + // Load transaction manager bean + String[] cfg = { + "configuration/transaction-bean.xml" + }; + return new ClassPathXmlApplicationContext( cfg , true , ctx ); + } + + + private void getBeans( ApplicationContext ctx ) + { + DataSource dSource = ctx.getBean( DataSource.class ); + PlatformTransactionManager tManager = ctx.getBean( PlatformTransactionManager.class ); + + this.tTemplate = new TransactionTemplate( tManager ); + + this.fCreateAdmin = new StoredProc( dSource , "admin" , "create_admin" ); + this.fCreateAdmin.addParameter( "address" , Types.VARCHAR ); + this.fCreateAdmin.addParameter( "appear_as" , Types.VARCHAR ); + this.fCreateAdmin.addParameter( "privileges" , Types.INTEGER ); + this.fCreateAdmin.addOutput( "err_code" , Types.INTEGER ); + this.fCreateAdmin.addOutput( "admin_id" , Types.INTEGER ); + } + + + @Override + public void run( ) + { + AbstractApplicationContext ctx = this.getContext( ); + this.getBeans( ctx ); + this.createAdmin( ); + } + + + private void createAdmin( ) + { + int id; + try { + id = this.tTemplate.execute( new TransactionCallback< Integer >( ) { + @Override + public Integer doInTransaction( TransactionStatus status ) + { + return doCreateAdmin( ); + } + } ); + } catch ( RuntimeException e ) { + this.logger.error( "administrator creation failed: " + e.getMessage( ) ); + return; + } + this.logger.info( "Administrator created with identifier #" + id ); + } + + + private int doCreateAdmin( ) + { + Map< String , Object > result; + result = this.fCreateAdmin.execute( this.address , this.appearAs , Privileges.SUPER.getBits( ) ); + + int errCode = (Integer) result.get( "err_code" ); + switch ( errCode ) { + case 0: + break; + case 1: + throw new RuntimeException( "unknown e-mail address " + this.address ); + case 2: + throw new RuntimeException( "user with e-mail address " + this.address + " has an invalid status" ); + case 3: + throw new RuntimeException( "administrator name " + this.appearAs + " is already in use" ); + case 4: + throw new RuntimeException( "user with e-mail address " + this.address + " is already an administrator" ); + default: + throw new RuntimeException( "unknown error code " + errCode ); + } + + return (Integer) result.get( "admin_id" ); + } + + + @Override + public boolean setOptions( String... options ) + { + if ( options.length == 2 ) { + this.address = options[ 0 ]; + this.appearAs = options[ 1 ]; + return true; + } + return false; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CreateUser.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CreateUser.java new file mode 100644 index 0000000..77bc8f5 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/CreateUser.java @@ -0,0 +1,168 @@ +package com.deepclone.lw.cli; + + +import java.sql.Types; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.utils.EmailAddress; +import com.deepclone.lw.utils.Password; +import com.deepclone.lw.utils.StoredProc; + + + +public class CreateUser + extends CLITool +{ + + private boolean query; + private String mailAddress; + private String password; + private String language; + + private String pSha1; + private String pMd5; + + private TransactionTemplate tTemplate; + private StoredProc fCreateUser; + + + private ClassPathXmlApplicationContext getContext( ) + { + // Load data source and Hibernate properties + String[] dataConfig = { + this.getDataSource( ) , + }; + FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( dataConfig ); + ctx.refresh( ); + + // Load transaction manager bean + String[] cfg = { + "configuration/transaction-bean.xml" + }; + return new ClassPathXmlApplicationContext( cfg , true , ctx ); + } + + + private void getBeans( ApplicationContext ctx ) + { + DataSource dSource = ctx.getBean( DataSource.class ); + PlatformTransactionManager tManager = ctx.getBean( PlatformTransactionManager.class ); + + this.tTemplate = new TransactionTemplate( tManager ); + + this.fCreateUser = new StoredProc( dSource , "users" , "create_inactive_account" ); + this.fCreateUser.addParameter( "address" , Types.VARCHAR ); + this.fCreateUser.addParameter( "lang_id" , Types.VARCHAR ); + this.fCreateUser.addParameter( "pass_md5" , Types.VARCHAR ); + this.fCreateUser.addParameter( "pass_sha1" , Types.VARCHAR ); + this.fCreateUser.addOutput( "err_code" , Types.INTEGER ); + this.fCreateUser.addOutput( "a_id" , Types.INTEGER ); + } + + + private void queryUser( ) + { + System.out.println( "User creation - E-mail address: " ); + this.mailAddress = CLITool.getLine( ); + System.out.println( "User creation - Password: " ); + this.password = CLITool.getLine( ); + System.out.println( "User creation - Language ID: " ); + this.language = CLITool.getLine( ); + } + + + private boolean validate( ) + { + EmailAddress addr = new EmailAddress( this.mailAddress ); + if ( !addr.isValid( ) ) { + System.err.println( "Invalid mail address" ); + return false; + } + this.mailAddress = addr.getAddress( ); + + Password pwd = new Password( this.password ); + if ( pwd.getStrength( ) < 10 ) { + System.err.println( "Weak password" ); + return false; + } + this.pSha1 = pwd.getSha1( ); + this.pMd5 = pwd.getMd5( ); + + return true; + } + + + private Map< String , Object > createAccount( ) + { + return this.tTemplate.execute( new TransactionCallback< Map< String , Object > >( ) { + @Override + public Map< String , Object > doInTransaction( TransactionStatus status ) + { + return fCreateUser.execute( mailAddress , language , pMd5 , pSha1 ); + } + } ); + } + + + @Override + public void run( ) + { + if ( this.query ) { + this.queryUser( ); + } + if ( !this.validate( ) ) { + return; + } + + AbstractApplicationContext ctx = this.getContext( ); + this.getBeans( ctx ); + + Map< String , Object > m = this.createAccount( ); + int errCode = (Integer) m.get( "err_code" ); + switch ( errCode ) { + case 0: + System.out.println( "Account #" + (Integer) m.get( "a_id" ) + " created." ); + break; + case -1: + System.err.println( "Address in use" ); + break; + case -2: + System.err.println( "Invalid language" ); + break; + } + + ToolBase.destroyContext( ctx ); + } + + + @Override + public boolean setOptions( String... options ) + { + if ( options.length == 0 ) { + this.query = true; + return true; + } + + if ( options.length == 3 ) { + this.query = false; + this.mailAddress = options[ 0 ]; + this.password = options[ 1 ]; + this.language = options[ 2 ]; + return true; + } + + return false; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ExportDB.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ExportDB.java new file mode 100644 index 0000000..488d63a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ExportDB.java @@ -0,0 +1,176 @@ +package com.deepclone.lw.cli; + + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.cli.dbexport.BugEventMapper; +import com.deepclone.lw.cli.dbexport.BugGroup; +import com.deepclone.lw.cli.dbexport.LegacyWorldsDB; +import com.deepclone.lw.cli.dbexport.UserMapper; +import com.thoughtworks.xstream.XStream; + + + +public class ExportDB + extends CLITool +{ + + private final String sGetUsers = "SELECT ul.* , al.administrator_id , al.name AS administrator_name , al.privileges , al.pass_sha1 AS administrator_sha1 , al.pass_md5 AS administrator_md5 " + + "FROM admin.users_list ul LEFT OUTER JOIN admin.admins_view al on al.account_id = ul.id " + + "WHERE ul.status IN ('ACTIVE' , 'VACATION' , 'START_VACATION' ) OR ( ul.game_credits > 0 AND ul.status <> 'BANNED' ) OR ( al IS NOT NULL AND al.active )"; + + private final String sListGroupEvents = "SELECT group_id , event_id FROM bugs.br_first_report INNER JOIN bugs.br_status USING( group_id ) INNER JOIN bugs.events USING( group_id ) " + + "WHERE status <> 'NOT_A_BUG' ORDER BY group_id"; + + private final String sGetBugEvents = "SELECT be.* , asd.account_status FROM bugs.br_first_report INNER JOIN bugs.br_status s USING( group_id ) INNER JOIN bugs.br_events be USING( bug_report_id ) " + + "LEFT OUTER JOIN bugs.account_status_data asd USING (event_id) WHERE s.status <> 'NOT_A_BUG' ORDER BY event_id"; + + private static class LongPair + { + public long id1; + public long id2; + } + + private static class LongPairMapper + implements RowMapper< LongPair > + { + + @Override + public LongPair mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + LongPair lp = new LongPair( ); + lp.id1 = rs.getLong( 1 ); + lp.id2 = rs.getLong( 2 ); + return lp; + } + + } + + private File file; + private TransactionTemplate tTemplate; + private SimpleJdbcTemplate dTemplate; + + + private ClassPathXmlApplicationContext createContext( ) + { + // Load data source + String[] dataConfig = { + this.getDataSource( ) , + }; + FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( dataConfig ); + ctx.refresh( ); + + // Load transaction manager bean + String[] cfg = { + "configuration/transaction-bean.xml" + }; + return new ClassPathXmlApplicationContext( cfg , true , ctx ); + } + + + private void prepareDataAccess( AbstractApplicationContext ctx ) + { + DataSource dSource = ctx.getBean( DataSource.class ); + PlatformTransactionManager tManager = ctx.getBean( PlatformTransactionManager.class ); + + this.tTemplate = new TransactionTemplate( tManager ); + this.dTemplate = new SimpleJdbcTemplate( dSource ); + } + + + @Override + public void run( ) + { + AbstractApplicationContext ctx = this.createContext( ); + this.prepareDataAccess( ctx ); + + LegacyWorldsDB db = this.tTemplate.execute( new TransactionCallback< LegacyWorldsDB >( ) { + @Override + public LegacyWorldsDB doInTransaction( TransactionStatus status ) + { + return readDB( ); + } + } ); + + this.writeFile( db ); + } + + + private LegacyWorldsDB readDB( ) + { + LegacyWorldsDB db = new LegacyWorldsDB( ); + db.users = this.dTemplate.query( sGetUsers , new UserMapper( ) ); + db.bugReports.groups = this.readBugGroups( ); + db.bugReports.events = this.dTemplate.query( sGetBugEvents , new BugEventMapper( ) ); + return db; + } + + + private List< BugGroup > readBugGroups( ) + { + List< BugGroup > groups = new ArrayList< BugGroup >( ); + Long prevGroupId = null; + BugGroup current = null; + + for ( LongPair lp : this.dTemplate.query( sListGroupEvents , new LongPairMapper( ) ) ) { + if ( prevGroupId == null || lp.id1 != prevGroupId ) { + prevGroupId = lp.id1; + current = new BugGroup( ); + groups.add( current ); + } + current.events.add( lp.id2 ); + } + + return groups; + } + + + private void writeFile( LegacyWorldsDB db ) + { + XStream xStream = new XStream( ); + xStream.autodetectAnnotations( true ); + + FileWriter file; + try { + file = new FileWriter( this.file ); + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + xStream.toXML( db , file ); + try { + file.close( ); + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + } + + + @Override + public boolean setOptions( String... options ) + { + if ( options.length != 1 ) { + return false; + } + this.file = new File( options[ 0 ] ); + return true; + } +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportBuildables.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportBuildables.java new file mode 100644 index 0000000..ab27ed1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportBuildables.java @@ -0,0 +1,316 @@ +package com.deepclone.lw.cli; + + +import java.io.*; +import java.sql.Types; +import java.util.List; + +import javax.sql.DataSource; + +import org.apache.log4j.Logger; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.sqld.game.BuildingOutputType; +import com.deepclone.lw.utils.StoredProc; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + + + +public class ImportBuildables + extends CLITool +{ + private final Logger logger = Logger.getLogger( ImportBuildables.class ); + + @SuppressWarnings( "serial" ) + @XStreamAlias( "buildables" ) + public static class BuildablesData + implements Serializable + { + @XStreamImplicit + public List< BuildableData > buildables; + } + + @SuppressWarnings( "serial" ) + public static abstract class BuildableData + implements Serializable + { + @XStreamAsAttribute + public String name; + + @XStreamAsAttribute + public String description; + + public CostData cost; + + public TechData tech; + } + + @SuppressWarnings( "serial" ) + @XStreamAlias( "cost" ) + public static class CostData + implements Serializable + { + @XStreamAsAttribute + public int build; + + @XStreamAsAttribute + public int upkeep; + + @XStreamAsAttribute + public int work; + } + + @SuppressWarnings( "serial" ) + @XStreamAlias( "tech" ) + public static class TechData + implements Serializable + { + @XStreamAsAttribute + public String name; + + @XStreamAsAttribute + public int level; + } + + @SuppressWarnings( "serial" ) + @XStreamAlias( "building" ) + public static class BuildingData + extends BuildableData + { + @XStreamAsAttribute + public BuildingOutputType type; + + @XStreamAsAttribute + public int output; + + @XStreamAsAttribute + public int workers; + } + + @SuppressWarnings( "serial" ) + @XStreamAlias( "ship" ) + public static class ShipData + extends BuildableData + { + @XStreamAsAttribute + public int time; + + @XStreamAsAttribute + public int power; + } + + private File file; + private TransactionTemplate tTemplate; + private StoredProc uocBuildingNoDep; + private StoredProc uocBuildingDep; + private StoredProc uocShipNoDep; + private StoredProc uocShipDep; + + + private XStream initXStream( ) + { + XStream xstream = new XStream( ); + xstream.processAnnotations( BuildablesData.class ); + xstream.processAnnotations( BuildingData.class ); + xstream.processAnnotations( ShipData.class ); + return xstream; + } + + + private BuildablesData loadData( ) + { + FileInputStream fis; + try { + fis = new FileInputStream( this.file ); + } catch ( FileNotFoundException e ) { + return null; + } + + try { + XStream xstream = this.initXStream( ); + return (BuildablesData) xstream.fromXML( fis ); + } catch ( Exception e ) { + e.printStackTrace( ); + return null; + } finally { + try { + fis.close( ); + } catch ( IOException e ) { + // EMPTY + } + } + } + + + private ClassPathXmlApplicationContext createContext( ) + { + // Load data source + String[] dataConfig = { + this.getDataSource( ) + }; + FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( dataConfig ); + ctx.refresh( ); + + // Load Hibernate bean + String[] cfg = { + "configuration/context-configuration.xml" , "configuration/transaction-bean.xml" + }; + return new ClassPathXmlApplicationContext( cfg , true , ctx ); + } + + + private void createTemplates( ApplicationContext ctx ) + { + PlatformTransactionManager tManager = ctx.getBean( PlatformTransactionManager.class ); + this.tTemplate = new TransactionTemplate( tManager ); + + DataSource dataSource = ctx.getBean( DataSource.class ); + + this.uocBuildingNoDep = new StoredProc( dataSource , "tech" , "uoc_building" ); + this.uocBuildingNoDep.addParameter( "name" , Types.VARCHAR ); + this.uocBuildingNoDep.addParameter( "description" , Types.VARCHAR ); + this.uocBuildingNoDep.addParameter( "cost" , Types.INTEGER ); + this.uocBuildingNoDep.addParameter( "work" , Types.INTEGER ); + this.uocBuildingNoDep.addParameter( "upkeep" , Types.INTEGER ); + this.uocBuildingNoDep.addParameter( "workers" , Types.INTEGER ); + this.uocBuildingNoDep.addParameter( "output_type" , "building_output_type" ); + this.uocBuildingNoDep.addParameter( "output" , Types.INTEGER ); + + this.uocBuildingDep = new StoredProc( dataSource , "tech" , "uoc_building" ); + this.uocBuildingDep.addParameter( "name" , Types.VARCHAR ); + this.uocBuildingDep.addParameter( "description" , Types.VARCHAR ); + this.uocBuildingDep.addParameter( "cost" , Types.INTEGER ); + this.uocBuildingDep.addParameter( "work" , Types.INTEGER ); + this.uocBuildingDep.addParameter( "upkeep" , Types.INTEGER ); + this.uocBuildingDep.addParameter( "workers" , Types.INTEGER ); + this.uocBuildingDep.addParameter( "output_type" , "building_output_type" ); + this.uocBuildingDep.addParameter( "output" , Types.INTEGER ); + this.uocBuildingDep.addParameter( "dep_name" , Types.VARCHAR ); + this.uocBuildingDep.addParameter( "dep_level" , Types.INTEGER ); + + this.uocShipNoDep = new StoredProc( dataSource , "tech" , "uoc_ship" ); + this.uocShipNoDep.addParameter( "name" , Types.VARCHAR ); + this.uocShipNoDep.addParameter( "description" , Types.VARCHAR ); + this.uocShipNoDep.addParameter( "cost" , Types.INTEGER ); + this.uocShipNoDep.addParameter( "work" , Types.INTEGER ); + this.uocShipNoDep.addParameter( "upkeep" , Types.INTEGER ); + this.uocShipNoDep.addParameter( "power" , Types.INTEGER ); + this.uocShipNoDep.addParameter( "flight_time" , Types.INTEGER ); + + this.uocShipDep = new StoredProc( dataSource , "tech" , "uoc_ship" ); + this.uocShipDep.addParameter( "name" , Types.VARCHAR ); + this.uocShipDep.addParameter( "description" , Types.VARCHAR ); + this.uocShipDep.addParameter( "cost" , Types.INTEGER ); + this.uocShipDep.addParameter( "work" , Types.INTEGER ); + this.uocShipDep.addParameter( "upkeep" , Types.INTEGER ); + this.uocShipDep.addParameter( "power" , Types.INTEGER ); + this.uocShipDep.addParameter( "flight_time" , Types.INTEGER ); + this.uocShipDep.addParameter( "dep_name" , Types.VARCHAR ); + this.uocShipDep.addParameter( "dep_level" , Types.INTEGER ); + } + + + private void importBuildables( BuildablesData buildables ) + { + for ( BuildableData buildable : buildables.buildables ) { + if ( buildable instanceof BuildingData ) { + this.importBuilding( (BuildingData) buildable ); + } else { + this.importShip( (ShipData) buildable ); + } + } + } + + + private void importShip( ShipData ship ) + { + this.logger.info( "Importing ship " + ship.name ); + + if ( ship.tech == null ) { + this.uocShipNoDep.execute( ship.name , ship.description , ship.cost.build , ship.cost.work , + ship.cost.upkeep , ship.power , ship.time ); + } else { + this.uocShipDep.execute( ship.name , ship.description , ship.cost.build , ship.cost.work , + ship.cost.upkeep , ship.power , ship.time , ship.tech.name , ship.tech.level ); + } + } + + + private void importBuilding( BuildingData building ) + { + this.logger.info( "Importing building " + building.name ); + if ( building.tech == null ) { + this.uocBuildingNoDep.execute( building.name , building.description , building.cost.build , + building.cost.work , building.cost.upkeep , building.workers , building.type.toString( ) , + building.output ); + } else { + this.uocBuildingDep.execute( building.name , building.description , building.cost.build , + building.cost.work , building.cost.upkeep , building.workers , building.type.toString( ) , + building.output , building.tech.name , building.tech.level ); + } + } + + + @Override + public void run( ) + { + final BuildablesData buildables = this.loadData( ); + AbstractApplicationContext ctx = this.createContext( ); + this.createTemplates( ctx ); + + boolean rv = this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + boolean rv; + try { + importBuildables( buildables ); + rv = true; + } catch ( RuntimeException e ) { + if ( e.getCause( ) != null ) { + logger.error( "Exception encoutered" , e ); + } + logger.error( e.getMessage( ) ); + rv = false; + } + if ( !rv ) { + status.setRollbackOnly( ); + } + return rv; + } + + } ); + + if ( rv ) { + this.logger.info( "Import successful" ); + } + + ToolBase.destroyContext( ctx ); + } + + + @Override + public boolean setOptions( String... options ) + { + if ( options.length != 1 ) { + return false; + } + this.file = new File( options[ 0 ] ); + if ( ! ( this.file.isFile( ) && this.file.canRead( ) ) ) { + return false; + } + return true; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportTechs.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportTechs.java new file mode 100644 index 0000000..cd15b30 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportTechs.java @@ -0,0 +1,217 @@ +package com.deepclone.lw.cli; + + +import java.io.*; +import java.sql.Types; +import java.util.List; + +import javax.sql.DataSource; + +import org.apache.log4j.Logger; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.deepclone.lw.utils.StoredProc; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + + + +public class ImportTechs + extends CLITool +{ + + private final Logger logger = Logger.getLogger( ImportTechs.class ); + + @XStreamAlias( "technologies" ) + @SuppressWarnings( "serial" ) + public static class Techs + implements Serializable + { + @XStreamImplicit( itemFieldName = "tech-line" ) + public List< TechLine > lines; + } + + @SuppressWarnings( "serial" ) + public static class TechLine + implements Serializable + { + @XStreamAsAttribute + public String name; + + @XStreamAsAttribute + public String description; + + @XStreamImplicit( itemFieldName = "level" ) + public List< TechLevel > levels; + } + + @SuppressWarnings( "serial" ) + public static class TechLevel + implements Serializable + { + @XStreamAsAttribute + public String name; + + @XStreamAsAttribute + public String description; + + @XStreamAsAttribute + public int points; + + @XStreamAsAttribute + public int cost; + } + + private File file; + private TransactionTemplate tTemplate; + private StoredProc uocLine; + private StoredProc uocLevel; + + + private XStream initXStream( ) + { + XStream xstream = new XStream( ); + xstream.processAnnotations( Techs.class ); + return xstream; + } + + + private Techs loadData( ) + { + FileInputStream fis; + try { + fis = new FileInputStream( this.file ); + } catch ( FileNotFoundException e ) { + return null; + } + + try { + XStream xstream = this.initXStream( ); + return (Techs) xstream.fromXML( fis ); + } catch ( Exception e ) { + e.printStackTrace( ); + return null; + } finally { + try { + fis.close( ); + } catch ( IOException e ) { + // EMPTY + } + } + } + + + private ClassPathXmlApplicationContext createContext( ) + { + // Load data source and Hibernate properties + String[] dataConfig = { + this.getDataSource( ) + }; + FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( dataConfig ); + ctx.refresh( ); + + // Load beans + String[] cfg = { + "configuration/context-configuration.xml" , "configuration/transaction-bean.xml" + }; + return new ClassPathXmlApplicationContext( cfg , true , ctx ); + } + + + private void getBeans( ApplicationContext ctx ) + { + PlatformTransactionManager tManager = ctx.getBean( PlatformTransactionManager.class ); + this.tTemplate = new TransactionTemplate( tManager ); + + DataSource dataSource = ctx.getBean( DataSource.class ); + this.uocLine = new StoredProc( dataSource , "tech" , "uoc_line" ); + this.uocLine.addParameter( "tln" , Types.VARCHAR ); + this.uocLine.addParameter( "tld" , Types.VARCHAR ); + + this.uocLevel = new StoredProc( dataSource , "tech" , "uoc_level" ); + this.uocLevel.addParameter( "tech_line" , Types.VARCHAR ); + this.uocLevel.addParameter( "level" , Types.INTEGER ); + this.uocLevel.addParameter( "name" , Types.VARCHAR ); + this.uocLevel.addParameter( "desc" , Types.VARCHAR ); + this.uocLevel.addParameter( "points" , Types.INTEGER ); + this.uocLevel.addParameter( "cost" , Types.INTEGER ); + } + + + private void importTechnologies( Techs data ) + { + for ( TechLine line : data.lines ) { + this.uocLine.execute( line.name , line.description ); + + int i = 1; + for ( TechLevel level : line.levels ) { + this.uocLevel.execute( line.name , i , level.name , level.description , level.points , level.cost ); + i++; + } + } + } + + + @Override + public void run( ) + { + final Techs data = this.loadData( ); + if ( data == null ) { + System.err.println( "could not read data" ); + return; + } + + AbstractApplicationContext ctx = this.createContext( ); + this.getBeans( ctx ); + boolean rv = this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + boolean rv; + try { + importTechnologies( data ); + rv = true; + } catch ( RuntimeException e ) { + logger.error( e.getMessage( ) ); + rv = false; + } + if ( !rv ) { + status.setRollbackOnly( ); + } + return rv; + } + + } ); + + if ( rv ) { + this.logger.info( "Import successful" ); + } + + this.tTemplate = null; + ToolBase.destroyContext( ctx ); + } + + + @Override + public boolean setOptions( String... options ) + { + if ( options.length != 1 ) { + return false; + } + this.file = new File( options[ 0 ] ); + if ( ! ( this.file.isFile( ) && this.file.canRead( ) ) ) { + return false; + } + return true; + } +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportText.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportText.java new file mode 100644 index 0000000..c3952ed --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ImportText.java @@ -0,0 +1,267 @@ +package com.deepclone.lw.cli; + + +import java.io.*; +import java.util.LinkedList; +import java.util.List; + +import javax.sql.DataSource; + +import org.apache.log4j.Logger; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.simple.SimpleJdbcCall; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallback; +import org.springframework.transaction.support.TransactionTemplate; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + + + +public class ImportText + extends CLITool +{ + + private final Logger logger = Logger.getLogger( ImportText.class ); + + @SuppressWarnings( "serial" ) + public abstract static class StringData + implements Serializable + { + @XStreamAsAttribute + public String id; + + + public abstract String getString( ); + } + + @SuppressWarnings( "serial" ) + @XStreamAlias( "inline-string" ) + public static class InlineString + extends StringData + { + public String value; + + + @Override + public String getString( ) + { + return this.value; + } + } + + @SuppressWarnings( "serial" ) + @XStreamAlias( "from-file" ) + public static class FileString + extends StringData + { + @XStreamAsAttribute + public String source; + + + @Override + public String getString( ) + { + StringBuilder sBuilder = new StringBuilder( ); + try { + BufferedReader in = new BufferedReader( new FileReader( source ) ); + String str; + while ( ( str = in.readLine( ) ) != null ) { + sBuilder.append( str ); + sBuilder.append( "\n" ); + } + in.close( ); + } catch ( IOException e ) { + throw new RuntimeException( "Could not read " + source ); + } + + return sBuilder.toString( ); + } + } + + @SuppressWarnings( "serial" ) + public static class LanguageData + implements Serializable + { + @XStreamAsAttribute + public String id; + + @XStreamAsAttribute + public String name; + + @XStreamImplicit + public List< StringData > strings = new LinkedList< StringData >( ); + } + + @SuppressWarnings( "serial" ) + @XStreamAlias( "lw-text-data" ) + public static class TextData + implements Serializable + { + @XStreamImplicit( itemFieldName = "language" ) + public List< LanguageData > languages = new LinkedList< LanguageData >( ); + } + + private File file; + private TransactionTemplate tTemplate; + private SimpleJdbcCall uocTranslation; + private SimpleJdbcCall uocLanguage; + + + private XStream initXStream( ) + { + XStream xstream = new XStream( ); + xstream.processAnnotations( TextData.class ); + xstream.processAnnotations( InlineString.class ); + xstream.processAnnotations( FileString.class ); + return xstream; + } + + + private TextData loadData( ) + { + FileInputStream fis; + try { + fis = new FileInputStream( this.file ); + } catch ( FileNotFoundException e ) { + return null; + } + + try { + XStream xstream = this.initXStream( ); + return (TextData) xstream.fromXML( fis ); + } catch ( Exception e ) { + e.printStackTrace( ); + return null; + } finally { + try { + fis.close( ); + } catch ( IOException e ) { + // EMPTY + } + } + } + + + private ClassPathXmlApplicationContext createContext( ) + { + // Load data source and Hibernate properties + String[] dataConfig = { + this.getDataSource( ) , + }; + FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( dataConfig ); + ctx.refresh( ); + + // Load transaction manager bean + String[] cfg = { + "configuration/transaction-bean.xml" + }; + return new ClassPathXmlApplicationContext( cfg , true , ctx ); + } + + + private void createTemplates( ApplicationContext ctx ) + { + DataSource dSource = ctx.getBean( DataSource.class ); + PlatformTransactionManager tManager = ctx.getBean( PlatformTransactionManager.class ); + + this.uocLanguage = new SimpleJdbcCall( dSource ).withCatalogName( "defs" ).withProcedureName( "uoc_language" ); + this.uocLanguage.withoutProcedureColumnMetaDataAccess( ); + this.uocLanguage.declareParameters( new SqlParameter( "lid" , java.sql.Types.VARCHAR ) , new SqlParameter( + "lname" , java.sql.Types.VARCHAR ) ); + + this.uocTranslation = new SimpleJdbcCall( dSource ).withCatalogName( "defs" ).withProcedureName( + "uoc_translation" ); + this.uocTranslation.withoutProcedureColumnMetaDataAccess( ); + this.uocTranslation.declareParameters( new SqlParameter( "lid" , java.sql.Types.VARCHAR ) , new SqlParameter( + "sid" , java.sql.Types.VARCHAR ) , new SqlParameter( "trans" , java.sql.Types.VARCHAR ) ); + + this.tTemplate = new TransactionTemplate( tManager ); + } + + + private void importText( TextData data ) + { + for ( LanguageData ld : data.languages ) { + this.importLanguage( ld ); + } + } + + + private void importLanguage( LanguageData ld ) + { + if ( ld.strings == null ) { + return; + } + + // Try creating or updating the language + this.uocLanguage.execute( ld.id , ld.name ); + + // Import translations + for ( StringData sd : ld.strings ) { + this.uocTranslation.execute( ld.id , sd.id , sd.getString( ) ); + } + } + + + @Override + public void run( ) + { + final TextData data = this.loadData( ); + if ( data == null ) { + System.err.println( "could not read data" ); + return; + } + + AbstractApplicationContext ctx = this.createContext( ); + this.createTemplates( ctx ); + boolean rv = this.tTemplate.execute( new TransactionCallback< Boolean >( ) { + + @Override + public Boolean doInTransaction( TransactionStatus status ) + { + boolean rv; + try { + importText( data ); + rv = true; + } catch ( RuntimeException e ) { + logger.error( "Caught runtime exception" , e ); + rv = false; + } + if ( !rv ) { + status.setRollbackOnly( ); + } + return rv; + } + + } ); + + if ( rv ) { + this.logger.info( "Text import successful" ); + } + + ToolBase.destroyContext( ctx ); + } + + + @Override + public boolean setOptions( String... options ) + { + if ( options.length != 1 ) { + return false; + } + this.file = new File( options[ 0 ] ); + if ( ! ( this.file.isFile( ) && this.file.canRead( ) ) ) { + return false; + } + return true; + } +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/Stop.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/Stop.java new file mode 100644 index 0000000..80ecfff --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/Stop.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.cli; + + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.ApplicationContext; + +import com.deepclone.lw.srv.ServerTerminator; + + + +public final class Stop + extends CLITool +{ + + private ApplicationContext getContext( ) + { + Map< String , String > rmiTerminator = new HashMap< String , String >( ); + rmiTerminator.put( "termSrv" , "com.deepclone.lw.srv.ServerTerminator" ); + + return this.createClientContext( rmiTerminator ); + } + + + @Override + public void run( ) + { + ApplicationContext ctx = this.getContext( ); + ServerTerminator terminator; + try { + terminator = (ServerTerminator) ctx.getBean( "termSrv" ); + } catch ( BeanCreationException e ) { + System.err.println("Could not connect to server"); + return; + } + terminator.terminate( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/Tick.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/Tick.java new file mode 100644 index 0000000..b2484fc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/Tick.java @@ -0,0 +1,114 @@ +package com.deepclone.lw.cli; + + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.context.support.GenericApplicationContext; + +import com.deepclone.lw.interfaces.sys.Ticker; +import com.deepclone.lw.interfaces.sys.Ticker.Frequency; + + + +public class Tick + extends CLITool +{ + + public static class FakeTickerBean + implements Ticker + { + Map< Frequency , List< Runnable > > tasks = new HashMap< Frequency , List< Runnable > >( ); + + + @Override + public boolean isActive( ) + { + return true; + } + + + @Override + public void pause( ) + throws IllegalStateException + { + // EMPTY + } + + + @Override + synchronized public void registerTask( Frequency frequency , String name , Runnable task ) + { + List< Runnable > tasks = this.tasks.get( frequency ); + if ( tasks == null ) { + tasks = new LinkedList< Runnable >( ); + this.tasks.put( frequency , tasks ); + } + tasks.add( task ); + } + + + @Override + public void unpause( ) + throws IllegalStateException + { + // EMPTY + } + + + public void runFrequency( Frequency frequency ) + { + List< Runnable > tasks = this.tasks.get( frequency ); + if ( tasks == null ) { + return; + } + for ( Runnable r : tasks ) { + r.run( ); + } + } + + } + + + private AbstractApplicationContext getContext( ) + { + // Load data source and Hibernate properties + String[] dataConfig = { + this.getDataSource( ) , + }; + FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( dataConfig ); + ctx.refresh( ); + + // Load fake ticker + GenericApplicationContext gac = new GenericApplicationContext( ctx ); + gac.registerBeanDefinition( "fakeTicker" , BeanDefinitionBuilder.rootBeanDefinition( FakeTickerBean.class ) + .getBeanDefinition( ) ); + gac.refresh( ); + + String[] cfg = { + "configuration/context-configuration.xml" , "configuration/transaction-bean.xml" , + "configuration/accounts-beans.xml" , "configuration/bt-beans.xml" , "configuration/eventlog-beans.xml" , + "configuration/i18n-beans.xml" , "configuration/mailer-beans.xml" , "configuration/naming-beans.xml" , + "configuration/simple-beans.xml" , + "configuration/system/constants-manager-bean.xml" , "configuration/system/system-status-bean.xml" + }; + return new ClassPathXmlApplicationContext( cfg , true , gac ); + } + + + @Override + public void run( ) + { + AbstractApplicationContext ctx = this.getContext( ); + FakeTickerBean ftb = ctx.getBean( FakeTickerBean.class ); + ftb.runFrequency( Frequency.MINUTE ); + ToolBase.destroyContext( ctx ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ToolBase.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ToolBase.java new file mode 100644 index 0000000..eafb148 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/ToolBase.java @@ -0,0 +1,70 @@ +package com.deepclone.lw.cli; + + +import org.springframework.context.support.AbstractApplicationContext; + + + +public abstract class ToolBase + implements Runnable +{ + + private String dataSource; + private int rmiPort; + private int servPort; + + + protected final String getDataSource( ) + { + return this.dataSource; + } + + + protected final int getRmiPort( ) + { + return this.rmiPort; + } + + + protected final int getServicePort( ) + { + return this.servPort; + } + + + protected final int getTerminationPort( ) + { + return this.servPort + 1; + } + + + protected static void destroyContext( AbstractApplicationContext aac ) + { + while ( aac != null ) { + AbstractApplicationContext p = (AbstractApplicationContext) aac.getParent( ); + aac.destroy( ); + aac = p; + } + System.gc( ); + try { + Thread.sleep( 1000L ); + } catch ( InterruptedException e ) { + e.printStackTrace( ); + } + } + + + public final void setMainSettings( String dataSource , int rmiPort , int servPort ) + { + this.dataSource = dataSource; + this.rmiPort = rmiPort; + this.servPort = servPort; + } + + + public boolean setOptions( String... options ) + { + return ( options == null || options.length == 0 ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/Administrator.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/Administrator.java new file mode 100644 index 0000000..f3713a9 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/Administrator.java @@ -0,0 +1,29 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "administrator" ) +public class Administrator + implements Serializable +{ + + @XStreamAsAttribute + public int id; + + @XStreamAsAttribute + public String name; + + @XStreamAsAttribute + public int privileges; + + public String md5; + public String sha1; + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREComment.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREComment.java new file mode 100644 index 0000000..0ea8f2c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREComment.java @@ -0,0 +1,20 @@ +package com.deepclone.lw.cli.dbexport; + + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "comment" ) +public class BREComment + extends BugReportEvent +{ + + @XStreamAsAttribute + public boolean visible; + + public String text; + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREInitialReport.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREInitialReport.java new file mode 100644 index 0000000..87bda4c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREInitialReport.java @@ -0,0 +1,22 @@ +package com.deepclone.lw.cli.dbexport; + + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "initial-report" ) +public class BREInitialReport + extends BugReportEvent +{ + + @XStreamAsAttribute + public String title; + + public String contents; + + public String xmlData; + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREMerger.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREMerger.java new file mode 100644 index 0000000..e100b34 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREMerger.java @@ -0,0 +1,19 @@ +package com.deepclone.lw.cli.dbexport; + + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "merge-reports" ) +public class BREMerger + extends BugReportEvent +{ + + @XStreamAsAttribute + @XStreamAlias( "from-report" ) + public long merged; + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREStatusChange.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREStatusChange.java new file mode 100644 index 0000000..e7735f7 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREStatusChange.java @@ -0,0 +1,18 @@ +package com.deepclone.lw.cli.dbexport; + + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "status-change" ) +public class BREStatusChange + extends BugReportEvent +{ + + @XStreamAsAttribute + public String status; + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREVisibilityChange.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREVisibilityChange.java new file mode 100644 index 0000000..009e016 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BREVisibilityChange.java @@ -0,0 +1,16 @@ +package com.deepclone.lw.cli.dbexport; + + +import com.thoughtworks.xstream.annotations.XStreamAlias; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "visibility-change" ) +public class BREVisibilityChange + extends BugReportEvent +{ + + public boolean visible; + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugEventMapper.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugEventMapper.java new file mode 100644 index 0000000..856be58 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugEventMapper.java @@ -0,0 +1,109 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.jdbc.core.RowMapper; + +import com.deepclone.lw.cmd.bt.data.BugEventType; + + + +public class BugEventMapper + implements RowMapper< BugReportEvent > +{ + + @Override + public BugReportEvent mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + BugEventType bet = BugEventType.valueOf( rs.getString( "event_type" ) ); + BugReportEvent bre; + + switch ( bet ) { + case COMMENT: + bre = this.getComment( rs ); + break; + case INIT: + bre = this.getInitialReport( rs ); + break; + case MERGE: + bre = this.getMerger( rs ); + break; + case STATUS: + bre = this.getStatusChange( rs ); + break; + case VISIBILITY: + bre = this.getVisibility( rs ); + break; + default: + throw new IllegalArgumentException( bet.toString( ) ); + } + + bre.id = rs.getLong( "event_id" ); + bre.timestamp = rs.getTimestamp( "event_timestamp" ); + bre.submitter = this.getSubmitter( rs ); + + return bre; + } + + + private BugSubmitter getSubmitter( ResultSet rs ) + throws SQLException + { + BugSubmitter submitter = new BugSubmitter( ); + submitter.isAdmin = rs.getBoolean( "submitter_admin" ); + submitter.name = rs.getString( "submitter_name" ); + return submitter; + } + + + private BugReportEvent getComment( ResultSet rs ) + throws SQLException + { + BREComment evt = new BREComment( ); + evt.text = rs.getString( "contents" ); + evt.visible = rs.getBoolean( "visible" ); + return evt; + } + + + private BugReportEvent getInitialReport( ResultSet rs ) + throws SQLException + { + BREInitialReport evt = new BREInitialReport( ); + evt.title = rs.getString( "title" ); + evt.contents = rs.getString( "contents" ); + evt.xmlData = rs.getString( "account_status" ); + return evt; + } + + + private BugReportEvent getMerger( ResultSet rs ) + throws SQLException + { + BREMerger evt = new BREMerger( ); + evt.merged = rs.getLong( "merged_report_id" ); + return evt; + } + + + private BugReportEvent getStatusChange( ResultSet rs ) + throws SQLException + { + BREStatusChange evt = new BREStatusChange( ); + evt.status = rs.getString( "status" ); + return evt; + } + + + private BugReportEvent getVisibility( ResultSet rs ) + throws SQLException + { + BREVisibilityChange evt = new BREVisibilityChange( ); + evt.visible = rs.getBoolean( "visible" ); + return evt; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugGroup.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugGroup.java new file mode 100644 index 0000000..63fd994 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugGroup.java @@ -0,0 +1,22 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "bug-group" ) +public class BugGroup + implements Serializable +{ + + @XStreamImplicit( itemFieldName = "event-id" ) + public List< Long > events = new ArrayList< Long >( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugReportEvent.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugReportEvent.java new file mode 100644 index 0000000..21d624d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugReportEvent.java @@ -0,0 +1,23 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.io.Serializable; +import java.sql.Timestamp; + +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +public abstract class BugReportEvent + implements Serializable +{ + + @XStreamAsAttribute + public long id; + + @XStreamAsAttribute + public Timestamp timestamp; + + public BugSubmitter submitter; +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugReports.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugReports.java new file mode 100644 index 0000000..8bb9fc4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugReports.java @@ -0,0 +1,17 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.io.Serializable; +import java.util.List; + + + +@SuppressWarnings( "serial" ) +public class BugReports + implements Serializable +{ + + public List< BugGroup > groups; + + public List< BugReportEvent > events; +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugSubmitter.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugSubmitter.java new file mode 100644 index 0000000..cfe7a6d --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/BugSubmitter.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "submitter" ) +public class BugSubmitter + implements Serializable +{ + + @XStreamAsAttribute + public String name; + + @XStreamAlias( "is-admin" ) + @XStreamAsAttribute + public boolean isAdmin; + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/LegacyWorldsDB.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/LegacyWorldsDB.java new file mode 100644 index 0000000..252e40a --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/LegacyWorldsDB.java @@ -0,0 +1,26 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.io.Serializable; +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "legacyworlds" ) +public class LegacyWorldsDB + implements Serializable +{ + + @XStreamAsAttribute + public int version = 1; + + public List< User > users; + + @XStreamAlias( "bug-reports" ) + public BugReports bugReports = new BugReports( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/User.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/User.java new file mode 100644 index 0000000..67dee6c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/User.java @@ -0,0 +1,39 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "user" ) +public class User + implements Serializable +{ + + @XStreamAsAttribute + public String address; + + @XStreamAsAttribute + public String language; + + @XStreamAsAttribute + @XStreamAlias( "game-credits" ) + public int gameCredits; + + @XStreamAsAttribute + @XStreamAlias("vacation-credits") + public int vacationCredits; + + public String md5; + public String sha1; + + public String empire; + + public Warnings warnings; + public Administrator administrator; + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/UserMapper.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/UserMapper.java new file mode 100644 index 0000000..b80a753 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/UserMapper.java @@ -0,0 +1,49 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.jdbc.core.RowMapper; + + + +public class UserMapper + implements RowMapper< User > +{ + + @Override + public User mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + User user = new User( ); + + user.address = rs.getString( "address" ); + user.language = rs.getString( "language" ); + user.gameCredits = rs.getInt( "game_credits" ); + user.vacationCredits = rs.getInt( "vacation_credits" ); + user.md5 = rs.getString( "pass_md5" ); + user.sha1 = rs.getString( "pass_sha1" ); + user.empire = rs.getString( "current_empire" ); + + int wCount = rs.getInt( "warnings_count" ); + if ( wCount > 0 ) { + user.warnings = new Warnings( ); + user.warnings.count = wCount; + user.warnings.last = rs.getTimestamp( "warnings_last" ); + } + + String aName = rs.getString( "administrator_name" ); + if ( aName != null ) { + user.administrator = new Administrator( ); + user.administrator.id = rs.getInt( "administrator_id" ); + user.administrator.name = aName; + user.administrator.privileges = rs.getInt( "privileges" ); + user.administrator.md5 = rs.getString( "administrator_md5" ); + user.administrator.sha1 = rs.getString( "administrator_sha1" ); + } + + return user; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/Warnings.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/Warnings.java new file mode 100644 index 0000000..284aebf --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/cli/dbexport/Warnings.java @@ -0,0 +1,23 @@ +package com.deepclone.lw.cli.dbexport; + + +import java.io.Serializable; +import java.sql.Timestamp; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "warnings" ) +public class Warnings + implements Serializable +{ + + @XStreamAsAttribute + public int count; + + @XStreamAsAttribute + public Timestamp last; +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/LogAppender.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/LogAppender.java new file mode 100644 index 0000000..def3414 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/LogAppender.java @@ -0,0 +1,513 @@ +package com.deepclone.lw.srv; + + +/** + * Adapted from the Apache Log4j DailyRollingFileAppender to extend the functionality of the + * existing class so that the user can limit the number of log backups and compress the backups to + * conserve disk space. + * + * @author Ryan Kimber + * + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file to You under the Apache + * License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Calendar; +import java.util.TimeZone; +import java.util.Locale; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +// We have to import the log4j package because this class used to be in it and references other +// classes in that package. +import org.apache.log4j.*; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.spi.LoggingEvent; + + + +/** + * CustodianDailyRollingFileAppender is based on + * {@link org.apache.log4j.appender.DailyRollingFileAppender} so most of the configuration options + * can be taken from the documentation on that class. + */ +public class LogAppender + extends FileAppender +{ + // The code assumes that the following constants are in a increasing + // sequence. + static final int TOP_OF_TROUBLE = -1; + static final int TOP_OF_MINUTE = 0; + static final int TOP_OF_HOUR = 1; + static final int HALF_DAY = 2; + static final int TOP_OF_DAY = 3; + static final int TOP_OF_WEEK = 4; + static final int TOP_OF_MONTH = 5; + + /** + * The date pattern. By default, the pattern is set to "'.'yyyy-MM-dd" meaning daily rollover. + */ + private String datePattern = "'.'yyyy-MM-dd"; + private String compressBackups = "false"; + private String maxNumberOfDays = "7"; + + /** + * The log file will be renamed to the value of the scheduledFilename variable when the next + * interval is entered. For example, if the rollover period is one hour, the log file will be + * renamed to the value of "scheduledFilename" at the beginning of the next hour. + * + * The precise time when a rollover occurs depends on logging activity. + */ + private String scheduledFilename; + + /** + * The next time we estimate a rollover should occur. + */ + private long nextCheck = System.currentTimeMillis( ) - 1; + + Date now = new Date( ); + + SimpleDateFormat sdf; + + RollingCalendar rc = new RollingCalendar( ); + + int checkPeriod = TOP_OF_TROUBLE; + + // The gmtTimeZone is used only in computeCheckPeriod() method. + static final TimeZone gmtTimeZone = TimeZone.getTimeZone( "GMT" ); + + + /** + * The default constructor does nothing. + */ + public LogAppender( ) + { + } + + + /** + * Instantiate a LogAppender and open the file designated by filename. The opened filename will + * become the ouput destination for this appender. + */ + public LogAppender( Layout layout , String filename , String datePattern ) + throws IOException + { + super( layout , filename , true ); + this.datePattern = datePattern; + activateOptions( ); + } + + + /** + * The DatePattern takes a string in the same format as expected by {@link SimpleDateFormat}. + * This options determines the rollover schedule. + */ + public void setDatePattern( String pattern ) + { + datePattern = pattern; + } + + + /** Returns the value of the DatePattern option. */ + public String getDatePattern( ) + { + return datePattern; + } + + + public void activateOptions( ) + { + super.activateOptions( ); + if ( datePattern != null && fileName != null ) { + now.setTime( System.currentTimeMillis( ) ); + sdf = new SimpleDateFormat( datePattern ); + int type = computeCheckPeriod( ); + printPeriodicity( type ); + rc.setType( type ); + File file = new File( fileName ); + scheduledFilename = fileName + sdf.format( new Date( file.lastModified( ) ) ); + + } else { + LogLog.error( "Either File or DatePattern options are not set for appender [" + name + "]." ); + } + } + + + void printPeriodicity( int type ) + { + switch ( type ) { + case TOP_OF_MINUTE: + LogLog.debug( "Appender [" + name + "] to be rolled every minute." ); + break; + case TOP_OF_HOUR: + LogLog.debug( "Appender [" + name + "] to be rolled on top of every hour." ); + break; + case HALF_DAY: + LogLog.debug( "Appender [" + name + "] to be rolled at midday and midnight." ); + break; + case TOP_OF_DAY: + LogLog.debug( "Appender [" + name + "] to be rolled at midnight." ); + break; + case TOP_OF_WEEK: + LogLog.debug( "Appender [" + name + "] to be rolled at start of week." ); + break; + case TOP_OF_MONTH: + LogLog.debug( "Appender [" + name + "] to be rolled at start of every month." ); + break; + default: + LogLog.warn( "Unknown periodicity for appender [" + name + "]." ); + } + } + + + // This method computes the roll over period by looping over the + // periods, starting with the shortest, and stopping when the r0 is + // different from from r1, where r0 is the epoch formatted according + // the datePattern (supplied by the user) and r1 is the + // epoch+nextMillis(i) formatted according to datePattern. All date + // formatting is done in GMT and not local format because the test + // logic is based on comparisons relative to 1970-01-01 00:00:00 + // GMT (the epoch). + + int computeCheckPeriod( ) + { + RollingCalendar rollingCalendar = new RollingCalendar( gmtTimeZone , Locale.ENGLISH ); + // set sate to 1970-01-01 00:00:00 GMT + Date epoch = new Date( 0 ); + if ( datePattern != null ) { + for ( int i = TOP_OF_MINUTE ; i <= TOP_OF_MONTH ; i++ ) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat( datePattern ); + simpleDateFormat.setTimeZone( gmtTimeZone ); // do all date + // formatting in GMT + String r0 = simpleDateFormat.format( epoch ); + rollingCalendar.setType( i ); + Date next = new Date( rollingCalendar.getNextCheckMillis( epoch ) ); + String r1 = simpleDateFormat.format( next ); + // System.out.println("Type = "+i+", r0 = "+r0+", r1 = "+r1); + if ( r0 != null && r1 != null && !r0.equals( r1 ) ) { + return i; + } + } + } + return TOP_OF_TROUBLE; // Deliberately head for trouble... + } + + + /** + * Rollover the current file to a new file. + */ + void rollOver( ) + throws IOException + { + + /* Compute filename, but only if datePattern is specified */ + if ( datePattern == null ) { + errorHandler.error( "Missing DatePattern option in rollOver()." ); + return; + } + + String datedFilename = fileName + sdf.format( now ); + // It is too early to roll over because we are still within the + // bounds of the current interval. Rollover will occur once the + // next interval is reached. + if ( scheduledFilename.equals( datedFilename ) ) { + return; + } + + // close current file, and rename it to datedFilename + this.closeFile( ); + + File target = new File( scheduledFilename ); + if ( target.exists( ) ) { + target.delete( ); + } + + File file = new File( fileName ); + boolean result = file.renameTo( target ); + if ( result ) { + LogLog.debug( fileName + " -> " + scheduledFilename ); + } else { + LogLog.error( "Failed to rename [" + fileName + "] to [" + scheduledFilename + "]." ); + } + + try { + // This will also close the file. This is OK since multiple + // close operations are safe. + this.setFile( fileName , false , this.bufferedIO , this.bufferSize ); + } catch ( IOException e ) { + errorHandler.error( "setFile(" + fileName + ", false) call failed." ); + } + scheduledFilename = datedFilename; + } + + + /** + * This method differentiates DailyRollingFileAppender from its super class. + * + * + * Before actually logging, this method will check whether it is time to do a rollover. If it + * is, it will schedule the next rollover time and then rollover. + * */ + protected void subAppend( LoggingEvent event ) + { + long n = System.currentTimeMillis( ); + if ( n >= nextCheck ) { + now.setTime( n ); + nextCheck = rc.getNextCheckMillis( now ); + try { + cleanupAndRollOver( ); + } catch ( IOException ioe ) { + LogLog.error( "cleanupAndRollover() failed." , ioe ); + } + } + super.subAppend( event ); + } + + + public String getCompressBackups( ) + { + return compressBackups; + } + + + public void setCompressBackups( String compressBackups ) + { + this.compressBackups = compressBackups; + } + + + public String getMaxNumberOfDays( ) + { + return maxNumberOfDays; + } + + + public void setMaxNumberOfDays( String maxNumberOfDays ) + { + this.maxNumberOfDays = maxNumberOfDays; + } + + + /* + * This method checks to see if we're exceeding the number of log backups that we are supposed + * to keep, and if so, deletes the offending files. It then delegates to the rollover method to + * rollover to a new file if required. + */ + protected void cleanupAndRollOver( ) + throws IOException + { + // Check to see if there are already 5 files + File file = new File( fileName ); + Calendar cal = Calendar.getInstance( ); + int maxDays = 7; + try { + maxDays = Integer.parseInt( getMaxNumberOfDays( ) ); + } catch ( Exception e ) { + // just leave it at 7. + } + cal.add( Calendar.DATE , -maxDays ); + Date cutoffDate = cal.getTime( ); + if ( file.getParentFile( ).exists( ) ) { + File[] files = file.getParentFile( ).listFiles( new StartsWithFileFilter( file.getName( ) , false ) ); + int nameLength = file.getName( ).length( ); + for ( int i = 0 ; i < files.length ; i++ ) { + String datePart = null; + try { + datePart = files[ i ].getName( ).substring( nameLength ); + Date date = sdf.parse( datePart ); + if ( date.before( cutoffDate ) ) { + files[ i ].delete( ); + } + // If we're supposed to zip files and this isn't already a zip + else if ( getCompressBackups( ).equalsIgnoreCase( "YES" ) + || getCompressBackups( ).equalsIgnoreCase( "TRUE" ) ) { + zipAndDelete( files[ i ] ); + } + } catch ( Exception pe ) { + // This isn't a file we should touch (it isn't named + // correctly) + } + } + } + rollOver( ); + } + + + /** + * Compresses the passed file to a .zip file, stores the .zip in the same directory as the + * passed file, and then deletes the original, leaving only the .zipped archive. + * + * @param file + */ + private void zipAndDelete( File file ) + throws IOException + { + if ( !file.getName( ).endsWith( ".zip" ) ) { + File zipFile = new File( file.getParent( ) , file.getName( ) + ".zip" ); + FileInputStream fis = new FileInputStream( file ); + FileOutputStream fos = new FileOutputStream( zipFile ); + ZipOutputStream zos = new ZipOutputStream( fos ); + ZipEntry zipEntry = new ZipEntry( file.getName( ) ); + zos.putNextEntry( zipEntry ); + + byte[] buffer = new byte[ 4096 ]; + while ( true ) { + int bytesRead = fis.read( buffer ); + if ( bytesRead == -1 ) + break; + else { + zos.write( buffer , 0 , bytesRead ); + } + } + zos.closeEntry( ); + fis.close( ); + zos.close( ); + file.delete( ); + } + } + + class StartsWithFileFilter + implements FileFilter + { + private String startsWith; + private boolean inclDirs = false; + + + /** + * + */ + public StartsWithFileFilter( String startsWith , boolean includeDirectories ) + { + super( ); + this.startsWith = startsWith.toUpperCase( ); + inclDirs = includeDirectories; + } + + + /* + * (non-Javadoc) + * + * @see java.io.FileFilter#accept(java.io.File) + */ + public boolean accept( File pathname ) + { + if ( !inclDirs && pathname.isDirectory( ) ) { + return false; + } else + return pathname.getName( ).toUpperCase( ).startsWith( startsWith ); + } + } +} + +/** + * RollingCalendar is a helper class to DailyRollingFileAppender. Given a periodicity type and the + * current time, it computes the start of the next interval. + * */ +class RollingCalendar + extends GregorianCalendar +{ + private static final long serialVersionUID = -3560331770601814177L; + + int type = LogAppender.TOP_OF_TROUBLE; + + + RollingCalendar( ) + { + super( ); + } + + + RollingCalendar( TimeZone tz , Locale locale ) + { + super( tz , locale ); + } + + + void setType( int type ) + { + this.type = type; + } + + + public long getNextCheckMillis( Date now ) + { + return getNextCheckDate( now ).getTime( ); + } + + + public Date getNextCheckDate( Date now ) + { + this.setTime( now ); + + switch ( type ) { + case LogAppender.TOP_OF_MINUTE: + this.set( Calendar.SECOND , 0 ); + this.set( Calendar.MILLISECOND , 0 ); + this.add( Calendar.MINUTE , 1 ); + break; + case LogAppender.TOP_OF_HOUR: + this.set( Calendar.MINUTE , 0 ); + this.set( Calendar.SECOND , 0 ); + this.set( Calendar.MILLISECOND , 0 ); + this.add( Calendar.HOUR_OF_DAY , 1 ); + break; + case LogAppender.HALF_DAY: + this.set( Calendar.MINUTE , 0 ); + this.set( Calendar.SECOND , 0 ); + this.set( Calendar.MILLISECOND , 0 ); + int hour = get( Calendar.HOUR_OF_DAY ); + if ( hour < 12 ) { + this.set( Calendar.HOUR_OF_DAY , 12 ); + } else { + this.set( Calendar.HOUR_OF_DAY , 0 ); + this.add( Calendar.DAY_OF_MONTH , 1 ); + } + break; + case LogAppender.TOP_OF_DAY: + this.set( Calendar.HOUR_OF_DAY , 0 ); + this.set( Calendar.MINUTE , 0 ); + this.set( Calendar.SECOND , 0 ); + this.set( Calendar.MILLISECOND , 0 ); + this.add( Calendar.DATE , 1 ); + break; + case LogAppender.TOP_OF_WEEK: + this.set( Calendar.DAY_OF_WEEK , getFirstDayOfWeek( ) ); + this.set( Calendar.HOUR_OF_DAY , 0 ); + this.set( Calendar.MINUTE , 0 ); + this.set( Calendar.SECOND , 0 ); + this.set( Calendar.MILLISECOND , 0 ); + this.add( Calendar.WEEK_OF_YEAR , 1 ); + break; + case LogAppender.TOP_OF_MONTH: + this.set( Calendar.DATE , 1 ); + this.set( Calendar.HOUR_OF_DAY , 0 ); + this.set( Calendar.MINUTE , 0 ); + this.set( Calendar.SECOND , 0 ); + this.set( Calendar.MILLISECOND , 0 ); + this.add( Calendar.MONTH , 1 ); + break; + default: + throw new IllegalStateException( "Unknown periodicity type." ); + } + return getTime( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/Server.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/Server.java new file mode 100644 index 0000000..f6a41e0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/Server.java @@ -0,0 +1,108 @@ +package com.deepclone.lw.srv; + + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.AbstractApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.FileSystemXmlApplicationContext; +import org.springframework.context.support.GenericApplicationContext; + +import com.deepclone.lw.cli.ToolBase; +import com.deepclone.lw.interfaces.session.SessionManager; + + + +public class Server + extends ToolBase +{ + private static final String[] beanConfigurations = { + "lw-server.xml" , + }; + + private Lock terminationLock = new ReentrantLock( ); + private Condition termination = this.terminationLock.newCondition( ); + + private AbstractApplicationContext applicationContext; + + + private void addRMIService( GenericApplicationContext ctx , String name , Object bean , Class< ? > iface , int sPort ) + { + BeanDefinitionBuilder builder; + builder = BeanDefinitionBuilder.rootBeanDefinition( "org.springframework.remoting.rmi.RmiServiceExporter" ); + builder.setScope( BeanDefinition.SCOPE_SINGLETON ); + builder.addPropertyValue( "serviceName" , name ); + builder.addPropertyValue( "service" , bean ); + builder.addPropertyValue( "ServiceInterface" , iface.getCanonicalName( ) ); + builder.addPropertyValue( "registryPort" , String.valueOf( this.getRmiPort( ) ) ); + builder.addPropertyValue( "servicePort" , String.valueOf( sPort ) ); + ctx.registerBeanDefinition( name , builder.getBeanDefinition( ) ); + } + + + private AbstractApplicationContext makeRMIContext( ApplicationContext parent ) + { + GenericApplicationContext context = new GenericApplicationContext( parent ); + this.addRMIService( context , "termSrv" , parent.getBean( "terminator" ) , ServerTerminator.class , this.getTerminationPort( ) ); + this.addRMIService( context , "sessionSrv" , parent.getBean( "sessionManager" ) , SessionManager.class , this.getServicePort( ) ); + context.refresh( ); + return context; + } + + + private ApplicationContext makeDataConfigContext( ) + { + String[] dSource = { + this.getDataSource( ) , + }; + FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( dSource ); + ctx.refresh( ); + return ctx; + } + + + private void createBeans( ) + { + ApplicationContext ctx = this.makeDataConfigContext( ); + ctx = new ClassPathXmlApplicationContext( Server.beanConfigurations , true , ctx ); + this.applicationContext = this.makeRMIContext( ctx ); + } + + + private void initialiseBeans( ) + { + this.createBeans( ); + this.applicationContext.getBean( "terminator" , ServerTerminatorBean.class ).setServer( this ); + } + + + private void waitForTermination( ) + { + this.terminationLock.lock( ); + this.termination.awaitUninterruptibly( ); + this.terminationLock.unlock( ); + } + + + @Override + public void run( ) + { + this.initialiseBeans( ); + this.waitForTermination( ); + ToolBase.destroyContext( this.applicationContext ); + } + + + public void terminate( ) + { + this.terminationLock.lock( ); + this.termination.signal( ); + this.terminationLock.unlock( ); + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/ServerTerminator.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/ServerTerminator.java new file mode 100644 index 0000000..d533c41 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/ServerTerminator.java @@ -0,0 +1,9 @@ +package com.deepclone.lw.srv; + + +public interface ServerTerminator +{ + + public void terminate( ); + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/ServerTerminatorBean.java b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/ServerTerminatorBean.java new file mode 100644 index 0000000..69994d0 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/java/com/deepclone/lw/srv/ServerTerminatorBean.java @@ -0,0 +1,25 @@ +package com.deepclone.lw.srv; + + +public class ServerTerminatorBean + implements ServerTerminator +{ + + private Server server = null; + + + public void setServer( Server server ) + { + this.server = server; + } + + + @Override + public void terminate( ) + { + if ( this.server != null ) { + this.server.terminate( ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/resources/configuration/context-configuration.xml b/legacyworlds-server/legacyworlds-server-main/src/main/resources/configuration/context-configuration.xml new file mode 100644 index 0000000..11e1a81 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/resources/configuration/context-configuration.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/resources/log4j.properties b/legacyworlds-server/legacyworlds-server-main/src/main/resources/log4j.properties new file mode 100644 index 0000000..994c335 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/resources/log4j.properties @@ -0,0 +1,38 @@ +log4j.appender.fullDebug=org.apache.log4j.RollingFileAppender +log4j.appender.fullDebug.File=./full-debug.log +log4j.appender.fullDebug.layout=org.apache.log4j.PatternLayout +log4j.appender.fullDebug.layout.ConversionPattern=%d{yyyy-MM-dd@HH:mm:ss} %5p (%40c{1}:%-5L) - %m%n +log4j.appender.fullDebug.MaxFileSize=100MB +log4j.appender.fullDebug.MaxBackupIndex=1 + +log4j.appender.server=com.deepclone.lw.srv.LogAppender +log4j.appender.server.File=./server.log +log4j.appender.server.Threshold=DEBUG +log4j.appender.server.layout=org.apache.log4j.PatternLayout +log4j.appender.server.layout.ConversionPattern=%d{yyyy-MM-dd@HH:mm:ss} %5p - %m%n +log4j.appender.server.DatePattern='.'yyyy-MM-dd +log4j.appender.server.MaxNumberOfDays=30 +log4j.appender.server.CompressBackups = true + +log4j.appender.consoleError=org.apache.log4j.ConsoleAppender +log4j.appender.consoleError.Target=System.out +log4j.appender.consoleError.Threshold=WARN +log4j.appender.consoleError.layout=org.apache.log4j.PatternLayout +log4j.appender.consoleError.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + + +#log4j.logger.org.springframework=DEBUG, consoleError, fullDebug +#log4j.logger.org.hibernate=DEBUG, consoleError, fullDebug +#log4j.logger.com.deepclone.lw=DEBUG, stdout, fullDebug +#log4j.logger.com.deepclone.lw.interfaces.eventlog=TRACE, fullDebug, server + + +log4j.logger.org.springframework=WARN, server +log4j.logger.org.springframework=INFO, fullDebug +log4j.logger.com.deepclone.lw=DEBUG, fullDebug +log4j.logger.com.deepclone.lw.interfaces.eventlog=DEBUG, server diff --git a/legacyworlds-server/legacyworlds-server-main/src/main/resources/lw-server.xml b/legacyworlds-server/legacyworlds-server-main/src/main/resources/lw-server.xml new file mode 100644 index 0000000..40e41af --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-main/src/main/resources/lw-server.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-tests/.classpath b/legacyworlds-server/legacyworlds-server-tests/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-tests/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-tests/.project b/legacyworlds-server/legacyworlds-server-tests/.project new file mode 100644 index 0000000..076ecb4 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-tests/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-tests + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-tests/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..96c9dfc --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 09 10:20:32 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-tests/pom.xml b/legacyworlds-server/legacyworlds-server-tests/pom.xml new file mode 100644 index 0000000..ccf4b6b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-tests/pom.xml @@ -0,0 +1,77 @@ + + 4.0.0 + + legacyworlds-server + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-tests + Legacy Worlds server tests + 5.99.1 + This package regroups all tests for server capabilities. + + + + legacyworlds-server-beans-accounts + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-bt + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-eventlog + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-i18n + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-mailer + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-naming + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-simple + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-system + com.deepclone.lw + ${project.version} + + + legacyworlds-server-beans-user + com.deepclone.lw + ${project.version} + + + + junit + junit + ${junit.version} + test + + + org.springframework + spring-test + ${org.springframework.version} + test + + + + diff --git a/legacyworlds-server/legacyworlds-server-utils/.classpath b/legacyworlds-server/legacyworlds-server-utils/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-server/legacyworlds-server-utils/.project b/legacyworlds-server/legacyworlds-server-utils/.project new file mode 100644 index 0000000..fc174e7 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/.project @@ -0,0 +1,23 @@ + + + legacyworlds-server-utils + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-server/legacyworlds-server-utils/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-server/legacyworlds-server-utils/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..6939a66 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 09 10:20:36 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-server/legacyworlds-server-utils/pom.xml b/legacyworlds-server/legacyworlds-server-utils/pom.xml new file mode 100644 index 0000000..492a2e1 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + + legacyworlds-server + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-server-utils + 5.99.1 + Legacy Worlds server utility classes + This package contains utility classes used by various parts of the server-side code. + + + + com.deepclone.lw + legacyworlds-utils + ${project.version} + + + \ No newline at end of file diff --git a/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/Base64Serializer.java b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/Base64Serializer.java new file mode 100644 index 0000000..9b9bd5c --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/Base64Serializer.java @@ -0,0 +1,91 @@ +package com.deepclone.lw.utils; + + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import org.apache.commons.codec.binary.Base64; + + + +/** + * Helper class for serialisation to Base-64 and de-serialisation from Base-64. + * + * @author tseeker + */ +public final class Base64Serializer +{ + + /** Empty, private constructor that prevents instantiation */ + private Base64Serializer( ) + { + // EMPTY + } + + + /** + * Serialises an object and encodes it as Base-64. + * + * @param value + * object to serialise + * @return Base-64 encoded data resulting from the serialisation + */ + public static String encode( Serializable value ) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream( ); + ObjectOutputStream oos; + + try { + oos = new ObjectOutputStream( baos ); + try { + oos.writeObject( value ); + } finally { + try { + oos.close( ); + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + } + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + + return Base64.encodeBase64String( baos.toByteArray( ) ); + } + + + /** + * De-serialises an object from a Base-64 encoded string. + * + * @param data + * Base-64 encoded string containing the serialised object + * @return de-serialised object + */ + public static Serializable decode( String data ) + { + ByteArrayInputStream bais = new ByteArrayInputStream( Base64.decodeBase64( data ) ); + ObjectInputStream ois; + + try { + ois = new ObjectInputStream( bais ); + try { + return (Serializable) ois.readObject( ); + } catch ( ClassNotFoundException e ) { + throw new RuntimeException( e ); + } finally { + try { + ois.close( ); + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + } + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + } + +} diff --git a/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/EmailAddress.java b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/EmailAddress.java new file mode 100644 index 0000000..5f1a169 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/EmailAddress.java @@ -0,0 +1,78 @@ +package com.deepclone.lw.utils; + + +import java.util.regex.Pattern; + + + +/** + * This class provides e-mail address validation and sanitation. + * + * @author tseeker + */ +public class EmailAddress +{ + + // RFC 2822 2.2.2 Structured Header Field Bodies + private static final String wsp = "[ \\t]"; // space or tab + private static final String fwsp = wsp + "*"; + + // RFC 2822 3.2.1 Primitive tokens + private static final String dquote = "\\\""; + // ASCII Control characters excluding white space: + private static final String noWsCtl = "\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F"; + // all ASCII characters except CR and LF: + private static final String asciiText = "[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F]"; + + // RFC 2822 3.2.2 Quoted characters: + // single backslash followed by a text char + private static final String quotedPair = "(\\\\" + asciiText + ")"; + + // RFC 2822 3.2.4 Atom: + private static final String atext = "[a-zA-Z0-9\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\_\\`\\{\\|\\}\\~]"; + private static final String dotAtomText = atext + "+" + "(" + "\\." + atext + "+)*"; + private static final String dotAtom = fwsp + "(" + dotAtomText + ")" + fwsp; + + // RFC 2822 3.2.5 Quoted strings: + // noWsCtl and the rest of ASCII except the doublequote and backslash characters: + private static final String qtext = "[" + noWsCtl + "\\x21\\x23-\\x5B\\x5D-\\x7E]"; + private static final String qcontent = "(" + qtext + "|" + quotedPair + ")"; + private static final String quotedString = dquote + "(" + fwsp + qcontent + ")*" + fwsp + dquote; + + // RFC 1035 tokens for domain names: + private static final String letter = "[a-zA-Z]"; + private static final String letDig = "[a-zA-Z0-9]"; + private static final String letDigHyp = "[a-zA-Z0-9-]"; + private static final String rfcLabel = letDig + "(" + letDigHyp + "{0,61}" + letDig + ")?"; + private static final String domain = rfcLabel + "(\\." + rfcLabel + ")*\\." + letter + "{2,6}"; + + private static final String localPart = "((" + dotAtom + ")|(" + quotedString + "))"; + private static final String addrSpec = localPart + "@" + domain; + + /** The pattern used to validate email addresses */ + public static final Pattern VALID_PATTERN = Pattern.compile( addrSpec ); + + /** The sanitised version of the original e-mail address */ + private String cleanAddress; + + + /** Creates a sanitiser/validator from a string */ + public EmailAddress( String address ) + { + this.cleanAddress = address.toLowerCase( ).trim( ); + } + + + /** @return the sanitised version of the address */ + public String getAddress( ) + { + return this.cleanAddress; + } + + + /** @return whether the specified address is valid or not */ + public boolean isValid( ) + { + return VALID_PATTERN.matcher( this.cleanAddress ).matches( ); + } +} diff --git a/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/Password.java b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/Password.java new file mode 100644 index 0000000..c7e34e7 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/Password.java @@ -0,0 +1,110 @@ +package com.deepclone.lw.utils; + + +import java.util.regex.Pattern; + + + +/** + * This class provide password-related services, such as strength evaluation and hashing. + * + * @author tseeker + */ +public class Password +{ + + /** The various regular expressions used to evaluate a password's strength */ + private static final String regexps[] = { + "[a-z]" , "[A-Z]" , "\\d" , ".*\\d.+\\d.+\\d" , "[^a-zA-Z\\d]" , "[^a-zA-Z\\d].*[^a-zA-Z\\d]" , + "([a-zA-Z].*\\d)|(\\d.*[a-zA-Z])" , "([a-z].*[A-Z])|([A-Z].*[a-z])" , + "([^a-zA-Z\\d][a-zA-Z\\d])|([a-zA-Z\\d][^a-zA-Z\\d])" + }; + + /** The scores associated with each regular expression */ + private static final int reScores[] = { + 1 , 5 , 5 , 5 , 5 , 5 , 2 , 2 , 2 + }; + + /** Compiled regular expressions for strength evaluation */ + private static Pattern patterns[] = null; + + + /** + * This method makes sure that strength evaluation RE's have been compiled and can be used. + */ + private static void initPatterns( ) + { + synchronized ( Password.class ) { + if ( Password.patterns != null ) { + return; + } + + Password.patterns = new Pattern[ Password.regexps.length ]; + for ( int i = 0 ; i < Password.regexps.length ; i++ ) { + Password.patterns[ i ] = Pattern.compile( Password.regexps[ i ] ); + } + } + } + + /** The original password string */ + private String password; + + + /** Initialise the instance with a specific password string */ + public Password( String password ) + { + this.password = password; + } + + + /** @return the password's strength */ + public int getStrength( ) + { + return this.getLengthStrength( ) + this.getPatternStrength( ); + } + + + /** @return the password's SHA-1 hash (hex encoded) */ + public String getSha1( ) + { + return DigestHelper.digest( "sha-1" , this.password ); + } + + + /** @return the password's MD5 hash (hex encoded) */ + public String getMd5( ) + { + return DigestHelper.digest( "md5" , this.password ); + } + + + /** @return the password's strength based on regular expressions */ + private int getPatternStrength( ) + { + int strength = 0; + Password.initPatterns( ); + for ( int i = 0 ; i < Password.regexps.length ; i++ ) { + if ( Password.patterns[ i ].matcher( this.password ).find( ) ) { + strength += Password.reScores[ i ]; + } else { + } + } + return strength; + } + + + /** @return the password's strength based on length */ + private int getLengthStrength( ) + { + int len = this.password.length( ); + if ( len < 5 ) { + return 3; + } else if ( len < 8 ) { + return 6; + } else if ( len < 16 ) { + return 12; + } + return 18; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/RandomStringGenerator.java b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/RandomStringGenerator.java new file mode 100644 index 0000000..e48af15 --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/RandomStringGenerator.java @@ -0,0 +1,95 @@ +package com.deepclone.lw.utils; + + +import java.util.HashSet; +import java.util.Set; + + + +/** + * This class implements a random string generator, for use by stuff like validation tokens, planet + * names, etc. It can be used either directly or as a bean. + * + * @author tseeker + */ +public class RandomStringGenerator +{ + + /** The set of characters that can be used */ + private Character[] characters = { + '0' , '1' + }; + + /** The length of the stings to generate */ + private int length = 2; + + + /** + * Updates the instance's character set. + * + * @param characters + * a string that contains the new set of characters. + * @throws IllegalArgumentException + * if there are less than 2 characters in the set + */ + public void setCharacterSet( String characters ) + throws IllegalArgumentException + { + Set< Character > chSet = new HashSet< Character >( ); + for ( Character c : characters.toCharArray( ) ) { + chSet.add( c ); + } + + if ( chSet.size( ) < 2 ) { + throw new IllegalArgumentException( ); + } + + this.characters = chSet.toArray( new Character[ 1 ] ); + } + + + /** + * Sets the instance's string length. + * + * @param length + * the new string length + * @throws IllegalArgumentException + * if the specified length is lower than 2 + */ + public void setLength( int length ) + throws IllegalArgumentException + { + if ( length < 2 ) { + throw new IllegalArgumentException( ); + } + this.length = length; + } + + + /** + * Generates a random string. The string will have a fixed length and contain only characters + * from the generator's character set. + * + * @return the generated string + */ + public String generate( ) + { + String str = ""; + for ( int i = 0 ; i < this.length ; i++ ) { + str += this.getRandomChar( ); + } + return str; + } + + + /** + * @return a random character from the character set. + */ + private Character getRandomChar( ) + { + Double d = Math.random( ); + d *= this.characters.length; + return this.characters[ (int) Math.floor( d ) ]; + } + +} diff --git a/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/StoredProc.java b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/StoredProc.java new file mode 100644 index 0000000..9277a1b --- /dev/null +++ b/legacyworlds-server/legacyworlds-server-utils/src/main/java/com/deepclone/lw/utils/StoredProc.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.utils; + + +import java.sql.Types; +import java.util.Map; + +import javax.sql.DataSource; + +import org.springframework.jdbc.core.SqlOutParameter; +import org.springframework.jdbc.core.SqlParameter; +import org.springframework.jdbc.core.simple.SimpleJdbcCall; + + + +public class StoredProc +{ + + private SimpleJdbcCall storedProc; + + + public StoredProc( DataSource dataSource , String schema , String function ) + { + this.storedProc = new SimpleJdbcCall( dataSource ); + this.storedProc.withCatalogName( schema ).withFunctionName( function ); + this.storedProc.withoutProcedureColumnMetaDataAccess( ); + } + + + public StoredProc addParameter( String name , int sqlType ) + { + this.storedProc.addDeclaredParameter( new SqlParameter( name , sqlType ) ); + return this; + } + + + public StoredProc addParameter( String name , String typeName ) + { + this.storedProc.addDeclaredParameter( new SqlParameter( name , Types.OTHER , typeName ) ); + return this; + } + + + public StoredProc addOutput( String name , int sqlType ) + { + this.storedProc.addDeclaredParameter( new SqlOutParameter( name , sqlType ) ); + return this; + } + + + public Map< String , Object > execute( Object... args ) + { + return this.storedProc.execute( args ); + } +} diff --git a/legacyworlds-server/pom.xml b/legacyworlds-server/pom.xml new file mode 100644 index 0000000..db8aa26 --- /dev/null +++ b/legacyworlds-server/pom.xml @@ -0,0 +1,85 @@ + + 4.0.0 + + legacyworlds + com.deepclone.lw + 5.99.1 + + com.deepclone.lw + legacyworlds-server + Legacy Worlds server + 5.99.1 + pom + This metapackage is the root of the game server's components' code. + + + + + org.springframework + spring-core + ${org.springframework.version} + + + org.springframework + spring-context + ${org.springframework.version} + + + commons-logging + commons-logging + + + + + org.springframework + spring-jdbc + ${org.springframework.version} + + + + org.slf4j + jcl-over-slf4j + ${org.slf4j.version} + + + org.slf4j + slf4j-api + ${org.slf4j.version} + + + org.slf4j + slf4j-log4j12 + ${org.slf4j.version} + + + + log4j + log4j + ${log4j.version} + + + + commons-dbcp + commons-dbcp + ${commons.dbcp.version} + + + + cglib + cglib + ${cglib.version} + + + + + + legacyworlds-server-data + legacyworlds-server-beans + legacyworlds-server-tests + legacyworlds-server-interfaces + legacyworlds-server-utils + legacyworlds-server-main + + + \ No newline at end of file diff --git a/legacyworlds-session/.classpath b/legacyworlds-session/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-session/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-session/.project b/legacyworlds-session/.project new file mode 100644 index 0000000..a0b0b33 --- /dev/null +++ b/legacyworlds-session/.project @@ -0,0 +1,23 @@ + + + legacyworlds-session + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-session/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-session/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..8d7d4ea --- /dev/null +++ b/legacyworlds-session/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Tue Apr 13 16:03:03 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-session/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-session/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..83991fa --- /dev/null +++ b/legacyworlds-session/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Tue Apr 13 16:03:03 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-session/pom.xml b/legacyworlds-session/pom.xml new file mode 100644 index 0000000..3ea53f7 --- /dev/null +++ b/legacyworlds-session/pom.xml @@ -0,0 +1,16 @@ + + 4.0.0 + + legacyworlds + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-session + 5.99.1 + Legacy Worlds sessions + This module contains the definition of sessions used in client-server communications and all related classes and exceptions. + + \ No newline at end of file diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/CreateAuthChallengeCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/CreateAuthChallengeCommand.java new file mode 100644 index 0000000..3a6bbef --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/CreateAuthChallengeCommand.java @@ -0,0 +1,11 @@ +package com.deepclone.lw.cmd; + +import com.deepclone.lw.session.Command; + +public class CreateAuthChallengeCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/CreateAuthChallengeResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/CreateAuthChallengeResponse.java new file mode 100644 index 0000000..1e5ad58 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/CreateAuthChallengeResponse.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd; + + +import com.deepclone.lw.session.CommandResponse; + + + +public class CreateAuthChallengeResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final String challenge; + + + public CreateAuthChallengeResponse( String challenge ) + { + this.challenge = challenge; + } + + + public String getChallenge( ) + { + return this.challenge; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/MailError.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/MailError.java new file mode 100644 index 0000000..33c805c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/MailError.java @@ -0,0 +1,12 @@ +package com.deepclone.lw.cmd; + + +public enum MailError { + + EMPTY , + INVALID , + IN_USE , + SEND_FAIL , + MISMATCH + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/MaintenanceResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/MaintenanceResponse.java new file mode 100644 index 0000000..efe9995 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/MaintenanceResponse.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.cmd; + + +import java.sql.Timestamp; +import java.util.Date; + +import com.deepclone.lw.session.CommandResponse; + + + +public class MaintenanceResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final Timestamp start; + + private final Timestamp end; + + private final String reason; + + + public MaintenanceResponse( Timestamp start , Timestamp end , String reason ) + { + this.start = start; + this.end = end; + this.reason = reason; + } + + + public Timestamp getStart( ) + { + return start; + } + + + public Timestamp getEnd( ) + { + return end; + } + + + public String getReason( ) + { + return reason; + } + + + public boolean isLate( ) + { + return this.end.before( new Date( ) ); + } + + + public Timestamp getCurrent( ) + { + return new Timestamp( new Date( ).getTime( ) ); + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ObjectNameError.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ObjectNameError.java new file mode 100644 index 0000000..650e8fb --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ObjectNameError.java @@ -0,0 +1,11 @@ +package com.deepclone.lw.cmd; + + +public enum ObjectNameError { + + EMPTY , + UNAVAILABLE , + BANNED , + INVALID + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/PasswordError.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/PasswordError.java new file mode 100644 index 0000000..c376da2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/PasswordError.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.cmd; + + +public enum PasswordError { + + EMPTY , + TOO_WEAK , + MISMATCH + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminOverviewCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminOverviewCommand.java new file mode 100644 index 0000000..fa340fe --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminOverviewCommand.java @@ -0,0 +1,11 @@ +package com.deepclone.lw.cmd.admin; + +import com.deepclone.lw.session.Command; + +public class AdminOverviewCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminOverviewResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminOverviewResponse.java new file mode 100644 index 0000000..b292818 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminOverviewResponse.java @@ -0,0 +1,29 @@ +package com.deepclone.lw.cmd.admin; + + +import com.deepclone.lw.cmd.admin.adata.AdminOverview; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class AdminOverviewResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + private final AdminOverview overview; + + + public AdminOverviewResponse( Administrator admin , AdminOverview overview ) + { + super( admin ); + this.overview = overview; + } + + + public AdminOverview getOverview( ) + { + return overview; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminResponse.java new file mode 100644 index 0000000..7be1d55 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/AdminResponse.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.cmd.admin; + + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.session.CommandResponse; + + + +public class AdminResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final Administrator admin; + private final boolean privilegeOk; + + + public AdminResponse( Administrator admin ) + { + this.admin = admin; + this.privilegeOk = true; + } + + + public AdminResponse( Administrator admin , boolean priv ) + { + this.admin = admin; + this.privilegeOk = priv; + } + + + public Administrator getAdmin( ) + { + return admin; + } + + + public boolean isPrivilegeOk( ) + { + return privilegeOk; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/NoOperationCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/NoOperationCommand.java new file mode 100644 index 0000000..4765054 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/NoOperationCommand.java @@ -0,0 +1,35 @@ +package com.deepclone.lw.cmd.admin; + + +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.session.Command; + + + +public class NoOperationCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final Privileges requirePrivilege; + + + public NoOperationCommand( ) + { + this.requirePrivilege = null; + } + + + public NoOperationCommand( Privileges requirePrivilege ) + { + this.requirePrivilege = requirePrivilege; + } + + + public Privileges getRequirePrivilege( ) + { + return requirePrivilege; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/SetPasswordCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/SetPasswordCommand.java new file mode 100644 index 0000000..49eeb2f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/SetPasswordCommand.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.admin; + + +import com.deepclone.lw.session.Command; + + + +public class SetPasswordCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String sha1Auth; + private final String md5Auth; + private final String password; + private final String passwordConfirm; + + + public SetPasswordCommand( String sha1Auth , String md5Auth , String password , String passwordConfirm ) + { + this.sha1Auth = sha1Auth; + this.md5Auth = md5Auth; + this.password = password; + this.passwordConfirm = passwordConfirm; + } + + + public String getSha1Auth( ) + { + return sha1Auth; + } + + + public String getMd5Auth( ) + { + return md5Auth; + } + + + public String getPassword( ) + { + return password; + } + + + public String getPasswordConfirm( ) + { + return passwordConfirm; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/SetPasswordResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/SetPasswordResponse.java new file mode 100644 index 0000000..a4a429f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/SetPasswordResponse.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.cmd.admin; + + +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class SetPasswordResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + public static enum PasswordChangeStatus { + OK , + EMPTY , + TOO_WEAK , + MISMATCH , + PROHIBITED + } + + private final boolean authError; + private final PasswordChangeStatus passwordError; + + + public SetPasswordResponse( ) + { + super( null ); + this.authError = false; + this.passwordError = PasswordChangeStatus.OK; + } + + + public SetPasswordResponse( Administrator admin , boolean authError , PasswordChangeStatus changeStatus ) + { + super( admin ); + this.authError = authError; + this.passwordError = changeStatus; + } + + + public boolean isAuthError( ) + { + return authError; + } + + + public PasswordChangeStatus getPasswordError( ) + { + return passwordError; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/AdminOverview.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/AdminOverview.java new file mode 100644 index 0000000..4eb221b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/AdminOverview.java @@ -0,0 +1,106 @@ +package com.deepclone.lw.cmd.admin.adata; + + +import java.io.Serializable; + + + +public class AdminOverview + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int id; + private long newMessages; + private Long pendingNames; + private Long pendingBans; + private Long pendingBugs; + private Long openBugs; + private Long updatedBugs; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public long getNewMessages( ) + { + return newMessages; + } + + + public void setNewMessages( Long newMessages ) + { + this.newMessages = newMessages; + } + + + public Long getPendingNames( ) + { + return pendingNames; + } + + + public void setPendingNames( Long pendingNames ) + { + this.pendingNames = pendingNames; + } + + + public Long getPendingBans( ) + { + return pendingBans; + } + + + public void setPendingBans( Long pendingBans ) + { + this.pendingBans = pendingBans; + } + + + public Long getPendingBugs( ) + { + return pendingBugs; + } + + + public void setPendingBugs( Long pendingBugs ) + { + this.pendingBugs = pendingBugs; + } + + + public Long getOpenBugs( ) + { + return openBugs; + } + + + public void setOpenBugs( Long openBugs ) + { + this.openBugs = openBugs; + } + + + public Long getUpdatedBugs( ) + { + return updatedBugs; + } + + + public void setUpdatedBugs( Long updatedBugs ) + { + this.updatedBugs = updatedBugs; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/Administrator.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/Administrator.java new file mode 100644 index 0000000..19c3dbf --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/Administrator.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.cmd.admin.adata; + + +import java.util.List; + + + +public class Administrator + extends AdministratorBasics +{ + + private static final long serialVersionUID = 1L; + + private String address; + private boolean passwordChange; + + + public String getAddress( ) + { + return address; + } + + + public void setAddress( String address ) + { + this.address = address; + } + + + public void setPasswordChange( boolean passChangeRequired ) + { + this.passwordChange = passChangeRequired; + } + + + public boolean isPasswordChange( ) + { + return passwordChange; + } + + + public List< PrivEntry > getAllPrivileges( ) + { + return PrivEntry.fromPrivileges( this.privileges ); + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/AdministratorBasics.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/AdministratorBasics.java new file mode 100644 index 0000000..2f7342b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/AdministratorBasics.java @@ -0,0 +1,139 @@ +package com.deepclone.lw.cmd.admin.adata; + + +import java.io.Serializable; +import java.util.List; + + + +public class AdministratorBasics + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int id; + private String name; + protected int privileges; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public void setPrivileges( int privileges ) + { + this.privileges = privileges; + } + + + public boolean isSuperuser( ) + { + return Privileges.SUPER.hasPrivilege( this.privileges ); + } + + + public boolean isCanSpam( ) + { + return Privileges.SPAM.hasPrivilege( this.privileges ); + } + + + public boolean isTranslator( ) + { + return Privileges.I18N.hasPrivilege( this.privileges ); + } + + + public boolean isConstantsAdmin( ) + { + return Privileges.CNST.hasPrivilege( this.privileges ); + } + + + public boolean isUserAdmin( ) + { + return Privileges.USER.hasPrivilege( this.privileges ); + } + + + public boolean isBanhammerUser( ) + { + return Privileges.BANH.hasPrivilege( this.privileges ); + } + + + public boolean isTickAdmin( ) + { + return Privileges.TICK.hasPrivilege( this.privileges ); + } + + + public boolean isNameAdmin( ) + { + return Privileges.NAME.hasPrivilege( this.privileges ); + } + + + public boolean isPrefAdmin( ) + { + return Privileges.PREF.hasPrivilege( this.privileges ); + } + + + public boolean isCanViewLogs( ) + { + return Privileges.LOGS.hasPrivilege( this.privileges ); + } + + + public boolean isBugMailReceiver( ) + { + return Privileges.BUGM.hasPrivilege( this.privileges ); + } + + + public boolean isBugTrackerAdmin( ) + { + return Privileges.BUGT.hasPrivilege( this.privileges ); + } + + + public boolean isMaintenanceAdmin( ) + { + return Privileges.MNTM.hasPrivilege( this.privileges ); + } + + + public boolean hasPrivilege( Privileges priv ) + { + return priv.hasPrivilege( this.privileges ); + } + + + public List< Privileges > getPrivileges( ) + { + return Privileges.getPrivileges( this.privileges ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/PrivEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/PrivEntry.java new file mode 100644 index 0000000..82c496d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/PrivEntry.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.cmd.admin.adata; + + +import java.util.LinkedList; +import java.util.List; + + + +public class PrivEntry +{ + private final Privileges privilege; + private final boolean present; + + + private PrivEntry( Privileges priv , int uPriv ) + { + this.privilege = priv; + this.present = ( priv == Privileges.SUPER && priv.hasPrivilege( uPriv ) ) + || ( !Privileges.SUPER.hasPrivilege( uPriv ) && priv.hasPrivilege( uPriv ) ); + } + + + public Privileges getPrivilege( ) + { + return privilege; + } + + + public boolean isPresent( ) + { + return present; + } + + + public static List< PrivEntry > fromPrivileges( int privileges ) + { + List< PrivEntry > privs = new LinkedList< PrivEntry >( ); + for ( Privileges p : Privileges.values( ) ) { + privs.add( new PrivEntry( p , privileges ) ); + } + return privs; + + } +} \ No newline at end of file diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/Privileges.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/Privileges.java new file mode 100644 index 0000000..824fb65 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/adata/Privileges.java @@ -0,0 +1,71 @@ +package com.deepclone.lw.cmd.admin.adata; + + +import java.util.ArrayList; +import java.util.List; + + + +public enum Privileges { + + SPAM( 0x00000001 , "Sending in-game spam" ) , + I18N( 0x00000002 , "Managing translations" ) , + CNST( 0x00000004 , "Modifying game constants" ) , + USER( 0x00000008 , "Managing user accounts" ) , + BANH( 0x00000010 , "Using the banhammer" ) , + TICK( 0x00000020 , "Pausing/restarting server-side tasks" ) , + NAME( 0x00000040 , "Validating empire and planet names" ) , + PREF( 0x00000080 , "Setting default preferences" ) , + LOGS( 0x00000100 , "Browsing server logs" ) , + BUGM( 0x00000200 , "Receiving automated error e-mail" ) , + BUGT( 0x00000400 , "Managing bugs reported through the bug tracker" ) , + MNTM( 0x00000800 , "Activating/disabling maintenance mode" ) , + SUPER( 0x80000000 , "Superuser (all privileges + admin management)" ); + + private final int bits; + private final String description; + + + private Privileges( int bits , String description ) + { + this.bits = bits; + this.description = description; + } + + + public int getBits( ) + { + return bits; + } + + + public String getDescription( ) + { + return description; + } + + + public boolean hasPrivilege( int privs ) + { + return ( privs & this.bits ) != 0 || ( privs & 0x80000000 ) != 0; + } + + + public static List< Privileges > getPrivileges( int privs ) + { + List< Privileges > result = new ArrayList< Privileges >( ); + for ( Privileges p : Privileges.values( ) ) { + if ( p.hasPrivilege( privs ) ) { + result.add( p ); + } + } + return result; + } + + + public int grant( int privileges ) + { + return privileges | this.bits; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ArchivedBanRequest.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ArchivedBanRequest.java new file mode 100644 index 0000000..d04e0ce --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ArchivedBanRequest.java @@ -0,0 +1,80 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import java.sql.Timestamp; + + + +public class ArchivedBanRequest + extends BanRequest +{ + + private static final long serialVersionUID = 1L; + + private Timestamp update; + private boolean expired; + private Integer rejectedById; + private String rejectedByName; + private String rejectionReason; + + + public Timestamp getUpdate( ) + { + return update; + } + + + public void setUpdate( Timestamp update ) + { + this.update = update; + } + + + public boolean isExpired( ) + { + return expired; + } + + + public void setExpired( boolean expired ) + { + this.expired = expired; + } + + + public Integer getRejectedById( ) + { + return rejectedById; + } + + + public void setRejectedById( Integer rejectedById ) + { + this.rejectedById = rejectedById; + } + + + public String getRejectedByName( ) + { + return rejectedByName; + } + + + public void setRejectedByName( String rejectedByName ) + { + this.rejectedByName = rejectedByName; + } + + + public String getRejectionReason( ) + { + return rejectionReason; + } + + + public void setRejectionReason( String rejectionReason ) + { + this.rejectionReason = rejectionReason; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BanRequest.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BanRequest.java new file mode 100644 index 0000000..dee4b52 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BanRequest.java @@ -0,0 +1,107 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public class BanRequest + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int id; + private int requestedById; + private String requestedByName; + private String reason; + private Timestamp timestamp; + private int accountId; + private String accountMail; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public int getRequestedById( ) + { + return requestedById; + } + + + public void setRequestedById( int requestedById ) + { + this.requestedById = requestedById; + } + + + public String getRequestedByName( ) + { + return requestedByName; + } + + + public void setRequestedByName( String requestedByName ) + { + this.requestedByName = requestedByName; + } + + + public String getReason( ) + { + return reason; + } + + + public void setReason( String reason ) + { + this.reason = reason; + } + + + public Timestamp getTimestamp( ) + { + return timestamp; + } + + + public void setTimestamp( Timestamp timestamp ) + { + this.timestamp = timestamp; + } + + + public int getAccountId( ) + { + return accountId; + } + + + public void setAccountId( int accountId ) + { + this.accountId = accountId; + } + + + public String getAccountMail( ) + { + return accountMail; + } + + + public void setAccountMail( String accountMail ) + { + this.accountMail = accountMail; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BanType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BanType.java new file mode 100644 index 0000000..fa2e744 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BanType.java @@ -0,0 +1,8 @@ +package com.deepclone.lw.cmd.admin.bans; + + +public enum BanType { + PENDING , + ARCHIVED , + VALIDATED +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BansSummaryCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BansSummaryCommand.java new file mode 100644 index 0000000..6b54955 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BansSummaryCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import com.deepclone.lw.session.Command; + + + +public class BansSummaryCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BansSummaryResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BansSummaryResponse.java new file mode 100644 index 0000000..9cfe672 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/BansSummaryResponse.java @@ -0,0 +1,39 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class BansSummaryResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final List< SummaryEntry > entries; + + + public BansSummaryResponse( Administrator admin ) + { + super( admin , false ); + this.entries = null; + } + + + public BansSummaryResponse( Administrator admin , List< SummaryEntry > entries ) + { + super( admin ); + this.entries = entries; + } + + + public List< SummaryEntry > getEntries( ) + { + return entries; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ConfirmBanCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ConfirmBanCommand.java new file mode 100644 index 0000000..3ff608c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ConfirmBanCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import com.deepclone.lw.session.Command; + + + +public class ConfirmBanCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int id; + + + public ConfirmBanCommand( int id ) + { + this.id = id; + } + + + public int getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/LiftBanCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/LiftBanCommand.java new file mode 100644 index 0000000..24f2067 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/LiftBanCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import com.deepclone.lw.session.Command; + + + +public class LiftBanCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int id; + + + public LiftBanCommand( int id ) + { + this.id = id; + } + + + public int getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ListBansCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ListBansCommand.java new file mode 100644 index 0000000..1ba7c91 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ListBansCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import com.deepclone.lw.session.Command; + + + +public class ListBansCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final BanType type; + + + public ListBansCommand( BanType type ) + { + this.type = type; + } + + + public BanType getType( ) + { + return type; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ListBansResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ListBansResponse.java new file mode 100644 index 0000000..c956cec --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ListBansResponse.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ListBansResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final BanType type; + private final List< BanRequest > bans; + + + public ListBansResponse( Administrator admin ) + { + super( admin , false ); + this.type = null; + this.bans = null; + } + + + public ListBansResponse( Administrator admin , BanType type , List< BanRequest > bans ) + { + super( admin ); + this.type = type; + this.bans = bans; + } + + + public BanType getType( ) + { + return type; + } + + + public List< BanRequest > getBans( ) + { + return bans; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RejectBanCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RejectBanCommand.java new file mode 100644 index 0000000..1e5e56b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RejectBanCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import com.deepclone.lw.session.Command; + + + +public class RejectBanCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int id; + private final String reason; + + + public RejectBanCommand( int id , String reason ) + { + this.id = id; + this.reason = reason; + } + + + public int getId( ) + { + return id; + } + + + public String getReason( ) + { + return reason; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RejectBanResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RejectBanResponse.java new file mode 100644 index 0000000..caa0a1e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RejectBanResponse.java @@ -0,0 +1,45 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class RejectBanResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + private final boolean error; + private final int id; + + + public RejectBanResponse( Administrator admin , boolean privError ) + { + super( admin , !privError ); + this.error = false; + this.id = 0; + } + + + public RejectBanResponse( Administrator admin , int requestId ) + { + super( admin ); + this.error = true; + this.id = requestId; + } + + + public boolean isError( ) + { + return error; + } + + + public int getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RequestBanCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RequestBanCommand.java new file mode 100644 index 0000000..8f6e882 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RequestBanCommand.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import com.deepclone.lw.session.Command; + + + +public class RequestBanCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String user; + private final boolean empire; + private final String reason; + + + public RequestBanCommand( String user , boolean empire , String reason ) + { + this.user = user; + this.empire = empire; + this.reason = reason; + } + + + public String getUser( ) + { + return user; + } + + + public boolean isEmpire( ) + { + return empire; + } + + + public String getReason( ) + { + return reason; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RequestBanResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RequestBanResponse.java new file mode 100644 index 0000000..8637681 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/RequestBanResponse.java @@ -0,0 +1,70 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class RequestBanResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + public static enum Error { + NOT_FOUND , + BANNED , + NO_REASON + } + + private final Error error; + private final String user; + private final boolean empire; + private final String reason; + + + public RequestBanResponse( Administrator admin , boolean privError ) + { + super( admin , !privError ); + this.error = null; + this.user = null; + this.empire = false; + this.reason = null; + } + + + public RequestBanResponse( Administrator admin , Error error , String user , boolean empire , String reason ) + { + super( admin ); + this.error = error; + this.user = user; + this.empire = empire; + this.reason = reason; + } + + + public Error getError( ) + { + return error; + } + + + public String getUser( ) + { + return user; + } + + + public boolean isEmpire( ) + { + return empire; + } + + + public String getReason( ) + { + return reason; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/SummaryEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/SummaryEntry.java new file mode 100644 index 0000000..0fcfa02 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/SummaryEntry.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import java.io.Serializable; + + + +public class SummaryEntry + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final BanType type; + private final long count; + + + public SummaryEntry( BanType type , long count ) + { + this.type = type; + this.count = count; + } + + + public BanType getType( ) + { + return type; + } + + + public long getCount( ) + { + return count; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ValidatedBanRequest.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ValidatedBanRequest.java new file mode 100644 index 0000000..dfa6945 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bans/ValidatedBanRequest.java @@ -0,0 +1,67 @@ +package com.deepclone.lw.cmd.admin.bans; + + +import java.sql.Timestamp; + + + +public class ValidatedBanRequest + extends BanRequest +{ + + private static final long serialVersionUID = 1L; + + private Timestamp update; + private boolean redeemable; + private int validatedById; + private String validatedByName; + + + public Timestamp getUpdate( ) + { + return update; + } + + + public void setUpdate( Timestamp update ) + { + this.update = update; + } + + + public boolean isRedeemable( ) + { + return redeemable; + } + + + public void setRedeemable( boolean redeemable ) + { + this.redeemable = redeemable; + } + + + public int getValidatedById( ) + { + return validatedById; + } + + + public void setValidatedById( int validatedById ) + { + this.validatedById = validatedById; + } + + + public String getValidatedByName( ) + { + return validatedByName; + } + + + public void setValidatedByName( String validatedByName ) + { + this.validatedByName = validatedByName; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/BugsSummaryCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/BugsSummaryCommand.java new file mode 100644 index 0000000..d5846a0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/BugsSummaryCommand.java @@ -0,0 +1,12 @@ +package com.deepclone.lw.cmd.admin.bt; + +import com.deepclone.lw.session.Command; + + +public class BugsSummaryCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/BugsSummaryResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/BugsSummaryResponse.java new file mode 100644 index 0000000..c399f41 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/BugsSummaryResponse.java @@ -0,0 +1,73 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class BugsSummaryResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final long pending; + private final long open; + private final long own; + private final long updated; + private final long total; + + + public BugsSummaryResponse( Administrator admin ) + { + super( admin , false ); + this.pending = 0; + this.open = 0; + this.own = 0; + this.updated = 0; + this.total = 0; + } + + + public BugsSummaryResponse( Administrator admin , long pending , long open , long own , long updated , long total ) + { + super( admin ); + this.pending = pending; + this.open = open; + this.own = own; + this.updated = updated; + this.total = total; + } + + + public long getPending( ) + { + return pending; + } + + + public long getOpen( ) + { + return open; + } + + + public long getOwn( ) + { + return own; + } + + + public long getUpdated( ) + { + return updated; + } + + + public long getTotal( ) + { + return total; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/GetSnapshotCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/GetSnapshotCommand.java new file mode 100644 index 0000000..9aa671a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/GetSnapshotCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.session.Command; + + + +public class GetSnapshotCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long bugId; + + + public GetSnapshotCommand( long bugId ) + { + this.bugId = bugId; + } + + + public long getBugId( ) + { + return bugId; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/GetSnapshotResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/GetSnapshotResponse.java new file mode 100644 index 0000000..439c768 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/GetSnapshotResponse.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class GetSnapshotResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final String snapshot; + + + public GetSnapshotResponse( Administrator admin , boolean privError ) + { + super( admin , !privError ); + this.snapshot = null; + } + + + public GetSnapshotResponse( Administrator admin , String snapshot ) + { + super( admin ); + this.snapshot = snapshot; + } + + + public String getSnapshot( ) + { + return snapshot; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ListBugsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ListBugsResponse.java new file mode 100644 index 0000000..4975ab8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ListBugsResponse.java @@ -0,0 +1,87 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.bt.data.BugReport; +import com.deepclone.lw.cmd.bt.data.BugStatus; + + + +public class ListBugsResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final BugStatus status; + private final boolean ownOnly; + private final long first; + private final int count; + private final long entries; + private final List< BugReport > reports; + + + public ListBugsResponse( Administrator admin ) + { + super( admin , false ); + this.status = null; + this.ownOnly = false; + this.first = 0; + this.count = 0; + this.entries = 0; + this.reports = null; + } + + + public ListBugsResponse( Administrator admin , BugStatus status , boolean ownOnly , long first , int count , + long entries , List< BugReport > reports ) + { + super( admin ); + this.status = status; + this.ownOnly = ownOnly; + this.first = first; + this.count = count; + this.entries = entries; + this.reports = reports; + } + + + public BugStatus getStatus( ) + { + return status; + } + + + public boolean isOwnOnly( ) + { + return ownOnly; + } + + + public long getFirst( ) + { + return first; + } + + + public int getCount( ) + { + return count; + } + + + public long getEntries( ) + { + return entries; + } + + + public List< BugReport > getReports( ) + { + return reports; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeError.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeError.java new file mode 100644 index 0000000..bd05c3c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeError.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.cmd.admin.bt; + + +public enum MergeError { + + NOT_FOUND , + MERGED , + STATUS + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeReportsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeReportsCommand.java new file mode 100644 index 0000000..f95de2f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeReportsCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.session.Command; + + + +public class MergeReportsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long id1; + private final long id2; + + + public MergeReportsCommand( long id1 , long id2 ) + { + this.id1 = id1; + this.id2 = id2; + } + + + public long getId1( ) + { + return id1; + } + + + public long getId2( ) + { + return id2; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeReportsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeReportsResponse.java new file mode 100644 index 0000000..aedcc55 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/MergeReportsResponse.java @@ -0,0 +1,66 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.bt.data.BugEvent; +import com.deepclone.lw.cmd.bt.data.BugReport; + + + +public class MergeReportsResponse + extends ViewBugResponse +{ + + private static final long serialVersionUID = 1L; + + private final MergeError mergeError; + private final long mergeId; + + + public MergeReportsResponse( Administrator admin ) + { + super( admin , false ); + this.mergeError = null; + this.mergeId = 0; + } + + + public MergeReportsResponse( Administrator admin , boolean privError ) + { + super( admin , privError ); + this.mergeError = MergeError.NOT_FOUND; + this.mergeId = 0; + } + + + public MergeReportsResponse( Administrator admin , BugReport report , List< BugEvent > events , + MergeError mergeError , long mergeId ) + { + super( admin , report , events ); + this.mergeError = mergeError; + this.mergeId = mergeId; + } + + + public MergeReportsResponse( MergeReportsResponse response , Object query ) + { + super( response , query ); + this.mergeError = response.mergeError; + this.mergeId = response.mergeId; + } + + + public MergeError getMergeError( ) + { + return mergeError; + } + + + public long getMergeId( ) + { + return mergeId; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ModerateCommentCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ModerateCommentCommand.java new file mode 100644 index 0000000..f648c86 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ModerateCommentCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.session.Command; + + + +public class ModerateCommentCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long id; + private final boolean validation; + + + public ModerateCommentCommand( long id , boolean validate ) + { + this.id = id; + this.validation = validate; + } + + + public long getId( ) + { + return id; + } + + + public boolean isValidation( ) + { + return validation; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/PostCommentResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/PostCommentResponse.java new file mode 100644 index 0000000..13a97f0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/PostCommentResponse.java @@ -0,0 +1,92 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import java.util.List; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.bt.data.BugEvent; +import com.deepclone.lw.cmd.bt.data.BugReport; + + + +public class PostCommentResponse + extends ViewBugResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean posted; + private final ObjectNameError commentError; + private final String comment; + private final boolean publicComment; + + + /** "Post comment" response indicating a successful post */ + public PostCommentResponse( Administrator admin ) + { + super( admin , false ); + this.posted = true; + this.comment = null; + this.commentError = null; + this.publicComment = false; + } + + + /** "Post comment" response indicating a missing report or privilege error */ + public PostCommentResponse( Administrator admin , boolean privError ) + { + super( admin , privError ); + this.posted = false; + this.comment = null; + this.commentError = null; + this.publicComment = false; + } + + + /** "Post comment" response indicating a comment error */ + public PostCommentResponse( Administrator admin , BugReport report , List< BugEvent > events , + ObjectNameError error , String comment , boolean publicComment ) + { + super( admin , report , events ); + this.posted = false; + this.commentError = error; + this.comment = comment; + this.publicComment = publicComment; + } + + + public PostCommentResponse( PostCommentResponse response , Object query ) + { + super( response , query ); + this.posted = false; + this.commentError = response.commentError; + this.comment = response.comment; + this.publicComment = response.publicComment; + } + + + public boolean isPosted( ) + { + return posted; + } + + + public ObjectNameError getCommentError( ) + { + return commentError; + } + + + public String getComment( ) + { + return comment; + } + + + public boolean isPublicComment( ) + { + return publicComment; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportBugResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportBugResponse.java new file mode 100644 index 0000000..3231103 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportBugResponse.java @@ -0,0 +1,119 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ReportBugResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final long bugId; + private final ObjectNameError titleError; + private final String title; + private final ObjectNameError descriptionError; + private final String description; + private final boolean publicReport; + private final Object query; + + + public ReportBugResponse( Administrator admin ) + { + super( admin , false ); + this.bugId = 0; + this.titleError = null; + this.title = null; + this.descriptionError = null; + this.description = null; + this.publicReport = false; + this.query = null; + } + + + public ReportBugResponse( Administrator admin , long bugId ) + { + super( admin ); + this.bugId = bugId; + this.titleError = null; + this.title = null; + this.descriptionError = null; + this.description = null; + this.publicReport = false; + this.query = null; + } + + + public ReportBugResponse( Administrator admin , ObjectNameError titleError , String title , + ObjectNameError descriptionError , String description , boolean publicReport ) + { + super( admin ); + this.bugId = 0; + this.titleError = titleError; + this.title = title; + this.descriptionError = descriptionError; + this.description = description; + this.publicReport = publicReport; + this.query = null; + } + + + public ReportBugResponse( ReportBugResponse response , Object query ) + { + super( response.getAdmin( ) , response.isPrivilegeOk( ) ); + this.bugId = 0; + this.titleError = response.titleError; + this.title = response.title; + this.descriptionError = response.descriptionError; + this.description = response.description; + this.publicReport = response.publicReport; + this.query = query; + } + + + public long getBugId( ) + { + return bugId; + } + + + public ObjectNameError getTitleError( ) + { + return titleError; + } + + + public String getTitle( ) + { + return title; + } + + + public ObjectNameError getDescriptionError( ) + { + return descriptionError; + } + + + public String getDescription( ) + { + return description; + } + + + public boolean isPublicReport( ) + { + return publicReport; + } + + + public Object getQuery( ) + { + return query; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportStatusCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportStatusCommand.java new file mode 100644 index 0000000..2f7ee85 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportStatusCommand.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.session.Command; + + + +public class ReportStatusCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long id; + private final BugStatus status; + + + public ReportStatusCommand( long id , BugStatus status ) + { + this.id = id; + this.status = status; + } + + + public long getId( ) + { + return id; + } + + + public BugStatus getStatus( ) + { + return status; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportVisibilityCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportVisibilityCommand.java new file mode 100644 index 0000000..04d82c1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ReportVisibilityCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.session.Command; + + + +public class ReportVisibilityCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long id; + + + public ReportVisibilityCommand( long id ) + { + this.id = id; + } + + + public long getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ValidateReportCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ValidateReportCommand.java new file mode 100644 index 0000000..704c018 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ValidateReportCommand.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.session.Command; + + + +public class ValidateReportCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long id; + private final BugStatus status; + private final boolean publicReport; + private final int grantCredits; + private final boolean snapshot; + + + public ValidateReportCommand( long id , BugStatus status , boolean publicReport , int grantCredits , + boolean snapshot ) + { + this.id = id; + this.status = status; + this.publicReport = publicReport; + this.grantCredits = grantCredits; + this.snapshot = snapshot; + } + + + public long getId( ) + { + return id; + } + + + public BugStatus getStatus( ) + { + return status; + } + + + public boolean isPublicReport( ) + { + return publicReport; + } + + + public int getGrantCredits( ) + { + return grantCredits; + } + + + public boolean isSnapshot( ) + { + return snapshot; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ViewBugResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ViewBugResponse.java new file mode 100644 index 0000000..eccb9d5 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/bt/ViewBugResponse.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.cmd.admin.bt; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.bt.data.BugEvent; +import com.deepclone.lw.cmd.bt.data.BugReport; + + + +public class ViewBugResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final BugReport report; + private final List< BugEvent > events; + private final Object query; + + + public ViewBugResponse( Administrator admin , boolean privError ) + { + super( admin , !privError ); + this.report = null; + this.events = null; + this.query = null; + } + + + public ViewBugResponse( Administrator admin , BugReport report , List< BugEvent > events ) + { + super( admin ); + this.report = report; + this.events = events; + this.query = null; + } + + + public ViewBugResponse( ViewBugResponse response , Object query ) + { + super( response.getAdmin( ) ); + this.report = response.report; + this.events = response.events; + this.query = query; + } + + + public BugReport getReport( ) + { + return report; + } + + + public List< BugEvent > getEvents( ) + { + return events; + } + + + public Object getQuery( ) + { + return query; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/Category.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/Category.java new file mode 100644 index 0000000..774a70a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/Category.java @@ -0,0 +1,49 @@ +package com.deepclone.lw.cmd.admin.constants; + + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + + + +public class Category + implements Serializable , Comparable< Category > +{ + + private static final long serialVersionUID = 1L; + + private final String name; + private final List< Definition > definitions; + + + public Category( String name , List< Definition > defs ) + { + this.name = name; + this.definitions = defs; + Collections.sort( defs ); + } + + + @Override + public int compareTo( Category other ) + { + if ( other == null ) { + return 1; + } + return this.name.compareTo( other.name ); + } + + + public String getName( ) + { + return name; + } + + + public List< Definition > getDefinitions( ) + { + return definitions; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/Definition.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/Definition.java new file mode 100644 index 0000000..7115438 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/Definition.java @@ -0,0 +1,90 @@ +package com.deepclone.lw.cmd.admin.constants; + + +import java.io.Serializable; + + + +public class Definition + implements Serializable , Comparable< Definition > +{ + + private static final long serialVersionUID = 1L; + + private String name; + private String description; + private double value; + private Double minValue; + private Double maxValue; + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getDescription( ) + { + return description; + } + + + public void setDescription( String description ) + { + this.description = description; + } + + + public double getValue( ) + { + return value; + } + + + public void setValue( double value ) + { + this.value = value; + } + + + public Double getMinValue( ) + { + return minValue; + } + + + public void setMinValue( Double minValue ) + { + this.minValue = minValue; + } + + + public Double getMaxValue( ) + { + return maxValue; + } + + + public void setMaxValue( Double maxValue ) + { + this.maxValue = maxValue; + } + + + @Override + public int compareTo( Definition other ) + { + if ( other == null ) { + return 1; + } + return this.name.compareTo( other.name ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/GetConstantsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/GetConstantsCommand.java new file mode 100644 index 0000000..93920a5 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/GetConstantsCommand.java @@ -0,0 +1,11 @@ +package com.deepclone.lw.cmd.admin.constants; + +import com.deepclone.lw.session.Command; + +public class GetConstantsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/GetConstantsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/GetConstantsResponse.java new file mode 100644 index 0000000..a31d96f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/GetConstantsResponse.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.cmd.admin.constants; + + +import java.util.Collections; +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class GetConstantsResponse + extends AdminResponse +{ + private static final long serialVersionUID = 1L; + private List< Category > categories; + + + public GetConstantsResponse( Administrator admin ) + { + super( admin , false ); + } + + + public GetConstantsResponse( Administrator admin , List< Category > constants ) + { + super( admin , true ); + this.categories = constants; + Collections.sort( this.categories ); + } + + + protected GetConstantsResponse( Administrator admin , boolean error ) + { + super( admin , !error ); + } + + + public List< Category > getCategories( ) + { + return this.categories; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/SetConstantCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/SetConstantCommand.java new file mode 100644 index 0000000..d2efe93 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/SetConstantCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.constants; + + +import com.deepclone.lw.session.Command; + + + +public class SetConstantCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String name; + private final double value; + + + public SetConstantCommand( String name , double value ) + { + this.name = name; + this.value = value; + } + + + public String getName( ) + { + return name; + } + + + public double getValue( ) + { + return value; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/SetConstantResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/SetConstantResponse.java new file mode 100644 index 0000000..cec5d9c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/constants/SetConstantResponse.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.cmd.admin.constants; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class SetConstantResponse + extends GetConstantsResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean error; + private final String name; + private final double value; + + + public SetConstantResponse( Administrator admin , boolean privError ) + { + super( admin , privError ); + this.error = false; + this.name = null; + this.value = 0; + } + + + public SetConstantResponse( Administrator admin , List< Category > cats , String name , double value ) + { + super( admin , cats ); + this.error = true; + this.name = name; + this.value = value; + } + + + public boolean isError( ) + { + return error; + } + + + public String getName( ) + { + return name; + } + + + public double getValue( ) + { + return value; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ChangeLanguageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ChangeLanguageCommand.java new file mode 100644 index 0000000..9882fd5 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ChangeLanguageCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import com.deepclone.lw.session.Command; + + + +public class ChangeLanguageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String id; + private final String name; + + + public ChangeLanguageCommand( String id , String name ) + { + this.id = id; + this.name = name; + } + + + public String getId( ) + { + return id; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ChangeLanguageResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ChangeLanguageResponse.java new file mode 100644 index 0000000..fd23d8e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ChangeLanguageResponse.java @@ -0,0 +1,45 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ChangeLanguageResponse + extends GetLanguageResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean nameError; + + + public ChangeLanguageResponse( Administrator admin , Language language , List< I18NString > strings ) + { + super( admin , language , strings ); + this.nameError = true; + } + + + public ChangeLanguageResponse( Administrator admin , Language language ) + { + super( admin , language , null ); + this.nameError = false; + } + + + public ChangeLanguageResponse( Administrator admin ) + { + super( admin ); + this.nameError = false; + } + + + public boolean isNameError( ) + { + return nameError; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/GetLanguageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/GetLanguageCommand.java new file mode 100644 index 0000000..9ed73bb --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/GetLanguageCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import com.deepclone.lw.session.Command; + + + +public class GetLanguageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String language; + + + public GetLanguageCommand( String language ) + { + this.language = language; + } + + + public String getLanguage( ) + { + return language; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/GetLanguageResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/GetLanguageResponse.java new file mode 100644 index 0000000..68cbe5a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/GetLanguageResponse.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import java.util.Collections; +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class GetLanguageResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final Language language; + private final List< I18NString > strings; + + + public GetLanguageResponse( Administrator admin ) + { + super( admin , false ); + this.language = null; + this.strings = null; + } + + + public GetLanguageResponse( Administrator admin , Language language , List< I18NString > strings ) + { + super( admin , true ); + this.language = language; + this.strings = strings; + if ( strings != null ) { + Collections.sort( this.strings ); + } + } + + + public Language getLanguage( ) + { + return language; + } + + + public List< I18NString > getStrings( ) + { + return strings; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/I18NString.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/I18NString.java new file mode 100644 index 0000000..06ada37 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/I18NString.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import java.io.Serializable; + + + +public class I18NString + implements Serializable , Comparable< I18NString > +{ + + private static final long serialVersionUID = 1L; + + private final String id; + private final String text; + + + public I18NString( String id , String text ) + { + this.id = id; + this.text = text; + } + + + public String getId( ) + { + return id; + } + + + public String getText( ) + { + return text; + } + + + @Override + public int compareTo( I18NString other ) + { + if ( other == null ) { + return 1; + } + return this.id.compareTo( other.id ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/Language.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/Language.java new file mode 100644 index 0000000..6258920 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/Language.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import java.io.Serializable; + + + +public class Language + implements Serializable , Comparable< Language > +{ + + private static final long serialVersionUID = 1L; + + private String id; + private String name; + private int completion; + + + public String getId( ) + { + return id; + } + + + public void setId( String id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public int getCompletion( ) + { + return completion; + } + + + public void setCompletion( int completion ) + { + this.completion = completion; + } + + + @Override + public int compareTo( Language other ) + { + if ( other == null ) { + return 1; + } + return this.id.compareTo( other.id ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/SetStringCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/SetStringCommand.java new file mode 100644 index 0000000..8cff779 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/SetStringCommand.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import com.deepclone.lw.session.Command; + + + +public class SetStringCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String language; + private final String id; + private final String text; + + + public SetStringCommand( String language , String id , String text ) + { + this.language = language; + this.id = id; + this.text = text; + } + + + public String getLanguage( ) + { + return language; + } + + + public String getId( ) + { + return id; + } + + + public String getText( ) + { + return text; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/SetStringResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/SetStringResponse.java new file mode 100644 index 0000000..5b3af0f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/SetStringResponse.java @@ -0,0 +1,45 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class SetStringResponse + extends GetLanguageResponse +{ + + private static final long serialVersionUID = 1L; + + private final String edited; + + + public SetStringResponse( Administrator admin ) + { + super( admin ); + this.edited = null; + } + + + public SetStringResponse( Administrator admin , Language language , List< I18NString > strings , String edited ) + { + super( admin , language , strings ); + this.edited = edited; + } + + + public SetStringResponse( Administrator admin , Language language ) + { + super( admin , language , null ); + this.edited = null; + } + + + public String getEdited( ) + { + return edited; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ViewLanguagesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ViewLanguagesCommand.java new file mode 100644 index 0000000..5a22e75 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ViewLanguagesCommand.java @@ -0,0 +1,12 @@ +package com.deepclone.lw.cmd.admin.i18n; + +import com.deepclone.lw.session.Command; + + +public class ViewLanguagesCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ViewLanguagesResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ViewLanguagesResponse.java new file mode 100644 index 0000000..96e66cf --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/i18n/ViewLanguagesResponse.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.cmd.admin.i18n; + + +import java.util.Collections; +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ViewLanguagesResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final List< Language > languages; + + + public ViewLanguagesResponse( Administrator admin ) + { + super( admin , false ); + this.languages = null; + } + + + public ViewLanguagesResponse( Administrator admin , List< Language > languages ) + { + super( admin , true ); + this.languages = languages; + Collections.sort( this.languages ); + } + + + public List< Language > getLanguages( ) + { + return languages; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ExceptionEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ExceptionEntry.java new file mode 100644 index 0000000..55d4aa3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ExceptionEntry.java @@ -0,0 +1,50 @@ +package com.deepclone.lw.cmd.admin.logs; + + +import java.io.Serializable; +import java.util.List; + + + +public class ExceptionEntry + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final String className; + private final String message; + private List< TraceEntry > trace; + + + public ExceptionEntry( String className , String message ) + { + this.className = className; + this.message = message; + } + + + public String getClassName( ) + { + return className; + } + + + public String getMessage( ) + { + return message; + } + + + public List< TraceEntry > getTrace( ) + { + return trace; + } + + + public void setTrace( List< TraceEntry > trace ) + { + this.trace = trace; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/GetEntryCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/GetEntryCommand.java new file mode 100644 index 0000000..c07f7c9 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/GetEntryCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.logs; + + +import com.deepclone.lw.session.Command; + + + +public class GetEntryCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long id; + + + public GetEntryCommand( long id ) + { + this.id = id; + } + + + public long getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/GetEntryResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/GetEntryResponse.java new file mode 100644 index 0000000..8d20250 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/GetEntryResponse.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.cmd.admin.logs; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class GetEntryResponse + extends AdminResponse +{ + private static final long serialVersionUID = 1L; + + private final LogEntry entry; + private final List< ExceptionEntry > exceptions; + + + public GetEntryResponse( Administrator admin , boolean privError ) + { + super( admin , !privError ); + this.entry = null; + this.exceptions = null; + } + + + public GetEntryResponse( Administrator admin , LogEntry entry , List< ExceptionEntry > exceptions ) + { + super( admin ); + this.entry = entry; + this.exceptions = exceptions; + } + + + public LogEntry getEntry( ) + { + return entry; + } + + + public List< ExceptionEntry > getExceptions( ) + { + return exceptions; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogEntry.java new file mode 100644 index 0000000..f203bb6 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogEntry.java @@ -0,0 +1,94 @@ +package com.deepclone.lw.cmd.admin.logs; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public class LogEntry + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private Long id; + private Timestamp timestamp; + private LogLevel level; + private String about; + private String entry; + private Long exception; + + + public Long getId( ) + { + return id; + } + + + public void setId( Long id ) + { + this.id = id; + } + + + public Timestamp getTimestamp( ) + { + return timestamp; + } + + + public void setTimestamp( Timestamp timestamp ) + { + this.timestamp = timestamp; + } + + + public LogLevel getLevel( ) + { + return level; + } + + + public void setLevel( LogLevel level ) + { + this.level = level; + } + + + public String getAbout( ) + { + return about; + } + + + public void setAbout( String about ) + { + this.about = about; + } + + + public String getEntry( ) + { + return entry; + } + + + public void setEntry( String entry ) + { + this.entry = entry; + } + + + public Long getException( ) + { + return exception; + } + + + public void setException( Long exception ) + { + this.exception = exception; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogLevel.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogLevel.java new file mode 100644 index 0000000..b3908e2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogLevel.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.logs; + + +/** + * This enumeration defines the various levels which can be affected to system log entries. + * + * @author tseeker + */ +public enum LogLevel { + + /** Trace mode entry */ + TRACE , + + /** Entry that may be used for debugging purposes, but has no other actual use */ + DEBUG , + + /** Entry that indicates that something important but mostly benign happened */ + INFO , + + /** + * Entry that indicates that something went wrong, although it is unlikely to affect the whole + * system + */ + WARNING , + + /** Entry that indicates that something went really wrong and might affect the whole system */ + ERROR +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogType.java new file mode 100644 index 0000000..131f7c4 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/LogType.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.cmd.admin.logs; + + +public enum LogType { + + SYSTEM( "System log" ) , + ADMIN( "Administration log" ) , + PLAYER( "Player log" ); + + private final String description; + + + private LogType( String description ) + { + this.description = description; + } + + + public String getDescription( ) + { + return description; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/TraceEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/TraceEntry.java new file mode 100644 index 0000000..885c6f4 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/TraceEntry.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.cmd.admin.logs; + + +import java.io.Serializable; + + + +public class TraceEntry + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final String location; + private final String fileName; + private final Integer line; + + + public TraceEntry( String location , String fileName , Integer line ) + { + this.location = location; + this.fileName = fileName; + this.line = line; + } + + + public String getLocation( ) + { + return location; + } + + + public String getFileName( ) + { + return fileName; + } + + + public Integer getLine( ) + { + return line; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ViewLogCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ViewLogCommand.java new file mode 100644 index 0000000..d3f3ad7 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ViewLogCommand.java @@ -0,0 +1,69 @@ +package com.deepclone.lw.cmd.admin.logs; + + +import com.deepclone.lw.session.Command; + + + +public class ViewLogCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final LogType type; + private final long firstEntry; + private final int count; + private final LogLevel minLogLevel; + private final String component; + private final boolean exceptionOnly; + + + public ViewLogCommand( LogType type , long firstEntry , int count , LogLevel minLogLevel , String component , + boolean exceptionOnly ) + { + this.type = type; + this.firstEntry = firstEntry; + this.count = count; + this.minLogLevel = minLogLevel; + this.component = component; + this.exceptionOnly = exceptionOnly; + } + + + public LogType getType( ) + { + return type; + } + + + public long getFirstEntry( ) + { + return firstEntry; + } + + + public int getCount( ) + { + return count; + } + + + public LogLevel getMinLogLevel( ) + { + return minLogLevel; + } + + + public String getComponent( ) + { + return component; + } + + + public boolean isExceptionOnly( ) + { + return exceptionOnly; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ViewLogResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ViewLogResponse.java new file mode 100644 index 0000000..3964c7e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/logs/ViewLogResponse.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.cmd.admin.logs; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ViewLogResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final long count; + private final List< LogEntry > entries; + + + public ViewLogResponse( Administrator admin ) + { + super( admin , false ); + this.count = 0; + this.entries = null; + } + + + public ViewLogResponse( Administrator admin , long count , List< LogEntry > entries ) + { + super( admin ); + this.count = count; + this.entries = entries; + } + + + public long getCount( ) + { + return count; + } + + + public List< LogEntry > getEntries( ) + { + return entries; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/EnableMaintenanceCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/EnableMaintenanceCommand.java new file mode 100644 index 0000000..2848b92 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/EnableMaintenanceCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.mntm; + + +import com.deepclone.lw.session.Command; + + + +public class EnableMaintenanceCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String reason; + private final int duration; + + + public EnableMaintenanceCommand( String reason , int duration ) + { + this.reason = reason; + this.duration = duration; + } + + + public String getReason( ) + { + return reason; + } + + + public int getDuration( ) + { + return duration; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/EndMaintenanceCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/EndMaintenanceCommand.java new file mode 100644 index 0000000..11d5a82 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/EndMaintenanceCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.admin.mntm; + + +import com.deepclone.lw.session.Command; + + + +public class EndMaintenanceCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/ExtendMaintenanceCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/ExtendMaintenanceCommand.java new file mode 100644 index 0000000..4a40d58 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/ExtendMaintenanceCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.mntm; + + +import com.deepclone.lw.session.Command; + + + +public class ExtendMaintenanceCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int duration; + + + public ExtendMaintenanceCommand( int duration ) + { + this.duration = duration; + } + + + public int getDuration( ) + { + return duration; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceChangeResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceChangeResponse.java new file mode 100644 index 0000000..c5ea32c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceChangeResponse.java @@ -0,0 +1,58 @@ +package com.deepclone.lw.cmd.admin.mntm; + + +import java.util.Date; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class MaintenanceChangeResponse + extends MaintenanceStatusResponse +{ + + private static final long serialVersionUID = 1L; + + private final String newReason; + private final ObjectNameError reasonError; + private final long newDuration; + + + public MaintenanceChangeResponse( Administrator admin , boolean privError ) + { + super( admin , privError ); + this.newReason = null; + this.reasonError = null; + this.newDuration = 0; + } + + + public MaintenanceChangeResponse( Administrator admin , String reason , Date started , Date until , + String newReason , ObjectNameError reasonError , long newDuration ) + { + super( admin , reason , started , until ); + this.newReason = newReason; + this.reasonError = reasonError; + this.newDuration = newDuration; + } + + + public String getNewReason( ) + { + return newReason; + } + + + public ObjectNameError getReasonError( ) + { + return reasonError; + } + + + public long getNewDuration( ) + { + return newDuration; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceStatusCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceStatusCommand.java new file mode 100644 index 0000000..c0fd9b0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceStatusCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.admin.mntm; + + +import com.deepclone.lw.session.Command; + + + +public class MaintenanceStatusCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceStatusResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceStatusResponse.java new file mode 100644 index 0000000..4f98983 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/mntm/MaintenanceStatusResponse.java @@ -0,0 +1,57 @@ +package com.deepclone.lw.cmd.admin.mntm; + + +import java.util.Date; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class MaintenanceStatusResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final String reason; + private final Date started; + private final Date until; + + + public MaintenanceStatusResponse( Administrator admin , boolean privError ) + { + super( admin , !privError ); + this.reason = null; + this.started = null; + this.until = null; + } + + + public MaintenanceStatusResponse( Administrator admin , String reason , Date start , Date end ) + { + super( admin ); + this.reason = reason; + this.started = start; + this.until = end; + } + + + public String getReason( ) + { + return reason; + } + + + public Date getStarted( ) + { + return started; + } + + + public Date getUntil( ) + { + return until; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ComposeMessageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ComposeMessageCommand.java new file mode 100644 index 0000000..5eb5314 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ComposeMessageCommand.java @@ -0,0 +1,97 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.session.Command; + + + +public class ComposeMessageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final Boolean inbox; + private final Long replyTo; + + private MessageType type; + private String target; + private String subject; + private String contents; + + + public ComposeMessageCommand( ) + { + this.inbox = null; + this.replyTo = null; + } + + + public ComposeMessageCommand( boolean inbox , long replyTo ) + { + this.inbox = inbox; + this.replyTo = replyTo; + } + + + public MessageType getType( ) + { + return type; + } + + + public void setType( MessageType type ) + { + this.type = type; + } + + + public String getTarget( ) + { + return target; + } + + + public void setTarget( String target ) + { + this.target = target; + } + + + public String getSubject( ) + { + return subject; + } + + + public void setSubject( String subject ) + { + this.subject = subject; + } + + + public String getContents( ) + { + return contents; + } + + + public void setContents( String contents ) + { + this.contents = contents; + } + + + public Boolean getInbox( ) + { + return inbox; + } + + + public Long getReplyTo( ) + { + return replyTo; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ComposeMessageResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ComposeMessageResponse.java new file mode 100644 index 0000000..7b01bc4 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ComposeMessageResponse.java @@ -0,0 +1,160 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.msgdata.Message; +import com.deepclone.lw.cmd.msgdata.MessageType; + + + +public class ComposeMessageResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private MessageType messageType; + private String target; + private String title; + private String contents; + + private final Boolean inbox; + private final Message replyTo; + + private boolean targetError = false; + private boolean timingError = false; + private boolean titleError = false; + private boolean contentsError = false; + + + public ComposeMessageResponse( Administrator admin ) + { + super( admin ); + this.inbox = null; + this.replyTo = null; + } + + + public ComposeMessageResponse( Administrator admin , boolean inbox , Message replyTo ) + { + super( admin ); + this.inbox = inbox; + this.replyTo = replyTo; + } + + + public Boolean getInbox( ) + { + return inbox; + } + + + public Message getReplyTo( ) + { + return replyTo; + } + + + public MessageType getMessageType( ) + { + return messageType; + } + + + public void setMessageType( MessageType messageType ) + { + this.messageType = messageType; + } + + + public String getTarget( ) + { + return target; + } + + + public void setTarget( String target ) + { + this.target = target; + } + + + public String getTitle( ) + { + return title; + } + + + public void setTitle( String title ) + { + this.title = title; + } + + + public String getContents( ) + { + return contents; + } + + + public void setContents( String contents ) + { + this.contents = contents; + } + + + public boolean isTargetError( ) + { + return targetError; + } + + + public void setTargetError( boolean targetError ) + { + this.targetError = targetError; + } + + + public boolean isTimingError( ) + { + return timingError; + } + + + public void setTimingError( boolean timingError ) + { + this.timingError = timingError; + } + + + public boolean isTitleError( ) + { + return titleError; + } + + + public void setTitleError( boolean titleError ) + { + this.titleError = titleError; + } + + + public boolean isContentsError( ) + { + return contentsError; + } + + + public void setContentsError( boolean contentsError ) + { + this.contentsError = contentsError; + } + + + public boolean isError( ) + { + return ( this.titleError || this.contentsError || this.targetError || this.timingError ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/GetMessagesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/GetMessagesCommand.java new file mode 100644 index 0000000..f6019f1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/GetMessagesCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import com.deepclone.lw.session.Command; + + + +public class GetMessagesCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean inbox; + + + public GetMessagesCommand( boolean inbox ) + { + this.inbox = inbox; + } + + + public boolean isInbox( ) + { + return inbox; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/GetMessagesResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/GetMessagesResponse.java new file mode 100644 index 0000000..bd0c6da --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/GetMessagesResponse.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.msgdata.MessageListEntry; + + + +public class GetMessagesResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final List< MessageListEntry > messages; + + + public GetMessagesResponse( Administrator admin , List< MessageListEntry > messages ) + { + super( admin ); + this.messages = messages; + } + + + public List< MessageListEntry > getMessages( ) + { + return messages; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/MessageBoxAction.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/MessageBoxAction.java new file mode 100644 index 0000000..e4fa82e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/MessageBoxAction.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.cmd.admin.msg; + + +public enum MessageBoxAction { + + DELETE , + MARK_READ , + MARK_UNREAD + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/MessageBoxCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/MessageBoxCommand.java new file mode 100644 index 0000000..c7431f2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/MessageBoxCommand.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import com.deepclone.lw.session.Command; + + + +public class MessageBoxCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final MessageBoxAction action; + private final boolean inbox; + private final long[] selection; + + + public MessageBoxCommand( boolean inbox , long[] selection ) + { + this.action = MessageBoxAction.DELETE; + this.inbox = inbox; + this.selection = selection; + } + + + public MessageBoxCommand( long[] selection , boolean read ) + { + this.action = read ? MessageBoxAction.MARK_READ : MessageBoxAction.MARK_UNREAD; + this.inbox = true; + this.selection = selection; + } + + + public MessageBoxAction getAction( ) + { + return action; + } + + + public boolean isInbox( ) + { + return inbox; + } + + + public long[] getSelection( ) + { + return selection; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/PrepareMessageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/PrepareMessageCommand.java new file mode 100644 index 0000000..0da0140 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/PrepareMessageCommand.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.session.Command; + + + +public class PrepareMessageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final MessageType type; + private final Long id; + private final Boolean inbox; + + + private PrepareMessageCommand( MessageType type , Long id ) + { + this.type = type; + this.id = id; + this.inbox = null; + } + + + public PrepareMessageCommand( long id , boolean inbox ) + { + this.type = MessageType.INTERNAL; + this.id = id; + this.inbox = inbox; + } + + + public MessageType getType( ) + { + return type; + } + + + public Long getId( ) + { + return id; + } + + + public Boolean getInbox( ) + { + return inbox; + } + + + public static PrepareMessageCommand newMessage( ) + { + return new PrepareMessageCommand( null , null ); + } + + + public static PrepareMessageCommand newMessageTo( MessageType type , int id ) + { + if ( type == MessageType.INTERNAL ) { + throw new IllegalArgumentException( ); + } + return new PrepareMessageCommand( type , (long) id ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ReadMessageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ReadMessageCommand.java new file mode 100644 index 0000000..e4d178f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ReadMessageCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import com.deepclone.lw.session.Command; + + + +public class ReadMessageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean inbox; + private final long id; + + + public ReadMessageCommand( boolean inbox , long id ) + { + this.inbox = inbox; + this.id = id; + } + + + public boolean isInbox( ) + { + return inbox; + } + + + public long getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ReadMessageResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ReadMessageResponse.java new file mode 100644 index 0000000..c310b93 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/ReadMessageResponse.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.msgdata.Message; + + + +public class ReadMessageResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean inbox; + private final Message message; + + + public ReadMessageResponse( Administrator admin , boolean inbox ) + { + super( admin ); + this.inbox = inbox; + this.message = null; + } + + + public ReadMessageResponse( Administrator admin , boolean inbox , Message message ) + { + super( admin ); + this.inbox = inbox; + this.message = message; + } + + + public boolean isInbox( ) + { + return inbox; + } + + + public Message getMessage( ) + { + return message; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/SendSpamCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/SendSpamCommand.java new file mode 100644 index 0000000..b282bcc --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/msg/SendSpamCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.msg; + + +import com.deepclone.lw.session.Command; + + + +public class SendSpamCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String title; + private final String body; + + + public SendSpamCommand( String title , String body ) + { + this.title = title; + this.body = body; + } + + + public String getTitle( ) + { + return title; + } + + + public String getBody( ) + { + return body; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/GetNamesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/GetNamesCommand.java new file mode 100644 index 0000000..1502f47 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/GetNamesCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.naming; + + +import com.deepclone.lw.session.Command; + + + +public class GetNamesCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final NameType type; + + + public GetNamesCommand( NameType type ) + { + this.type = type; + } + + + public NameType getType( ) + { + return type; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/GetNamesResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/GetNamesResponse.java new file mode 100644 index 0000000..735a487 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/GetNamesResponse.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.cmd.admin.naming; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class GetNamesResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final NameType type; + private final List< Name > names; + + + public GetNamesResponse( Administrator admin ) + { + super( admin , false ); + this.type = null; + this.names = null; + } + + + public GetNamesResponse( Administrator admin , NameType type , List< Name > names ) + { + super( admin ); + this.type = type; + this.names = names; + } + + + public NameType getType( ) + { + return type; + } + + + public List< Name > getNames( ) + { + return names; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/Name.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/Name.java new file mode 100644 index 0000000..c3f67e8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/Name.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.admin.naming; + + +import java.io.Serializable; + + + +public class Name + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final int id; + private final String name; + private final String extra; + private final NameType type; + + + public Name( int id , String name , String extra , NameType type ) + { + this.id = id; + this.name = name; + this.extra = extra; + this.type = type; + } + + + public int getId( ) + { + return id; + } + + + public String getName( ) + { + return name; + } + + + public String getExtra( ) + { + return extra; + } + + + public NameType getType( ) + { + return type; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NameAction.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NameAction.java new file mode 100644 index 0000000..2901c9d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NameAction.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.cmd.admin.naming; + +public enum NameAction { + + VALIDATE , + REJECT , + REJECT_BAN , + RESET + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NameType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NameType.java new file mode 100644 index 0000000..16de002 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NameType.java @@ -0,0 +1,30 @@ +package com.deepclone.lw.cmd.admin.naming; + + +public enum NameType { + MAP_PENDING( "Map names - validation pending" ) , + MAP_VALIDATED( "Map names - validated" ) , + MAP_CHANGED( "Map names - modified" ) , + EMPIRE( "Empire names" ) , + ALLIANCE( "Alliance names" ); + + private String description; + + + private NameType( String description ) + { + this.description = description; + } + + + public String getDescription( ) + { + return this.description; + } + + + public String getId( ) + { + return this.toString( ).replace( "_" , "-" ).toLowerCase( ); + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesActionCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesActionCommand.java new file mode 100644 index 0000000..0b778e1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesActionCommand.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.cmd.admin.naming; + + +import com.deepclone.lw.session.Command; + + + +public class NamesActionCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final NameType type; + private final NameAction action; + private final int[] identifiers; + + + public NamesActionCommand( NameType type , NameAction action , int[] identifiers ) + { + this.type = type; + this.identifiers = identifiers; + this.action = action; + } + + + public NameType getType( ) + { + return type; + } + + + public NameAction getAction( ) + { + return action; + } + + + public int[] getIdentifiers( ) + { + return identifiers; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesSummaryCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesSummaryCommand.java new file mode 100644 index 0000000..96ea84a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesSummaryCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.admin.naming; + + +import com.deepclone.lw.session.Command; + + + +public class NamesSummaryCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesSummaryResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesSummaryResponse.java new file mode 100644 index 0000000..adbb523 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/naming/NamesSummaryResponse.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.cmd.admin.naming; + + +import java.io.Serializable; +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class NamesSummaryResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + @SuppressWarnings( "serial" ) + public static class Entry + implements Serializable + { + private final NameType type; + private final long count; + + + public Entry( NameType type , long count ) + { + this.type = type; + this.count = count; + } + + + public NameType getType( ) + { + return type; + } + + + public long getCount( ) + { + return count; + } + + } + + private final List< Entry > entries; + + + public NamesSummaryResponse( Administrator admin , List< Entry > entries ) + { + super( admin ); + this.entries = entries; + } + + + public NamesSummaryResponse( Administrator admin ) + { + super( admin , false ); + this.entries = null; + } + + + public List< Entry > getEntries( ) + { + return entries; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/GetPrefDefaultsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/GetPrefDefaultsCommand.java new file mode 100644 index 0000000..0946c22 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/GetPrefDefaultsCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.admin.prefs; + + +import com.deepclone.lw.session.Command; + + + +public class GetPrefDefaultsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/PrefDefaultsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/PrefDefaultsResponse.java new file mode 100644 index 0000000..fed8047 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/PrefDefaultsResponse.java @@ -0,0 +1,40 @@ +package com.deepclone.lw.cmd.admin.prefs; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.player.gdata.account.PrefCategory; + + + +public class PrefDefaultsResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final List< PrefCategory > preferences; + + + public PrefDefaultsResponse( Administrator admin ) + { + super( admin , false ); + this.preferences = null; + } + + + public PrefDefaultsResponse( Administrator admin , List< PrefCategory > preferences ) + { + super( admin ); + this.preferences = preferences; + } + + + public List< PrefCategory > getPreferences( ) + { + return preferences; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/SetPrefDefaultCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/SetPrefDefaultCommand.java new file mode 100644 index 0000000..35f3945 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/prefs/SetPrefDefaultCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.prefs; + + +import com.deepclone.lw.session.Command; + + + +public class SetPrefDefaultCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String preference; + private final String value; + + + public SetPrefDefaultCommand( String preference , String value ) + { + this.preference = preference; + this.value = value; + } + + + public String getPreference( ) + { + return preference; + } + + + public String getValue( ) + { + return value; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/AddAdministratorCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/AddAdministratorCommand.java new file mode 100644 index 0000000..ed1eeb8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/AddAdministratorCommand.java @@ -0,0 +1,49 @@ +package com.deepclone.lw.cmd.admin.su; + + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.session.Command; + + + +public class AddAdministratorCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String address; + private final String appearAs; + private final Set< Privileges > privileges; + + + public AddAdministratorCommand( String address , String appearAs , Collection< Privileges > privileges ) + { + this.address = address; + this.appearAs = appearAs; + this.privileges = new HashSet< Privileges >( privileges ); + } + + + public String getAddress( ) + { + return address; + } + + + public String getAppearAs( ) + { + return appearAs; + } + + + public Set< Privileges > getPrivileges( ) + { + return privileges; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/AddAdministratorResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/AddAdministratorResponse.java new file mode 100644 index 0000000..a31e6d4 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/AddAdministratorResponse.java @@ -0,0 +1,99 @@ +package com.deepclone.lw.cmd.admin.su; + + +import java.util.List; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.PrivEntry; + + + +public class AddAdministratorResponse + extends AdminResponse +{ + private static final long serialVersionUID = 1L; + + public static enum AddressError { + EMPTY , + INVALID , + NOT_FOUND , + ALREADY_ADMIN , + STATUS + } + + private final AddressError addressError; + private final String address; + private final ObjectNameError nameError; + private final String name; + private final boolean privError; + private final int privileges; + + + public AddAdministratorResponse( Administrator admin , boolean privError ) + { + super( admin , !privError ); + this.addressError = null; + this.address = null; + this.nameError = null; + this.name = null; + this.privError = false; + this.privileges = 0; + } + + + public AddAdministratorResponse( Administrator admin , AddressError aError , String address , + ObjectNameError nError , String name , boolean pError , int privileges ) + { + super( admin , true ); + this.addressError = aError; + this.address = address; + this.nameError = nError; + this.name = name; + this.privError = pError; + this.privileges = privileges; + } + + + public AddressError getAddressError( ) + { + return addressError; + } + + + public String getAddress( ) + { + return address; + } + + + public ObjectNameError getNameError( ) + { + return nameError; + } + + + public String getName( ) + { + return name; + } + + + public boolean isPrivError( ) + { + return privError; + } + + + public List< PrivEntry > getPrivileges( ) + { + return PrivEntry.fromPrivileges( this.privileges ); + } + + + public boolean isError( ) + { + return this.addressError != null || this.nameError != null || this.privError; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ListAdministratorsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ListAdministratorsCommand.java new file mode 100644 index 0000000..8133b1c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ListAdministratorsCommand.java @@ -0,0 +1,11 @@ +package com.deepclone.lw.cmd.admin.su; + +import com.deepclone.lw.session.Command; + +public class ListAdministratorsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ListAdministratorsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ListAdministratorsResponse.java new file mode 100644 index 0000000..9a49ab2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ListAdministratorsResponse.java @@ -0,0 +1,39 @@ +package com.deepclone.lw.cmd.admin.su; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ListAdministratorsResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final List< Administrator > administrators; + + + public ListAdministratorsResponse( Administrator admin ) + { + super( admin , false ); + this.administrators = null; + } + + + public ListAdministratorsResponse( Administrator admin , List< Administrator > administrators ) + { + super( admin ); + this.administrators = administrators; + } + + + public List< Administrator > getAdministrators( ) + { + return administrators; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ResetAdminPasswordCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ResetAdminPasswordCommand.java new file mode 100644 index 0000000..78c5bb0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ResetAdminPasswordCommand.java @@ -0,0 +1,15 @@ +package com.deepclone.lw.cmd.admin.su; + + +public class ResetAdminPasswordCommand + extends ViewAdministratorCommand +{ + private static final long serialVersionUID = 1L; + + + public ResetAdminPasswordCommand( int identifier ) + { + super( identifier ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/SetPrivilegesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/SetPrivilegesCommand.java new file mode 100644 index 0000000..ea902e3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/SetPrivilegesCommand.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.cmd.admin.su; + + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.deepclone.lw.cmd.admin.adata.Privileges; + + + +public class SetPrivilegesCommand + extends ViewAdministratorCommand +{ + + private static final long serialVersionUID = 1L; + + private final Set< Privileges > privileges; + + + public SetPrivilegesCommand( int identifier , Collection< Privileges > privileges ) + { + super( identifier ); + this.privileges = new HashSet< Privileges >( privileges ); + } + + + public Set< Privileges > getPrivileges( ) + { + return privileges; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ViewAdministratorCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ViewAdministratorCommand.java new file mode 100644 index 0000000..8b6e119 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ViewAdministratorCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.su; + + +import com.deepclone.lw.session.Command; + + + +public class ViewAdministratorCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int identifier; + + + public ViewAdministratorCommand( int identifier ) + { + this.identifier = identifier; + } + + + public int getIdentifier( ) + { + return identifier; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ViewAdministratorResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ViewAdministratorResponse.java new file mode 100644 index 0000000..a903ccc --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/su/ViewAdministratorResponse.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.cmd.admin.su; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ViewAdministratorResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final Administrator view; + + + public ViewAdministratorResponse( Administrator admin , boolean privError ) + { + super( admin , !privError ); + this.view = null; + } + + + public ViewAdministratorResponse( Administrator admin , Administrator view ) + { + super( admin , true ); + this.view = view; + } + + + public Administrator getView( ) + { + return view; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/SetTaskStatusCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/SetTaskStatusCommand.java new file mode 100644 index 0000000..82645b8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/SetTaskStatusCommand.java @@ -0,0 +1,51 @@ +package com.deepclone.lw.cmd.admin.tick; + + +import com.deepclone.lw.session.Command; + + + +public class SetTaskStatusCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int task; + private final TickerTaskStatus newStatus; + private final Long delay; + + + public SetTaskStatusCommand( int task , boolean run ) + { + this.task = task; + this.newStatus = run ? TickerTaskStatus.RUNNING : TickerTaskStatus.STOPPED; + this.delay = null; + } + + + public SetTaskStatusCommand( int task , long delay ) + { + this.task = task; + this.newStatus = TickerTaskStatus.AUTO; + this.delay = delay; + } + + + public int getTask( ) + { + return task; + } + + + public TickerTaskStatus getNewStatus( ) + { + return newStatus; + } + + + public Long getDelay( ) + { + return delay; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerStatusCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerStatusCommand.java new file mode 100644 index 0000000..e6dda40 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerStatusCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.admin.tick; + + +import com.deepclone.lw.session.Command; + + + +public class TickerStatusCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerStatusResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerStatusResponse.java new file mode 100644 index 0000000..9de84db --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerStatusResponse.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.cmd.admin.tick; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class TickerStatusResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean paused; + private final List< TickerTaskInfo > tasks; + + + public TickerStatusResponse( Administrator admin ) + { + super( admin , false ); + this.paused = false; + this.tasks = null; + } + + + public TickerStatusResponse( Administrator admin , boolean paused , List< TickerTaskInfo > tasks ) + { + super( admin ); + this.paused = paused; + this.tasks = tasks; + } + + + public boolean isPaused( ) + { + return paused; + } + + + public List< TickerTaskInfo > getTasks( ) + { + return tasks; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerTaskInfo.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerTaskInfo.java new file mode 100644 index 0000000..5f189de --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerTaskInfo.java @@ -0,0 +1,91 @@ +package com.deepclone.lw.cmd.admin.tick; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public class TickerTaskInfo + implements Serializable , Comparable< TickerTaskInfo > +{ + + private static final long serialVersionUID = 1L; + + private int id; + private String name; + private TickerTaskStatus status; + private Timestamp start; + private Long timeToStart; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public TickerTaskStatus getStatus( ) + { + return status; + } + + + public void setStatus( TickerTaskStatus status ) + { + this.status = status; + } + + + public Timestamp getStart( ) + { + return start; + } + + + public void setStart( Timestamp start ) + { + this.start = start; + } + + + public Long getTimeToStart( ) + { + return timeToStart; + } + + + public void setTimeToStart( Long timeToStart ) + { + this.timeToStart = timeToStart; + } + + + @Override + public int compareTo( TickerTaskInfo other ) + { + if ( other == null ) { + return 1; + } + return this.name.compareTo( other.name ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerTaskStatus.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerTaskStatus.java new file mode 100644 index 0000000..e1b0afc --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/TickerTaskStatus.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.cmd.admin.tick; + + +public enum TickerTaskStatus { + + RUNNING( "Running" ) , + STOPPED( "Stopped" ) , + AUTO( "Scheduled to start automatically" ); + + private final String description; + + + private TickerTaskStatus( String description ) + { + this.description = description; + } + + + public String getDescription( ) + { + return description; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/ToggleTickerCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/ToggleTickerCommand.java new file mode 100644 index 0000000..797781f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/tick/ToggleTickerCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.admin.tick; + + +import com.deepclone.lw.session.Command; + + + +public class ToggleTickerCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountBanEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountBanEntry.java new file mode 100644 index 0000000..6f124e0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountBanEntry.java @@ -0,0 +1,67 @@ +package com.deepclone.lw.cmd.admin.users; + + +import java.io.Serializable; + + + +public class AccountBanEntry + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private String requestedByName; + private int requestedById; + private String confirmedByName; + private int confirmedById; + + + public String getRequestedByName( ) + { + return requestedByName; + } + + + public void setRequestedByName( String requestedByName ) + { + this.requestedByName = requestedByName; + } + + + public int getRequestedById( ) + { + return requestedById; + } + + + public void setRequestedById( int requestedById ) + { + this.requestedById = requestedById; + } + + + public String getConfirmedByName( ) + { + return confirmedByName; + } + + + public void setConfirmedByName( String confirmedByName ) + { + this.confirmedByName = confirmedByName; + } + + + public int getConfirmedById( ) + { + return confirmedById; + } + + + public void setConfirmedById( int confirmedById ) + { + this.confirmedById = confirmedById; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountListEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountListEntry.java new file mode 100644 index 0000000..f102958 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountListEntry.java @@ -0,0 +1,80 @@ +package com.deepclone.lw.cmd.admin.users; + + +import java.io.Serializable; + + + +public class AccountListEntry + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int id; + private String address; + private AccountStatus status; + private String currentEmpire; + private String language; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getAddress( ) + { + return address; + } + + + public void setAddress( String address ) + { + this.address = address; + } + + + public AccountStatus getStatus( ) + { + return status; + } + + + public void setStatus( AccountStatus status ) + { + this.status = status; + } + + + public String getCurrentEmpire( ) + { + return currentEmpire; + } + + + public void setCurrentEmpire( String currentEmpire ) + { + this.currentEmpire = currentEmpire; + } + + + public String getLanguage( ) + { + return language; + } + + + public void setLanguage( String language ) + { + this.language = language; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountSessionEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountSessionEntry.java new file mode 100644 index 0000000..ff8594d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountSessionEntry.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.cmd.admin.users; + + +import java.util.List; + + + +public class AccountSessionEntry + extends AccountListEntry +{ + private static final long serialVersionUID = 1L; + + private List< UserSession > sessions; + + + public AccountSessionEntry( ) + { + // EMPTY + } + + public AccountSessionEntry( AccountListEntry e ) { + this.setId( e.getId( ) ); + this.setAddress( e.getAddress( ) ); + this.setCurrentEmpire( e.getCurrentEmpire( ) ); + this.setLanguage( e.getLanguage( ) ); + this.setStatus( e.getStatus( ) ); + } + + + public List< UserSession > getSessions( ) + { + return sessions; + } + + + public void setSessions( List< UserSession > sessions ) + { + this.sessions = sessions; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountStatus.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountStatus.java new file mode 100644 index 0000000..92d693d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountStatus.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.cmd.admin.users; + + +/** + * Account status enumeration + * + * This enumerated type defines the various possible statuses for an account. Each status is + * associated with a boolean value indicating whether the status corresponds to an active or + * inactive account. + * + * @author tseeker + */ +public enum AccountStatus { + + /** Unconfirmed account, still needs initial validation */ + UNCONFIRMED( false , "unconfirmed" ) , + + /** Active account */ + ACTIVE( true , "active") , + + /** Account currently in vacation mode */ + VACATION( true , "on vacation" ) , + + /** Account currently entering vacation mode */ + START_VACATION( true , "entering vacation" ) , + + /** Account being disabled by its owner */ + QUITTING( true , "leaving" ) , + + /** Disabled account, either because it was closed or because it became inactive */ + DISABLED( false , "disabled" ) , + + /** Banned account */ + BANNED( false , "banned" ) , + + /** Account being re-activated */ + REACTIVATING( false , "being reactivated" ); + + /** Activity flag */ + private boolean active; + + /** Description used in the admin interface */ + private final String description; + + + private AccountStatus( boolean active , String description ) + { + this.active = active; + this.description = description; + } + + + /** @return true if the account status corresponds to an active account */ + public boolean isActive( ) + { + return this.active; + } + + + public String getDescription( ) + { + return description; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountViewEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountViewEntry.java new file mode 100644 index 0000000..44ff78d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/AccountViewEntry.java @@ -0,0 +1,147 @@ +package com.deepclone.lw.cmd.admin.users; + + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + + + +public class AccountViewEntry + extends AccountListEntry +{ + + private static final long serialVersionUID = 1L; + + private Integer empireId; + private int gameCredits; + private int vacationCredits; + private Timestamp statusStart; + private String inactivityReason; + private AccountBanEntry ban; + private boolean online; + private List< String > empireNames = new ArrayList< String >( 0 ); + private int warnings; + private Timestamp lastWarning; + + + public Integer getEmpireId( ) + { + return empireId; + } + + + public void setEmpireId( Integer empireId ) + { + this.empireId = empireId; + } + + + public int getGameCredits( ) + { + return gameCredits; + } + + + public void setGameCredits( int gameCredits ) + { + this.gameCredits = gameCredits; + } + + + public int getVacationCredits( ) + { + return vacationCredits; + } + + + public void setVacationCredits( int vacationCredits ) + { + this.vacationCredits = vacationCredits; + } + + + public Timestamp getStatusStart( ) + { + return statusStart; + } + + + public void setStatusStart( Timestamp statusStart ) + { + this.statusStart = statusStart; + } + + + public String getInactivityReason( ) + { + return inactivityReason; + } + + + public void setInactivityReason( String inactivityReason ) + { + this.inactivityReason = inactivityReason; + } + + + public AccountBanEntry getBan( ) + { + return ban; + } + + + public void setBan( AccountBanEntry ban ) + { + this.ban = ban; + } + + + public boolean isOnline( ) + { + return online; + } + + + public void setOnline( boolean isOnline ) + { + this.online = isOnline; + } + + + public List< String > getEmpireNames( ) + { + return empireNames; + } + + + public void setEmpireNames( List< String > empireNames ) + { + this.empireNames = empireNames; + } + + + public int getWarnings( ) + { + return warnings; + } + + + public void setWarnings( int warnings ) + { + this.warnings = warnings; + } + + + public Timestamp getLastWarning( ) + { + return lastWarning; + } + + + public void setLastWarning( Timestamp lastWarning ) + { + this.lastWarning = lastWarning; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/GiveCreditsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/GiveCreditsCommand.java new file mode 100644 index 0000000..5ab9330 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/GiveCreditsCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.admin.users; + + +import com.deepclone.lw.session.Command; + + + +public class GiveCreditsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int id; + private final int credits; + + + public GiveCreditsCommand( int id , int credits ) + { + this.id = id; + this.credits = credits; + } + + + public int getId( ) + { + return id; + } + + + public int getCredits( ) + { + return credits; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListAccountsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListAccountsCommand.java new file mode 100644 index 0000000..5b52707 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListAccountsCommand.java @@ -0,0 +1,50 @@ +package com.deepclone.lw.cmd.admin.users; + + +import com.deepclone.lw.session.Command; + + + +public class ListAccountsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final AccountStatus status; + private final boolean online; + + + public ListAccountsCommand( ) + { + this.status = null; + this.online = false; + } + + + public ListAccountsCommand( AccountStatus status ) + { + this.status = status; + this.online = false; + } + + + public ListAccountsCommand( AccountStatus status , boolean online ) + { + this.status = status; + this.online = online; + } + + + public AccountStatus getStatus( ) + { + return status; + } + + + public boolean isOnline( ) + { + return online; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListAccountsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListAccountsResponse.java new file mode 100644 index 0000000..389bd1e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListAccountsResponse.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.cmd.admin.users; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ListAccountsResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final AccountStatus status; + private final boolean online; + private final List< AccountListEntry > entries; + + + public ListAccountsResponse( Administrator admin , AccountStatus status , boolean online , + List< AccountListEntry > entries ) + { + super( admin ); + this.status = status; + this.online = online; + this.entries = entries; + } + + + public ListAccountsResponse( Administrator admin ) + { + super( admin , false ); + this.status = null; + this.online = false; + this.entries = null; + } + + + public AccountStatus getStatus( ) + { + return status; + } + + + public boolean isOnline( ) + { + return online; + } + + + public List< AccountListEntry > getEntries( ) + { + return entries; + } + + + public AccountStatus[] getAllStatuses( ) + { + return AccountStatus.values( ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListSessionsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListSessionsCommand.java new file mode 100644 index 0000000..0dd8336 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListSessionsCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.users; + + +import com.deepclone.lw.session.Command; + + + +public class ListSessionsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int id; + + + public ListSessionsCommand( int id ) + { + this.id = id; + } + + + public int getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListSessionsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListSessionsResponse.java new file mode 100644 index 0000000..a9ae818 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ListSessionsResponse.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.cmd.admin.users; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ListSessionsResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final AccountSessionEntry account; + + + public ListSessionsResponse( Administrator admin ) + { + super( admin , false ); + this.account = null; + } + + + public ListSessionsResponse( Administrator admin , AccountSessionEntry account ) + { + super( admin ); + this.account = account; + } + + + public AccountSessionEntry getAccount( ) + { + return account; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/SessionTerminationType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/SessionTerminationType.java new file mode 100644 index 0000000..04e933e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/SessionTerminationType.java @@ -0,0 +1,26 @@ +package com.deepclone.lw.cmd.admin.users; + + +public enum SessionTerminationType { + + MANUAL( "Logged out" ) , + GONE( "User account is gone" ) , + EXPIRED( "Session expired" ) , + EXCLUSIVE( "Terminated by new session" ) , + SERVER( "Server restart" ); + + private final String description; + + + private SessionTerminationType( String description ) + { + this.description = description; + } + + + public String getDescription( ) + { + return description; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/UserSession.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/UserSession.java new file mode 100644 index 0000000..b66cb2b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/UserSession.java @@ -0,0 +1,134 @@ +package com.deepclone.lw.cmd.admin.users; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public class UserSession + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long id; + private int credentialsId; + private String clientName; + private String sessionName; + private boolean exclusive; + private String fromAddress; + + private Timestamp started; + private Timestamp ended; + private SessionTerminationType endType; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public int getCredentialsId( ) + { + return credentialsId; + } + + + public void setCredentialsId( int credentialsId ) + { + this.credentialsId = credentialsId; + } + + + public String getClientName( ) + { + return clientName; + } + + + public void setClientName( String clientName ) + { + this.clientName = clientName; + } + + + public String getSessionName( ) + { + return sessionName; + } + + + public void setSessionName( String sessionName ) + { + this.sessionName = sessionName; + } + + + public boolean isExclusive( ) + { + return exclusive; + } + + + public void setExclusive( boolean exclusive ) + { + this.exclusive = exclusive; + } + + + public String getFromAddress( ) + { + return fromAddress; + } + + + public void setFromAddress( String fromAddress ) + { + this.fromAddress = fromAddress; + } + + + public Timestamp getStarted( ) + { + return started; + } + + + public void setStarted( Timestamp started ) + { + this.started = started; + } + + + public Timestamp getEnded( ) + { + return ended; + } + + + public void setEnded( Timestamp ended ) + { + this.ended = ended; + } + + + public SessionTerminationType getEndType( ) + { + return endType; + } + + + public void setEndType( SessionTerminationType endType ) + { + this.endType = endType; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ViewAccountCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ViewAccountCommand.java new file mode 100644 index 0000000..aa05383 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ViewAccountCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.admin.users; + + +import com.deepclone.lw.session.Command; + + + +public class ViewAccountCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int id; + + + public ViewAccountCommand( int id ) + { + this.id = id; + } + + + public int getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ViewAccountResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ViewAccountResponse.java new file mode 100644 index 0000000..add90f9 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/admin/users/ViewAccountResponse.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.cmd.admin.users; + + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; + + + +public class ViewAccountResponse + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final AccountViewEntry account; + + + public ViewAccountResponse( Administrator admin ) + { + super( admin , false ); + this.account = null; + } + + + public ViewAccountResponse( Administrator admin , AccountViewEntry account ) + { + super( admin ); + this.account = account; + } + + + public AccountViewEntry getAccount( ) + { + return account; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ListBugsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ListBugsCommand.java new file mode 100644 index 0000000..18763af --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ListBugsCommand.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.cmd.bt; + + +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.session.Command; + + + +public class ListBugsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final BugStatus status; + private final boolean ownOnly; + private final long first; + private final int count; + + + public ListBugsCommand( BugStatus status , boolean ownOnly , long first , int count ) + { + this.status = status; + this.ownOnly = ownOnly; + this.first = first; + this.count = count; + } + + + public BugStatus getStatus( ) + { + return status; + } + + + public boolean isOwnOnly( ) + { + return ownOnly; + } + + + public long getFirst( ) + { + return first; + } + + + public int getCount( ) + { + return count; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/PostCommentCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/PostCommentCommand.java new file mode 100644 index 0000000..d032610 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/PostCommentCommand.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.bt; + + +import com.deepclone.lw.session.Command; + + + +public class PostCommentCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long id; + private final String comment; + private final boolean publicComment; + + + public PostCommentCommand( long id , String comment ) + { + this.id = id; + this.comment = comment; + this.publicComment = false; + } + + + public PostCommentCommand( long id , String comment , boolean publicComment ) + { + this.id = id; + this.comment = comment; + this.publicComment = publicComment; + } + + + public long getId( ) + { + return id; + } + + + public String getComment( ) + { + return comment; + } + + + public boolean isPublicComment( ) + { + return publicComment; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ReportBugCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ReportBugCommand.java new file mode 100644 index 0000000..92425fe --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ReportBugCommand.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.bt; + + +import com.deepclone.lw.session.Command; + + + +public class ReportBugCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String title; + private final String description; + private final boolean publicReport; + + + public ReportBugCommand( String title , String description ) + { + this.title = title; + this.description = description; + this.publicReport = false; + } + + + public ReportBugCommand( String title , String description , boolean publicReport ) + { + this.title = title; + this.description = description; + this.publicReport = publicReport; + } + + + public String getTitle( ) + { + return title; + } + + + public String getDescription( ) + { + return description; + } + + + public boolean isPublicReport( ) + { + return publicReport; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ViewBugCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ViewBugCommand.java new file mode 100644 index 0000000..1ef74ba --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/ViewBugCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.bt; + + +import com.deepclone.lw.session.Command; + + + +public class ViewBugCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long id; + + + public ViewBugCommand( long id ) + { + this.id = id; + } + + + public long getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugEvent.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugEvent.java new file mode 100644 index 0000000..027b9d7 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugEvent.java @@ -0,0 +1,134 @@ +package com.deepclone.lw.cmd.bt.data; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public class BugEvent + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long id; + private BugEventType type; + private Timestamp timestamp; + private BugSubmitter submitter; + + private String title; + private String contents; + private Long mergedId; + private BugStatus status; + private Boolean visible; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public BugEventType getType( ) + { + return type; + } + + + public void setType( BugEventType type ) + { + this.type = type; + } + + + public Timestamp getTimestamp( ) + { + return timestamp; + } + + + public void setTimestamp( Timestamp timestamp ) + { + this.timestamp = timestamp; + } + + + public BugSubmitter getSubmitter( ) + { + return submitter; + } + + + public void setSubmitter( BugSubmitter submitter ) + { + this.submitter = submitter; + } + + + public String getTitle( ) + { + return title; + } + + + public void setTitle( String title ) + { + this.title = title; + } + + + public String getContents( ) + { + return contents; + } + + + public void setContents( String contents ) + { + this.contents = contents; + } + + + public Long getMergedId( ) + { + return mergedId; + } + + + public void setMergedId( Long mergedId ) + { + this.mergedId = mergedId; + } + + + public BugStatus getStatus( ) + { + return status; + } + + + public void setStatus( BugStatus status ) + { + this.status = status; + } + + + public Boolean getVisible( ) + { + return visible; + } + + + public void setVisible( Boolean visible ) + { + this.visible = visible; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugEventType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugEventType.java new file mode 100644 index 0000000..d21cc93 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugEventType.java @@ -0,0 +1,12 @@ +package com.deepclone.lw.cmd.bt.data; + + +public enum BugEventType { + + INIT , + MERGE , + STATUS , + COMMENT , + VISIBILITY + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugReport.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugReport.java new file mode 100644 index 0000000..2767173 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugReport.java @@ -0,0 +1,133 @@ +package com.deepclone.lw.cmd.bt.data; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public class BugReport + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long reportId; + private String title; + private Timestamp posted; + private boolean visible; + private BugStatus status; + private BugSubmitter initialSubmitter; + private Timestamp lastUpdate; + private BugSubmitter latestSubmitter; + private boolean updated; + + + public long getReportId( ) + { + return reportId; + } + + + public void setReportId( long reportId ) + { + this.reportId = reportId; + } + + + public String getTitle( ) + { + return title; + } + + + public void setTitle( String title ) + { + this.title = title; + } + + + public Timestamp getPosted( ) + { + return posted; + } + + + public void setPosted( Timestamp posted ) + { + this.posted = posted; + } + + + public boolean isVisible( ) + { + return visible; + } + + + public void setVisible( boolean visible ) + { + this.visible = visible; + } + + + public BugStatus getStatus( ) + { + return status; + } + + + public void setStatus( BugStatus status ) + { + this.status = status; + } + + + public BugSubmitter getInitialSubmitter( ) + { + return initialSubmitter; + } + + + public void setInitialSubmitter( BugSubmitter initialSubmitter ) + { + this.initialSubmitter = initialSubmitter; + } + + + public Timestamp getLastUpdate( ) + { + return lastUpdate; + } + + + public void setLastUpdate( Timestamp lastUpdate ) + { + this.lastUpdate = lastUpdate; + } + + + public BugSubmitter getLatestSubmitter( ) + { + return latestSubmitter; + } + + + public void setLatestSubmitter( BugSubmitter latestSubmitter ) + { + this.latestSubmitter = latestSubmitter; + } + + + public boolean isUpdated( ) + { + return updated; + } + + + public void setUpdated( boolean updated ) + { + this.updated = updated; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugStatus.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugStatus.java new file mode 100644 index 0000000..8636860 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugStatus.java @@ -0,0 +1,12 @@ +package com.deepclone.lw.cmd.bt.data; + + +public enum BugStatus { + + PENDING , + OPEN , + NOT_A_BUG , + WONT_FIX , + RESOLVED + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugSubmitter.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugSubmitter.java new file mode 100644 index 0000000..3e6e5b8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/bt/data/BugSubmitter.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.cmd.bt.data; + + +import java.io.Serializable; + + + +public class BugSubmitter + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private boolean isAdmin; + private String name; + private Integer userId; + + + public boolean isAdmin( ) + { + return isAdmin; + } + + + public void setAdmin( boolean isAdmin ) + { + this.isAdmin = isAdmin; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public Integer getUserId( ) + { + return userId; + } + + + public void setUserId( Integer userId ) + { + this.userId = userId; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ConfirmPasswordRecoveryCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ConfirmPasswordRecoveryCommand.java new file mode 100644 index 0000000..fe21b7d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ConfirmPasswordRecoveryCommand.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.cmd.ext; + + +import com.deepclone.lw.session.Command; + + + +public class ConfirmPasswordRecoveryCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String mailAddress; + + private final String token; + + private final String password; + + private final String passwordConfirm; + + + public ConfirmPasswordRecoveryCommand( String mailAddress , String token , String password , String passwordConfirm ) + { + this.mailAddress = mailAddress; + this.token = token; + this.password = password; + this.passwordConfirm = passwordConfirm; + } + + + public String getMailAddress( ) + { + return this.mailAddress; + } + + + public String getToken( ) + { + return this.token; + } + + + public String getPassword( ) + { + return this.password; + } + + + public String getPasswordConfirm( ) + { + return this.passwordConfirm; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ConfirmPasswordRecoveryResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ConfirmPasswordRecoveryResponse.java new file mode 100644 index 0000000..4342cdd --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ConfirmPasswordRecoveryResponse.java @@ -0,0 +1,38 @@ +package com.deepclone.lw.cmd.ext; + + +import com.deepclone.lw.session.CommandResponse; + + + +public class ConfirmPasswordRecoveryResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + public static enum PasswordRecoveryStatus { + OK , + INVALID_MAIL , + WEAK_PASSWORD , + MISMATCH_PASSWORD , + NOT_FOUND , + ACCOUNT_STATUS , + PROHIBITED + } + + private final PasswordRecoveryStatus status; + + + public ConfirmPasswordRecoveryResponse( PasswordRecoveryStatus status ) + { + this.status = status; + } + + + public PasswordRecoveryStatus getStatus( ) + { + return this.status; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/CreateAccountCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/CreateAccountCommand.java new file mode 100644 index 0000000..a4d0d32 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/CreateAccountCommand.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.cmd.ext; + + +import com.deepclone.lw.session.Command; + + + +public final class CreateAccountCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + private final String mail; + private final String mailConfirm; + private final String password; + private final String passwordConfirm; + private final String language; + + + public CreateAccountCommand( String mail , String mailConfirm , String password , String passwordConfirm , + String language ) + { + this.mail = mail; + this.mailConfirm = mailConfirm; + this.password = password; + this.passwordConfirm = passwordConfirm; + this.language = language; + } + + + public String getMail( ) + { + return this.mail; + } + + + public String getMailConfirm( ) + { + return this.mailConfirm; + } + + + public String getPassword( ) + { + return this.password; + } + + + public String getPasswordConfirm( ) + { + return this.passwordConfirm; + } + + + public String getLanguage( ) + { + return this.language; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/CreateAccountResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/CreateAccountResponse.java new file mode 100644 index 0000000..d7fff8b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/CreateAccountResponse.java @@ -0,0 +1,98 @@ +package com.deepclone.lw.cmd.ext; + + +import java.util.Map; + +import com.deepclone.lw.cmd.MailError; +import com.deepclone.lw.cmd.PasswordError; +import com.deepclone.lw.session.CommandResponse; + + + +public final class CreateAccountResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean created; + + private final String language; + + private final String mail; + + private final String mailConfirm; + + private final PasswordError passwordError; + + private final MailError mailError; + + private final ListLanguagesResponse supportedLanguages; + + + public CreateAccountResponse( String mail , String language ) + { + this.created = true; + this.language = language; + this.mail = mail; + this.mailConfirm = null; + this.passwordError = null; + this.mailError = null; + this.supportedLanguages = null; + } + + + public CreateAccountResponse( String mail , String mailConfirm , PasswordError passwordError , MailError mailError , + String language , Map< String , String > supportedLanguages ) + { + this.created = false; + this.language = language; + this.mail = mail; + this.mailConfirm = mailConfirm; + this.passwordError = passwordError; + this.mailError = mailError; + this.supportedLanguages = new ListLanguagesResponse( supportedLanguages ); + } + + + public boolean getCreated( ) + { + return created; + } + + + public String getLanguage( ) + { + return language; + } + + + public String getMail( ) + { + return mail; + } + + + public String getMailConfirm( ) + { + return mailConfirm; + } + + + public PasswordError getPasswordError( ) + { + return passwordError; + } + + + public MailError getMailError( ) + { + return mailError; + } + + + public ListLanguagesResponse getSupportedLanguages( ) + { + return supportedLanguages; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ListLanguagesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ListLanguagesCommand.java new file mode 100644 index 0000000..d04a39e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ListLanguagesCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.ext; + + +import com.deepclone.lw.session.Command; + + + +public class ListLanguagesCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ListLanguagesResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ListLanguagesResponse.java new file mode 100644 index 0000000..5f046c3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/ListLanguagesResponse.java @@ -0,0 +1,66 @@ +package com.deepclone.lw.cmd.ext; + + +import java.io.Serializable; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import com.deepclone.lw.session.CommandResponse; + + + +public class ListLanguagesResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + public static class Language + implements Serializable + { + private static final long serialVersionUID = 1L; + + private final String id; + + private final String name; + + + private Language( String id , String name ) + { + this.id = id; + this.name = name; + } + + + public String getId( ) + { + return this.id; + } + + + public String getName( ) + { + return this.name; + } + } + + private final List< Language > languages; + + + public ListLanguagesResponse( Map< String , String > languages ) + { + List< Language > theList = new LinkedList< Language >( ); + for ( Map.Entry< String , String > lDef : languages.entrySet( ) ) { + theList.add( new Language( lDef.getKey( ) , lDef.getValue( ) ) ); + } + this.languages = Collections.unmodifiableList( theList ); + } + + + public List< Language > getLanguages( ) + { + return this.languages; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/RequestPasswordRecoveryCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/RequestPasswordRecoveryCommand.java new file mode 100644 index 0000000..dea1b75 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/RequestPasswordRecoveryCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.ext; + + +import com.deepclone.lw.session.Command; + + + +public class RequestPasswordRecoveryCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String mailAddress; + + + public RequestPasswordRecoveryCommand( String mailAddress ) + { + this.mailAddress = mailAddress; + } + + + public String getMailAddress( ) + { + return this.mailAddress; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/RequestPasswordRecoveryResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/RequestPasswordRecoveryResponse.java new file mode 100644 index 0000000..cdf6407 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/ext/RequestPasswordRecoveryResponse.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.cmd.ext; + + +import com.deepclone.lw.session.CommandResponse; + + + +public class RequestPasswordRecoveryResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + public static enum PasswordRecoveryRequestStatus { + OK , + INVALID_INPUT , + ACCOUNT_NOT_FOUND , + ACCOUNT_STATUS , + RECOVERY_IN_PROGRESS , + MAIL_ERROR + } + + private final PasswordRecoveryRequestStatus status; + + + public RequestPasswordRecoveryResponse( PasswordRecoveryRequestStatus status ) + { + this.status = status; + } + + + public PasswordRecoveryRequestStatus getStatus( ) + { + return status; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/Message.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/Message.java new file mode 100644 index 0000000..d3e8547 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/Message.java @@ -0,0 +1,164 @@ +package com.deepclone.lw.cmd.msgdata; + + +import java.io.Serializable; +import java.sql.Timestamp; + +import com.deepclone.lw.cmd.player.gdata.GameTime; + + + +public class Message + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long id; + private Long previous; + private Long next; + + private boolean unread; + private MessageType type; + + private String sender; + private String receiver; + private Timestamp time; + private GameTime gameTime; + + private String title; + private String contents; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public Long getPrevious( ) + { + return previous; + } + + + public void setPrevious( Long previous ) + { + this.previous = previous; + } + + + public Long getNext( ) + { + return next; + } + + + public void setNext( Long next ) + { + this.next = next; + } + + + public boolean isUnread( ) + { + return unread; + } + + + public void setUnread( boolean unread ) + { + this.unread = unread; + } + + + public MessageType getType( ) + { + return type; + } + + + public void setType( MessageType type ) + { + this.type = type; + } + + + public String getSender( ) + { + return sender; + } + + + public void setSender( String sender ) + { + this.sender = sender; + } + + + public String getReceiver( ) + { + return receiver; + } + + + public void setReceiver( String receiver ) + { + this.receiver = receiver; + } + + + public Timestamp getTime( ) + { + return time; + } + + + public void setTime( Timestamp time ) + { + this.time = time; + } + + + public GameTime getGameTime( ) + { + return gameTime; + } + + + public void setGameTime( long tick ) + { + this.gameTime = new GameTime( tick ); + } + + + public String getTitle( ) + { + return title; + } + + + public void setTitle( String title ) + { + this.title = title; + } + + + public String getContents( ) + { + return contents; + } + + + public void setContents( String contents ) + { + this.contents = contents; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/MessageListEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/MessageListEntry.java new file mode 100644 index 0000000..aee6cac --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/MessageListEntry.java @@ -0,0 +1,94 @@ +package com.deepclone.lw.cmd.msgdata; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public class MessageListEntry + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long id; + private MessageType type; + private boolean read; + private String title; + private String sender; + private Timestamp time; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public MessageType getType( ) + { + return type; + } + + + public void setType( MessageType type ) + { + this.type = type; + } + + + public boolean isRead( ) + { + return read; + } + + + public void setRead( boolean read ) + { + this.read = read; + } + + + public String getTitle( ) + { + return title; + } + + + public void setTitle( String title ) + { + this.title = title; + } + + + public String getSender( ) + { + return sender; + } + + + public void setSender( String sender ) + { + this.sender = sender; + } + + + public Timestamp getTime( ) + { + return time; + } + + + public void setTime( Timestamp time ) + { + this.time = time; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/MessageType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/MessageType.java new file mode 100644 index 0000000..319d557 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/msgdata/MessageType.java @@ -0,0 +1,9 @@ +package com.deepclone.lw.cmd.msgdata; + + +public enum MessageType { + EMPIRE , + ALLIANCE , + ADMINISTRATOR , + INTERNAL +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/EmpireResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/EmpireResponse.java new file mode 100644 index 0000000..7b6eea1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/EmpireResponse.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.player; + + +import java.util.Collections; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.battles.BattleListEntry; +import com.deepclone.lw.cmd.player.gdata.empire.OverviewData; +import com.deepclone.lw.cmd.player.gdata.empire.ResearchLineData; + + + +public class EmpireResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + private final OverviewData overview; + private final List< ResearchLineData > research; + private final List< BattleListEntry > battles; + + + public EmpireResponse( GamePageData page , OverviewData overview , List< ResearchLineData > research , + List< BattleListEntry > battles ) + { + super( page ); + this.overview = overview; + this.battles = battles; + this.research = Collections.unmodifiableList( research ); + } + + + public OverviewData getOverview( ) + { + return overview; + } + + + public List< ResearchLineData > getResearch( ) + { + return research; + } + + + public List< BattleListEntry > getBattles( ) + { + return battles; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/GetNewPlanetCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/GetNewPlanetCommand.java new file mode 100644 index 0000000..0901c47 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/GetNewPlanetCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player; + + +import com.deepclone.lw.session.Command; + + + +public class GetNewPlanetCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String name; + + + public GetNewPlanetCommand( String name ) + { + this.name = name; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/GetNewPlanetResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/GetNewPlanetResponse.java new file mode 100644 index 0000000..772d507 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/GetNewPlanetResponse.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.cmd.player; + + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; + + + +public class GetNewPlanetResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final String name; + private final ObjectNameError error; + private final Integer planet; + + + public GetNewPlanetResponse( GamePageData page , String name , ObjectNameError error ) + { + super( page ); + this.name = name; + this.error = error; + this.planet = null; + } + + + public GetNewPlanetResponse( GamePageData page , int planet ) + { + super( page ); + this.name = null; + this.error = null; + this.planet = planet; + } + + + public String getName( ) + { + return name; + } + + + public ObjectNameError getError( ) + { + return error; + } + + + public Integer getPlanet( ) + { + return planet; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ImplementTechCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ImplementTechCommand.java new file mode 100644 index 0000000..9a26ed7 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ImplementTechCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player; + + +import com.deepclone.lw.session.Command; + + + +public class ImplementTechCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int tech; + + + public ImplementTechCommand( int tech ) + { + this.tech = tech; + } + + + public int getTech( ) + { + return tech; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ListPlanetsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ListPlanetsCommand.java new file mode 100644 index 0000000..bf8b5e8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ListPlanetsCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player; + + +import com.deepclone.lw.session.Command; + + + +public class ListPlanetsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ListPlanetsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ListPlanetsResponse.java new file mode 100644 index 0000000..0e93aac --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ListPlanetsResponse.java @@ -0,0 +1,34 @@ +package com.deepclone.lw.cmd.player; + + +import java.util.Collections; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.PlanetListData; + + + +public class ListPlanetsResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final List< PlanetListData > planets; + + + public ListPlanetsResponse( GamePageData page , List< PlanetListData > planets ) + { + super( page ); + this.planets = Collections.unmodifiableList( planets ); + } + + + public List< PlanetListData > getPlanets( ) + { + return planets; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/OverviewCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/OverviewCommand.java new file mode 100644 index 0000000..030a27b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/OverviewCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player; + + +import com.deepclone.lw.session.Command; + + + +public class OverviewCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ViewMapCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ViewMapCommand.java new file mode 100644 index 0000000..2eb03bb --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ViewMapCommand.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.cmd.player; + + +import com.deepclone.lw.cmd.player.gdata.MapSize; +import com.deepclone.lw.session.Command; + + + +public class ViewMapCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean defaults; + private final Integer x; + private final Integer y; + private final MapSize size; + + + public ViewMapCommand( ) + { + this.defaults = true; + this.x = null; + this.y = null; + this.size = null; + } + + + public ViewMapCommand( int x , int y , MapSize size ) + { + this.defaults = false; + this.x = x; + this.y = y; + this.size = size; + } + + + public boolean isDefaults( ) + { + return defaults; + } + + + public Integer getX( ) + { + return x; + } + + + public Integer getY( ) + { + return y; + } + + + public MapSize getSize( ) + { + return size; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ViewMapResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ViewMapResponse.java new file mode 100644 index 0000000..703b122 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/ViewMapResponse.java @@ -0,0 +1,74 @@ +package com.deepclone.lw.cmd.player; + + +import java.util.Collections; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.MapSize; +import com.deepclone.lw.cmd.player.gdata.map.MapSystemData; + + + +public class ViewMapResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final int x; + private final int y; + private final MapSize size; + private final List< String > sizes; + private final MapSystemData[][] systems; + + + public ViewMapResponse( GamePageData page , int x , int y , MapSize size , List< String > sizes , + MapSystemData[][] systems ) + { + super( page ); + this.x = x; + this.y = y; + this.size = size; + this.sizes = Collections.unmodifiableList( sizes ); + this.systems = systems; + } + + + public int getX( ) + { + return x; + } + + + public int getY( ) + { + return y; + } + + + public MapSize getSize( ) + { + return size; + } + + + public int getSizeOrdinal( ) + { + return size.ordinal( ); + } + + + public List< String > getSizes( ) + { + return sizes; + } + + + public MapSystemData[][] getSystems( ) + { + return systems; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountReactivationCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountReactivationCommand.java new file mode 100644 index 0000000..2634d43 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountReactivationCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class AccountReactivationCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountReactivationResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountReactivationResponse.java new file mode 100644 index 0000000..9eddc44 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountReactivationResponse.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.CommandResponse; + + + +public class AccountReactivationResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final String address; + + private final boolean success; + + + public AccountReactivationResponse( String address , boolean success ) + { + this.address = address; + this.success = success; + } + + + public String getAddress( ) + { + return this.address; + } + + + public boolean isSuccess( ) + { + return this.success; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountValidationCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountValidationCommand.java new file mode 100644 index 0000000..9854256 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountValidationCommand.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class AccountValidationCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean initialisation; + + private final String token; + + private final String empire; + + private final String planet; + + + public AccountValidationCommand( ) + { + this.initialisation = true; + this.token = null; + this.empire = null; + this.planet = null; + } + + + public AccountValidationCommand( String token , String empire , String planet ) + { + this.initialisation = false; + this.token = token; + this.empire = empire; + this.planet = planet; + } + + + public boolean isInitialisation( ) + { + return this.initialisation; + } + + + public String getToken( ) + { + return this.token; + } + + + public String getEmpire( ) + { + return this.empire; + } + + + public String getPlanet( ) + { + return this.planet; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountValidationResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountValidationResponse.java new file mode 100644 index 0000000..8bd908f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/AccountValidationResponse.java @@ -0,0 +1,121 @@ +package com.deepclone.lw.cmd.player.account; + + +import java.util.Collections; +import java.util.List; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.session.CommandResponse; + + + +public class AccountValidationResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean validated; + + private final List< String > previousEmpires; + + private final String token; + + private final String empire; + + private final String planet; + + private final boolean wrongToken; + + private final ObjectNameError empireError; + + private final ObjectNameError planetError; + + + public AccountValidationResponse( ) + { + this.validated = true; + this.previousEmpires = null; + this.token = null; + this.empire = null; + this.planet = null; + this.wrongToken = false; + this.empireError = null; + this.planetError = null; + } + + + public AccountValidationResponse( List< String > previous ) + { + this.validated = false; + this.previousEmpires = Collections.unmodifiableList( previous ); + this.token = null; + this.empire = null; + this.planet = null; + this.wrongToken = false; + this.empireError = null; + this.planetError = null; + } + + + public AccountValidationResponse( List< String > previous , String token , String empire , String planet , + boolean wrongToken , ObjectNameError empireError , ObjectNameError planetError ) + { + this.validated = false; + this.previousEmpires = Collections.unmodifiableList( previous ); + this.token = token; + this.empire = empire; + this.planet = planet; + this.wrongToken = wrongToken; + this.empireError = empireError; + this.planetError = planetError; + } + + + public boolean isValidated( ) + { + return this.validated; + } + + + public List< String > getPreviousEmpires( ) + { + return this.previousEmpires; + } + + + public String getToken( ) + { + return this.token; + } + + + public String getEmpire( ) + { + return this.empire; + } + + + public String getPlanet( ) + { + return this.planet; + } + + + public boolean isWrongToken( ) + { + return this.wrongToken; + } + + + public ObjectNameError getEmpireError( ) + { + return this.empireError; + } + + + public ObjectNameError getPlanetError( ) + { + return this.planetError; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/BanDetailsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/BanDetailsCommand.java new file mode 100644 index 0000000..dca68e4 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/BanDetailsCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class BanDetailsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/BanDetailsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/BanDetailsResponse.java new file mode 100644 index 0000000..20e70c3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/BanDetailsResponse.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.cmd.player.account; + + +import java.sql.Timestamp; + +import com.deepclone.lw.session.CommandResponse; + + + +public class BanDetailsResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final Timestamp banTime; + private final String banReason; + private final boolean redeemable; + + + public BanDetailsResponse( Timestamp banTime , String banReason , boolean redeemable ) + { + this.banTime = banTime; + this.banReason = banReason; + this.redeemable = redeemable; + } + + + public Timestamp getBanTime( ) + { + return banTime; + } + + + public String getBanReason( ) + { + return banReason; + } + + + public boolean isRedeemable( ) + { + return redeemable; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/CancelQuitCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/CancelQuitCommand.java new file mode 100644 index 0000000..062f377 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/CancelQuitCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class CancelQuitCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetAccountCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetAccountCommand.java new file mode 100644 index 0000000..e51d582 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetAccountCommand.java @@ -0,0 +1,11 @@ +package com.deepclone.lw.cmd.player.account; + +import com.deepclone.lw.session.Command; + +public class GetAccountCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetAccountResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetAccountResponse.java new file mode 100644 index 0000000..3deb26c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetAccountResponse.java @@ -0,0 +1,31 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; + + + +public class GetAccountResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final AccountData account; + + + public GetAccountResponse( GamePageData page , AccountData account ) + { + super( page ); + this.account = account; + } + + + public AccountData getAccount( ) + { + return account; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetLanguageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetLanguageCommand.java new file mode 100644 index 0000000..b60f61c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetLanguageCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class GetLanguageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetLanguageResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetLanguageResponse.java new file mode 100644 index 0000000..c18ad3d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/GetLanguageResponse.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.CommandResponse; + + + +public class GetLanguageResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final String language; + + + public GetLanguageResponse( String language ) + { + this.language = language; + } + + + public String getLanguage( ) + { + return this.language; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/QuitGameCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/QuitGameCommand.java new file mode 100644 index 0000000..c0a4776 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/QuitGameCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class QuitGameCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String reason; + + + public QuitGameCommand( String reason ) + { + this.reason = ( reason == null ? "" : reason.trim( ) ); + } + + + public String getReason( ) + { + return reason; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetAddressCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetAddressCommand.java new file mode 100644 index 0000000..3362047 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetAddressCommand.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class SetAddressCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String sha1Auth; + private final String md5Auth; + private final String mail; + private final String mailConfirm; + + + public SetAddressCommand( String sha1Auth , String md5Auth , String mail , String mailConfirm ) + { + this.sha1Auth = sha1Auth; + this.md5Auth = md5Auth; + this.mail = mail; + this.mailConfirm = mailConfirm; + } + + + public String getSha1Auth( ) + { + return sha1Auth; + } + + + public String getMd5Auth( ) + { + return md5Auth; + } + + + public String getMail( ) + { + return mail; + } + + + public String getMailConfirm( ) + { + return mailConfirm; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetAddressResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetAddressResponse.java new file mode 100644 index 0000000..b281611 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetAddressResponse.java @@ -0,0 +1,65 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; + + + +public class SetAddressResponse + extends GetAccountResponse +{ + + private static final long serialVersionUID = 1L; + + public static enum AddressChangeStatus { + OK , + EMPTY , + INVALID , + MISMATCH , + IN_USE , + SEND_FAIL + } + + private final boolean mailAuthError; + private final AddressChangeStatus mailError; + private final String mail; + + + public SetAddressResponse( ) + { + super( null , null ); + this.mailAuthError = false; + this.mailError = AddressChangeStatus.OK; + this.mail = null; + } + + + public SetAddressResponse( GamePageData page , AccountData account , boolean mailAuthError , + AddressChangeStatus changeStatus , String mail ) + { + super( page , account ); + this.mailAuthError = mailAuthError; + this.mailError = changeStatus; + this.mail = mail; + } + + + public boolean isMailAuthError( ) + { + return mailAuthError; + } + + + public AddressChangeStatus getMailError( ) + { + return mailError; + } + + + public String getMail( ) + { + return mail; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetLanguageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetLanguageCommand.java new file mode 100644 index 0000000..75b7984 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetLanguageCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class SetLanguageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String language; + + + public SetLanguageCommand( String language ) + { + this.language = language; + } + + + public String getLanguage( ) + { + return language; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPasswordCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPasswordCommand.java new file mode 100644 index 0000000..ef777be --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPasswordCommand.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class SetPasswordCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final String sha1Auth; + private final String md5Auth; + private final String password; + private final String passwordConfirm; + + + public SetPasswordCommand( String sha1Auth , String md5Auth , String password , String passwordConfirm ) + { + this.sha1Auth = sha1Auth; + this.md5Auth = md5Auth; + this.password = password; + this.passwordConfirm = passwordConfirm; + } + + + public String getSha1Auth( ) + { + return sha1Auth; + } + + + public String getMd5Auth( ) + { + return md5Auth; + } + + + public String getPassword( ) + { + return password; + } + + + public String getPasswordConfirm( ) + { + return passwordConfirm; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPasswordResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPasswordResponse.java new file mode 100644 index 0000000..3d6e71d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPasswordResponse.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; + + + +public class SetPasswordResponse + extends GetAccountResponse +{ + + private static final long serialVersionUID = 1L; + + public static enum PasswordChangeStatus { + OK , + EMPTY , + TOO_WEAK , + MISMATCH , + PROHIBITED + } + + private final boolean authError; + private final PasswordChangeStatus passwordError; + + + public SetPasswordResponse( ) + { + super( null , null ); + this.authError = false; + this.passwordError = PasswordChangeStatus.OK; + } + + + public SetPasswordResponse( GamePageData page , AccountData account , boolean authError , + PasswordChangeStatus changeStatus ) + { + super( page , account ); + this.authError = authError; + this.passwordError = changeStatus; + } + + + public boolean isAuthError( ) + { + return authError; + } + + + public PasswordChangeStatus getPasswordError( ) + { + return passwordError; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPreferencesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPreferencesCommand.java new file mode 100644 index 0000000..d1c4057 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/SetPreferencesCommand.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.cmd.player.account; + + +import java.util.Map; + +import com.deepclone.lw.session.Command; + + + +public class SetPreferencesCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final Map< String , String > values; + + + public SetPreferencesCommand( ) + { + this.values = null; + } + + + public SetPreferencesCommand( Map< String , String > values ) + { + this.values = values; + } + + + public boolean isReset( ) + { + return this.values == null; + } + + + public Map< String , String > getValues( ) + { + return this.values; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ToggleVacationCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ToggleVacationCommand.java new file mode 100644 index 0000000..da6d81a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ToggleVacationCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class ToggleVacationCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ValidateSetAddressCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ValidateSetAddressCommand.java new file mode 100644 index 0000000..69ad994 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ValidateSetAddressCommand.java @@ -0,0 +1,43 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.session.Command; + + + +public class ValidateSetAddressCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean cancel; + private final String code; + + + public ValidateSetAddressCommand( ) + { + this.code = null; + this.cancel = true; + } + + + public ValidateSetAddressCommand( String code ) + { + this.code = code; + this.cancel = false; + } + + + public boolean isCancel( ) + { + return cancel; + } + + + public String getCode( ) + { + return code; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ValidateSetAddressResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ValidateSetAddressResponse.java new file mode 100644 index 0000000..5f1f15a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/account/ValidateSetAddressResponse.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.cmd.player.account; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.account.AccountData; + + + +public class ValidateSetAddressResponse + extends GetAccountResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean codeError; + private final String code; + + + public ValidateSetAddressResponse( ) + { + super( null , null ); + this.code = null; + this.codeError = false; + } + + + public ValidateSetAddressResponse( GamePageData page , AccountData account , String code ) + { + super( page , account ); + this.code = code; + this.codeError = true; + } + + + public boolean isCodeError( ) + { + return codeError; + } + + + public String getCode( ) + { + return code; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/AllianceStatusCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/AllianceStatusCommand.java new file mode 100644 index 0000000..ceeb01c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/AllianceStatusCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class AllianceStatusCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/AllianceStatusResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/AllianceStatusResponse.java new file mode 100644 index 0000000..f2eea70 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/AllianceStatusResponse.java @@ -0,0 +1,31 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceData; + + + +public class AllianceStatusResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final AllianceData alliance; + + + public AllianceStatusResponse( GamePageData page , AllianceData alliance ) + { + super( page ); + this.alliance = alliance; + } + + + public AllianceData getAlliance( ) + { + return alliance; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CancelJoinCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CancelJoinCommand.java new file mode 100644 index 0000000..54af717 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CancelJoinCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class CancelJoinCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CreateAllianceCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CreateAllianceCommand.java new file mode 100644 index 0000000..5e250e7 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CreateAllianceCommand.java @@ -0,0 +1,35 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class CreateAllianceCommand + extends Command +{ + private static final long serialVersionUID = 1L; + + private final String tag; + private final String name; + + + public CreateAllianceCommand( String tag , String name ) + { + this.tag = tag; + this.name = name; + } + + + public String getTag( ) + { + return tag; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CreateAllianceResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CreateAllianceResponse.java new file mode 100644 index 0000000..c484453 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/CreateAllianceResponse.java @@ -0,0 +1,31 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceCreationStatus; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceData; + + + +public class CreateAllianceResponse + extends AllianceStatusResponse +{ + + private static final long serialVersionUID = 1L; + + private final AllianceCreationStatus creation; + + + public CreateAllianceResponse( GamePageData page , AllianceData alliance , AllianceCreationStatus creation ) + { + super( page , alliance ); + this.creation = creation; + } + + + public AllianceCreationStatus getCreation( ) + { + return creation; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/JoinAllianceCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/JoinAllianceCommand.java new file mode 100644 index 0000000..e0fe9cd --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/JoinAllianceCommand.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class JoinAllianceCommand + extends Command +{ + private static final long serialVersionUID = 1L; + + private final String tag; + + + public JoinAllianceCommand( String tag ) + { + this.tag = tag; + } + + + public String getTag( ) + { + return tag; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/JoinAllianceResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/JoinAllianceResponse.java new file mode 100644 index 0000000..d544543 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/JoinAllianceResponse.java @@ -0,0 +1,30 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceData; + + + +public class JoinAllianceResponse + extends AllianceStatusResponse +{ + + private static final long serialVersionUID = 1L; + + private final String joinFailure; + + + public JoinAllianceResponse( GamePageData page , AllianceData alliance , String tag ) + { + super( page , alliance ); + this.joinFailure = tag; + } + + + public String getJoinFailure( ) + { + return joinFailure; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/KickMembersCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/KickMembersCommand.java new file mode 100644 index 0000000..fddf2a3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/KickMembersCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class KickMembersCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int[] members; + + + public KickMembersCommand( int[] members ) + { + this.members = members; + } + + + public int[] getMembers( ) + { + return members; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/LeaveAllianceCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/LeaveAllianceCommand.java new file mode 100644 index 0000000..4cf33da --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/LeaveAllianceCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class LeaveAllianceCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ManageRequestsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ManageRequestsCommand.java new file mode 100644 index 0000000..826e1a1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ManageRequestsCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class ManageRequestsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int[] members; + private final boolean accept; + + + public ManageRequestsCommand( int[] members , boolean accept ) + { + this.members = members; + this.accept = accept; + } + + + public int[] getMembers( ) + { + return members; + } + + + public boolean isAccept( ) + { + return accept; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/TransferLeadershipCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/TransferLeadershipCommand.java new file mode 100644 index 0000000..558d360 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/TransferLeadershipCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class TransferLeadershipCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int toMember; + + + public TransferLeadershipCommand( int toMember ) + { + this.toMember = toMember; + } + + + public int getToMember( ) + { + return toMember; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ViewAllianceCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ViewAllianceCommand.java new file mode 100644 index 0000000..aa201bf --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ViewAllianceCommand.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.session.Command; + + + +public class ViewAllianceCommand + extends Command +{ + private static final long serialVersionUID = 1L; + + private final String tag; + + + public ViewAllianceCommand( String tag ) + { + this.tag = tag; + } + + + public String getTag( ) + { + return tag; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ViewAllianceResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ViewAllianceResponse.java new file mode 100644 index 0000000..2f3e083 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/alliances/ViewAllianceResponse.java @@ -0,0 +1,40 @@ +package com.deepclone.lw.cmd.player.alliances; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.alliance.AllianceData; +import com.deepclone.lw.cmd.player.gdata.alliance.PublicAllianceInformation; + + + +public class ViewAllianceResponse + extends AllianceStatusResponse +{ + + private static final long serialVersionUID = 1L; + + private final String requested; + private final PublicAllianceInformation info; + + + public ViewAllianceResponse( GamePageData page , AllianceData alliance , String requested , + PublicAllianceInformation info ) + { + super( page , alliance ); + this.requested = requested; + this.info = info; + } + + + public String getRequested( ) + { + return requested; + } + + + public PublicAllianceInformation getInfo( ) + { + return info; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/GetBattleCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/GetBattleCommand.java new file mode 100644 index 0000000..555c2f4 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/GetBattleCommand.java @@ -0,0 +1,43 @@ +package com.deepclone.lw.cmd.player.battles; + + +import com.deepclone.lw.session.Command; + + + +public class GetBattleCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long battle; + private final Long tick; + + + public GetBattleCommand( long battle ) + { + this.battle = battle; + this.tick = null; + } + + + public GetBattleCommand( long battle , long tick ) + { + this.battle = battle; + this.tick = tick; + } + + + public long getBattle( ) + { + return battle; + } + + + public Long getTick( ) + { + return tick; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/GetBattleResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/GetBattleResponse.java new file mode 100644 index 0000000..bf46be5 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/GetBattleResponse.java @@ -0,0 +1,29 @@ +package com.deepclone.lw.cmd.player.battles; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.battles.BattleView; + + + +public class GetBattleResponse + extends GameResponseBase +{ + private static final long serialVersionUID = 1L; + private final BattleView battle; + + + public GetBattleResponse( GamePageData page , BattleView battle ) + { + super( page ); + this.battle = battle; + } + + + public BattleView getBattle( ) + { + return battle; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/ListBattlesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/ListBattlesCommand.java new file mode 100644 index 0000000..6b8041a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/ListBattlesCommand.java @@ -0,0 +1,34 @@ +package com.deepclone.lw.cmd.player.battles; + + +import com.deepclone.lw.session.Command; + + + +public class ListBattlesCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int page; + + + public ListBattlesCommand( ) + { + this.page = 0; + } + + + public ListBattlesCommand( int page ) + { + this.page = page; + } + + + public int getPage( ) + { + return page; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/ListBattlesResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/ListBattlesResponse.java new file mode 100644 index 0000000..a4856c7 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/battles/ListBattlesResponse.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.cmd.player.battles; + + +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.battles.BattleListEntry; + + + +public class ListBattlesResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + private final List< BattleListEntry > list; + private final int currentPage; + private final int pages; + + + public ListBattlesResponse( GamePageData page , List< BattleListEntry > list , int cPage , int pages ) + { + super( page ); + this.list = list; + this.currentPage = cPage; + this.pages = pages; + } + + + public List< BattleListEntry > getList( ) + { + return list; + } + + + public int getCurrentPage( ) + { + return currentPage; + } + + + public int getPages( ) + { + return pages; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ListBugsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ListBugsResponse.java new file mode 100644 index 0000000..6481ab0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ListBugsResponse.java @@ -0,0 +1,75 @@ +package com.deepclone.lw.cmd.player.bt; + + +import java.util.List; + +import com.deepclone.lw.cmd.bt.data.BugReport; +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; + + + +public class ListBugsResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final BugStatus status; + private final boolean ownOnly; + private final long first; + private final int count; + private final long entries; + private final List< BugReport > reports; + + + public ListBugsResponse( GamePageData page , BugStatus status , boolean ownOnly , long first , int count , + long entries , List< BugReport > reports ) + { + super( page ); + this.status = status; + this.ownOnly = ownOnly; + this.first = first; + this.count = count; + this.entries = entries; + this.reports = reports; + } + + + public BugStatus getStatus( ) + { + return status; + } + + + public boolean isOwnOnly( ) + { + return ownOnly; + } + + + public long getFirst( ) + { + return first; + } + + + public int getCount( ) + { + return count; + } + + + public long getEntries( ) + { + return entries; + } + + + public List< BugReport > getReports( ) + { + return reports; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/PostCommentResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/PostCommentResponse.java new file mode 100644 index 0000000..2c7c353 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/PostCommentResponse.java @@ -0,0 +1,69 @@ +package com.deepclone.lw.cmd.player.bt; + + +import java.util.List; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.bt.data.BugEvent; +import com.deepclone.lw.cmd.bt.data.BugReport; +import com.deepclone.lw.cmd.player.gdata.GamePageData; + + + +public class PostCommentResponse + extends ViewBugResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean posted; + private final ObjectNameError commentError; + private final String comment; + + + public PostCommentResponse( GamePageData page , boolean posted ) + { + super( page ); + this.posted = posted; + this.comment = null; + this.commentError = null; + } + + + public PostCommentResponse( GamePageData page , BugReport report , List< BugEvent > events , ObjectNameError error , + String comment ) + { + super( page , report , events ); + this.posted = false; + this.commentError = error; + this.comment = comment; + } + + + public PostCommentResponse( PostCommentResponse response , Object query ) + { + super( response , query ); + this.posted = false; + this.commentError = response.commentError; + this.comment = response.comment; + } + + + public boolean isPosted( ) + { + return posted; + } + + + public ObjectNameError getCommentError( ) + { + return commentError; + } + + + public String getComment( ) + { + return comment; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ReportBugResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ReportBugResponse.java new file mode 100644 index 0000000..6fb47c9 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ReportBugResponse.java @@ -0,0 +1,96 @@ +package com.deepclone.lw.cmd.player.bt; + + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; + + + +public class ReportBugResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final long bugId; + private final ObjectNameError titleError; + private final String title; + private final ObjectNameError descriptionError; + private final String description; + private final Object query; + + + public ReportBugResponse( GamePageData page , long bugId ) + { + super( page ); + this.bugId = bugId; + this.titleError = null; + this.title = null; + this.descriptionError = null; + this.description = null; + this.query = null; + } + + + public ReportBugResponse( GamePageData page , ObjectNameError titleError , String title , + ObjectNameError descriptionError , String description ) + { + super( page ); + this.bugId = 0; + this.titleError = titleError; + this.title = title; + this.descriptionError = descriptionError; + this.description = description; + this.query = null; + } + + + public ReportBugResponse( ReportBugResponse response , Object query ) + { + super( response.getPage( ) ); + this.bugId = 0; + this.titleError = response.titleError; + this.title = response.title; + this.descriptionError = response.descriptionError; + this.description = response.description; + this.query = query; + } + + + public long getBugId( ) + { + return bugId; + } + + + public ObjectNameError getTitleError( ) + { + return titleError; + } + + + public String getTitle( ) + { + return title; + } + + + public ObjectNameError getDescriptionError( ) + { + return descriptionError; + } + + + public String getDescription( ) + { + return description; + } + + + public Object getQuery( ) + { + return query; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ViewBugResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ViewBugResponse.java new file mode 100644 index 0000000..0f487c5 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/bt/ViewBugResponse.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.cmd.player.bt; + + +import java.util.List; + +import com.deepclone.lw.cmd.bt.data.BugEvent; +import com.deepclone.lw.cmd.bt.data.BugReport; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; + + + +public class ViewBugResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final BugReport report; + private final List< BugEvent > events; + private final Object query; + + + public ViewBugResponse( GamePageData page ) + { + super( page ); + this.report = null; + this.events = null; + this.query = null; + } + + + public ViewBugResponse( GamePageData page , BugReport report , List< BugEvent > events ) + { + super( page ); + this.report = report; + this.events = events; + this.query = null; + } + + + public ViewBugResponse( ViewBugResponse response , Object query ) + { + super( response.getPage( ) ); + this.report = response.report; + this.events = response.events; + this.query = query; + } + + + public BugReport getReport( ) + { + return report; + } + + + public List< BugEvent > getEvents( ) + { + return events; + } + + + public Object getQuery( ) + { + return query; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/AddEnemyCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/AddEnemyCommand.java new file mode 100644 index 0000000..f4342b2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/AddEnemyCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.player.elist; + + +import com.deepclone.lw.session.Command; + + + +public class AddEnemyCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean alliance; + private final String name; + + + public AddEnemyCommand( boolean alliance , String name ) + { + this.alliance = alliance; + this.name = name; + } + + + public boolean isAlliance( ) + { + return alliance; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/AddEnemyResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/AddEnemyResponse.java new file mode 100644 index 0000000..0e3e7e2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/AddEnemyResponse.java @@ -0,0 +1,50 @@ +package com.deepclone.lw.cmd.player.elist; + + +import java.util.List; + +import com.deepclone.lw.cmd.ObjectNameError; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class AddEnemyResponse + extends EnemyListResponse +{ + + private static final long serialVersionUID = 1L; + + private final ObjectNameError error; + private final boolean alliance; + private final String name; + + + public AddEnemyResponse( GamePageData page , List< NameIdPair > empires , List< NameIdPair > alliances , + ObjectNameError error , boolean alliance , String name ) + { + super( page , empires , alliances ); + this.error = error; + this.alliance = alliance; + this.name = name; + } + + + public ObjectNameError getError( ) + { + return error; + } + + + public boolean isAlliance( ) + { + return alliance; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/EnemyListCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/EnemyListCommand.java new file mode 100644 index 0000000..d72bf7d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/EnemyListCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.elist; + + +import com.deepclone.lw.session.Command; + + + +public class EnemyListCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/EnemyListResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/EnemyListResponse.java new file mode 100644 index 0000000..85ebd0d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/EnemyListResponse.java @@ -0,0 +1,40 @@ +package com.deepclone.lw.cmd.player.elist; + + +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class EnemyListResponse + extends GameResponseBase +{ + private static final long serialVersionUID = 1L; + + private final List< NameIdPair > empires; + private final List< NameIdPair > alliances; + + + public EnemyListResponse( GamePageData page , List< NameIdPair > empires , List< NameIdPair > alliances ) + { + super( page ); + this.empires = empires; + this.alliances = alliances; + } + + + public List< NameIdPair > getEmpires( ) + { + return empires; + } + + + public List< NameIdPair > getAlliances( ) + { + return alliances; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/RemoveEnemiesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/RemoveEnemiesCommand.java new file mode 100644 index 0000000..9a3ffbe --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/elist/RemoveEnemiesCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.player.elist; + + +import com.deepclone.lw.session.Command; + + + +public class RemoveEnemiesCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean alliance; + private final int[] identifiers; + + + public RemoveEnemiesCommand( boolean alliance , int[] identifiers ) + { + this.alliance = alliance; + this.identifiers = identifiers; + } + + + public boolean isAlliance( ) + { + return alliance; + } + + + public int[] getIdentifiers( ) + { + return identifiers; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/DisbandFleetsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/DisbandFleetsCommand.java new file mode 100644 index 0000000..4ac3589 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/DisbandFleetsCommand.java @@ -0,0 +1,25 @@ +package com.deepclone.lw.cmd.player.fleets; + + +public class DisbandFleetsCommand + extends MultiFleetsCommand +{ + + private static final long serialVersionUID = 1L; + + private final boolean confirm; + + + public DisbandFleetsCommand( long[] fleets , boolean confirm ) + { + super( fleets ); + this.confirm = confirm; + } + + + public boolean isConfirm( ) + { + return confirm; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/DisbandFleetsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/DisbandFleetsResponse.java new file mode 100644 index 0000000..9eace3b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/DisbandFleetsResponse.java @@ -0,0 +1,20 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; + + + +public class DisbandFleetsResponse + extends MultiFleetsResponse +{ + + private static final long serialVersionUID = 1L; + + + public DisbandFleetsResponse( GamePageData page ) + { + super( page ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MergeFleetsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MergeFleetsCommand.java new file mode 100644 index 0000000..f5029ce --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MergeFleetsCommand.java @@ -0,0 +1,16 @@ +package com.deepclone.lw.cmd.player.fleets; + + +public class MergeFleetsCommand + extends MultiFleetsCommand +{ + + private static final long serialVersionUID = 1L; + + + public MergeFleetsCommand( long[] fleets ) + { + super( fleets ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MergeFleetsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MergeFleetsResponse.java new file mode 100644 index 0000000..f0e92a5 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MergeFleetsResponse.java @@ -0,0 +1,20 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; + + + +public class MergeFleetsResponse + extends MultiFleetsResponse +{ + + private static final long serialVersionUID = 1L; + + + public MergeFleetsResponse( GamePageData page ) + { + super( page ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MoveFleetsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MoveFleetsCommand.java new file mode 100644 index 0000000..1efee46 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MoveFleetsCommand.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.cmd.player.fleets; + + +public class MoveFleetsCommand + extends MultiFleetsCommand +{ + + private static final long serialVersionUID = 1L; + + private final String destination; + private final Boolean mode; + + + public MoveFleetsCommand( long[] fleets ) + { + super( fleets ); + this.destination = null; + this.mode = null; + } + + + public MoveFleetsCommand( long[] fleets , String destination , boolean mode ) + { + super( fleets ); + this.destination = destination; + this.mode = mode; + } + + + public String getDestination( ) + { + return destination; + } + + + public Boolean getMode( ) + { + return mode; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MoveFleetsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MoveFleetsResponse.java new file mode 100644 index 0000000..e524398 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MoveFleetsResponse.java @@ -0,0 +1,60 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; + + + +public class MoveFleetsResponse + extends MultiFleetsResponse +{ + + private static final long serialVersionUID = 1L; + + private boolean error; + private String destination; + private Boolean mode; + + + public MoveFleetsResponse( GamePageData page ) + { + super( page ); + } + + + public boolean isError( ) + { + return error; + } + + + public void setError( boolean error ) + { + this.error = error; + } + + + public String getDestination( ) + { + return destination; + } + + + public void setDestination( String destination ) + { + this.destination = destination; + } + + + public Boolean getMode( ) + { + return mode; + } + + + public void setMode( Boolean mode ) + { + this.mode = mode; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MultiFleetsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MultiFleetsCommand.java new file mode 100644 index 0000000..4ebc86c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MultiFleetsCommand.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import com.deepclone.lw.session.Command; + + + +public abstract class MultiFleetsCommand + extends Command +{ + private static final long serialVersionUID = 1L; + + private final long fleets[]; + + + public MultiFleetsCommand( long fleets[] ) + { + this.fleets = fleets.clone( ); + } + + + public long[] getFleets( ) + { + return fleets; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MultiFleetsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MultiFleetsResponse.java new file mode 100644 index 0000000..3728e18 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/MultiFleetsResponse.java @@ -0,0 +1,39 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.fleets.ShortFleetView; + + + +public abstract class MultiFleetsResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final List< ShortFleetView > fleets = new LinkedList< ShortFleetView >( ); + + + public MultiFleetsResponse( GamePageData page ) + { + super( page ); + } + + + public void addFleet( ShortFleetView fleet ) + { + this.fleets.add( fleet ); + } + + + public List< ShortFleetView > getFleets( ) + { + return fleets; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/RenameFleetsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/RenameFleetsCommand.java new file mode 100644 index 0000000..95393e6 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/RenameFleetsCommand.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.cmd.player.fleets; + + +public class RenameFleetsCommand + extends MultiFleetsCommand +{ + + private static final long serialVersionUID = 1L; + + private final boolean rename; + private final String name; + + + public RenameFleetsCommand( long[] fleets ) + { + super( fleets ); + this.name = null; + this.rename = false; + } + + + public RenameFleetsCommand( long[] fleets , String name ) + { + super( fleets ); + this.name = name; + this.rename = true; + } + + + public boolean isRename( ) + { + return rename; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/RenameFleetsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/RenameFleetsResponse.java new file mode 100644 index 0000000..e20a569 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/RenameFleetsResponse.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; + + + +public class RenameFleetsResponse + extends MultiFleetsResponse +{ + + private static final long serialVersionUID = 1L; + + private boolean error; + private String name; + + + public RenameFleetsResponse( GamePageData page ) + { + super( page ); + } + + + public boolean isError( ) + { + return error; + } + + + public void setError( boolean error ) + { + this.error = error; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SetFleetsModeCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SetFleetsModeCommand.java new file mode 100644 index 0000000..3f44ab3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SetFleetsModeCommand.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.cmd.player.fleets; + + +public class SetFleetsModeCommand + extends MultiFleetsCommand +{ + + private static final long serialVersionUID = 1L; + + private final boolean attack; + private final boolean confirm; + + + public SetFleetsModeCommand( long[] fleets , boolean attack , boolean confirm ) + { + super( fleets ); + this.attack = attack; + this.confirm = confirm; + } + + + public boolean isAttack( ) + { + return attack; + } + + + public boolean isConfirm( ) + { + return confirm; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SetFleetsModeResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SetFleetsModeResponse.java new file mode 100644 index 0000000..edf245c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SetFleetsModeResponse.java @@ -0,0 +1,34 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; + + + +public class SetFleetsModeResponse + extends MultiFleetsResponse +{ + + private static final long serialVersionUID = 1L; + + private boolean attack; + + + public SetFleetsModeResponse( GamePageData page ) + { + super( page ); + } + + + public boolean isAttack( ) + { + return attack; + } + + + public void setAttack( boolean attack ) + { + this.attack = attack; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SplitFleetCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SplitFleetCommand.java new file mode 100644 index 0000000..686a3c2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SplitFleetCommand.java @@ -0,0 +1,63 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import java.util.Map; + +import com.deepclone.lw.session.Command; + + + +public class SplitFleetCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final long fleet; + private final Map< Integer , Integer > ships; + private final Integer nFleets; + private final String name; + + + public SplitFleetCommand( long fleet ) + { + this.fleet = fleet; + this.ships = null; + this.nFleets = null; + this.name = null; + } + + + public SplitFleetCommand( long fleet , Map< Integer , Integer > ships , Integer nFleets , String name ) + { + this.fleet = fleet; + this.ships = ships; + this.nFleets = nFleets; + this.name = name; + } + + + public long getFleet( ) + { + return fleet; + } + + + public Map< Integer , Integer > getShips( ) + { + return ships; + } + + + public Integer getnFleets( ) + { + return nFleets; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SplitFleetResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SplitFleetResponse.java new file mode 100644 index 0000000..6351066 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/SplitFleetResponse.java @@ -0,0 +1,106 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.fleets.ShortFleetView; +import com.deepclone.lw.cmd.player.gdata.fleets.SplitShips; + + + +public class SplitFleetResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private ShortFleetView initialFleet; + private final List< SplitShips > ships = new LinkedList< SplitShips >( ); + + private int nFleets = 1; + private String name = ""; + private boolean nameError = false; + private boolean shipsError = false; + + + public SplitFleetResponse( GamePageData page ) + { + super( page ); + } + + + public ShortFleetView getInitialFleet( ) + { + return initialFleet; + } + + + public void setInitialFleet( ShortFleetView initialFleet ) + { + this.initialFleet = initialFleet; + } + + + public int getnFleets( ) + { + return nFleets; + } + + + public void setnFleets( int nFleets ) + { + this.nFleets = nFleets; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public boolean isNameError( ) + { + return nameError; + } + + + public void setNameError( boolean nameError ) + { + this.nameError = nameError; + } + + + public boolean isShipsError( ) + { + return shipsError; + } + + + public void setShipsError( boolean shipsError ) + { + this.shipsError = shipsError; + } + + + public void addShips( SplitShips ships ) + { + this.ships.add( ships ); + } + + + public List< SplitShips > getShips( ) + { + return ships; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/ViewFleetsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/ViewFleetsCommand.java new file mode 100644 index 0000000..67f33d3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/ViewFleetsCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import com.deepclone.lw.session.Command; + + + +public class ViewFleetsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/ViewFleetsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/ViewFleetsResponse.java new file mode 100644 index 0000000..d1c6484 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/fleets/ViewFleetsResponse.java @@ -0,0 +1,30 @@ +package com.deepclone.lw.cmd.player.fleets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.fleets.FleetsView; + + + +public class ViewFleetsResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + private final FleetsView fleets; + + + public ViewFleetsResponse( GamePageData page , FleetsView view ) + { + super( page ); + this.fleets = view; + } + + + public FleetsView getFleets( ) + { + return fleets; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GamePageData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GamePageData.java new file mode 100644 index 0000000..82e1767 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GamePageData.java @@ -0,0 +1,87 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.io.Serializable; +import java.util.Collections; +import java.util.Date; +import java.util.List; + + + +public class GamePageData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + private final String empire; + private final Character special; + private final String alliance; + private final long cash; + private final Date serverTime; + private final GameTime gameTime; + private final List< NameIdPair > planets; + private final boolean useRLTime; + + + public GamePageData( String empire , Character special , String alliance , long cash , long gameTime , + List< NameIdPair > planets , boolean useRLTime ) + { + this.empire = empire; + this.special = special; + this.alliance = alliance; + this.cash = cash; + this.serverTime = new Date( ); + this.gameTime = new GameTime( gameTime ); + this.planets = Collections.unmodifiableList( planets ); + this.useRLTime = useRLTime; + } + + + public String getEmpire( ) + { + return empire; + } + + + public Character getSpecial( ) + { + return special; + } + + + public String getAlliance( ) + { + return alliance; + } + + + public long getCash( ) + { + return cash; + } + + + public Date getServerTime( ) + { + return serverTime; + } + + + public GameTime getGameTime( ) + { + return gameTime; + } + + + public List< NameIdPair > getPlanets( ) + { + return planets; + } + + + public boolean isUseRLTime( ) + { + return useRLTime; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GameResponseBase.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GameResponseBase.java new file mode 100644 index 0000000..f535b9d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GameResponseBase.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import com.deepclone.lw.session.CommandResponse; + + + +public abstract class GameResponseBase + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + + private final GamePageData page; + + + public GameResponseBase( GamePageData page ) + { + this.page = page; + } + + + public GamePageData getPage( ) + { + return page; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GameTime.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GameTime.java new file mode 100644 index 0000000..ac2c9b1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/GameTime.java @@ -0,0 +1,58 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.io.Serializable; + + + +public class GameTime + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final int years; + private final int weeks; + private final int days; + private final int hours; + + + public GameTime( long time ) + { + if ( time <= 0 ) { + this.hours = this.days = this.weeks = this.years = 0; + } else { + this.hours = (int) ( time % 24 ); + time = ( time - this.hours ) / 24; + this.days = (int) ( time % 7 ); + time = ( time - this.days ) / 7; + this.weeks = (int) ( time % 52 ); + this.years = (int) ( ( time - this.weeks ) / 52 ); + } + } + + + public int getYears( ) + { + return years; + } + + + public int getWeeks( ) + { + return weeks; + } + + + public int getDays( ) + { + return days; + } + + + public int getHours( ) + { + return hours; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/MailPreference.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/MailPreference.java new file mode 100644 index 0000000..c4f9eb1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/MailPreference.java @@ -0,0 +1,32 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.util.HashMap; +import java.util.Map; + + + +public enum MailPreference { + + NO_MAIL( "mailPrefNo" ) , + DAILY_RECAP( "mailPrefRecap" ) , + INSTANT( "mailPrefInstant" ); + + private String i18nId; + + + private MailPreference( String i18nId ) + { + this.i18nId = i18nId; + } + + + public static Map< MailPreference , String > getValues( ) + { + Map< MailPreference , String > v = new HashMap< MailPreference , String >( ); + for ( MailPreference s : MailPreference.values( ) ) { + v.put( s , s.i18nId ); + } + return v; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/MapSize.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/MapSize.java new file mode 100644 index 0000000..058c7f8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/MapSize.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.util.HashMap; +import java.util.Map; + + + +public enum MapSize { + + SMALL( "mapSizeSmall" ) , + MEDIUM( "mapSizeMedium" ) , + LARGE( "mapSizeLarge" ); + + private String i18nId; + + + private MapSize( String i18nId ) + { + this.i18nId = i18nId; + } + + + public static Map< MapSize , String > getValues( ) + { + Map< MapSize , String > v = new HashMap< MapSize , String >( ); + for ( MapSize s : MapSize.values( ) ) { + v.put( s , s.i18nId ); + } + return v; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/NameIdPair.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/NameIdPair.java new file mode 100644 index 0000000..4bea9e4 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/NameIdPair.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.io.Serializable; + + + +public class NameIdPair + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final long id; + private final String name; + + + public NameIdPair( long id , String name ) + { + this.id = id; + this.name = name; + } + + + public long getId( ) + { + return id; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetListData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetListData.java new file mode 100644 index 0000000..27c4571 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetListData.java @@ -0,0 +1,335 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.io.Serializable; + + + +public class PlanetListData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int id; + private String name; + + private int x; + private int y; + private int orbit; + + private long population; + private int happiness; + + private long income; + private long upkeep; + + private long militaryProduction; + private long industrialProduction; + private long growthProduction; + + private long civInvestment; + private int civAmount; + private boolean civDestroy; + private String civName; + + private long milInvestment; + private int milAmount; + private String milName; + + private long fpStatic; + private long fpOwn; + private long fpFriendly; + private long fpHostile; + + private Long battle; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public long getPopulation( ) + { + return population; + } + + + public void setPopulation( long population ) + { + this.population = population; + } + + + public int getHappiness( ) + { + return happiness; + } + + + public void setHappiness( int happiness ) + { + this.happiness = happiness; + } + + + public long getIncome( ) + { + return income; + } + + + public void setIncome( long income ) + { + this.income = income; + } + + + public long getUpkeep( ) + { + return upkeep; + } + + + public void setUpkeep( long upkeep ) + { + this.upkeep = upkeep; + } + + + public long getMilitaryProduction( ) + { + return militaryProduction; + } + + + public void setMilitaryProduction( long militaryProduction ) + { + this.militaryProduction = militaryProduction; + } + + + public long getIndustrialProduction( ) + { + return industrialProduction; + } + + + public void setIndustrialProduction( long industrialProduction ) + { + this.industrialProduction = industrialProduction; + } + + + public long getGrowthProduction( ) + { + return growthProduction; + } + + + public void setGrowthProduction( long growthProduction ) + { + this.growthProduction = growthProduction; + } + + + public long getCivInvestment( ) + { + return civInvestment; + } + + + public void setCivInvestment( long civInvestment ) + { + this.civInvestment = civInvestment; + } + + + public int getCivAmount( ) + { + return civAmount; + } + + + public void setCivAmount( int civAmount ) + { + this.civAmount = civAmount; + } + + + public boolean isCivDestroy( ) + { + return civDestroy; + } + + + public void setCivDestroy( boolean civDestroy ) + { + this.civDestroy = civDestroy; + } + + + public String getCivName( ) + { + return civName; + } + + + public void setCivName( String civName ) + { + this.civName = civName; + } + + + public long getMilInvestment( ) + { + return milInvestment; + } + + + public void setMilInvestment( long milInvestment ) + { + this.milInvestment = milInvestment; + } + + + public int getMilAmount( ) + { + return milAmount; + } + + + public void setMilAmount( int milAmount ) + { + this.milAmount = milAmount; + } + + + public String getMilName( ) + { + return milName; + } + + + public void setMilName( String milName ) + { + this.milName = milName; + } + + + public long getFpStatic( ) + { + return fpStatic; + } + + + public void setFpStatic( long fpStatic ) + { + this.fpStatic = fpStatic; + } + + + public long getFpOwn( ) + { + return fpOwn; + } + + + public void setFpOwn( long fpOwn ) + { + this.fpOwn = fpOwn; + } + + + public long getFpFriendly( ) + { + return fpFriendly; + } + + + public void setFpFriendly( long fpFriendly ) + { + this.fpFriendly = fpFriendly; + } + + + public long getFpHostile( ) + { + return fpHostile; + } + + + public void setFpHostile( long fpHostile ) + { + this.fpHostile = fpHostile; + } + + + public Long getBattle( ) + { + return battle; + } + + + public void setBattle( Long battle ) + { + this.battle = battle; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetReference.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetReference.java new file mode 100644 index 0000000..fb111b3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetReference.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.io.Serializable; + + + +public class PlanetReference + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final long identifier; + private final String name; + + + public PlanetReference( long identifier , String name ) + { + this.identifier = identifier; + this.name = name; + } + + + public long getIdentifier( ) + { + return identifier; + } + + + public String getName( ) + { + return name; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetRelationType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetRelationType.java new file mode 100644 index 0000000..4934723 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/PlanetRelationType.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.cmd.player.gdata; + + +public enum PlanetRelationType { + + OWN , + ALLIED , + ENEMY + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/ShortBattleView.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/ShortBattleView.java new file mode 100644 index 0000000..111f17e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/ShortBattleView.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.io.Serializable; + + + +public class ShortBattleView + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long id; + private long friendly; + private long hostile; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public long getFriendly( ) + { + return friendly; + } + + + public void setFriendly( long friendly ) + { + this.friendly = friendly; + } + + + public long getHostile( ) + { + return hostile; + } + + + public void setHostile( long hostile ) + { + this.hostile = hostile; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/TimeCombo.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/TimeCombo.java new file mode 100644 index 0000000..4f180d2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/TimeCombo.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.io.Serializable; + + + +public class TimeCombo + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long ticks; + private GameTime gameTime; + + + public TimeCombo( long time ) + { + this.ticks = time; + this.gameTime = new GameTime( time ); + } + + + public long getTicks( ) + { + return ticks; + } + + + public GameTime getGameTime( ) + { + return gameTime; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/AccountData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/AccountData.java new file mode 100644 index 0000000..8b94e01 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/AccountData.java @@ -0,0 +1,156 @@ +package com.deepclone.lw.cmd.player.gdata.account; + + +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.ext.ListLanguagesResponse; +import com.deepclone.lw.cmd.player.gdata.GameTime; + + + +public class AccountData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private String address; + private int gameCredits; + + private int vacCredits; + private GameTime vacTime; + private Timestamp vacStart; + + private Timestamp quitGame; + + private ListLanguagesResponse supportedLanguages; + private String language; + + private MailChangeData mailChange; + + private List< PrefCategory > preferences = new LinkedList< PrefCategory >( ); + + + public String getAddress( ) + { + return address; + } + + + public void setAddress( String address ) + { + this.address = address; + } + + + public int getGameCredits( ) + { + return gameCredits; + } + + + public void setGameCredits( int gameCredits ) + { + this.gameCredits = gameCredits; + } + + + public int getVacCredits( ) + { + return vacCredits; + } + + + public void setVacCredits( int vacCredits ) + { + this.vacCredits = vacCredits; + } + + + public GameTime getVacTime( ) + { + return this.vacTime; + } + + + public void setVacTime( int vacTime ) + { + this.vacTime = ( vacTime >= 60 ) ? new GameTime( vacTime / 60 ) : null; + } + + + public Timestamp getVacStart( ) + { + return vacStart; + } + + + public void setVacStart( Timestamp vacStart ) + { + this.vacStart = vacStart; + } + + + public Timestamp getQuitGame( ) + { + return quitGame; + } + + + public void setQuitGame( Timestamp quitGame ) + { + this.quitGame = quitGame; + } + + + public ListLanguagesResponse getSupportedLanguages( ) + { + return supportedLanguages; + } + + + public void setSupportedLanguages( ListLanguagesResponse supportedLanguages ) + { + this.supportedLanguages = supportedLanguages; + } + + + public String getLanguage( ) + { + return language; + } + + + public void setLanguage( String language ) + { + this.language = language; + } + + + public MailChangeData getMailChange( ) + { + return mailChange; + } + + + public void setMailChange( MailChangeData mailChange ) + { + this.mailChange = mailChange; + } + + + public void addPreferenceCategory( PrefCategory cat ) + { + this.preferences.add( cat ); + } + + + public List< PrefCategory > getPreferences( ) + { + return preferences; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/MailChangeData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/MailChangeData.java new file mode 100644 index 0000000..65957a1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/MailChangeData.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.cmd.player.gdata.account; + + +import java.io.Serializable; +import java.sql.Timestamp; + + + +public class MailChangeData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final Timestamp until; + + private final boolean used; + + private final String newAddress; + + + public MailChangeData( Timestamp until ) + { + this.until = until; + this.used = true; + this.newAddress = null; + } + + + public MailChangeData( Timestamp until , String newAddress ) + { + this.until = until; + this.used = false; + this.newAddress = newAddress; + } + + + public Timestamp getUntil( ) + { + return until; + } + + + public boolean isUsed( ) + { + return used; + } + + + public String getNewAddress( ) + { + return newAddress; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefCategory.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefCategory.java new file mode 100644 index 0000000..6641104 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefCategory.java @@ -0,0 +1,43 @@ +package com.deepclone.lw.cmd.player.gdata.account; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + + + +public class PrefCategory + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private String name; + private List< PrefValue > preferences = new LinkedList< PrefValue >( ); + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public void addValue( PrefValue value ) + { + this.preferences.add( value ); + } + + + public List< PrefValue > getPreferences( ) + { + return preferences; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefChoice.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefChoice.java new file mode 100644 index 0000000..fe45669 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefChoice.java @@ -0,0 +1,35 @@ +package com.deepclone.lw.cmd.player.gdata.account; + + +import java.io.Serializable; + + + +public class PrefChoice + implements Serializable +{ + private static final long serialVersionUID = 1L; + + private String value; + private String display; + + + public PrefChoice( String value , String display ) + { + this.value = value; + this.display = display; + } + + + public String getValue( ) + { + return value; + } + + + public String getDisplay( ) + { + return display; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefType.java new file mode 100644 index 0000000..267e203 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefType.java @@ -0,0 +1,9 @@ +package com.deepclone.lw.cmd.player.gdata.account; + + +public enum PrefType { + STRING , + INTEGER , + BOOLEAN , + CHOICE +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefValue.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefValue.java new file mode 100644 index 0000000..1ed93ed --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/account/PrefValue.java @@ -0,0 +1,94 @@ +package com.deepclone.lw.cmd.player.gdata.account; + + +import java.io.Serializable; +import java.util.List; + + + +public class PrefValue + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private String id; + private String name; + private String description; + private PrefType type; + private List< PrefChoice > choices; + private String value; + + + public String getId( ) + { + return id; + } + + + public void setId( String id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getDescription( ) + { + return description; + } + + + public void setDescription( String description ) + { + this.description = description; + } + + + public PrefType getType( ) + { + return type; + } + + + public void setType( PrefType type ) + { + this.type = type; + } + + + public List< PrefChoice > getChoices( ) + { + return choices; + } + + + public void setChoices( List< PrefChoice > choices ) + { + this.choices = choices; + } + + + public String getValue( ) + { + return value; + } + + + public void setValue( String value ) + { + this.value = value; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceCreationStatus.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceCreationStatus.java new file mode 100644 index 0000000..241b5a3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceCreationStatus.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.cmd.player.gdata.alliance; + + +import java.io.Serializable; + +import com.deepclone.lw.cmd.ObjectNameError; + + + +public class AllianceCreationStatus + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final String tag; + private final ObjectNameError tagError; + private final String name; + private final ObjectNameError nameError; + + + public AllianceCreationStatus( String tag , ObjectNameError tagError , String name , ObjectNameError nameError ) + { + this.tag = tag; + this.tagError = tagError; + this.name = name; + this.nameError = nameError; + } + + + public String getTag( ) + { + return tag; + } + + + public ObjectNameError getTagError( ) + { + return tagError; + } + + + public String getName( ) + { + return name; + } + + + public ObjectNameError getNameError( ) + { + return nameError; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceData.java new file mode 100644 index 0000000..08b670c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceData.java @@ -0,0 +1,45 @@ +package com.deepclone.lw.cmd.player.gdata.alliance; + + +import java.io.Serializable; + + + + +public class AllianceData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final PublicAllianceInformation main; + private final AllianceMemberData member; + private final AllianceLeaderData leader; + + + public AllianceData( PublicAllianceInformation main , AllianceMemberData member , AllianceLeaderData leader ) + { + this.main = main; + this.member = member; + this.leader = leader; + } + + + public PublicAllianceInformation getMain( ) + { + return main; + } + + + public AllianceMemberData getMember( ) + { + return member; + } + + + public AllianceLeaderData getLeader( ) + { + return leader; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceLeaderData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceLeaderData.java new file mode 100644 index 0000000..a5293df --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceLeaderData.java @@ -0,0 +1,31 @@ +package com.deepclone.lw.cmd.player.gdata.alliance; + + +import java.io.Serializable; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class AllianceLeaderData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final List< NameIdPair > requests; + + + public AllianceLeaderData( List< NameIdPair > requests ) + { + this.requests = requests; + } + + + public List< NameIdPair > getRequests( ) + { + return requests; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceMemberData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceMemberData.java new file mode 100644 index 0000000..48f35a3 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AllianceMemberData.java @@ -0,0 +1,39 @@ +package com.deepclone.lw.cmd.player.gdata.alliance; + + +import java.io.Serializable; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class AllianceMemberData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final List< NameIdPair > members; + private final List< AlliancePlanetData > planets; + + + public AllianceMemberData( List< NameIdPair > members , List< AlliancePlanetData > planets ) + { + this.members = members; + this.planets = planets; + } + + + public List< NameIdPair > getMembers( ) + { + return members; + } + + + public List< AlliancePlanetData > getPlanets( ) + { + return planets; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AlliancePlanetData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AlliancePlanetData.java new file mode 100644 index 0000000..a17aa8a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/AlliancePlanetData.java @@ -0,0 +1,146 @@ +package com.deepclone.lw.cmd.player.gdata.alliance; + + +import java.io.Serializable; + + + +public class AlliancePlanetData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int id; + private String name; + private int x; + private int y; + private int orbit; + private int ownerId; + private String owner; + + private boolean battle; + private long defence; + private long attack; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public int getOwnerId( ) + { + return ownerId; + } + + + public void setOwnerId( int ownerId ) + { + this.ownerId = ownerId; + } + + + public String getOwner( ) + { + return owner; + } + + + public void setOwner( String owner ) + { + this.owner = owner; + } + + + public boolean isBattle( ) + { + return battle; + } + + + public void setBattle( boolean battle ) + { + this.battle = battle; + } + + + public long getDefence( ) + { + return defence; + } + + + public void setDefence( long defence ) + { + this.defence = defence; + } + + + public long getAttack( ) + { + return attack; + } + + + public void setAttack( long attack ) + { + this.attack = attack; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/PublicAllianceInformation.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/PublicAllianceInformation.java new file mode 100644 index 0000000..76463c1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/alliance/PublicAllianceInformation.java @@ -0,0 +1,69 @@ +package com.deepclone.lw.cmd.player.gdata.alliance; + + +import java.io.Serializable; + + + +public class PublicAllianceInformation + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final int id; + private final String tag; + private final String name; + private final int leaderId; + private final String leaderName; + private final long planets; + + + public PublicAllianceInformation( int id , String tag , String name , int leaderId , String leaderName , + long planets ) + { + this.id = id; + this.tag = tag; + this.name = name; + this.leaderId = leaderId; + this.leaderName = leaderName; + this.planets = planets; + } + + + public int getId( ) + { + return id; + } + + + public String getTag( ) + { + return tag; + } + + + public String getName( ) + { + return name; + } + + + public int getLeaderId( ) + { + return leaderId; + } + + + public String getLeaderName( ) + { + return leaderName; + } + + + public long getPlanets( ) + { + return planets; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleDescription.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleDescription.java new file mode 100644 index 0000000..22eed1e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleDescription.java @@ -0,0 +1,83 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class BattleDescription + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long id; + private NameIdPair location; + private int x; + private int y; + private int orbit; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public NameIdPair getLocation( ) + { + return location; + } + + + public void setLocation( NameIdPair location ) + { + this.location = location; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleDisplay.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleDisplay.java new file mode 100644 index 0000000..e6d94d0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleDisplay.java @@ -0,0 +1,70 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.TimeCombo; + + + +public class BattleDisplay + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private TimeCombo current; + private TimeCombo previous; + private TimeCombo next; + private List< TimeCombo > all = new LinkedList< TimeCombo >( ); + + + public TimeCombo getCurrent( ) + { + return current; + } + + + public void setCurrent( long current ) + { + this.current = new TimeCombo( current ); + } + + + public TimeCombo getPrevious( ) + { + return previous; + } + + + public void setPrevious( long previous ) + { + this.previous = new TimeCombo( previous ); + } + + + public TimeCombo getNext( ) + { + return next; + } + + + public void setNext( long next ) + { + this.next = new TimeCombo( next ); + } + + + public void addTime( long time ) + { + this.all.add( new TimeCombo( time ) ); + } + + + public List< TimeCombo > getAll( ) + { + return all; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleEvent.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleEvent.java new file mode 100644 index 0000000..6e99a05 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleEvent.java @@ -0,0 +1,82 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + + + +public class BattleEvent + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private BattleEventType type; + private boolean planet; + private String name; + private Boolean hostile; + private List< BattleShipType > ships = new LinkedList< BattleShipType >( ); + + + public BattleEventType getType( ) + { + return type; + } + + + public void setType( BattleEventType type ) + { + this.type = type; + } + + + public boolean isPlanet( ) + { + return planet; + } + + + public void setPlanet( boolean planet ) + { + this.planet = planet; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public Boolean getHostile( ) + { + return hostile; + } + + + public void setHostile( Boolean attack ) + { + this.hostile = attack; + } + + + public void addShip( BattleShipType shipType ) + { + this.ships.add( shipType ); + } + + + public List< BattleShipType > getShips( ) + { + return ships; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleEventType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleEventType.java new file mode 100644 index 0000000..34ed24f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleEventType.java @@ -0,0 +1,13 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +public enum BattleEventType { + + RENAME , + SWITCH , + ARRIVE , + DEPART , + BUILD , + DESTROY + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleHistoryInterval.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleHistoryInterval.java new file mode 100644 index 0000000..7c15e5e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleHistoryInterval.java @@ -0,0 +1,75 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.TimeCombo; + + + +public class BattleHistoryInterval + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private TimeCombo begin; + private boolean battleBegins; + private TimeCombo end; + private boolean battleEnds; + + private final List< BattleHistoryTick > entries = new LinkedList< BattleHistoryTick >( ); + + + public TimeCombo getBegin( ) + { + return begin; + } + + + public boolean isBattleBegins( ) + { + return battleBegins; + } + + + public void setBegin( long tick , boolean battle ) + { + this.battleBegins = battle; + this.begin = new TimeCombo( tick ); + } + + + public TimeCombo getEnd( ) + { + return end; + } + + + public boolean isBattleEnds( ) + { + return battleEnds; + } + + + public void setEnd( long tick , boolean battle ) + { + this.battleEnds = battle; + this.end = new TimeCombo( tick ); + } + + + public List< BattleHistoryTick > getEntries( ) + { + return entries; + } + + + public void addEntry( BattleHistoryTick cTick ) + { + this.entries.add( cTick ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleHistoryTick.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleHistoryTick.java new file mode 100644 index 0000000..526de4f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleHistoryTick.java @@ -0,0 +1,45 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.TimeCombo; + + + +public class BattleHistoryTick + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final TimeCombo time; + private final List< BattleEvent > events = new LinkedList< BattleEvent >( ); + + + public BattleHistoryTick( long tick ) + { + this.time = new TimeCombo( tick ); + } + + + public void addEvent( BattleEvent event ) + { + this.events.add( event ); + } + + + public TimeCombo getTime( ) + { + return time; + } + + + public List< BattleEvent > getEvents( ) + { + return events; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleListEntry.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleListEntry.java new file mode 100644 index 0000000..aca40ad --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleListEntry.java @@ -0,0 +1,109 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.TimeCombo; + + + +public class BattleListEntry + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long id; + private NameIdPair location; + private int x; + private int y; + private int orbit; + private TimeCombo first; + private TimeCombo last; + + + public long getId( ) + { + return id; + } + + + public void setId( long id ) + { + this.id = id; + } + + + public NameIdPair getLocation( ) + { + return location; + } + + + public void setLocation( NameIdPair location ) + { + this.location = location; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public TimeCombo getFirst( ) + { + return first; + } + + + public void setFirst( long first ) + { + this.first = new TimeCombo( first ); + } + + + public TimeCombo getLast( ) + { + return last; + } + + + public void setLast( long last ) + { + this.last = new TimeCombo( last ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattlePlanetBuildings.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattlePlanetBuildings.java new file mode 100644 index 0000000..d416dd1 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattlePlanetBuildings.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import com.deepclone.lw.cmd.player.gdata.PlanetRelationType; + + + +public class BattlePlanetBuildings + extends BattleShipsList +{ + + private static final long serialVersionUID = 1L; + + private PlanetRelationType relation; + + + public PlanetRelationType getRelation( ) + { + return relation; + } + + + public void setRelation( PlanetRelationType relation ) + { + this.relation = relation; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattlePlayerShips.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattlePlayerShips.java new file mode 100644 index 0000000..af042d8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattlePlayerShips.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class BattlePlayerShips + extends BattleShipsList +{ + + private static final long serialVersionUID = 1L; + + private NameIdPair player; + + + public NameIdPair getPlayer( ) + { + return player; + } + + + public void setPlayer( NameIdPair player ) + { + this.player = player; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipType.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipType.java new file mode 100644 index 0000000..3133440 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipType.java @@ -0,0 +1,111 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; + + + +public class BattleShipType + implements Serializable , Comparable< BattleShipType > +{ + + private static final long serialVersionUID = 1L; + + private String name; + private long cAmount; + private long cPower; + private long lAmount; + private long lPower; + + + public BattleShipType( ) + { + // EMPTY + } + + + public BattleShipType( BattleShipType shipType ) + { + this.name = shipType.name; + this.cAmount = shipType.cAmount; + this.cPower = shipType.cPower; + this.lAmount = shipType.lAmount; + this.lPower = shipType.lPower; + } + + + public void add( BattleShipType shipType ) + { + this.cAmount += shipType.cAmount; + this.cPower += shipType.cPower; + this.lAmount += shipType.lAmount; + this.lPower += shipType.lPower; + } + + + @Override + public int compareTo( BattleShipType o ) + { + return this.name.compareTo( o.name ); + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public long getcAmount( ) + { + return cAmount; + } + + + public void setcAmount( long cAmount ) + { + this.cAmount = cAmount; + } + + + public long getcPower( ) + { + return cPower; + } + + + public void setcPower( long cPower ) + { + this.cPower = cPower; + } + + + public long getlAmount( ) + { + return lAmount; + } + + + public void setlAmount( long lAmount ) + { + this.lAmount = lAmount; + } + + + public long getlPower( ) + { + return lPower; + } + + + public void setlPower( long lPower ) + { + this.lPower = lPower; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipsList.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipsList.java new file mode 100644 index 0000000..389771b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipsList.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + + + +public abstract class BattleShipsList + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + protected List< BattleShipType > ships = new LinkedList< BattleShipType >( ); + protected long cPower = 0; + protected long lPower = 0; + + + public void addShip( BattleShipType shipType ) + { + this.ships.add( shipType ); + this.cPower += shipType.getcPower( ); + this.lPower += shipType.getlPower( ); + } + + + public List< BattleShipType > getShips( ) + { + return ships; + } + + + public long getcPower( ) + { + return cPower; + } + + + public long getlPower( ) + { + return lPower; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipsView.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipsView.java new file mode 100644 index 0000000..d38d726 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleShipsView.java @@ -0,0 +1,43 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; + + + +public class BattleShipsView + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final BattlePlayerShips own = new BattlePlayerShips( ); + private final BattleSideShips friendly = new BattleSideShips( false ); + private final BattleSideShips hostile = new BattleSideShips( true ); + private final BattlePlanetBuildings planet = new BattlePlanetBuildings( ); + + + public BattlePlayerShips getOwn( ) + { + return own; + } + + + public BattleSideShips getFriendly( ) + { + return friendly; + } + + + public BattleSideShips getHostile( ) + { + return hostile; + } + + + public BattlePlanetBuildings getPlanet( ) + { + return planet; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleSideShips.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleSideShips.java new file mode 100644 index 0000000..6dca7ad --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleSideShips.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + + + +public class BattleSideShips + extends BattleShipsList +{ + + private static final long serialVersionUID = 1L; + + private final boolean hostile; + private final List< BattlePlayerShips > players = new LinkedList< BattlePlayerShips >( ); + + + public BattleSideShips( boolean hostile ) + { + this.hostile = hostile; + } + + + public boolean isHostile( ) + { + return hostile; + } + + + public List< BattlePlayerShips > getPlayers( ) + { + return players; + } + + + public void addPlayer( BattlePlayerShips player ) + { + this.players.add( player ); + for ( BattleShipType pShipType : player.getShips( ) ) { + boolean found = false; + + for ( BattleShipType shipType : this.ships ) { + if ( shipType.compareTo( pShipType ) != 0 ) { + continue; + } + + shipType.add( pShipType ); + found = true; + break; + } + + if ( !found ) { + this.ships.add( new BattleShipType( pShipType ) ); + } + this.cPower += pShipType.getcPower( ); + this.lPower += pShipType.getlPower( ); + } + Collections.sort( this.ships ); + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleView.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleView.java new file mode 100644 index 0000000..c9fc728 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/battles/BattleView.java @@ -0,0 +1,69 @@ +package com.deepclone.lw.cmd.player.gdata.battles; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + + + +public class BattleView + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private BattleDescription description; + private BattleDisplay display; + private BattleShipsView ships; + private final List< BattleHistoryInterval > history = new LinkedList< BattleHistoryInterval >( ); + + + public BattleDescription getDescription( ) + { + return description; + } + + + public void setDescription( BattleDescription description ) + { + this.description = description; + } + + + public BattleDisplay getDisplay( ) + { + return display; + } + + + public void setDisplay( BattleDisplay display ) + { + this.display = display; + } + + + public BattleShipsView getShips( ) + { + return ships; + } + + + public void setShips( BattleShipsView ships ) + { + this.ships = ships; + } + + + public void addHistoryInterval( BattleHistoryInterval entry ) + { + this.history.add( entry ); + } + + + public List< BattleHistoryInterval > getHistory( ) + { + return history; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/OverviewData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/OverviewData.java new file mode 100644 index 0000000..d82cc66 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/OverviewData.java @@ -0,0 +1,132 @@ +package com.deepclone.lw.cmd.player.gdata.empire; + + +import java.io.Serializable; + + + +public class OverviewData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long planets; + private int newMessages; + private long population; + private int avgHappiness; + private long fleetPower; + private long planetIncome; + private long planetUpkeep; + private long fleetUpkeep; + private long investment; + + + public long getPlanets( ) + { + return planets; + } + + + public void setPlanets( long planets ) + { + this.planets = planets; + } + + + public int getNewMessages( ) + { + return newMessages; + } + + + public void setNewMessages( int newMessages ) + { + this.newMessages = newMessages; + } + + + public long getPopulation( ) + { + return population; + } + + + public void setPopulation( long population ) + { + this.population = population; + } + + + public int getAvgHappiness( ) + { + return avgHappiness; + } + + + public void setAvgHappiness( int avgHappiness ) + { + this.avgHappiness = avgHappiness; + } + + + public long getFleetPower( ) + { + return fleetPower; + } + + + public void setFleetPower( long fleetPower ) + { + this.fleetPower = fleetPower; + } + + + public long getPlanetIncome( ) + { + return planetIncome; + } + + + public void setPlanetIncome( long planetIncome ) + { + this.planetIncome = planetIncome; + } + + + public long getPlanetUpkeep( ) + { + return planetUpkeep; + } + + + public void setPlanetUpkeep( long planetUpkeep ) + { + this.planetUpkeep = planetUpkeep; + } + + + public long getFleetUpkeep( ) + { + return fleetUpkeep; + } + + + public void setFleetUpkeep( long fleetUpkeep ) + { + this.fleetUpkeep = fleetUpkeep; + } + + + public long getInvestment( ) + { + return investment; + } + + + public void setInvestment( long investment ) + { + this.investment = investment; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/ResearchLineData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/ResearchLineData.java new file mode 100644 index 0000000..a48f027 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/ResearchLineData.java @@ -0,0 +1,70 @@ +package com.deepclone.lw.cmd.player.gdata.empire; + + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + + + +public class ResearchLineData + implements Serializable , Comparable< ResearchLineData > +{ + + private static final long serialVersionUID = 1L; + + private final long id; + private final String name; + private final String description; + private final List< TechnologyData > implemented; + private final TechnologyData current; + + + public ResearchLineData( long id , String name , String description , List< TechnologyData > implemented , + TechnologyData current ) + { + this.id = id; + this.name = name; + this.description = description; + this.implemented = Collections.unmodifiableList( implemented ); + this.current = current; + } + + + @Override + public int compareTo( ResearchLineData other ) + { + return this.name.compareTo( other.name ); + } + + + public long getId( ) + { + return id; + } + + + public String getName( ) + { + return name; + } + + + public String getDescription( ) + { + return description; + } + + + public List< TechnologyData > getImplemented( ) + { + return implemented; + } + + + public TechnologyData getCurrent( ) + { + return current; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/TechnologyData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/TechnologyData.java new file mode 100644 index 0000000..7ea35f0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/TechnologyData.java @@ -0,0 +1,70 @@ +package com.deepclone.lw.cmd.player.gdata.empire; + + +import java.io.Serializable; + + + +public class TechnologyData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final String name; + private final String description; + private final Integer researched; + private final Long cost; + + + public TechnologyData( String name , String description ) + { + this.name = name; + this.description = description; + this.researched = null; + this.cost = null; + } + + + public TechnologyData( String name , String description , int researched ) + { + this.name = name; + this.description = description; + this.researched = researched; + this.cost = null; + } + + + public TechnologyData( String name , String description , int researched , long cost ) + { + this.name = name; + this.description = description; + this.researched = researched; + this.cost = cost; + } + + + public String getName( ) + { + return name; + } + + + public String getDescription( ) + { + return description; + } + + + public Integer getResearched( ) + { + return researched; + } + + + public Long getCost( ) + { + return cost; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetLocation.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetLocation.java new file mode 100644 index 0000000..464936b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetLocation.java @@ -0,0 +1,181 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.ShortBattleView; + + + +public class FleetLocation + extends NameIdPair +{ + + private static final long serialVersionUID = 1L; + + private boolean own; + private boolean attacking; + private int x; + private int y; + private int orbit; + private String tag; + private int picture; + private long population; + private long defence; + private ShortBattleView battle; + private boolean onVacation; + private final List< FleetOwner > fleetOwners = new LinkedList< FleetOwner >( ); + + + public FleetLocation( long id , String name ) + { + super( id , name ); + } + + + public boolean isOwn( ) + { + return own; + } + + + public void setOwn( boolean own ) + { + this.own = own; + } + + + public boolean isAttacking( ) + { + return attacking; + } + + + public void setAttacking( boolean attacking ) + { + this.attacking = attacking; + } + + + public int getX( ) + { + return x; + } + + + public void setX( int x ) + { + this.x = x; + } + + + public int getY( ) + { + return y; + } + + + public void setY( int y ) + { + this.y = y; + } + + + public int getOrbit( ) + { + return orbit; + } + + + public void setOrbit( int orbit ) + { + this.orbit = orbit; + } + + + public String getTag( ) + { + return tag; + } + + + public void setTag( String tag ) + { + this.tag = tag; + } + + + public int getPicture( ) + { + return picture; + } + + + public void setPicture( int picture ) + { + this.picture = picture; + } + + + public long getPopulation( ) + { + return population; + } + + + public void setPopulation( long population ) + { + this.population = population; + } + + + public long getDefence( ) + { + return defence; + } + + + public void setDefence( long defence ) + { + this.defence = defence; + } + + + public ShortBattleView getBattle( ) + { + return battle; + } + + + public void setBattle( ShortBattleView battle ) + { + this.battle = battle; + } + + + public boolean isOnVacation( ) + { + return onVacation; + } + + + public void setOnVacation( boolean onVacation ) + { + this.onVacation = onVacation; + } + + + public void addFleetOwner( FleetOwner fOwner ) + { + this.fleetOwners.add( fOwner ); + } + + + public List< FleetOwner > getFleetOwners( ) + { + return fleetOwners; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetOwner.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetOwner.java new file mode 100644 index 0000000..2653142 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetOwner.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.PlanetRelationType; + + + +; + +public class FleetOwner + extends NameIdPair +{ + + private static final long serialVersionUID = 1L; + + private final PlanetRelationType relation; + private final List< StaticFleet > fleets = new LinkedList< StaticFleet >( ); + + + public FleetOwner( long id , String name , PlanetRelationType relation ) + { + super( id , name ); + this.relation = relation; + } + + + public PlanetRelationType getRelation( ) + { + return relation; + } + + + public void addFleet( StaticFleet fleet ) + { + this.fleets.add( fleet ); + } + + + public List< StaticFleet > getFleets( ) + { + return fleets; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetShips.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetShips.java new file mode 100644 index 0000000..a29a8a6 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetShips.java @@ -0,0 +1,67 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +import java.io.Serializable; + + + +public class FleetShips + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int type; + private String name; + private long amount; + private long power; + + + public int getType( ) + { + return type; + } + + + public void setType( int type ) + { + this.type = type; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public long getAmount( ) + { + return amount; + } + + + public void setAmount( long amount ) + { + this.amount = amount; + } + + + public long getPower( ) + { + return power; + } + + + public void setPower( long power ) + { + this.power = power; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetStatus.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetStatus.java new file mode 100644 index 0000000..e588b40 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetStatus.java @@ -0,0 +1,11 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +public enum FleetStatus { + + AVAILABLE , + DEPLOYING , + REDEPLOYING , + REDIRECTING + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetsView.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetsView.java new file mode 100644 index 0000000..dc16fe4 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/FleetsView.java @@ -0,0 +1,43 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + + + +public class FleetsView + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final List< FleetLocation > locations = new LinkedList< FleetLocation >( ); + private final List< MovingFleet > moving = new LinkedList< MovingFleet >( ); + + + public void addLocation( FleetLocation location ) + { + this.locations.add( location ); + } + + + public List< FleetLocation > getLocations( ) + { + return locations; + } + + + public void addMovingFleet( MovingFleet fleet ) + { + this.moving.add( fleet ); + } + + + public List< MovingFleet > getMoving( ) + { + return moving; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/MovingFleet.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/MovingFleet.java new file mode 100644 index 0000000..e37a38f --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/MovingFleet.java @@ -0,0 +1,130 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +import com.deepclone.lw.cmd.player.gdata.GameTime; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class MovingFleet + extends StaticFleet +{ + + private static final long serialVersionUID = 1L; + + private long timeLeft; + private boolean attacking; + private NameIdPair source; + private NameIdPair destination; + private double currentX; + private double currentY; + private NameIdPair nearest; + + + public MovingFleet( long id , String name ) + { + super( id , name ); + } + + + public long getTimeLeft( ) + { + return timeLeft; + } + + + public GameTime getGameTimeLeft( ) + { + return new GameTime( this.timeLeft ); + } + + + public void setTimeLeft( long timeLeft ) + { + this.timeLeft = timeLeft; + } + + + public boolean isAttacking( ) + { + return attacking; + } + + + public void setAttacking( boolean attacking ) + { + this.attacking = attacking; + } + + + public NameIdPair getSource( ) + { + return source; + } + + + public void setSource( NameIdPair source ) + { + this.source = source; + } + + + public NameIdPair getDestination( ) + { + return destination; + } + + + public void setDestination( NameIdPair destination ) + { + this.destination = destination; + } + + + public double getCurrentX( ) + { + return currentX; + } + + + public void setCurrentX( double currentX ) + { + this.currentX = currentX; + } + + + public double getCurrentY( ) + { + return currentY; + } + + + public void setCurrentY( double currentY ) + { + this.currentY = currentY; + } + + + public NameIdPair getNearest( ) + { + return nearest; + } + + + public void setNearest( NameIdPair nearest ) + { + this.nearest = nearest; + } + + + public long getEta( ) + { + return this.getPenalty( ) + this.timeLeft; + } + + + public GameTime getGameEta( ) + { + return new GameTime( this.getPenalty( ) + this.timeLeft ); + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/ShortFleetView.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/ShortFleetView.java new file mode 100644 index 0000000..a19833a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/ShortFleetView.java @@ -0,0 +1,147 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +import com.deepclone.lw.cmd.player.gdata.GameTime; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class ShortFleetView + extends NameIdPair +{ + + private static final long serialVersionUID = 1L; + + private int flightTime; + private GameTime gameFlightTime; + private long power; + private FleetStatus status; + private int penalty; + private boolean attack; + private double x; + private double y; + private boolean atPlanet; + private NameIdPair nearest; + + + public ShortFleetView( long id , String name ) + { + super( id , name ); + } + + + public int getFlightTime( ) + { + return flightTime; + } + + + public GameTime getGameFlightTime( ) + { + return gameFlightTime; + } + + + public void setFlightTime( int flightTime ) + { + this.flightTime = flightTime; + this.gameFlightTime = new GameTime( flightTime ); + } + + + public long getPower( ) + { + return power; + } + + + public void setPower( long power ) + { + this.power = power; + } + + + public FleetStatus getStatus( ) + { + return status; + } + + + public void setStatus( FleetStatus status ) + { + this.status = status; + } + + + public int getPenalty( ) + { + return penalty; + } + + + public void setPenalty( int penalty ) + { + this.penalty = penalty; + } + + + public boolean isAttack( ) + { + return attack; + } + + + public void setAttack( boolean attack ) + { + this.attack = attack; + } + + + public double getX( ) + { + return x; + } + + + public void setX( double x ) + { + this.x = x; + } + + + public double getY( ) + { + return y; + } + + + public void setY( double y ) + { + this.y = y; + } + + + public boolean isAtPlanet( ) + { + return atPlanet; + } + + + public void setAtPlanet( boolean atPlanet ) + { + this.atPlanet = atPlanet; + } + + + public NameIdPair getNearest( ) + { + return nearest; + } + + + public void setNearest( NameIdPair nearest ) + { + this.nearest = nearest; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/SplitShips.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/SplitShips.java new file mode 100644 index 0000000..b464387 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/SplitShips.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +public class SplitShips + extends FleetShips +{ + + private static final long serialVersionUID = 1L; + + private int id; + private int selectedAmount = 0; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public int getSelectedAmount( ) + { + return selectedAmount; + } + + + public void setSelectedAmount( int selectedAmount ) + { + this.selectedAmount = selectedAmount; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/StaticFleet.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/StaticFleet.java new file mode 100644 index 0000000..32d9ac9 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/fleets/StaticFleet.java @@ -0,0 +1,101 @@ +package com.deepclone.lw.cmd.player.gdata.fleets; + + +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.GameTime; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; + + + +public class StaticFleet + extends NameIdPair +{ + + private static final long serialVersionUID = 1L; + + private FleetStatus status; + private long penalty; + private long power; + private int flightTime; + private final List< FleetShips > ships = new LinkedList< FleetShips >( ); + + + public StaticFleet( long id , String name ) + { + super( id , name ); + } + + + public FleetStatus getStatus( ) + { + return status; + } + + + public void setStatus( FleetStatus status ) + { + this.status = status; + } + + + public long getPenalty( ) + { + return penalty; + } + + public GameTime getGamePenalty( ) + { + return new GameTime( penalty); + } + + + public void setPenalty( int penalty ) + { + this.penalty = penalty; + } + + + public long getPower( ) + { + return power; + } + + + public void setPower( long power ) + { + this.power = power; + } + + + public long getFlightTime( ) + { + return flightTime; + } + + + public GameTime getGameFlightTime( ) + { + return new GameTime( this.flightTime ); + } + + + public void setFlightTime( int flightTime ) + { + this.flightTime = flightTime; + } + + + public void addShips( FleetShips ships ) + { + this.ships.add( ships ); + } + + + public List< FleetShips > getShips( ) + { + return ships; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/map/MapPlanetData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/map/MapPlanetData.java new file mode 100644 index 0000000..8a04d19 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/map/MapPlanetData.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.cmd.player.gdata.map; + + +import java.io.Serializable; + +import com.deepclone.lw.cmd.player.gdata.PlanetRelationType; + + + +public class MapPlanetData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final long id; + private final int picture; + private final String name; + private final String tag; + private final PlanetRelationType relation; + + + public MapPlanetData( long id , int picture , String name , String tag , PlanetRelationType relation ) + { + this.id = id; + this.picture = picture; + this.name = name; + this.tag = tag; + this.relation = relation; + } + + + public long getId( ) + { + return id; + } + + + public int getPicture( ) + { + return picture; + } + + + public String getName( ) + { + return name; + } + + + public String getTag( ) + { + return tag; + } + + + public PlanetRelationType getRelation( ) + { + return relation; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/map/MapSystemData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/map/MapSystemData.java new file mode 100644 index 0000000..db7a54a --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/map/MapSystemData.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.cmd.player.gdata.map; + + +import java.io.Serializable; + + + +public class MapSystemData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final MapPlanetData planets[] = new MapPlanetData[ 5 ]; + + + public MapPlanetData[] getPlanets( ) + { + return this.planets; + } + + + public void setPlanet( int orbit , MapPlanetData planet ) + { + this.planets[ orbit - 1 ] = planet; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableBuildingData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableBuildingData.java new file mode 100644 index 0000000..34c5ce6 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableBuildingData.java @@ -0,0 +1,50 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +public class BuildableBuildingData + extends BuildableItemData +{ + + private static final long serialVersionUID = 1L; + + private int workers; + private String prodType; + private int output; + + + public int getWorkers( ) + { + return workers; + } + + + public void setWorkers( int workers ) + { + this.workers = workers; + } + + + public String getProdType( ) + { + return prodType; + } + + + public void setProdType( String prodType ) + { + this.prodType = prodType; + } + + + public int getOutput( ) + { + return output; + } + + + public void setOutput( int output ) + { + this.output = output; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableItemData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableItemData.java new file mode 100644 index 0000000..5ae878e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableItemData.java @@ -0,0 +1,107 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; + +import com.deepclone.lw.cmd.player.gdata.GameTime; + + + +public abstract class BuildableItemData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int id; + private String name; + private String description; + private int cost; + private int upkeep; + private Long time; + private GameTime gameTime; + + + public int getId( ) + { + return id; + } + + + public void setId( int id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getDescription( ) + { + return description; + } + + + public void setDescription( String description ) + { + this.description = description; + } + + + public int getCost( ) + { + return cost; + } + + + public void setCost( int cost ) + { + this.cost = cost; + } + + + public int getUpkeep( ) + { + return upkeep; + } + + + public void setUpkeep( int upkeep ) + { + this.upkeep = upkeep; + } + + + public Long getTime( ) + { + return time; + } + + + public void setTime( Long time ) + { + this.time = time; + if ( time == null ) { + this.gameTime = null; + } else { + this.gameTime = new GameTime( time ); + } + } + + + public GameTime getGameTime( ) + { + return gameTime; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableShipData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableShipData.java new file mode 100644 index 0000000..99c6d5b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildableShipData.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + +import com.deepclone.lw.cmd.player.gdata.GameTime; + + +public class BuildableShipData + extends BuildableItemData +{ + + private static final long serialVersionUID = 1L; + + private int power; + private int flightTime; + private GameTime gameFlightTime; + + + public int getPower( ) + { + return power; + } + + + public void setPower( int power ) + { + this.power = power; + } + + + public int getFlightTime( ) + { + return flightTime; + } + + + public GameTime getGameFlightTime( ) + { + return gameFlightTime; + } + + + public void setFlightTime( int flightTime ) + { + this.flightTime = flightTime; + this.gameFlightTime = new GameTime( flightTime ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildingData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildingData.java new file mode 100644 index 0000000..7647c24 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/BuildingData.java @@ -0,0 +1,119 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; + + + +public class BuildingData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private Integer id; + private String name; + private String description; + private int amount; + private String produces; + private Long output; + private Integer jobs; + private Long upkeep; + + + public Integer getId( ) + { + return id; + } + + + public void setId( Integer id ) + { + this.id = id; + } + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getDescription( ) + { + return description; + } + + + public void setDescription( String description ) + { + this.description = description; + } + + + public int getAmount( ) + { + return amount; + } + + + public void setAmount( int amount ) + { + this.amount = amount; + } + + + public String getProduces( ) + { + return produces; + } + + + public void setProduces( String produces ) + { + this.produces = produces; + } + + + public Long getOutput( ) + { + return output; + } + + + public void setOutput( Long output ) + { + this.output = output; + } + + + public Integer getJobs( ) + { + return jobs; + } + + + public void setJobs( Integer jobs ) + { + this.jobs = jobs; + } + + + public Long getUpkeep( ) + { + return upkeep; + } + + + public void setUpkeep( Long upkeep ) + { + this.upkeep = upkeep; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/OwnPlanetStatusData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/OwnPlanetStatusData.java new file mode 100644 index 0000000..6013826 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/OwnPlanetStatusData.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; + +import com.deepclone.lw.cmd.player.gdata.GameTime; + + + +public class OwnPlanetStatusData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private boolean abandonPossible; + private boolean renamePossible; + private Integer abandonTime; + private GameTime abandonGameTime; + + + public boolean isAbandonPossible( ) + { + return abandonPossible; + } + + + public void setAbandonPossible( boolean abandonPossible ) + { + this.abandonPossible = abandonPossible; + } + + + public boolean isRenamePossible( ) + { + return renamePossible; + } + + + public void setRenamePossible( boolean renamePossible ) + { + this.renamePossible = renamePossible; + } + + + public Integer getAbandonTime( ) + { + return abandonTime; + } + + + public void setAbandonTime( Integer abandonTime ) + { + this.abandonTime = abandonTime; + if ( abandonTime == null ) { + this.abandonGameTime = null; + } else { + this.abandonGameTime = new GameTime( abandonTime.longValue( ) ); + } + } + + + public GameTime getAbandonGameTime( ) + { + return abandonGameTime; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetBasicView.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetBasicView.java new file mode 100644 index 0000000..31de86e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetBasicView.java @@ -0,0 +1,79 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; + + + +public class PlanetBasicView + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final String name; + private final int picture; + private final String alliance; + private final int x; + private final int y; + private final int orbit; + + + public PlanetBasicView( String name , int picture , String alliance , int x , int y , int orbit ) + { + this.name = name; + this.picture = picture; + this.alliance = alliance; + this.x = x; + this.y = y; + this.orbit = orbit; + } + + + public PlanetBasicView( PlanetBasicView source , String newName ) + { + this.name = newName; + this.picture = source.picture; + this.alliance = source.alliance; + this.x = source.x; + this.y = source.y; + this.orbit = source.orbit; + } + + + public String getName( ) + { + return name; + } + + + public int getPicture( ) + { + return picture; + } + + + public String getAlliance( ) + { + return alliance; + } + + + public int getX( ) + { + return x; + } + + + public int getY( ) + { + return y; + } + + + public int getOrbit( ) + { + return orbit; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetOrbitalView.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetOrbitalView.java new file mode 100644 index 0000000..5992b9c --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetOrbitalView.java @@ -0,0 +1,107 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; +import java.util.List; + + + +public class PlanetOrbitalView + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private long population; + private long defencePoints; + private long ownFleet; + private long friendlyFleet; + private long hostileFleet; + private Long battle; + private List< BuildingData > buildings; + + + public long getPopulation( ) + { + return population; + } + + + public void setPopulation( long population ) + { + this.population = population; + } + + + public long getDefencePoints( ) + { + return defencePoints; + } + + + public void setDefencePoints( long defencePoints ) + { + this.defencePoints = defencePoints; + } + + + public long getOwnFleet( ) + { + return ownFleet; + } + + + public void setOwnFleet( long ownFleet ) + { + this.ownFleet = ownFleet; + } + + + public long getFriendlyFleet( ) + { + return friendlyFleet; + } + + + public void setFriendlyFleet( long friendlyFleet ) + { + this.friendlyFleet = friendlyFleet; + } + + + public long getHostileFleet( ) + { + return hostileFleet; + } + + + public void setHostileFleet( long hostileFleet ) + { + this.hostileFleet = hostileFleet; + } + + + public Long getBattle( ) + { + return battle; + } + + + public void setBattle( Long battle ) + { + this.battle = battle; + } + + + public List< BuildingData > getBuildings( ) + { + return buildings; + } + + + public void setBuildings( List< BuildingData > buildings ) + { + this.buildings = buildings; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetOwnView.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetOwnView.java new file mode 100644 index 0000000..a567a8e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetOwnView.java @@ -0,0 +1,133 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; +import java.util.List; + + + +public class PlanetOwnView + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private int happiness; + private int hChange; + private long income; + private long upkeep; + private OwnPlanetStatusData status; + private QueueData civQueue; + private QueueData milQueue; + private List< BuildableShipData > bShips; + private List< BuildableBuildingData > bBuildings; + + + public int getHappiness( ) + { + return happiness; + } + + + public void setHappiness( int happiness ) + { + this.happiness = happiness; + } + + + public int gethChange( ) + { + return hChange; + } + + + public void sethChange( int hChange ) + { + this.hChange = hChange; + } + + + public long getIncome( ) + { + return income; + } + + + public void setIncome( long income ) + { + this.income = income; + } + + + public long getUpkeep( ) + { + return upkeep; + } + + + public void setUpkeep( long upkeep ) + { + this.upkeep = upkeep; + } + + + public OwnPlanetStatusData getStatus( ) + { + return status; + } + + + public void setStatus( OwnPlanetStatusData status ) + { + this.status = status; + } + + + public QueueData getCivQueue( ) + { + return civQueue; + } + + + public void setCivQueue( QueueData civQueue ) + { + this.civQueue = civQueue; + } + + + public QueueData getMilQueue( ) + { + return milQueue; + } + + + public void setMilQueue( QueueData milQueue ) + { + this.milQueue = milQueue; + } + + + public List< BuildableShipData > getbShips( ) + { + return bShips; + } + + + public void setbShips( List< BuildableShipData > bShips ) + { + this.bShips = bShips; + } + + + public List< BuildableBuildingData > getbBuildings( ) + { + return bBuildings; + } + + + public void setbBuildings( List< BuildableBuildingData > bBuildings ) + { + this.bBuildings = bBuildings; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/QueueData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/QueueData.java new file mode 100644 index 0000000..8aad730 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/QueueData.java @@ -0,0 +1,38 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; +import java.util.Collections; +import java.util.List; + + + +public class QueueData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private final boolean appendPossible; + private final List< QueueItemData > items; + + + public QueueData( boolean appendPossible , List< QueueItemData > items ) + { + this.appendPossible = appendPossible; + this.items = Collections.unmodifiableList( items ); + } + + + public boolean isAppendPossible( ) + { + return appendPossible; + } + + + public List< QueueItemData > getItems( ) + { + return items; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/QueueItemData.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/QueueItemData.java new file mode 100644 index 0000000..a1000df --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/QueueItemData.java @@ -0,0 +1,107 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; + +import com.deepclone.lw.cmd.player.gdata.GameTime; + + + +public class QueueItemData + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private String name; + private String description; + private int amount; + private boolean destroy; + private long invested; + private Long timeLeft; + private GameTime gameTimeLeft; + + + public String getName( ) + { + return name; + } + + + public void setName( String name ) + { + this.name = name; + } + + + public String getDescription( ) + { + return description; + } + + + public void setDescription( String description ) + { + this.description = description; + } + + + public int getAmount( ) + { + return amount; + } + + + public void setAmount( int amount ) + { + this.amount = amount; + } + + + public boolean isDestroy( ) + { + return destroy; + } + + + public void setDestroy( boolean destroy ) + { + this.destroy = destroy; + } + + + public long getInvested( ) + { + return invested; + } + + + public void setInvested( long invested ) + { + this.invested = invested; + } + + + public Long getTimeLeft( ) + { + return timeLeft; + } + + + public void setTimeLeft( Long timeLeft ) + { + this.timeLeft = timeLeft; + if ( timeLeft == null ) { + this.gameTimeLeft = null; + } else { + this.gameTimeLeft = new GameTime( timeLeft ); + } + } + + + public GameTime getGameTimeLeft( ) + { + return gameTimeLeft; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ComposeMessageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ComposeMessageCommand.java new file mode 100644 index 0000000..8d7a441 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ComposeMessageCommand.java @@ -0,0 +1,97 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.session.Command; + + + +public class ComposeMessageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final Boolean inbox; + private final Long replyTo; + + private MessageType type; + private String target; + private String subject; + private String contents; + + + public ComposeMessageCommand( ) + { + this.inbox = null; + this.replyTo = null; + } + + + public ComposeMessageCommand( boolean inbox , long replyTo ) + { + this.inbox = inbox; + this.replyTo = replyTo; + } + + + public MessageType getType( ) + { + return type; + } + + + public void setType( MessageType type ) + { + this.type = type; + } + + + public String getTarget( ) + { + return target; + } + + + public void setTarget( String target ) + { + this.target = target; + } + + + public String getSubject( ) + { + return subject; + } + + + public void setSubject( String subject ) + { + this.subject = subject; + } + + + public String getContents( ) + { + return contents; + } + + + public void setContents( String contents ) + { + this.contents = contents; + } + + + public Boolean getInbox( ) + { + return inbox; + } + + + public Long getReplyTo( ) + { + return replyTo; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ComposeMessageResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ComposeMessageResponse.java new file mode 100644 index 0000000..45b95c0 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ComposeMessageResponse.java @@ -0,0 +1,160 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import com.deepclone.lw.cmd.msgdata.Message; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; + + + +public class ComposeMessageResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private MessageType messageType; + private String target; + private String title; + private String contents; + + private final Boolean inbox; + private final Message replyTo; + + private boolean targetError = false; + private boolean timingError = false; + private boolean titleError = false; + private boolean contentsError = false; + + + public ComposeMessageResponse( GamePageData page ) + { + super( page ); + this.inbox = null; + this.replyTo = null; + } + + + public ComposeMessageResponse( GamePageData page , boolean inbox , Message replyTo ) + { + super( page ); + this.inbox = inbox; + this.replyTo = replyTo; + } + + + public Boolean getInbox( ) + { + return inbox; + } + + + public Message getReplyTo( ) + { + return replyTo; + } + + + public MessageType getMessageType( ) + { + return messageType; + } + + + public void setMessageType( MessageType messageType ) + { + this.messageType = messageType; + } + + + public String getTarget( ) + { + return target; + } + + + public void setTarget( String target ) + { + this.target = target; + } + + + public String getTitle( ) + { + return title; + } + + + public void setTitle( String title ) + { + this.title = title; + } + + + public String getContents( ) + { + return contents; + } + + + public void setContents( String contents ) + { + this.contents = contents; + } + + + public boolean isTargetError( ) + { + return targetError; + } + + + public void setTargetError( boolean targetError ) + { + this.targetError = targetError; + } + + + public boolean isTimingError( ) + { + return timingError; + } + + + public void setTimingError( boolean timingError ) + { + this.timingError = timingError; + } + + + public boolean isTitleError( ) + { + return titleError; + } + + + public void setTitleError( boolean titleError ) + { + this.titleError = titleError; + } + + + public boolean isContentsError( ) + { + return contentsError; + } + + + public void setContentsError( boolean contentsError ) + { + this.contentsError = contentsError; + } + + + public boolean isError( ) + { + return ( this.titleError || this.contentsError || this.targetError || this.timingError ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/GetMessagesCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/GetMessagesCommand.java new file mode 100644 index 0000000..92d24ef --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/GetMessagesCommand.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import com.deepclone.lw.session.Command; + + + +public class GetMessagesCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean inbox; + + + public GetMessagesCommand( boolean inbox ) + { + this.inbox = inbox; + } + + + public boolean isInbox( ) + { + return inbox; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/GetMessagesResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/GetMessagesResponse.java new file mode 100644 index 0000000..09025bc --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/GetMessagesResponse.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import java.util.List; + +import com.deepclone.lw.cmd.msgdata.MessageListEntry; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; + + + +public class GetMessagesResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final List< MessageListEntry > messages; + + + public GetMessagesResponse( GamePageData page , List< MessageListEntry > messages ) + { + super( page ); + this.messages = messages; + } + + + public List< MessageListEntry > getMessages( ) + { + return messages; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ListTargetsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ListTargetsCommand.java new file mode 100644 index 0000000..9809a62 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ListTargetsCommand.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import com.deepclone.lw.session.Command; + + + +public class ListTargetsCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ListTargetsResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ListTargetsResponse.java new file mode 100644 index 0000000..28aa092 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ListTargetsResponse.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import java.util.List; + +import com.deepclone.lw.cmd.admin.adata.AdministratorBasics; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.NameIdPair; +import com.deepclone.lw.cmd.player.gdata.alliance.PublicAllianceInformation; + + + +public class ListTargetsResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final List< NameIdPair > empires; + private final List< PublicAllianceInformation > alliances; + private final List< AdministratorBasics > admins; + + + public ListTargetsResponse( GamePageData page , List< NameIdPair > empires , + List< PublicAllianceInformation > alliances , List< AdministratorBasics > admins ) + { + super( page ); + this.empires = empires; + this.alliances = alliances; + this.admins = admins; + } + + + public List< NameIdPair > getEmpires( ) + { + return empires; + } + + + public List< PublicAllianceInformation > getAlliances( ) + { + return alliances; + } + + + public List< AdministratorBasics > getAdmins( ) + { + return admins; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/MessageBoxAction.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/MessageBoxAction.java new file mode 100644 index 0000000..cb6b467 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/MessageBoxAction.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.cmd.player.msgs; + + +public enum MessageBoxAction { + + DELETE , + MARK_READ , + MARK_UNREAD + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/MessageBoxCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/MessageBoxCommand.java new file mode 100644 index 0000000..757cd99 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/MessageBoxCommand.java @@ -0,0 +1,52 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import com.deepclone.lw.session.Command; + + + +public class MessageBoxCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final MessageBoxAction action; + private final boolean inbox; + private final long[] selection; + + + public MessageBoxCommand( boolean inbox , long[] selection ) + { + this.action = MessageBoxAction.DELETE; + this.inbox = inbox; + this.selection = selection; + } + + + public MessageBoxCommand( long[] selection , boolean read ) + { + this.action = read ? MessageBoxAction.MARK_READ : MessageBoxAction.MARK_UNREAD; + this.inbox = true; + this.selection = selection; + } + + + public MessageBoxAction getAction( ) + { + return action; + } + + + public boolean isInbox( ) + { + return inbox; + } + + + public long[] getSelection( ) + { + return selection; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/PrepareMessageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/PrepareMessageCommand.java new file mode 100644 index 0000000..3abe09e --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/PrepareMessageCommand.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.session.Command; + + + +public class PrepareMessageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final MessageType type; + private final Long id; + private final Boolean inbox; + + + private PrepareMessageCommand( MessageType type , Long id ) + { + this.type = type; + this.id = id; + this.inbox = null; + } + + + public PrepareMessageCommand( long id , boolean inbox ) + { + this.type = MessageType.INTERNAL; + this.id = id; + this.inbox = inbox; + } + + + public MessageType getType( ) + { + return type; + } + + + public Long getId( ) + { + return id; + } + + + public Boolean getInbox( ) + { + return inbox; + } + + + public static PrepareMessageCommand newMessage( ) + { + return new PrepareMessageCommand( null , null ); + } + + + public static PrepareMessageCommand newMessageTo( MessageType type , int id ) + { + if ( type == MessageType.INTERNAL ) { + throw new IllegalArgumentException( ); + } + return new PrepareMessageCommand( type , (long) id ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ReadMessageCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ReadMessageCommand.java new file mode 100644 index 0000000..1656175 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ReadMessageCommand.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import com.deepclone.lw.session.Command; + + + +public class ReadMessageCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final boolean inbox; + private final long id; + + + public ReadMessageCommand( boolean inbox , long id ) + { + this.inbox = inbox; + this.id = id; + } + + + public boolean isInbox( ) + { + return inbox; + } + + + public long getId( ) + { + return id; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ReadMessageResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ReadMessageResponse.java new file mode 100644 index 0000000..436de68 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/msgs/ReadMessageResponse.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.cmd.player.msgs; + + +import com.deepclone.lw.cmd.msgdata.Message; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; + + + +public class ReadMessageResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final boolean inbox; + private final Message message; + + + public ReadMessageResponse( GamePageData page , boolean inbox ) + { + super( page ); + this.inbox = inbox; + this.message = null; + } + + + public ReadMessageResponse( GamePageData page , boolean inbox , Message message ) + { + super( page ); + this.inbox = inbox; + this.message = message; + } + + + public boolean isInbox( ) + { + return inbox; + } + + + public Message getMessage( ) + { + return message; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/AbandonPlanetCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/AbandonPlanetCommand.java new file mode 100644 index 0000000..34711e2 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/AbandonPlanetCommand.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.cmd.player.planets; + + +public class AbandonPlanetCommand + extends ViewPlanetCommand +{ + private static final long serialVersionUID = 1L; + + private final boolean cancel; + + + public AbandonPlanetCommand( int id , boolean cancel ) + { + super( id ); + this.cancel = cancel; + } + + + public boolean isCancel( ) + { + return cancel; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildShipsCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildShipsCommand.java new file mode 100644 index 0000000..62d8521 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildShipsCommand.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.cmd.player.planets; + + +public class BuildShipsCommand + extends ViewPlanetCommand +{ + + private static final long serialVersionUID = 1L; + + private final int sType; + private final int amount; + + + public BuildShipsCommand( int id , int sType , int amount ) + { + super( id ); + this.sType = sType; + this.amount = amount; + } + + + public int getsType( ) + { + return sType; + } + + + public int getAmount( ) + { + return amount; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildingActionCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildingActionCommand.java new file mode 100644 index 0000000..4d7ec2b --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildingActionCommand.java @@ -0,0 +1,41 @@ +package com.deepclone.lw.cmd.player.planets; + + +public class BuildingActionCommand + extends ViewPlanetCommand +{ + + private static final long serialVersionUID = 1L; + + private final int bType; + private final int amount; + private final boolean destroy; + + + public BuildingActionCommand( int id , int bType , int amount , boolean destroy ) + { + super( id ); + this.bType = bType; + this.amount = amount; + this.destroy = destroy; + } + + + public int getbType( ) + { + return bType; + } + + + public int getAmount( ) + { + return amount; + } + + + public boolean isDestroy( ) + { + return destroy; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildingActionResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildingActionResponse.java new file mode 100644 index 0000000..86a4daf --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/BuildingActionResponse.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.cmd.player.planets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetBasicView; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetOrbitalView; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetOwnView; + + + +public class BuildingActionResponse + extends ViewPlanetResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean destructionFailed; + + + public BuildingActionResponse( int id , GamePageData page , PlanetBasicView basic , PlanetOrbitalView orbital , + PlanetOwnView own ) + { + super( id , page , basic , orbital , own ); + this.destructionFailed = true; + } + + + public boolean isDestructionFailed( ) + { + return destructionFailed; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/FlushQueueCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/FlushQueueCommand.java new file mode 100644 index 0000000..d2e1b08 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/FlushQueueCommand.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.cmd.player.planets; + + +public class FlushQueueCommand + extends ViewPlanetCommand +{ + private static final long serialVersionUID = 1L; + + private final boolean military; + + + public FlushQueueCommand( int id , boolean military ) + { + super( id ); + this.military = military; + } + + + public boolean isMilitary( ) + { + return military; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/RenamePlanetCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/RenamePlanetCommand.java new file mode 100644 index 0000000..09a586d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/RenamePlanetCommand.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.cmd.player.planets; + + +public class RenamePlanetCommand + extends ViewPlanetCommand +{ + + private static final long serialVersionUID = 1L; + + private final String name; + + + public RenamePlanetCommand( int id , String name ) + { + super( id ); + this.name = name; + } + + + public String getName( ) + { + return name; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/RenamePlanetResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/RenamePlanetResponse.java new file mode 100644 index 0000000..9073eb6 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/RenamePlanetResponse.java @@ -0,0 +1,40 @@ +package com.deepclone.lw.cmd.player.planets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetBasicView; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetOrbitalView; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetOwnView; + + + +public class RenamePlanetResponse + extends ViewPlanetResponse +{ + + private static final long serialVersionUID = 1L; + + private final String renamingTo; + private final String renameError; + + + public RenamePlanetResponse( int id , GamePageData page , PlanetBasicView basic , PlanetOrbitalView orbital , + PlanetOwnView own , String failName , String error ) + { + super( id , page , basic , orbital , own ); + this.renamingTo = failName; + this.renameError = error; + } + + + public String getRenamingTo( ) + { + return renamingTo; + } + + + public String getRenameError( ) + { + return renameError; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/ViewPlanetCommand.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/ViewPlanetCommand.java new file mode 100644 index 0000000..b3d1137 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/ViewPlanetCommand.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.cmd.player.planets; + + +import com.deepclone.lw.session.Command; + + + +public class ViewPlanetCommand + extends Command +{ + + private static final long serialVersionUID = 1L; + + private final int id; + + + public ViewPlanetCommand( int id ) + { + this.id = id; + } + + + public int getId( ) + { + return this.id; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/ViewPlanetResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/ViewPlanetResponse.java new file mode 100644 index 0000000..6761652 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/planets/ViewPlanetResponse.java @@ -0,0 +1,87 @@ +package com.deepclone.lw.cmd.player.planets; + + +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetBasicView; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetOrbitalView; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetOwnView; + + + +public class ViewPlanetResponse + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final Integer id; + private final boolean ownershipError; + private final PlanetBasicView basic; + private final PlanetOrbitalView orbit; + private final PlanetOwnView own; + + + public ViewPlanetResponse( GamePageData page ) + { + super( page ); + this.id = null; + this.ownershipError = true; + this.basic = null; + this.orbit = null; + this.own = null; + } + + + public ViewPlanetResponse( int id , GamePageData page , PlanetBasicView basic , PlanetOrbitalView orbital , + PlanetOwnView own ) + { + super( page ); + this.id = id; + this.ownershipError = false; + this.basic = basic; + this.orbit = orbital; + this.own = own; + } + + + public ViewPlanetResponse( int id , GamePageData page , PlanetBasicView basic , PlanetOrbitalView orbital ) + { + super( page ); + this.id = id; + this.ownershipError = true; + this.basic = basic; + this.orbit = orbital; + this.own = null; + } + + + public Integer getId( ) + { + return id; + } + + + public boolean isOwnershipError( ) + { + return ownershipError; + } + + + public PlanetBasicView getBasic( ) + { + return basic; + } + + + public PlanetOrbitalView getOrbit( ) + { + return orbit; + } + + + public PlanetOwnView getOwn( ) + { + return own; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/Command.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/Command.java new file mode 100644 index 0000000..5733eae --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/Command.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.session; + + +import java.io.Serializable; + + + +public abstract class Command + implements Serializable +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/CommandResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/CommandResponse.java new file mode 100644 index 0000000..bef3cd8 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/CommandResponse.java @@ -0,0 +1,14 @@ +package com.deepclone.lw.session; + + +import java.io.Serializable; + + + +public abstract class CommandResponse + implements Serializable +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/NullResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/NullResponse.java new file mode 100644 index 0000000..a7f44ab --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/NullResponse.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.session; + + +public final class NullResponse + extends CommandResponse +{ + + private static final long serialVersionUID = 1L; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionAccessor.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionAccessor.java new file mode 100644 index 0000000..1d3b734 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionAccessor.java @@ -0,0 +1,25 @@ +package com.deepclone.lw.session; + +import java.net.InetAddress; + + +public interface SessionAccessor +{ + + SessionReference create( String type , String client , InetAddress ip ) + throws SessionInternalException; + + + SessionReference authenticate( String session , String identifier , String sha1Hash , String md5Hash ) + throws SessionIdentifierException , SessionStateException , SessionInternalException; + + + SessionResponse executeCommand( String session , Command command ) + throws SessionIdentifierException , SessionStateException , SessionCommandException , + SessionInternalException; + + + void terminate( String session ) + throws SessionIdentifierException , SessionInternalException; + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionCommandException.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionCommandException.java new file mode 100644 index 0000000..bc53083 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionCommandException.java @@ -0,0 +1,15 @@ +package com.deepclone.lw.session; + + +public class SessionCommandException + extends SessionException +{ + + private static final long serialVersionUID = 1L; + + + public SessionCommandException( String message ) + { + super( true , message ); + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionException.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionException.java new file mode 100644 index 0000000..8490fb9 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionException.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.session; + + +public abstract class SessionException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + private boolean keepSession; + + + public SessionException( boolean keep ) + { + this.keepSession = keep; + } + + + public SessionException( boolean keep , String message ) + { + super( message ); + this.keepSession = keep; + } + + + public SessionException( boolean keep , Throwable cause ) + { + super( cause ); + this.keepSession = keep; + } + + + public SessionException( boolean keep , String message , Throwable cause ) + { + super( message , cause ); + this.keepSession = keep; + } + + + public final boolean isSessionKept( ) + { + return this.keepSession; + } +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionIdentifierException.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionIdentifierException.java new file mode 100644 index 0000000..4273f76 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionIdentifierException.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.session; + + +/** + * Thrown when a session identifier does not exist on the server. + * + * @author tseeker + */ +public final class SessionIdentifierException + extends SessionException +{ + + private static final long serialVersionUID = 1L; + + + public SessionIdentifierException( String identifier ) + { + super( false , identifier ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionInternalException.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionInternalException.java new file mode 100644 index 0000000..42474ee --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionInternalException.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.session; + + +/** + * Thrown when a runtime error occurs while handling a session-related request. + * + * @author tseeker + */ +public final class SessionInternalException + extends SessionException +{ + + private static final long serialVersionUID = 1L; + + + public SessionInternalException( boolean keep , Throwable cause ) + { + super( keep , cause.getClass( ).getName( ) + " (" + cause.getMessage( ) + ")" ); + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionReference.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionReference.java new file mode 100644 index 0000000..4e7fb70 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionReference.java @@ -0,0 +1,51 @@ +package com.deepclone.lw.session; + + +import java.io.Serializable; + + + +/** + * Session reference. + * + *

+ * Session references are send from the server to the client for all session-related actions. They + * contain information about the session itself (identifier and type of session) and about its state + * (authentication and sub-type). + * + * @author tseeker + */ +public final class SessionReference + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + /** String identifier of the session */ + public final String identifier; + + /** Type of the session */ + public final String type; + + /** Whether the session has been authenticated or not */ + public final boolean authenticated; + + /** + * Extra state information. + * + *

+ * If the session needs authentication, this field contains a challenge to use when + * authenticating. If the session has been authenticated, it contains the session's sub-type. + */ + public final String extra; + + + public SessionReference( String identifier , String type , boolean authenticated , String extra ) + { + this.identifier = identifier; + this.type = type; + this.authenticated = authenticated; + this.extra = extra; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionResponse.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionResponse.java new file mode 100644 index 0000000..6071671 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionResponse.java @@ -0,0 +1,39 @@ +package com.deepclone.lw.session; + + +import java.io.Serializable; + + + +/** + * Response to a session command. + * + * @author tseeker + */ +public class SessionResponse + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + /** Updated session reference */ + public final SessionReference session; + + /** Response data, if any */ + public final CommandResponse data; + + + public SessionResponse( SessionReference session ) + { + this.session = session; + this.data = null; + } + + + public SessionResponse( SessionReference session , CommandResponse data ) + { + this.session = session; + this.data = data; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionStateException.java b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionStateException.java new file mode 100644 index 0000000..eaa69e5 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/session/SessionStateException.java @@ -0,0 +1,20 @@ +package com.deepclone.lw.session; + + +/** + * Thrown when an authentication request is issued to an authenticated session or vice-versa. + * + * @author tseeker + */ +public final class SessionStateException + extends SessionException +{ + + private static final long serialVersionUID = 1L; + + + public SessionStateException( ) + { + super( true ); + } +} diff --git a/legacyworlds-utils/.classpath b/legacyworlds-utils/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-utils/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-utils/.project b/legacyworlds-utils/.project new file mode 100644 index 0000000..fd839fa --- /dev/null +++ b/legacyworlds-utils/.project @@ -0,0 +1,23 @@ + + + legacyworlds-utils + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-utils/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-utils/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..878d24f --- /dev/null +++ b/legacyworlds-utils/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Mon Apr 19 12:23:34 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-utils/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-utils/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..762f9e9 --- /dev/null +++ b/legacyworlds-utils/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Mon Apr 19 12:23:33 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-utils/pom.xml b/legacyworlds-utils/pom.xml new file mode 100644 index 0000000..195d0d6 --- /dev/null +++ b/legacyworlds-utils/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + legacyworlds + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-utils + 5.99.1 + Legacy Worlds common utilities + The classes in this package are used by all parts of the Legacy Worlds code. + + + + commons-codec + commons-codec + ${commons.codec.version} + jar + + + \ No newline at end of file diff --git a/legacyworlds-utils/src/main/java/com/deepclone/lw/utils/DigestHelper.java b/legacyworlds-utils/src/main/java/com/deepclone/lw/utils/DigestHelper.java new file mode 100644 index 0000000..17471b5 --- /dev/null +++ b/legacyworlds-utils/src/main/java/com/deepclone/lw/utils/DigestHelper.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.utils; + + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.commons.codec.binary.Hex; + + + +/** + * This class provides a static method which simplies computing hex-encoded digests of strings using + * some hashing algorithm. + * + * @author tseeker + */ +public final class DigestHelper +{ + + private DigestHelper( ) + { + // EMPTY + } + + + /** + * This method computes a hex-encoded digest of a string using the specified algorithm. + * + * @param algo + * the digest algorithm to use + * @param source + * the string to digest + * @return the hex-encoded digest + */ + public static String digest( String algo , String source ) + { + // Create digest + MessageDigest digestAlgorithm; + try { + digestAlgorithm = MessageDigest.getInstance( algo ); + } catch ( NoSuchAlgorithmException e ) { + throw new RuntimeException( "'" + algo + "' digest not supported" ); + } + // Add data + try { + digestAlgorithm.update( source.getBytes( "UTF-8" ) ); + } catch ( UnsupportedEncodingException e ) { + throw new RuntimeException( "UTF-8 not supported? I must be dreaming." ); + } + // Compute digest and return its hexadecimal encoding + byte[] digest = digestAlgorithm.digest( ); + return Hex.encodeHexString( digest ); + } + +} diff --git a/legacyworlds-web/.project b/legacyworlds-web/.project new file mode 100644 index 0000000..b64463a --- /dev/null +++ b/legacyworlds-web/.project @@ -0,0 +1,17 @@ + + + legacyworlds-web + + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-web/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-web/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..32dc0c3 --- /dev/null +++ b/legacyworlds-web/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Thu Apr 15 18:51:39 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-web/legacyworlds-web-admin/.classpath b/legacyworlds-web/legacyworlds-web-admin/.classpath new file mode 100644 index 0000000..3d4e21c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.classpath @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-admin/.project b/legacyworlds-web/legacyworlds-web-admin/.project new file mode 100644 index 0000000..073b138 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.project @@ -0,0 +1,37 @@ + + + legacyworlds-web-admin + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/legacyworlds-web/legacyworlds-web-admin/.settings/.jsdtscope b/legacyworlds-web/legacyworlds-web-admin/.settings/.jsdtscope new file mode 100644 index 0000000..bbb8e68 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.settings/.jsdtscope @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..4e54f2c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Thu Apr 15 19:33:04 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.common.component b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..45b17b5 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.common.component @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.common.project.facet.core.xml b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..9680654 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.jsdt.ui.superType.container b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.jsdt.ui.superType.name b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.ws.service.policy.prefs b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.ws.service.policy.prefs new file mode 100644 index 0000000..5095f8b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.settings/org.eclipse.wst.ws.service.policy.prefs @@ -0,0 +1,3 @@ +#Mon Apr 19 12:39:12 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.wst.ws.service.policy.projectEnabled=false diff --git a/legacyworlds-web/legacyworlds-web-admin/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-web/legacyworlds-web-admin/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..bb79aef --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Thu Apr 15 19:11:01 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/META-INF/MANIFEST.MF b/legacyworlds-web/legacyworlds-web-admin/WebContent/META-INF/MANIFEST.MF new file mode 100644 index 0000000..5e94951 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/admin-servlet.xml b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/admin-servlet.xml new file mode 100644 index 0000000..0391a5a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/admin-servlet.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/ROOT.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/ROOT.ftl new file mode 100644 index 0000000..7bb596f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/ROOT.ftl @@ -0,0 +1,11 @@ +<#setting url_escaping_charset='UTF-8'> +<#setting number_format='computer'> +<#include "/version.ftl"> +<#include "/layout/columns.ftl"> +<#include "/layout/datatable.ftl"> +<#include "/layout/fields.ftl"> +<#include "/layout/form.ftl"> +<#include "/layout/lists.ftl"> +<#include "/layout/tabs.ftl"> +<#include "containers/${container}.ftl" /> +<#include "types/${type}.ftl" /> diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/containers/external.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/containers/external.ftl new file mode 100644 index 0000000..8bf39b8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/containers/external.ftl @@ -0,0 +1,20 @@ +<#macro page title> + + + + + LW Beta 6 <@version/> Administration - ${title?xhtml} + + + +

+
+ <#nested> +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/containers/internal.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/containers/internal.ftl new file mode 100644 index 0000000..3f00a0d --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/containers/internal.ftl @@ -0,0 +1,72 @@ +<#macro page title> + + + + + LW Beta 6 <@version/> Administration - ${title?xhtml} + + + + + +
+ +
+ <#nested> +
+
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/columns.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/columns.ftl new file mode 100644 index 0000000..6d79301 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/columns.ftl @@ -0,0 +1,18 @@ +<#macro left_column width=0> + <#if width gt 0> +
+ <#else> +
+ + <#nested> +
+ +<#macro right_column width=0> + <#if width gt 0> +
+ <#else> +
+ + <#nested> +
+ diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/datatable.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/datatable.ftl new file mode 100644 index 0000000..e02f8e8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/datatable.ftl @@ -0,0 +1,20 @@ +<#macro dt_main title=""> + + <#if title != ""> + + + <#nested> +
${title}
+ +<#macro dt_entry title abbr="" width=0> + + style="width: ${width}px"><#if title == ""> <#else><#if abbr != "">${abbr?xhtml}<#else>${title?xhtml}: + <#nested> + + +<#macro dt_blank> +   + +<#macro dt_status> + <#nested> + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/fields.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/fields.ftl new file mode 100644 index 0000000..63dcdcd --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/fields.ftl @@ -0,0 +1,20 @@ +<#macro ff_text name value id="" maxLength=0 size=0> + maxlength="${maxLength?string}" <#if size gt 0>size="${size?string}" /> + +<#macro ff_pwd id name> + + +<#macro ff_select id name style=""> + + +<#macro ff_checkbox id name value checked=false> + checked="checked" /> + +<#macro form_option text="" selected=false value=""> + value="${value?xhtml}"<#if selected> selected="selected"><#if text == ""><#nested><#else>${text?xhtml} + +<#macro ff_submit label extraClass="" name="" style=""> + name="${name?xhtml}" type="submit" value="${label?xhtml}" <#if style != "">style="${style}" /> + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/form.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/form.ftl new file mode 100644 index 0000000..c39631c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/form.ftl @@ -0,0 +1,98 @@ +<#macro form action hash=""> +
+
#${hash?url}" method="post"> + + <#nested> +
+
+
+ +<#macro form_field_line label id> + + + <#nested> + + +<#macro form_text label name value id="" maxLength=0 multiline=false> + <#if id = ""> + <#local id = name> + + <@form_field_line label=label id=id> + <#if multiline> + + <#else> + <@ff_text id=id name=name maxLength=maxLenth value=value /> + + + +<#macro form_checkbox label name value id="" checked=false> + <#if id = ""> + <#local id = name> + + <@form_field_line label=label id=id> + <@ff_checkbox id=id name=name value=value checked=checked /> + + +<#macro form_pwd label name id=""> + <#if id = ""> + <#local id = name> + + <@form_field_line label=label id=id> + <@ff_pwd id=id name=name /> + + +<#macro form_select label name id=""> + <#if id = ""> + <#local id = name> + + <@form_field_line label=label id=id> + <@ff_select id=id name=name> + <#nested> + + + +<#macro form_part title> + + ${title} + + +<#macro form_extra> + + <#nested> + + +<#macro form_error> + + <#nested> + + +<#macro standalone_error> +
+ + + + +
<#nested>
+
+ +<#macro form_submit label extraClass=""> + +   + <@ff_submit label=label extraClass=extraClass /> + + +<#macro form_extended_submit label extraClass=""> + +   + <@ff_submit label=label extraClass=extraClass /><#nested /> + + +<#macro lineform action name="" hash=""> +
+
#${hash?url}" method="post"> + + +
<#nested>
+
+
+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/lists.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/lists.ftl new file mode 100644 index 0000000..86e36bb --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/lists.ftl @@ -0,0 +1,25 @@ +<#macro listview> + + <#nested> +
+ +<#macro lv_line headers=false class=""> + class="${class}<#if headers>headers"<#elseif headers> class="headers"> + <#nested> + + +<#macro lv_column width=0 centered=false> + <#if width?is_string> + + <#nested> + + <#elseif width gt 0> + + <#nested> + + <#else> + + <#nested> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/tabs.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/tabs.ftl new file mode 100644 index 0000000..b1ab861 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/layout/tabs.ftl @@ -0,0 +1,13 @@ +<#macro tabs> +
+ <#nested> +
+ +<#macro tab id title> +
+

${title?xhtml}

+
+ <#nested> +
+
+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/addAdmin.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/addAdmin.ftl new file mode 100644 index 0000000..ecf9868 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/addAdmin.ftl @@ -0,0 +1,68 @@ +<#macro render_privs> + <#if data.privileges?has_content> + <#local source = data.privileges> + <#local useSource = true> + <#else> + <#local source = data.admin.allPrivileges> + <#local useSource = false> + + + Privileges: + + <#list source as privilege> + <#if useSource> + <#local value = privilege.present> + <#else> + <#local value = false> + + checked="checked" /> + + + + + +<@page title="Add administrator"> + <@form action="add-admin"> + + <#switch data.addressError!> + <#case 'EMPTY'> + <@form_error>Please specify the user's address. + <#break> + <#case 'INVALID'> + <@form_error>Invalid address. + <#break> + <#case 'NOT_FOUND'> + <@form_error>User not found. + <#break> + <#case 'STATUS'> + <@form_error>Invalid user status (banned or unconfirmed). + <#break> + <#case 'ALREADY_ADMIN'> + <@form_error>This user is already an administrator. + <#break> + + <@form_text label="E-mail address" name="address" value=data.address! /> + + <#switch data.nameError!> + <#case 'EMPTY'> + <@form_error>Please specify a name. + <#break> + <#case 'INVALID'> + <@form_error>Invalid name. + <#break> + <#case 'UNAVAILABLE'> + <@form_error>This name is already in use. + <#break> + + <@form_text label="Administrator name" name="name" value=data.name! /> + + <#-- Privs --> + <#if data.privError!false> + <@form_error>Please select the new administrator's privileges. + + <@render_privs /> + + <@form_submit label="Add administrator" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/admins.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/admins.ftl new file mode 100644 index 0000000..86306ca --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/admins.ftl @@ -0,0 +1,43 @@ +<#macro render_admin admin> + <#if admin.id = data.admin.id> + <#local begin = ""> + <#local end = ""> + <#elseif admin.privileges?size = 0> + <#local begin = ""> + <#local end = ""> + + + <@lv_line> + <@lv_column>${begin!}${admin.name?xhtml}${end!} + <@lv_column> + <#if admin.address?has_content> + ${begin!}${admin.address?xhtml}${end!} + <#else> + ${begin!}N/A${end!} + + + <@lv_column> + <#if admin.privileges?size gt 0> + <#list admin.privileges as priv> + ${priv} + + <#else> + (inactive) + + + + + +<@page title="Administrators"> + <@listview> + <@lv_line headers=true> + <@lv_column width=300>Name + <@lv_column width=300>Address + <@lv_column width="x">Privileges + + <#list data.administrators as admin> + <@render_admin admin=admin /> + + +

Add administrator

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/banReject.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/banReject.ftl new file mode 100644 index 0000000..27600a3 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/banReject.ftl @@ -0,0 +1,9 @@ +<@page title="Reject ban request"> + <@form action="reject-ban-${data.id}"> + <#if data.error!false> + <@form_error>You must give a reason + + <@form_text label="Rejection reason" name="reason" value="" multiline=true maxLength = 10 /> + <@form_submit label="Reject ban request" /> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/banRequest.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/banRequest.ftl new file mode 100644 index 0000000..f58b163 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/banRequest.ftl @@ -0,0 +1,20 @@ +<@page title="Request ban"> + <@form action="request-ban"> + <#switch data.error!""> + <#case "NOT_FOUND"><@form_error>User not found<#break> + <#case "BANNED"><@form_error>User is already banned or has a pending ban request.<#break> + <#case "NO_REASON"><@form_error>You have no reason!...<#break> + + <#if data.empire!false> + <#assign eValue = data.user!"" > + <#assign mValue = "" > + <#else> + <#assign mValue = data.user!"" > + <#assign eValue = "" > + + <@form_text label="Empire name" value="" name="eName" value=eValue /> + <@form_text label="(or) User address" value="" name="eMail" value=mValue /> + <@form_text label="Reason" name="reason" value="" multiline=true maxLength=10 value=data.reason!"" /> + <@form_submit label="Request ban" /> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bans.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bans.ftl new file mode 100644 index 0000000..75ca31b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bans.ftl @@ -0,0 +1,75 @@ +<#if data.type = 'PENDING'> + <#assign title = "Pending ban requests"> +<#elseif data.type = 'ARCHIVED'> + <#assign title = "Expired/rejected ban requests"> +<#else> + <#assign title = "Confirmed ban requests"> + +<@page title=title> + <#if data.bans?size = 0> +

No ban requests in this category.

+ <#else> + <@listview> + + <@lv_line headers=true> + <@lv_column width="x">User address + <@lv_column width="x">Requested by + <@lv_column width="x">Requested on + <@lv_column width="x">Reason + <#if data.type = 'ARCHIVED'> + <@lv_column width="x">Cancelled on + <@lv_column width="x">Rejected by + <@lv_column width="x">Rejection reason + <#elseif data.type = 'VALIDATED'> + <@lv_column width="x">Validated on + <@lv_column width="x">Validated by + <@lv_column>  + <#else> + <@lv_column>  + + + + <#list data.bans as ban> + <@lv_line> + <@lv_column>${ban.accountMail?xhtml} + <@lv_column>${ban.requestedByName?xhtml} + <@lv_column>${ban.timestamp?string("yyyy-MM-dd HH:mm:ss")} + <@lv_column>${ban.reason?xhtml} + <#if data.type = 'ARCHIVED'> + <@lv_column>${ban.update?string("yyyy-MM-dd HH:mm:ss")} + <@lv_column> + <#if ban.rejectedByName?has_content> + ${ban.rejectedByName?xhtml} + <#else> + (expired) + + + <@lv_column> + <#if ban.rejectedByName?has_content> + ${ban.rejectionReason?xhtml} + <#else> + (expired) + + + <#elseif data.type = 'VALIDATED'> + <@lv_column>${ban.update?string("yyyy-MM-dd HH:mm:ss")} + <@lv_column> + ${ban.validatedByName?xhtml} + + <@lv_column> + <#if ban.redeemable>Redeem<#else>Lift ban + + <#else> + <@lv_column> + <#if ban.requestedById != data.admin.id> + Confirm ban - + + Reject ban + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bansSummary.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bansSummary.ftl new file mode 100644 index 0000000..f05ed56 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bansSummary.ftl @@ -0,0 +1,37 @@ +<@page title="Banhammer"> + <@listview> + + <@lv_line headers=true> + <@lv_column width=300>  + <@lv_column width=100 centered=true>Entries + + + <#list data.entries as entry> + <@lv_line> + <@lv_column> + <#if entry.count gt 0> + + + <#switch entry.type> + <#case "PENDING"> + Pending requests + <#break> + <#case "ARCHIVED"> + Expired and rejected requests + <#break> + <#case "VALIDATED"> + Confirmed bans + <#break> + + <#if entry.count gt 0> + + + + <@lv_column centered=true>${entry.count} + + + +

Request ban

+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsList.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsList.ftl new file mode 100644 index 0000000..736b587 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsList.ftl @@ -0,0 +1,151 @@ +<#include "bugsTabs.ftl"> +<#macro render_navigation current count total qString> + + + + + + +
+ <#if current gt 0> + + + << + <#if current gt 0> + + + + <#if total gt 1> + ${total?string(',##0')} entries found. + <#elseif total = 1> + 1 entry found. + <#else> + No entries found. + + + <#if current lt total - count> + + + >> + <#if current lt total - count> + + +
+ +<#macro render> +<#if data.ownOnly> + <#local ownOnly = "1"> +<#else> + <#local ownOnly = "0"> + +<#local qString = "status=${data.status!'x'}&own=${ownOnly}" > +<@page title="Bug tracker"> + <#-- Tabs --> + <@bugTabs selected="bugsList" qString="${qString}&first=${data.first}" /> + + <#-- Selection --> +
+
+ + +
+ List + <@ff_select id="sel-own" name="own"> + <@form_option value="0">all + <@form_option value="1" selected=(data.ownOnly)>my own + + reports with the following status: + <@ff_select id="sel-stat" name="status"> + <@form_option value="x">(indifferent) + <@form_option value="PENDING" selected=((data.status!"") = 'PENDING')>pending validation + <@form_option value="OPEN" selected=((data.status!"") = 'OPEN')>being handled + <@form_option value="RESOLVED" selected=((data.status!"") = 'RESOLVED')>fixed + <@form_option value="WONT_FIX" selected=((data.status!"") = 'WONT_FIX')>won't fix + <@form_option value="NOT_A_BUG" selected=((data.status!"") = 'NOT_A_BUG')>not a bug + + <@ff_submit label="Search" /> +
+
+
+ + <#-- Navigation --> + <@render_navigation current=data.first count=data.count total=data.entries qString=qString /> + + <#-- List of bugs --> + <#if data.reports?size gt 0> + <@listview> + + <@lv_line headers=true> + <@lv_column centered=true width=60># + <@lv_column width=300>Title + <#if !( data.status?has_content )> + <@lv_column width=130 centered=true>Status + + <@lv_column width=150 centered=true>Initial post + <@lv_column width=150 centered=true>Last update + + + <#list data.reports as report> + + <#if !data.ownOnly && report.initialSubmitter.userId?has_content && report.initialSubmitter.admin && report.initialSubmitter.userId = data.admin.id> + <#local eClass="own-fleet"> + <#else> + <#local eClass=""> + + + <@lv_line class=eClass> + <@lv_column centered=true>${report.reportId?string(",##0")} + <@lv_column>${report.title?xhtml} + <#if !( data.status?has_content )> + <@lv_column centered=true><@bugStatus status=report.status /> + + <@lv_column centered=true> + ${report.posted?string("yyyy-MM-dd HH:mm:ss")} + + <@lv_column centered=true> + <#if report.updated> + + + ${report.lastUpdate?string("yyyy-MM-dd HH:mm:ss")} + <#if report.updated> + + + + + <@lv_line class=eClass> + <#if data.status?has_content> + + <#else> + + +   + <@lv_column centered=true> + by + <#if report.initialSubmitter.admin> + + + ${report.initialSubmitter.name} + <#if report.initialSubmitter.admin> + + + + <@lv_column centered=true> + by + <#if report.latestSubmitter.admin> + + + ${report.latestSubmitter.name} + <#if report.latestSubmitter.admin> + + + + + + + + + + + + +<@render /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsReport.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsReport.ftl new file mode 100644 index 0000000..df98218 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsReport.ftl @@ -0,0 +1,42 @@ +<#include "bugsTabs.ftl"> +<#macro render> +<#if data.query.ownOnly> + <#local ownOnly = "1"> +<#else> + <#local ownOnly = "0"> + +<#local qString = "status=${data.query.status!'x'}&own=${ownOnly}" > +<@page title="Bug tracker - Report bug"> + <@bugTabs selected="bugsReport" qString="${qString}&first=${data.query.first}" /> + + <@form action="report-bug"> + + + + + + + <#switch data.titleError!""> + <#case "EMPTY"><@form_error>Please specify the report's title<#break> + <#case "INVALID"><@form_error>Title should be at least 10 characters long<#break> + + <@form_text label="Title" name="title" value=data.title!"" maxLength=127 /> + + <#switch data.descriptionError!""> + <#case "EMPTY"><@form_error>Please specify the bug's description<#break> + <#case "INVALID"><@form_error>Title should be at least 30 characters long<#break> + + <@form_text label="Description" name="description" value=data.description!"" multiline=true maxLength=10 /> + + <@form_select name="public" label="Visible by players"> + <@form_option value="0">No + <@form_option value="1" selected=data.publicReport!false>Yes + + + <@form_submit label="Post bug report" /> + + + + + +<@render /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsSummary.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsSummary.ftl new file mode 100644 index 0000000..7977481 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsSummary.ftl @@ -0,0 +1,53 @@ +<#include "bugsTabs.ftl"> +<#macro summary_entry label amount qString> + + <@lv_line> + <@lv_column> + <#if amount gt 0> + + + ${label} + <#if amount gt 0> + + + + <@lv_column centered=true> + ${amount?string(",##0")} + + + + +<#macro render> +<#local qString = "status=x&own=0" > +<@page title="Bug tracker - Summary"> + <#-- Tabs --> + <@bugTabs selected="bugsSummary" qString=qString /> + + <#-- Summary --> + <@listview> + <@lv_line headers=true> + <@lv_column width=300>  + <@lv_column width=100>  + + <@summary_entry label="Pending validation" amount=data.pending qString="status=PENDING&own=0" /> + <@summary_entry label="Open bugs" amount=data.open qString="status=OPEN&own=0" /> + <@summary_entry label="Bugs you reported" amount=data.own qString="status=x&own=1" /> + <@summary_entry label="Total bugs" amount=data.total qString="status=x&own=0" /> + <#if data.updated gt 0> + <@lv_line> + <@lv_column>  + <@lv_column>  + + <@lv_line> + <@lv_column> + Updated bug reports + + <@lv_column centered=true> + ${data.updated?string(",##0")} + + + + + + +<@render /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsTabs.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsTabs.ftl new file mode 100644 index 0000000..2e40787 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsTabs.ftl @@ -0,0 +1,19 @@ +<#macro bugTab href title selected> + ${title} + +<#macro bugTabs selected qString> +
+ <@bugTab href="btracker" title="Summary" selected=( selected = 'bugsSummary' ) /> + <@bugTab href="bugs?${qString}" title="List bugs" selected=( selected = 'bugsList' ) /> + <@bugTab href="report-bug?${qString}" title="Report bug" selected=( selected = 'bugsReport' ) /> +
+ +<#macro bugStatus status> + <#switch status> + <#case "PENDING">pending validation<#break> + <#case "OPEN">being handled<#break> + <#case "RESOLVED">fixed<#break> + <#case "WONT_FIX">won't fix<#break> + <#case "NOT_A_BUG">not a bug<#break> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsView.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsView.ftl new file mode 100644 index 0000000..73566e6 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/bugsView.ftl @@ -0,0 +1,220 @@ +<#include "bugsTabs.ftl" /> +<#macro render_submitter s> + <#if s.admin> + + <#if s.userId?has_content && s.userId = data.admin.id> + + + + ${s.name?xhtml} + <#if s.admin> + <#if s.userId?has_content && s.userId = data.admin.id> + + + + + +<#macro render_event e> +
+ ${e.timestamp?string("yyyy-MM-dd HH:mm:ss")} - <@render_submitter s=e.submitter /> + <#nested> +
+ +<#macro render_report_event e> + <@render_event e=e> + posted bug report #${e.id?string(",##0")} + +

${e.title}

+
+ ${e.contents} +
+ <#if e.visible!false> +
+ This report includes an XML snapshot of the empire's status + (download). +
+ + +<#macro render_status_event e> + <@render_event e=e> + set the report's status to <@bugStatus status=e.status /> + + +<#macro render_visibility_event e> + <@render_event e=e> + set the report's visibility to <#if e.visible>public<#else>private + + +<#macro render_merge_event e> + <@render_event e=e> + merged current bug report with bug report #${e.mergedId?string(",##0")} + + +<#macro render_comment_event e> + <@render_event e=e> + posted a comment + +
+ ${e.contents} +
+ <#if !e.visible> + <@lineform action="bug-${data.report.reportId}-comment-moderation"> + + + + + This comment is currently hidden. + <@ff_select name="cAction" id="cAction-${e.id}"> + <@form_option value="1">Validate it + <@form_option value="0">Delete it + + <@ff_submit label="Go" /> + + + +<#macro render> +<#if data.query.ownOnly> + <#assign ownOnly = "1"> +<#else> + <#assign ownOnly = "0"> + +<#local qString = "status=${data.query.status!'x'}&own=${ownOnly}" > +<@page title="Bug #${data.report.reportId?string(',##0')} - ${data.report.title}"> + <#-- Tabs --> + <@bugTabs selected="" qString="${qString}&first=${data.query.first}" /> + + <#-- Bug info --> + <@dt_main> + <@dt_entry title="Status"><@bugStatus status=data.report.status /> + <@dt_entry title="Public"><#if data.report.visible>yes<#else>no + <@dt_entry title="Initially reported"> + ${data.report.posted?string("yyyy-MM-dd HH:mm:ss")} + by <@render_submitter s=data.report.initialSubmitter /> + + <@dt_entry title="Latest update"> + ${data.report.lastUpdate?string("yyyy-MM-dd HH:mm:ss")} + by <@render_submitter s=data.report.latestSubmitter /> + + + + <#-- List events --> + <#list data.events as event> +
+ <#switch event.type> + <#case 'INIT'> + <@render_report_event e=event /> + <#break> + <#case 'STATUS'> + <@render_status_event e=event /> + <#break> + <#case 'COMMENT'> + <@render_comment_event e=event /> + <#break> + <#case 'VISIBILITY'> + <@render_visibility_event e=event /> + <#break> + <#case 'MERGE'> + <@render_merge_event e=event /> + <#break> + + + + <#-- Controls --> +
+ <#if data.report.status = 'PENDING'> + <@form action="bug-${data.report.reportId}-validation" hash="br-controls"> + + + + + + + + <@form_extra>This report is currently pending validation. + <@form_select label="Set status to" name="nStatus"> + <@form_option value="OPEN"><@bugStatus status="OPEN" /> + <@form_option value="RESOLVED"><@bugStatus status="RESOLVED" /> + <@form_option value="WONT_FIX"><@bugStatus status="WONT_FIX" /> + <@form_option value="NOT_A_BUG"><@bugStatus status="NOT_A_BUG" /> + + <@form_select label="Visibility" name="visibility"> + <@form_option value="1">public + <@form_option value="0">hidden + + <@form_select label="Grant game credits" name="credits"> + <@form_option value="0">no + <@form_option value="1" selected=true>low priority bug - small amount + <@form_option value="2">normal bug - medium amount + <@form_option value="3">critical bug - large amount + + <@form_select label="Empire status snapshot" name="snapshot"> + <@form_option value="1">keep + <@form_option value="0">delete + + <@form_submit label="Go" /> + + <#else> + <@lineform action="bug-${data.report.reportId}-status" hash="br-controls"> + + + + Change status to + <@ff_select name="nStatus" id="nStatus"> + <@form_option value="OPEN" selected=( data.report.status = 'OPEN' )><@bugStatus status="OPEN" /> + <@form_option value="RESOLVED" selected=( data.report.status = 'RESOLVED' )><@bugStatus status="RESOLVED" /> + <@form_option value="WONT_FIX" selected=( data.report.status = 'WONT_FIX' )><@bugStatus status="WONT_FIX" /> + <@form_option value="NOT_A_BUG" selected=( data.report.status = 'NOT_A_BUG' )><@bugStatus status="NOT_A_BUG" /> + + <@ff_submit label="Go" /> + + <#if data.report.status = 'OPEN'> + <@lineform action="bug-${data.report.reportId}-visibility" hash="br-controls"> + + + + Change visibility to + <#if data.report.visible> + hidden + <#else> + public + + <@ff_submit label="Go" /> + + <#switch data.mergeError!> + <#case "NOT_FOUND"><@standalone_error>Bug report not found<#break> + <#case "MERGED"><@standalone_error>Bug reports already merged<#break> + <#case "STATUS"><@standalone_error>Both bug reports must be open<#break> + + <@lineform action="bug-${data.report.reportId}-merge" hash="br-controls"> + + + + Merge into bug report #<@ff_text name="mergeId" id="merge-into" value=data.mergeId!"" /> + <@ff_submit label="Go" /> + +
+ <@form action="bug-${data.report.reportId}-comment" hash="post-comment"> + + + + + + + + <#switch data.commentError!""> + <#case "EMPTY"><@form_error>You should type a comment before posting a comment.<#break> + <#case "INVALID"><@form_error>Comments must be at least 30 characters long.<#break> + + <@form_text label="New comment" name="comment" multiline=true maxLength=6 value=data.comment!"" /> + <@form_select label="Visibility" name="visibility"> + <@form_option value="1">public + <@form_option value="0" selected=(! data.publicComment!true )>hidden + + <@form_submit label="Post comment" /> + + + + + + +<@render /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/changePassword.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/changePassword.ftl new file mode 100644 index 0000000..3552562 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/changePassword.ftl @@ -0,0 +1,31 @@ +<@page title="Change password"> + <@form action="change-password"> + <#if data.admin.passwordChange!false> + <@form_extra>Your administration password is currently the same as your player account's password. You must change it before you can proceed. + + + <#if data.authError!false> + <@form_error>Incorrect password + + <@form_pwd name="current" label="Current password" /> + + <#switch data.passwordError!> + <#case 'EMPTY'> + <@form_error>No password specified + <#break> + <#case 'TOO_WEAK'> + <@form_error>Password too weak + <#break> + <#case 'MISMATCH'> + <@form_error>Password and password confirmation did not match + <#break> + <#case 'PROHIBITED'> + <@form_error>You are not allowed to use your player account's password. + <#break> + + <@form_pwd name="password" label="New password" /> + <@form_pwd name="passwordConfirm" label="New password (confirmation)" /> + + <@form_submit label="Change password" /> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/constants.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/constants.ftl new file mode 100644 index 0000000..542b875 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/constants.ftl @@ -0,0 +1,29 @@ +<#macro render_constant constant wrong> +

${constant.name?xhtml}

+

${constant.description?xhtml}

+ <#if wrong> + <@standalone_error>Invalid constant value + <#local cValue = data.value> + <#else> + <#local cValue = constant.value> + + <@lineform action="set-constant" hash=constant.name?replace("." , "-")> + Value: + <@ff_text name="value" id=constant.name?replace("." , "-") value=cValue?string("#.###") maxLength=10 size=10 /> + <#if constant.minValue?has_content || constant.maxValue?has_content> + (<#if constant.minValue?has_content>min.: ${constant.minValue?string("#.###")}<#if constant.maxValue?has_content> ; <#if constant.maxValue?has_content>max.: ${constant.maxValue?string("#.###")}) + + <@ff_submit label="Change" /> + + +

 

+ +<@page title="Constants"> + <#list data.categories as category> +

${category.name?xhtml}

+ <#list category.definitions as constant> + <@render_constant constant=constant wrong=(((data.name!"") == constant.name) && data.error!false) /> + +

 

+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/language.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/language.ftl new file mode 100644 index 0000000..a9300f9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/language.ftl @@ -0,0 +1,37 @@ +<#macro render_string str> + + ${str.id} + + <#if (data.edited!"") == str.id> +
Empty strings are not allowed
+ +
+
+ + +
+ +
+
+ + + +<@page title="Language '${data.language.name}'"> + +

Change language name

+ <@form action="i18n-${data.language.id}-edit"> + <#if data.nameError!false> + <@form_error>Invalid name + + <@form_text name="name" label="New name" value=data.language.name! /> + <@form_submit label="Change name" /> + + +

Translations

+ + <#list data.strings as str> + <@render_string str=str /> + +
+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/languages.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/languages.ftl new file mode 100644 index 0000000..c791270 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/languages.ftl @@ -0,0 +1,24 @@ +<#macro render_language lang> + <@lv_line> + <@lv_column centered=true>${lang.id} + <@lv_column>${lang.name?xhtml} + <@lv_column centered=true>${lang.completion}% + <@lv_column centered=true>(XML export) + + +<@page title="Languages"> + <@listview> + + <@lv_line headers=true> + <@lv_column width=100 centered=true>ID + <@lv_column width="x">Name + <@lv_column width=200 centered=true>Completion % + <@lv_column width=150>  + + + <#list data.languages as lang> + <@render_language lang=lang /> + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/logEntry.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/logEntry.ftl new file mode 100644 index 0000000..2a51ced --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/logEntry.ftl @@ -0,0 +1,41 @@ +<@page title="Log entry #${data.entry.id?string(',##0')}"> +

Basics

+ <@dt_main> + <@dt_entry title="Date">${data.entry.timestamp?string("yyyy-MM-dd")} + <@dt_entry title="Time">${data.entry.timestamp?string("HH:mm:ss")} + <@dt_entry title="Log level">${data.entry.level} + <@dt_entry title="Component">${data.entry.about?xhtml} + <@dt_entry title="Message">${data.entry.entry?xhtml} + +

 

+ + <#if data.exceptions?size gt 0> +

Exception log

+ + <#list data.exceptions as exc> + + + + <#list exc.trace as stEntry> + + + + + + +
+ ${exc.className?xhtml} + <#if exc.message?has_content>: ${exc.message?xhtml} +
  + In + <#if stEntry.location?has_content> + ${stEntry.location?xhtml} + <#else> + ??? + + <#if stEntry.fileName?has_content> + (in file ${stEntry.fileName?xhtml}<#if stEntry.line?has_content> at line ${stEntry.line?string(",##0")}) + +
+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/login.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/login.ftl new file mode 100644 index 0000000..5d563ea --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/login.ftl @@ -0,0 +1,10 @@ +<@page title="Log in"> + <@form action="login"> + <#if data.failed!false> + <@form_error>Invalid address or password + + <@form_text name="mail" label="E-mail address" value=data.mail! /> + <@form_pwd name="password" label="Password" /> + <@form_submit label="Log in" /> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/logs.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/logs.ftl new file mode 100644 index 0000000..7a2d9e7 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/logs.ftl @@ -0,0 +1,103 @@ +<@page title="Logs viewer"> +

Log entries

+ + + + + + +
+ <#if data.params.first = 0> + << + <#else> + <#if data.params.first gt 30> + 1<#else>0&first=${data.params.first - 30 }"> + <#else> + 1<#else>0&first=0"> + + << + + + <#if data.count = 0> + No entries found. + <#else> + ${data.count?string(",##0")} entries + + + <#if (data.params.first + 30) gt data.count> + >> + <#else> + 1<#else>0&first=${data.params.first + 30 }"> + >> + +
+ <#if data.count gt 0> + + + <@lv_line headers=true> + <@lv_column width=60 centered=true>Date + <@lv_column width=60 centered=true>Time + <@lv_column width=60 centered=true>Log level + <@lv_column width=200 centered=true> + <#if data.params.type = "SYSTEM"> + Component + <#else> + User + + + <@lv_column width="x">Message + <@lv_column width=50>  + + + <#list data.entries as entry> + <@lv_line class="log-entry-${entry.level?lower_case}"> + <@lv_column centered=true>${entry.timestamp?string("yyyy-MM-dd")} + <@lv_column centered=true>${entry.timestamp?string("HH:mm:ss")} + <@lv_column centered=true>${entry.level} + <@lv_column centered=true>${entry.about?xhtml} + <@lv_column>${entry.entry?xhtml} + <@lv_column> + <#if entry.exception?has_content> + Details + <#else> +   + + + + + +
+ + +

Search parameters

+
+
+ + + <@form_select name="logType" label="Log type"> + <@form_option value="SYSTEM" selected=((data.params.type!"") = "SYSTEM")>system log + <@form_option value="ADMIN" selected=((data.params.type!"") = "ADMIN")>administrative actions + <@form_option value="PLAYER" selected=((data.params.type!"") = "PLAYER")>player actions + + + <@form_select name="logLevel" label="Minimal log level"> + <@form_option value="TRACE" selected=((data.params.level!"") = "TRACE")>TRACE + <@form_option value="DEBUG" selected=((data.params.level!"") = "DEBUG")>DEBUG + <@form_option value="INFO" selected=((data.params.level!"") = "INFO")>INFO + <@form_option value="WARNING" selected=((data.params.level!"") = "WARNING")>WARNING + <@form_option value="ERROR" selected=((data.params.level!"") = "ERROR")>ERROR + + + <@form_text label="Component / user" name="component" value=data.params.component! /> + + <@form_select name="excOnly" label="Only entries with exceptions"> + <@form_option value="0" selected=!( data.params.excOnly!false)>no + <@form_option value="1" selected=data.params.excOnly!false>yes + + + <@form_submit label="Search"/> +
+
+
+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/main.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/main.ftl new file mode 100644 index 0000000..c1a1c52 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/main.ftl @@ -0,0 +1,42 @@ +<@page title="Overview"> +

Your administrative account

+

+ E-mail address: ${data.admin.address?xhtml} +

+

+ Privileges: + <#list data.admin.privileges as priv> + ${priv} + +

+

+ Change password +

+

 

+ +

Overview

+

+ Unread messages: ${data.overview.newMessages} +

+ <#if data.overview.pendingNames?has_content> +

+ Unvalidated map names: ${data.overview.pendingNames} +

+ + <#if data.overview.pendingBans?has_content> +

+ Unvalidated ban requests: ${data.overview.pendingBans} +

+ + <#if data.overview.pendingBugs?has_content> +

+ Bug reports pending validation: ${data.overview.pendingBugs} +

+

+ Open bug reports: ${data.overview.openBugs} +

+

+ Updated bug reports: ${data.overview.updatedBugs} +

+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/maintenance.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/maintenance.ftl new file mode 100644 index 0000000..32bbd62 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/maintenance.ftl @@ -0,0 +1,40 @@ +<@page title="Maintenance mode"> + + <#if data.reason?has_content> + +

Maintenance mode is enabled.

+ <@dt_main> + <@dt_entry title="Started">${data.started?string("yyyy-MM-dd HH:mm:ss")} + <@dt_entry title="Scheduled to end">${data.until?string("yyyy-MM-dd HH:mm:ss")} + <@dt_entry title="Reason">${data.reason?xhtml} + + + + <@form action="maintenance-extend"> + <@form_text label="Duration (minutes)" name="duration" value="" /> + <@form_submit label="Extend maintenance mode"/> + + <@form action="maintenance-end"> + <@form_submit label="Disable maintenance mode"/> + + + <#else> + +

Maintenance mode is currently disabled.

+ + <@form action="maintenance-start"> + <#switch data.reasonError!""> + <#case 'EMPTY'><@form_error>You must specify a reason.<#break> + <#case 'INVALID'><@form_error>Reason too short (must be at least 10 characters long).<#break> + + <@form_text label="Reason for maintenance activation" name="reason" value=data.newReason!"" /> + <#if ( data.newReason!"" ) != "" && ! data.reasonError?has_content> + <@form_error>Invalid duration + + <@form_text label="Duration (minutes)" name="duration" value=data.newDuration!"" /> + <@form_submit label="Enable maintenance mode"/> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/message.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/message.ftl new file mode 100644 index 0000000..028ef4a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/message.ftl @@ -0,0 +1,96 @@ +<#macro render_navigation message inbox> + <#if inbox> + <#local link="inbox-message-"> + <#else> + <#local link="outbox-message-"> + + + + + + + +
+ <#if message.previous?has_content> + + + << + <#if message.previous?has_content> + + + + <#if inbox> + Received messages + <#else> + Sent messages + + + <#if message.next?has_content> + + + >> + <#if message.next?has_content> + + +
+ +<#macro render> +<#if data.inbox> + <#local title="Received messages"> + <#local timeTtl="Received"> +<#else> + <#local title="Sent messages"> + <#local timeTtl="Sent"> + +<@page title=title> + <@render_navigation message=data.message inbox=data.inbox /> + + <@dt_main> + <@dt_entry width=100 title="From"> + ${data.message.sender!} + <#if data.inbox> + (${data.message.type?lower_case}) + + + <@dt_entry width=100 title="To"> + ${data.message.receiver!} + <#if !data.inbox> + (${data.message.type?lower_case}) + + + <@dt_entry width=100 title=timeTtl> + ${data.message.time?string("yyyy-MM-dd HH:mm:ss")} + + <#if data.message.unread> + <@dt_entry width=100 title="">New! + + + + <@listview><@lv_line headers=true>  + +

${data.message.title}

+
+ ${data.message.contents} +
+ + <@listview><@lv_line headers=true>  + <@lineform action="message"> + + + <#if data.message.previous?has_content> + <#local afterDelete = data.message.previous> + <#elseif data.message.next?has_content> + <#local afterDelete = data.message.next> + <#else> + <#local afterDelete = "x"> + + + <@ff_submit label="Delete message" name="delete" /> + <#if data.inbox && data.message.type != 'INTERNAL'> + <@ff_submit label="Compose reply" name="reply" /> + + + + + +<@render /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageBox.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageBox.ftl new file mode 100644 index 0000000..f0e5ace --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageBox.ftl @@ -0,0 +1,112 @@ +<#include "messageTabs.ftl" /> +<#macro render_navigation current total inbox> + <#if inbox> + <#local link="inbox-"> + <#else> + <#local link="outbox-"> + + + + + + + +
+ <#if current gt 0> + + + << + <#if current gt 0> + + + + <#if total gt 0> + Page ${current + 1} / ${total} + <#elseif inbox> + No messages received. + <#else> + No messages sent. + + + <#if current lt total - 1> + + + >> + <#if current lt total - 1> + + +
+ +<#macro render> +<#if data.inbox> + <#local title="Received messages"> + <#local tab="inbox"> +<#else> + <#local title="Sent messages"> + <#local tab="outbox"> + +<@page title=title> + <@messageTabs selected=tab /> + <@render_navigation current=data.cPage total=data.pages inbox=data.inbox /> + <#if data.messages?size gt 0> +
+ + + <@listview> + + <@lv_line headers=true> + <@lv_column width=16 centered=true>  + <@lv_column width="x">Subject + <@lv_column width=150 centered=true><#if data.inbox>From<#else>To + <@lv_column width=150 centered=true><#if data.inbox>Received<#else>Sent + + + <#list data.messages as message> + <#if ! message.read> + <#local mType = "unread-msg"> + <#else> + <#local mType = ""> + + + <@lv_line class=mType> + <@lv_column centered=true> + + + <@lv_column><#if message.type = 'EMPIRE'>${message.title}<#else>${message.title} + <@lv_column centered=true>${message.sender!} + <@lv_column centered=true>${message.time?string("yyyy-MM-dd HH:mm:ss")} + + + + + <#if data.inbox> +
+ With + <@ff_select name="target" id="target"> + <@form_option value="0">selected + <@form_option value="1">all + + messages: + <@ff_select name="action" id="action"> + <@form_option value="r">mark as read + <@form_option value="u">mark as unread + <@form_option value="d">delete + + <@ff_submit label="Go" /> +
+ <#else> +
+ + Delete + <@ff_select name="target" id="target"> + <@form_option value="0">selected + <@form_option value="1">all + + messages <@ff_submit label="Go" /> +
+ +
+ + + +<@render /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageTabs.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageTabs.ftl new file mode 100644 index 0000000..33c248e --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageTabs.ftl @@ -0,0 +1,10 @@ +<#macro messageTab href title selected> + ${title} + +<#macro messageTabs selected> +
+ <@messageTab href="messages" title="Received" selected=( selected = 'inbox' ) /> + <@messageTab href="outbox" title="Sent" selected=( selected = 'outbox' ) /> + <@messageTab href="compose-message" title="Compose" selected=( selected = 'compose' ) /> +
+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageWriter.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageWriter.ftl new file mode 100644 index 0000000..f003b62 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/messageWriter.ftl @@ -0,0 +1,79 @@ +<#include "messageTabs.ftl" /> +<#macro render> +<#if data.replyTo?has_content> + <#local title="Reply to message"> +<#else> + <#local title="Compose new message"> + +<@page title=title> + <@messageTabs selected="compose" /> + +
+
+ <#if data.replyTo?has_content> + + + + + + <#if data.timingError> + <@form_error>Not so fast! Wait a few seconds before trying again. + + + <#-- Message recipient --> + <#if data.targetError> + <@form_error>Message recipient not found. + + <@form_select label="Recipient type" name="toType"> + <@form_option value="ADMINISTRATOR" selected=( data.messageType = 'ADMINISTRATOR' )>Administrator + <@form_option value="EMPIRE" selected=( data.messageType = 'EMPIRE' )>Empire + + <@form_text label="Recipient name" name="toName" maxLength=48 value=data.target /> + + <#-- Subject --> + <#if data.titleError> + <@form_error>Subject is too short (min.: 2 characters) + + <@form_text label="Subject" name="title" maxLength=64 value=data.title /> + + <#-- Body --> + <#if data.contentsError> + <@form_error>Contents are too short (min.: 2 characters) + + <@form_text label="Contents" name="contents" value=data.contents multiline=true maxLength=10 /> + + <@form_extended_submit label="Send message"> + <@ff_submit label="Cancel" name="cancel" /> + +
+ +
+
+ + <#-- Original message --> + <#if data.replyTo?has_content> + <@listview><@lv_line headers=true>  + <@dt_main> + <@dt_entry width=100 title="">Original message: + <@dt_entry width=100 title="From"> + ${data.replyTo.sender!} + + <@dt_entry width=100 title="To"> + ${data.replyTo.receiver!} + + <@dt_entry width=100 title="Received"> + ${data.replyTo.time?string("yyyy-MM-dd HH:mm:ss")} + + + + <@listview><@lv_line headers=true>  + +

${data.replyTo.title}

+
+ ${data.replyTo.contents} +
+ + + + +<@render /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/names.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/names.ftl new file mode 100644 index 0000000..55a9c32 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/names.ftl @@ -0,0 +1,72 @@ +<#macro render_name_entry name> + <@lv_line> + <@lv_column centered=true> + <#if data.type = "EMPIRE" && (name.extra!"x") == ""> + <@lv_column> + <#else> + <@lv_column> + + <#if data.type = "ALLIANCE"> + <@lv_column> + <#elseif data.type = "MAP_CHANGED"> + <@lv_column centered=true><#if name.type = "MAP_PENDING">No<#else>Yes + + + +<#macro render_actions> + <#if data.type = "MAP_PENDING"> + <@ff_select name="action" id="action"> + <@form_option value="VALIDATE">Validate + <@form_option value="REJECT">Reject and send warning + <@form_option value="REJECT_BAN">Reject, send warning and ban name + + <#elseif data.type = "MAP_VALIDATED"> + <@ff_select name="action" id="action"> + <@form_option value="REJECT">Reject and send warning + <@form_option value="REJECT_BAN">Reject, send warning and ban name + <@form_option value="RESET">Allow early renaming + + <#elseif data.type = "MAP_CHANGED"> + <@ff_select name="action" id="action"> + <@form_option value="VALIDATE">Validate + <@form_option value="REJECT">Reject and send warning + <@form_option value="REJECT_BAN">Reject, send warning and ban name + <@form_option value="RESET">Allow early renaming + + <#elseif data.type = "EMPIRE"> + <@ff_select name="action" id="action"> + <@form_option value="REJECT">Forcibly rename to "RudeGuyXXX" + <@form_option value="REJECT_BAN">Forcibly rename and ban old name + + <#else> + + Disband selected alliance(s) + + +<@page title=data.type.description> + <#if data.names?size = 0> +

No names to display

+

There are no such names at the moment.

+ <#else> +
+ <@listview> + <@lv_line headers=true> + <@lv_column width=24>  + <#if data.type = "ALLIANCE"> + <@lv_column width=100>Tag + <@lv_column width=300>Name + <#elseif data.type = "MAP_CHANGED"> + <@lv_column width=300>Name + <@lv_column width=150 centered=true>Validated + <#else> + <@lv_column width=300>Name + + + <#list data.names as name> + <@render_name_entry name=name /> + + +

<@render_actions />

+
+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/namesSummary.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/namesSummary.ftl new file mode 100644 index 0000000..39857d4 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/namesSummary.ftl @@ -0,0 +1,20 @@ +<@page title="Names"> + <@listview> + <@lv_line headers=true> + <@lv_column width=250>Status + <@lv_column width=100 centered=true>Names + + <#list data.entries as entry> + <@lv_line> + <@lv_column> + <#if entry.count gt 0> + ${entry.type.description?xhtml} + <#else> + ${entry.type.description?xhtml} + + + <@lv_column centered=true>${entry.count?string(",##0")} + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/offline.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/offline.ftl new file mode 100644 index 0000000..a59838f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/offline.ftl @@ -0,0 +1,5 @@ +<@page title="Server off-line"> +

+ The Legacy Worlds game server is currently off-line. Manual repairs need to be undertaken. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/preferences.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/preferences.ftl new file mode 100644 index 0000000..413d959 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/preferences.ftl @@ -0,0 +1,53 @@ +<#macro render_preference pref> +
+
+ + + + + + <#switch pref.type> + <#case 'BOOLEAN'> + <@form_select label="Default value" name="value" id="pref-${pref.id}"> + <@form_option value="0" text="No" selected=( pref.value != "1" )/> + <@form_option value="1" text="Yes" selected=( pref.value == "1" )/> + + <#break> + <#case 'INTEGER'> + <#case 'STRING'> + <@form_text label="Default value" name="value" id="pref-${pref.id}" value=pref.value /> + <#break> + <#case 'CHOICE'> + <@form_select label="Default value" name="value" id="pref-${pref.id}"> + <#list pref.choices as choice> + <@form_option value=choice.value text=choice.display selected=( pref.value == choice.value )/> + + + <#break> + + <#if pref.description?has_content> + + + + + + <@form_submit label="Update default value" /> +
Preference name: + ${pref.name?xhtml} + +
Description:${pref.description?xhtml}
+
+

 

+
+ +<#macro render_prefs_category category> +

${category.name?xhtml}

+ <#list category.preferences as p> + <@render_preference pref=p /> + + +<@page title="Default preferences"> + <#list data.preferences as c> + <@render_prefs_category category=c /> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/resetAdmin.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/resetAdmin.ftl new file mode 100644 index 0000000..41ee429 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/resetAdmin.ftl @@ -0,0 +1,18 @@ +<@page title="Administrator ${data.view.name} - reset password"> + <@dt_main> + <@dt_entry title="Name">${data.view.name?xhtml} + <@dt_entry title="Address"> + <#if data.view.address?has_content> + ${data.view.address?xhtml} + <#else> + (account deleted) + + + + + <@form action="do-reset-admin-${data.view.id}"> + <@form_extended_submit label="Reset password"> + <@ff_submit label="Cancel" name="cancel" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/spam.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/spam.ftl new file mode 100644 index 0000000..b658b85 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/spam.ftl @@ -0,0 +1,27 @@ +<@page title="Spaminator! (TM)"> + <#if data.preview?has_content> +

Message preview

+
${data.preview}
+

 

+ + +

Compose spam

+

This message is going to be sent to every player in the game, so please don't be a complete idiot while typing it.

+ <@form action="send-spam"> + + <#if data.titleError!false> + <@form_error>Spam title missing, too short or too long + + <@form_text name="title" label="Title" value=data.title!"" maxLength=64/> + + <#if data.bodyError!false> + <@form_error>Spam body missing or too short + + <@form_text name="body" label="Body" value=data.body!"" multiline=true maxLength=10 /> + + <@form_extended_submit label="Spam, spam, spam!"> + <@ff_submit label="Preview" name="preview" /> + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/ticker.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/ticker.ftl new file mode 100644 index 0000000..367969a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/ticker.ftl @@ -0,0 +1,51 @@ +<#macro render_task task> + <@lv_line> + <@lv_column>  + <@lv_column>${task.name?xhtml} + <@lv_column>${task.status.description?xhtml}<#if task.status = 'AUTO'> +
${task.start?string("yyyy-MM-dd HH:mm:ss")} + + <@lv_column> +
+ <#if task.status != 'RUNNING'> + Start - + + <#if task.status != 'STOPPED'> + Stop + +
+ Schedule automatic start in + <@ff_text name="delay" value="1" id="delay" maxLength=5 /> + <@ff_select name="multiplier" id="multiplier"> + <@form_option value="86400">day(s) + <@form_option value="3600">hour(s) + <@form_option value="60">minute(s) + <@form_option value="1">second(s) + + <@ff_submit label="Go" /> +
+ + + +<@page title="Ticker status"> +

Ticker tasks

+ <@listview> + <@lv_line headers=true> + <@lv_column width=40>  + <@lv_column width=180>Task name + <@lv_column width=200>Status + <@lv_column width="x">  + + <#list data.tasks as task> + <@render_task task=task /> + + +

 

+ +

Ticker main thread

+ <#if data.paused> +

The main ticker thread is currently paused. Start it

+ <#else> +

The main ticker thread is currently running. Pause it

+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/user.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/user.ftl new file mode 100644 index 0000000..acfdeba --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/user.ftl @@ -0,0 +1,58 @@ +<#assign accnt = data.account> +<@page title="User #${accnt.id?string(',##0')} - ${accnt.address}"> + <@dt_main> + + <@dt_entry title="User ID">${accnt.id?string(',##0')} + <@dt_entry title="E-mail address">${accnt.address?xhtml} + <@dt_entry title="Language code">${accnt.language} + + <@dt_blank /> + + <@dt_entry title="Current status">${accnt.status.description?xhtml} + <#if accnt.statusStart?has_content> + <@dt_entry title="Since / Starting from">${accnt.statusStart?string("yyyy-MM-dd HH:mm:ss")} + + <#if accnt.inactivityReason?has_content> + <@dt_entry title="Reason">${accnt.inactivityReason?xhtml} + + <#if accnt.ban?has_content> + <#assign be = accnt.ban> + <@dt_entry title="Requested by">${be.requestedByName?xhtml} + <@dt_entry title="Confirmed by">${be.confirmedByName?xhtml} + + <@dt_entry title="Warnings received">${accnt.warnings} + <#if accnt.warnings gt 0> + <@dt_entry title="Last warning">${accnt.lastWarning?string("yyyy-MM-dd HH:mm:ss")} + + + <@dt_blank /> + + <#if accnt.online> + <@dt_entry title="">CURRENTLY ONLINE + + <@dt_entry title="">View sessions + + <@dt_blank /> + + <@dt_entry title="Vacation credits">${accnt.vacationCredits?string(",##0")} + <@dt_entry title="Game credits">${accnt.gameCredits?string(",##0")} + <@dt_entry title=""> +
+ Grant this user <@ff_text name="credits" id="credits" value=1 /> credit(s) + <@ff_submit label="Go" /> +
+ + + <@dt_blank /> + + <#if accnt.currentEmpire?has_content> + <@dt_entry title="Currently playing as">${accnt.currentEmpire?xhtml} + + <#if accnt.empireNames?size gt 0> + <@dt_entry title="All empire names"> + <#list accnt.empireNames as name>${name?xhtml}
+ + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/userSessions.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/userSessions.ftl new file mode 100644 index 0000000..4b05631 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/userSessions.ftl @@ -0,0 +1,57 @@ +<@page title="User #${data.account.id?string(',##0')} - Sessions"> +

Account

+ <@dt_main> + <@dt_entry title="E-mail address">${data.account.address?xhtml} + <@dt_entry title="Language code">${data.account.language} + <@dt_entry title="Current status">${data.account.status.description?xhtml} + <#if data.account.currentEmpire?has_content> + <@dt_entry title="Currently playing as">${data.account.currentEmpire?xhtml} + + <@dt_entry title="">Back to account page + + +

Sessions

+ <#if data.account.sessions?size = 0> +

No sessions for this account.

+ <#else> + <@listview> + + <@lv_line headers=true> + <@lv_column width=60 centered=true>ID# + <@lv_column width=60 centered=true>C.T. + <@lv_column width=120 centered=true>IP address + <@lv_column width=60 centered=true>Start date + <@lv_column width=60 centered=true>- time + <@lv_column width=60 centered=true>End date + <@lv_column width=60 centered=true>- time + <@lv_column width="x">Termination reason + + + <#list data.account.sessions as session> + <@lv_line> + <@lv_column centered=true>${session.id?string(",##0")} + <@lv_column centered=true> + <#if session.exclusive> + ${session.clientName?xhtml} + <#else> + ${session.clientName?xhtml} + + + <@lv_column centered=true>${session.fromAddress?xhtml} + <@lv_column centered=true>${session.started?string('yyyy-MM-dd')} + <@lv_column centered=true>${session.started?string('HH:mm:ss')} + + <#if session.ended?has_content> + <@lv_column centered=true>${session.ended?string('yyyy-MM-dd')} + <@lv_column centered=true>${session.ended?string('HH:mm:ss')} + <@lv_column>${session.endType.description?xhtml} + <#else> + Still connected + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/users.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/users.ftl new file mode 100644 index 0000000..2ffe322 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/users.ftl @@ -0,0 +1,49 @@ +<#if data.status?has_content> + <#assign pTitle= "Users with status '${data.status.description}'"> + +<@page title=pTitle!"Users"> +
+

+ Display + <@ff_select name="online" id="online"> + <@form_option value="0">all + <@form_option value="1" selected=data.online!false>online + + users that have the following status: + <@ff_select name="status" id="status"> + <@form_option value="x" selected=!(data.status?has_content)>(all users) + <#list data.allStatuses as st> + <@form_option value=st selected=((data.status!"") = st)>${st.description} + + + <@ff_submit label="Filter" /> +

+
+ + <#if data.entries?size gt 0> +

${data.entries?size} account(s) found.

+ <@listview> + + <@lv_line headers=true> + <@lv_column width=40>  + <@lv_column width=250>E-mail address + <@lv_column width=250>Current empire + <@lv_column width=100 centered=true>Status + <@lv_column width=100 centered=true>Language + + + <#list data.entries as entry> + <@lv_line> + <@lv_column>  + <@lv_column>${entry.address?xhtml} + <@lv_column><#if entry.currentEmpire?has_content>${entry.currentEmpire?xhtml}<#else>N/A + <@lv_column centered=true>${entry.status.description?xhtml} + <@lv_column centered=true>${entry.language} + + + + + <#else> +

No accounts found

+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/viewAdmin.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/viewAdmin.ftl new file mode 100644 index 0000000..5276f7b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/types/viewAdmin.ftl @@ -0,0 +1,41 @@ +<@page title="Administrator ${data.view.name}"> +

General information

+ <@dt_main> + <@dt_entry title="Name">${data.view.name?xhtml} + <@dt_entry title="Address"> + <#if data.view.address?has_content> + ${data.view.address?xhtml} + <#else> + (account deleted) + + + + <@dt_entry title="Password modified"> + <#if data.view.passwordChange> + no + <#else> + yes + + + <#if data.view.id != data.admin.id && data.view.address?has_content && !data.view.passwordChange> + <@dt_entry title="">Reset administration password + + + + <#if data.view.id != data.admin.id && data.view.address?has_content> +

 

+

Privileges

+ <@form action="admin-privileges-${data.view.id}"> + + Privileges: + + <#list data.view.allPrivileges as privilege> + checked="checked" /> + + + + + <@form_submit label="Update privileges" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/version.ftl b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/version.ftl new file mode 100644 index 0000000..c9406cf --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/fm/version.ftl @@ -0,0 +1,2 @@ +<#macro version>Milestone 1 +<#macro full_version>Beta 6 milestone 1 (5.99.1) \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/web.xml b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/web.xml new file mode 100644 index 0000000..72556c9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/WEB-INF/web.xml @@ -0,0 +1,61 @@ + + + + legacyworlds-web-admin + + + charsetFilter + org.springframework.web.filter.CharacterEncodingFilter + + encoding + UTF-8 + + + forceEncoding + 1 + + + + + charsetFilter + /* + + + + admin + org.springframework.web.servlet.DispatcherServlet + 1 + + + + pass-through + org.apache.catalina.servlets.DefaultServlet + + + + pass-through + *.js + + + + pass-through + *.css + + + + pass-through + *.jpg + + + + pass-through + *.png + + + + admin + / + + + diff --git a/legacyworlds-web/legacyworlds-web-admin/WebContent/css/main.css b/legacyworlds-web/legacyworlds-web-admin/WebContent/css/main.css new file mode 100644 index 0000000..ed50e64 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/WebContent/css/main.css @@ -0,0 +1,171 @@ +* { + color: black; + font-family: Arial, sans-serif; + font-size: 10pt; + margin: 0; + padding: 0 +} + +body { + background-color: #ffefef; +} + +/* Page header */ +div.page-header { + width: 80%; + margin: 5px auto 20px auto; + background-color: #ff7f7f; + border-color: #ff0000; + border-width: 1px; + border-style: solid; +} + +.page-header * { + text-align: center; + color: white; +} + +.page-header h1 { + font-size: 16pt; +} + +.page-header h2 { + font-size: 12pt; +} + +.page-header h3 { + font-size: 9pt; + font-style: italic; +} + +/* Page body */ +div.page-full { + width: 100%; +} + +.page-full.page-contents { + padding: 0px 20px; +} + +.page-full .page-contents { + padding: 0px 20px 0px 250px; +} + +/* Side bar */ +.side-bar { + float: left; + margin: 0px 5px; + padding: 5px; + width: 225px; + background-color: #ffafaf; + border-color: #ff7f7f; + border-width: 1px; + border-style: solid; +} + +.side-bar .admin { + font-size: 11pt; + font-weight: bold; + padding: 0 0 10px 0; + text-align: center; +} + +.side-bar a { + display: block; + width: 100%; + text-decoration: none; + text-align: center; + padding: 3px 0; +} + +.side-bar a:hover { + background-color: #ff0000; + color: white; +} + +/* Text */ +h1 { + font-size: 14pt; + margin: 0 0 10px 0; +} + +h2 { + font-size: 13pt; + margin: 0 0 10px 10px; +} + +h3 { + font-size: 12pt; + margin: 0 0 10px 20px; +} + +h4 { + font-size: 11pt; + margin: 0 0 10px 40px; +} + +.page-contents p { + margin: 5px 10px 5px 30px; + text-align: justify; + text-indent: 20px; +} + +.page-contents ul,.page-contents ol { + margin: 0px 0px 0px 20px; + padding: 0px 0px 0px 10px; +} + +.page-contents li { + margin: 0px 0px 0px 20px; + padding: 0px 0px 0px 0px; +} + +/* Forms */ +.form-container table { + margin: 0 0 0 80px; +} + +.form-error { + background-color: red; + font-weight: bold; +} + +.form-error,.form-error * { + color: yellow; + padding: 2px; +} + +/* List views */ +.list-view th,.list-view td { + padding: 0 15px 0 0; +} + +/* Log entries */ +tr.log-entry-error,tr.log-entry-error * { + background-color: #ff0000; + color: #ffff00; +} + +tr.log-entry-warning,tr.log-entry-warning * { + background-color: #ffff00; + color: #0000ff; +} + +tr.log-entry-info,tr.log-entry-info * { + background-color: #ffffff; + color: #000000; +} + +tr.log-entry-debug,tr.log-entry-debug * { + background-color: #afffff; + color: #000000; +} + +tr.log-entry-trace,tr.log-entry-trace * { + background-color: #afffaf; + color: #000000; +} + +.unread-msg * { + font-weight: bold; +} \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/pom.xml b/legacyworlds-web/legacyworlds-web-admin/pom.xml new file mode 100644 index 0000000..5d1f361 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/pom.xml @@ -0,0 +1,95 @@ + + 4.0.0 + + legacyworlds-web + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-web-admin + 5.99.1 + war + Legacy Worlds administration site + + + + com.deepclone.lw + legacyworlds-web-beans + ${project.version} + + + + javax.servlet + servlet-api + 2.5 + provided + + + + org.freemarker + freemarker + ${org.freemarker.version} + runtime + + + + com.thoughtworks.xstream + xstream + ${com.thoughtworks.xstream.version} + jar + + + + + + + + + + org.apache.maven.plugins + maven-war-plugin + 2.0 + + + + legacyworlds-web/legacyworlds-web-admin/WebContent + + + + + + build-admin-war + package + + war + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/BanhammerPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/BanhammerPages.java new file mode 100644 index 0000000..c57ed04 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/BanhammerPages.java @@ -0,0 +1,172 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bans.BanType; +import com.deepclone.lw.cmd.admin.bans.BansSummaryResponse; +import com.deepclone.lw.cmd.admin.bans.ListBansResponse; +import com.deepclone.lw.cmd.admin.bans.RejectBanResponse; +import com.deepclone.lw.cmd.admin.bans.RequestBanResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class BanhammerPages + extends PageControllerBase +{ + + @RequestMapping( "/bans" ) + public String bansSummary( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BansSummaryResponse response = this.getSession( AdminSession.class , request ).getBansSummary( ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "bansSummary" , response ); + } + + + @RequestMapping( "/bans-{type}" ) + public String listBans( HttpServletRequest request , Model model , @PathVariable( "type" ) String sType ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BanType type; + try { + type = BanType.valueOf( sType.toUpperCase( ) ); + } catch ( IllegalArgumentException e ) { + return this.redirect( "bans" ); + } + + ListBansResponse response = this.getSession( AdminSession.class , request ).getBans( type ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + + return this.render( model , "internal" , "en" , "bans" , response ); + } + + + @RequestMapping( "/request-ban" ) + public String requestBan( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminResponse response = this.getSession( AdminSession.class , request ).noOp( Privileges.BANH ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "banRequest" , response ); + } + + + @RequestMapping( value = "/request-ban.action" , method = RequestMethod.POST ) + public String requestBan( HttpServletRequest request , Model model , @RequestParam( "eName" ) String eName , + @RequestParam( "eMail" ) String eMail , @RequestParam( "reason" ) String reason ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + boolean empire = "".equals( eMail ); + String user = empire ? eName : eMail; + + RequestBanResponse response = this.getSession( AdminSession.class , request ).requestBan( user , empire , + reason ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getError( ) == null ) { + return this.redirect( "bans" ); + } + return this.render( model , "internal" , "en" , "banRequest" , response ); + } + + + @RequestMapping( value = "reject-ban-{id}" ) + public String rejectBan( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bans-pending" ); + } + + AdminResponse response = this.getSession( AdminSession.class , request ).noOp( Privileges.BANH ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + + return this.renderMap( model , "internal" , "en" , "banReject" , "admin" , response.getAdmin( ) , "id" , id ); + } + + + @RequestMapping( value = "reject-ban-{id}.action" , method = RequestMethod.POST ) + public String rejectBan( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId , + @RequestParam( "reason" ) String reason ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bans-pending" ); + } + + RejectBanResponse response = this.getSession( AdminSession.class , request ).rejectBan( id , reason ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( !response.isError( ) ) { + return this.redirect( "bans-pending" ); + } + + return this.render( model , "internal" , "en" , "banReject" , response ); + } + + + @RequestMapping( "confirm-ban-{id}.action" ) + public String confirmBan( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bans-pending" ); + } + + this.getSession( AdminSession.class , request ).confirmBan( id ); + return this.redirect( "bans-pending" ); + } + + + @RequestMapping( "lift-ban-{id}.action" ) + public String liftBan( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bans-validated" ); + } + + this.getSession( AdminSession.class , request ).liftBan( id ); + return this.redirect( "bans-validated" ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/BugTrackerPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/BugTrackerPages.java new file mode 100644 index 0000000..95c4176 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/BugTrackerPages.java @@ -0,0 +1,373 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.bt.*; +import com.deepclone.lw.cmd.bt.data.BugEvent; +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.msgs.MessageFormatter; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.BugTrackerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class BugTrackerPages + extends BugTrackerBase +{ + private static final int perPage = 20; + + private MessageFormatter formatter; + + + @Autowired( required = true ) + public void setFormatter( MessageFormatter formatter ) + { + this.formatter = formatter; + } + + + @RequestMapping( "/btracker" ) + public String getSummary( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugsSummaryResponse summary = this.getSession( AdminSession.class , request ).getBugsSummary( ); + if ( !summary.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "bugsSummary" , summary ); + } + + + @RequestMapping( "/bugs" ) + public String listBugs( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + AdminSession aSession = this.getSession( AdminSession.class , request ); + ListBugsResponse response = aSession.listBugs( query.status , query.ownOnly , query.first , perPage ); + return this.render( model , "internal" , "en" , "bugsList" , response ); + } + + + @RequestMapping( "/report-bug" ) + public String showReportForm( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + AdminSession aSession = this.getSession( AdminSession.class , request ); + Administrator admin = aSession.noOp( Privileges.BUGT ).getAdmin( ); + return this.renderMap( model , "internal" , "en" , "bugsReport" , "admin" , admin , "query" , query ); + } + + + @RequestMapping( value = "/report-bug.action" , method = RequestMethod.POST ) + public String postReport( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @RequestParam( "title" ) String title , + @RequestParam( "description" ) String description , + @RequestParam( value = "public" , required = false , defaultValue = "0" ) String publicReport ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + AdminSession aSession = this.getSession( AdminSession.class , request ); + ReportBugResponse response = aSession.reportBug( title , description , "1".equals( publicReport ) ); + + if ( response.getTitle( ) == null ) { + // Successful post + String rTo = "bug-" + response.getBugId( ) + this.makeGetParams( query ); + return this.redirect( rTo ); + } + + response = new ReportBugResponse( response , query ); + return this.render( model , "internal" , "en" , "bugsReport" , response ); + } + + + @RequestMapping( value = "/bug-{id}" ) + public String viewBug( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugs" + this.makeGetParams( query ) ); + } + + ViewBugResponse response = this.getSession( AdminSession.class , request ).getBugReport( bugId ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getReport( ) == null ) { + return this.redirect( "bugs" + this.makeGetParams( query ) ); + } + + response = new ViewBugResponse( response , query ); + return this.displayReport( model , response ); + } + + + @RequestMapping( value = "/bug-{id}-comment.action" , method = RequestMethod.POST ) + public String commentBug( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId , + @RequestParam( "comment" ) String comment , @RequestParam( "visibility" ) String visibility ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + PostCommentResponse response = this.getSession( AdminSession.class , request ).postBugComment( bugId , comment , + "1".equals( visibility ) ); + if ( response.isPosted( ) ) { + String rTo = "bug-" + bugId + this.makeGetParams( query ); + return this.redirect( rTo ); + } else if ( response.getReport( ) == null ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + response = new PostCommentResponse( response , query ); + return this.displayReport( model , response ); + } + + + private String displayReport( Model model , ViewBugResponse response ) + { + for ( BugEvent event : response.getEvents( ) ) { + if ( event.getTitle( ) != null ) { + event.setTitle( this.formatter.cleanMessage( event.getTitle( ) ) ); + } + if ( event.getContents( ) != null ) { + event.setContents( this.formatter.formatMessage( event.getContents( ) , false ) ); + } + } + return this.render( model , "internal" , "en" , "bugsView" , response ); + } + + + @RequestMapping( value = "/bug-{id}-comment-moderation.action" , method = RequestMethod.POST ) + public String moderateComment( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId , + @RequestParam( "comment" ) String sComment , @RequestParam( "cAction" ) String validate ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + long commentId; + try { + commentId = Long.parseLong( sComment ); + } catch ( NumberFormatException e ) { + return this.redirect( "bug-" + bugId + this.makeGetParams( query ) ); + } + + this.getSession( AdminSession.class , request ).moderateBugComment( commentId , "1".equals( validate ) ); + return this.redirect( "bug-" + bugId + this.makeGetParams( query ) ); + } + + + @RequestMapping( value = "/bug-{id}-validation.action" , method = RequestMethod.POST ) + public String moderateReport( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId , + @RequestParam( "nStatus" ) String sNewStatus , @RequestParam( "visibility" ) String visibility , + @RequestParam( "credits" ) String sCredits , @RequestParam( "snapshot" ) String keepSnapshot ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + BugStatus newStatus; + try { + newStatus = BugStatus.valueOf( sNewStatus ); + } catch ( IllegalArgumentException e ) { + newStatus = BugStatus.PENDING; + } + + boolean visible = "1".equals( visibility ); + boolean snapshot = "1".equals( keepSnapshot ); + int grantCredits; + try { + grantCredits = Integer.parseInt( sCredits ); + } catch ( NumberFormatException e ) { + grantCredits = -1; + } + if ( grantCredits < 0 || grantCredits > 3 || newStatus == BugStatus.PENDING ) { + return this.redirect( "bug-" + bugId + this.makeGetParams( query ) ); + } + + this.getSession( AdminSession.class , request ).validateReport( bugId , newStatus , visible , grantCredits , + snapshot ); + return this.redirect( "bug-" + bugId + this.makeGetParams( query ) ); + } + + + @RequestMapping( value = "/bug-{id}-status.action" , method = RequestMethod.POST ) + public String setReportStatus( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId , + @RequestParam( "nStatus" ) String sNewStatus ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + BugStatus newStatus; + try { + newStatus = BugStatus.valueOf( sNewStatus ); + } catch ( IllegalArgumentException e ) { + newStatus = BugStatus.PENDING; + } + + if ( newStatus != BugStatus.PENDING ) { + this.getSession( AdminSession.class , request ).setReportStatus( bugId , newStatus ); + } + return this.redirect( "bug-" + bugId + this.makeGetParams( query ) ); + } + + + @RequestMapping( value = "/bug-{id}-visibility.action" , method = RequestMethod.POST ) + public String toggleReportVisibility( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + this.getSession( AdminSession.class , request ).toggleReportVisibility( bugId ); + return this.redirect( "bug-" + bugId + this.makeGetParams( query ) ); + } + + + @RequestMapping( value = "/bug-{id}-merge.action" , method = RequestMethod.POST ) + public String mergeReports( HttpServletRequest request , Model model , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId , + @RequestParam( "mergeId" ) String sMerge ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + long mergeId; + try { + mergeId = Long.parseLong( sMerge ); + } catch ( NumberFormatException e ) { + return this.redirect( "bug-" + bugId + this.makeGetParams( query ) ); + } + + MergeReportsResponse response = this.getSession( AdminSession.class , request ).mergeReports( bugId , mergeId ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getReport( ) == null ) { + if ( response.getMergeError( ) == null ) { + return this.redirect( "bug-" + mergeId + this.makeGetParams( query ) ); + } else { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + } + + response = new MergeReportsResponse( response , query ); + return this.displayReport( model , response ); + } + + + @RequestMapping( "/bug-{id}-xmlsnapshot" ) + public ResponseEntity< String > downloadSnapshot( HttpServletRequest request , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return new ResponseEntity< String >( "GTFO" , HttpStatus.NOT_FOUND ); + } + + GetSnapshotResponse response = this.getSession( AdminSession.class , request ).getSnapshot( bugId ); + if ( !response.isPrivilegeOk( ) ) { + return new ResponseEntity< String >( "GTFO" , HttpStatus.FORBIDDEN ); + } else if ( response.getSnapshot( ) == null ) { + return new ResponseEntity< String >( "GTFO" , HttpStatus.NOT_FOUND ); + } + + HttpHeaders rHeaders = new HttpHeaders( ); + rHeaders.setContentType( MediaType.APPLICATION_OCTET_STREAM ); + return new ResponseEntity< String >( response.getSnapshot( ) , rHeaders , HttpStatus.OK ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/ConstantsPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/ConstantsPages.java new file mode 100644 index 0000000..5bacd2e --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/ConstantsPages.java @@ -0,0 +1,64 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.constants.GetConstantsResponse; +import com.deepclone.lw.cmd.admin.constants.SetConstantResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class ConstantsPages + extends PageControllerBase +{ + + @RequestMapping( "/constants" ) + public String getConstants( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminSession session = this.getSession( AdminSession.class , request ); + GetConstantsResponse response = session.getConstants( ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "constants" , response ); + } + + + @RequestMapping( value = "/set-constant.action" , method = RequestMethod.POST ) + public String setConstant( HttpServletRequest request , Model model , @RequestParam( "name" ) String name , + @RequestParam( "value" ) String sValue ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + double value; + try { + value = Double.parseDouble( sValue ); + } catch ( NumberFormatException e ) { + return this.redirect( "constants" ); + } + + AdminSession session = this.getSession( AdminSession.class , request ); + SetConstantResponse response = session.setConstant( name , value ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( !response.isError( ) ) { + return this.redirect( "constants" ); + } + + return this.render( model , "internal" , "en" , "constants" , response ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/ErrorHandlerBean.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/ErrorHandlerBean.java new file mode 100644 index 0000000..b3ff978 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/ErrorHandlerBean.java @@ -0,0 +1,44 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.deepclone.lw.session.SessionCommandException; +import com.deepclone.lw.session.SessionIdentifierException; +import com.deepclone.lw.web.beans.session.SessionServerException; + + + +public class ErrorHandlerBean + implements HandlerExceptionResolver +{ + + @Override + public ModelAndView resolveException( HttpServletRequest request , HttpServletResponse response , Object handler , + Exception ex ) + { + if ( ex instanceof SessionServerException ) { + return this.offline( request ); + } else if ( ex instanceof SessionIdentifierException || ex instanceof SessionCommandException ) { + return new ModelAndView( "redirect:admin-session" ); + } + + // Other exceptions are not handled + return null; + } + + + private ModelAndView offline( HttpServletRequest request ) + { + ModelAndView mav = new ModelAndView( "ROOT" ); + mav.addObject( "container" , "external" ); + mav.addObject( "language" , "en" ); + mav.addObject( "type" , "offline" ); + return mav; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/I18NPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/I18NPages.java new file mode 100644 index 0000000..b6e7d14 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/I18NPages.java @@ -0,0 +1,131 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.i18n.ChangeLanguageResponse; +import com.deepclone.lw.cmd.admin.i18n.GetLanguageResponse; +import com.deepclone.lw.cmd.admin.i18n.I18NString; +import com.deepclone.lw.cmd.admin.i18n.SetStringResponse; +import com.deepclone.lw.cmd.admin.i18n.ViewLanguagesResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.admin.i18ne.LanguageExport; +import com.deepclone.lw.web.admin.i18ne.StringExport; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; +import com.thoughtworks.xstream.XStream; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class I18NPages + extends PageControllerBase +{ + + @RequestMapping( "/i18n" ) + public String listLanguages( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ViewLanguagesResponse response = this.getSession( AdminSession.class , request ).listLanguages( ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "languages" , response ); + } + + + @RequestMapping( "/i18n-{language}" ) + public String viewLanguage( HttpServletRequest request , Model model , @PathVariable( "language" ) String language ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + GetLanguageResponse response = this.getSession( AdminSession.class , request ).getLanguage( language ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getLanguage( ) == null ) { + return this.redirect( "i18n" ); + } + return this.render( model , "internal" , "en" , "language" , response ); + } + + + @RequestMapping( "/i18n-export-{language}" ) + public ResponseEntity< String > exportLanguage( HttpServletRequest request , + @PathVariable( "language" ) String language ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + HttpHeaders rHeaders = new HttpHeaders( ); + GetLanguageResponse response = this.getSession( AdminSession.class , request ).getLanguage( language ); + + if ( !response.isPrivilegeOk( ) ) { + return new ResponseEntity< String >( "GTFO" , HttpStatus.FORBIDDEN ); + } else if ( response.getLanguage( ) == null ) { + return new ResponseEntity< String >( "GTFO" , HttpStatus.NOT_FOUND ); + } + + LanguageExport lExport = new LanguageExport( ); + lExport.id = response.getLanguage( ).getId( ); + lExport.name = response.getLanguage( ).getName( ); + for ( I18NString str : response.getStrings( ) ) { + StringExport sExport = new StringExport( ); + sExport.id = str.getId( ); + sExport.value = str.getText( ); + lExport.strings.add( sExport ); + } + + XStream xStream = new XStream( ); + xStream.autodetectAnnotations( true ); + rHeaders.setContentType( MediaType.APPLICATION_OCTET_STREAM ); + return new ResponseEntity< String >( xStream.toXML( lExport ) , rHeaders , HttpStatus.OK ); + } + + + @RequestMapping( value = "/i18n-{language}-edit.action" , method = RequestMethod.POST ) + public String changeLanguage( HttpServletRequest request , Model model , + @PathVariable( "language" ) String language , @RequestParam( "name" ) String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ChangeLanguageResponse response; + response = this.getSession( AdminSession.class , request ).setLanguageName( language , name ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getLanguage( ) == null ) { + return this.redirect( "i18n" ); + } else if ( !response.isNameError( ) ) { + return this.redirect( "i18n-" + response.getLanguage( ).getId( ) ); + } + return this.render( model , "internal" , "en" , "language" , response ); + } + + + @RequestMapping( value = "/i18n-{language}-set-string.action" , method = RequestMethod.POST ) + public String setString( HttpServletRequest request , Model model , @PathVariable( "language" ) String language , + @RequestParam( "string" ) String string , @RequestParam( "value" ) String value ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + SetStringResponse response; + response = this.getSession( AdminSession.class , request ).setTranslation( language , string , value ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getLanguage( ) == null ) { + return this.redirect( "i18n" ); + } else if ( response.getEdited( ) == null ) { + return this.redirect( "i18n-" + response.getLanguage( ).getId( ) ); + } + return this.render( model , "internal" , "en" , "language" , response ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/LogPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/LogPages.java new file mode 100644 index 0000000..4f60c6b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/LogPages.java @@ -0,0 +1,144 @@ +package com.deepclone.lw.web.admin; + + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import com.deepclone.lw.cmd.admin.logs.GetEntryResponse; +import com.deepclone.lw.cmd.admin.logs.LogLevel; +import com.deepclone.lw.cmd.admin.logs.LogType; +import com.deepclone.lw.cmd.admin.logs.ViewLogResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class LogPages + extends PageControllerBase +{ + private final int pageSize = 30; + + + @RequestMapping( value = "/logs" , method = RequestMethod.GET ) + public String viewLogs( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int first = this.getFirstIndex( request ); + LogType logType = this.getLogType( request ); + LogLevel logLevel = this.getLogLevel( request ); + String component = request.getParameter( "component" ); + if ( component == null ) { + component = ""; + } else { + component = component.trim( ).toLowerCase( ); + } + boolean excOnly = "1".equals( request.getParameter( "excOnly" ) ); + + AdminSession aSession = this.getSession( AdminSession.class , request ); + ViewLogResponse response = aSession.viewLog( logType , first , pageSize , logLevel , component , excOnly ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + + Map< String , Object > params = new HashMap< String , Object >( ); + params.put( "type" , logType ); + params.put( "level" , logLevel ); + params.put( "component" , component ); + params.put( "excOnly" , (Boolean) excOnly ); + params.put( "first" , first ); + + Map< String , Object > data = new HashMap< String , Object >( ); + data.put( "admin" , response.getAdmin( ) ); + data.put( "entries" , response.getEntries( ) ); + data.put( "count" , response.getCount( ) ); + data.put( "params" , params ); + + return this.render( model , "internal" , "en" , "logs" , data ); + } + + + private int getFirstIndex( HttpServletRequest request ) + { + String sIndex = request.getParameter( "first" ); + if ( sIndex == null ) { + return 0; + } + int f; + try { + f = Integer.parseInt( sIndex ); + } catch ( NumberFormatException e ) { + return 0; + } + return ( f > 0 ) ? f : 0; + } + + + private LogType getLogType( HttpServletRequest request ) + { + LogType logType; + String sLogType = request.getParameter( "logType" ); + if ( sLogType == null ) { + logType = LogType.SYSTEM; + } else { + try { + logType = LogType.valueOf( sLogType ); + } catch ( IllegalArgumentException e ) { + logType = LogType.SYSTEM; + } + } + return logType; + } + + + private LogLevel getLogLevel( HttpServletRequest request ) + { + LogLevel logLevel; + String sLogLevel = request.getParameter( "logLevel" ); + if ( sLogLevel == null ) { + logLevel = LogLevel.INFO; + } else { + try { + logLevel = LogLevel.valueOf( sLogLevel ); + } catch ( IllegalArgumentException e ) { + logLevel = LogLevel.INFO; + } + } + return logLevel; + } + + + @RequestMapping( "/view-log-entry-{id}" ) + public String viewLogEntry( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long id; + try { + id = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "logs" ); + } + + GetEntryResponse response = this.getSession( AdminSession.class , request ).getLogEntry( id ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getEntry( ) == null ) { + return this.redirect( "logs" ); + } + + return this.render( model , "internal" , "en" , "logEntry" , response ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/LoginPage.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/LoginPage.java new file mode 100644 index 0000000..14aae05 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/LoginPage.java @@ -0,0 +1,53 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = false , redirectTo = "admin-session" ) +public class LoginPage + extends PageControllerBase +{ + @RequestMapping( value = "/" ) + public String root( HttpServletRequest request , Model model ) + { + return this.redirect( "login" ); + } + + @RequestMapping( value = "/login" ) + public String login( HttpServletRequest request , Model model ) + { + return this.renderMap( model , "external" , "en" , "login" , "failed" , (Boolean) false ); + } + + + @RequestMapping( value = "/login.action" , method = RequestMethod.POST ) + public String login( HttpServletRequest request , Model model , @RequestParam( "mail" ) String mail , + @RequestParam( "password" ) String password ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminSession aSession = this.initSession( AdminSession.class , request ); + boolean authenticated = aSession.authenticate( mail , password ); + if ( !authenticated ) { + this.clearSession( request ); + return this.renderMap( model , "external" , "en" , "login" , "failed" , (Boolean) true ); + } + return this.redirect( "admin-session" ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MaintenancePages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MaintenancePages.java new file mode 100644 index 0000000..052e5c0 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MaintenancePages.java @@ -0,0 +1,89 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.mntm.*; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class MaintenancePages + extends PageControllerBase +{ + + @RequestMapping( "/maintenance" ) + public String getMaintenanceStatus( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + MaintenanceStatusResponse response = this.getSession( AdminSession.class , request ).getMaintenanceStatus( ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "maintenance" , response ); + } + + + @RequestMapping( value = "/maintenance-start.action" , method = RequestMethod.POST ) + public String enableMaintenance( HttpServletRequest request , Model model , + @RequestParam( "reason" ) String reason , @RequestParam( "duration" ) String sDuration ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int duration; + try { + duration = Integer.parseInt( sDuration ); + } catch ( NumberFormatException e ) { + duration = -1; + } + + AdminSession aSession = this.getSession( AdminSession.class , request ); + MaintenanceChangeResponse response = aSession.enableMaintenance( reason , duration ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getNewReason( ) == null ) { + return this.redirect( "maintenance" ); + } + + return this.render( model , "internal" , "en" , "maintenance" , response ); + } + + + @RequestMapping( value = "/maintenance-extend.action" , method = RequestMethod.POST ) + public String extendMaintenance( HttpServletRequest request , Model model , + @RequestParam( "duration" ) String sDuration ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int duration; + try { + duration = Integer.parseInt( sDuration ); + } catch ( NumberFormatException e ) { + duration = -1; + } + + this.getSession( AdminSession.class , request ).extendMaintenance( duration ); + return this.redirect( "maintenance" ); + } + + + @RequestMapping( value = "/maintenance-end.action" , method = RequestMethod.POST ) + public String endMaintenance( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.getSession( AdminSession.class , request ).endMaintenance( ); + return this.redirect( "maintenance" ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MessageBoxView.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MessageBoxView.java new file mode 100644 index 0000000..42c879e --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MessageBoxView.java @@ -0,0 +1,73 @@ +package com.deepclone.lw.web.admin; + + +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Administrator; +import com.deepclone.lw.cmd.msgdata.MessageListEntry; + + + +public class MessageBoxView + extends AdminResponse +{ + + private static final long serialVersionUID = 1L; + + private final boolean inbox; + private int pages; + private int cPage; + private final List< MessageListEntry > messages = new LinkedList< MessageListEntry >( ); + + + public MessageBoxView( Administrator admin , boolean inbox ) + { + super( admin ); + this.inbox = inbox; + } + + + public int getPages( ) + { + return pages; + } + + + public void setPages( int pages ) + { + this.pages = pages; + } + + + public int getcPage( ) + { + return cPage; + } + + + public void setcPage( int cPage ) + { + this.cPage = cPage; + } + + + public boolean isInbox( ) + { + return inbox; + } + + + public List< MessageListEntry > getMessages( ) + { + return messages; + } + + + public void addMessage( MessageListEntry entry ) + { + this.messages.add( entry ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MessagesPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MessagesPages.java new file mode 100644 index 0000000..5b61879 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/MessagesPages.java @@ -0,0 +1,453 @@ +package com.deepclone.lw.web.admin; + + +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.msg.*; +import com.deepclone.lw.cmd.msgdata.*; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.msgs.MessageFormatter; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class MessagesPages + extends PageControllerBase +{ + + private final static int perPage = 30; + + private MessageFormatter formatter; + + + @Autowired( required = true ) + public void setFormatter( MessageFormatter formatter ) + { + this.formatter = formatter; + } + + + @RequestMapping( "/messages" ) + public String viewInbox( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + MessageBoxView view = this.viewMessageBox( true , this.getSession( AdminSession.class , request ) , 0 ); + return this.render( model , "internal" , "en" , "messageBox" , view ); + } + + + @RequestMapping( "/inbox-{page}" ) + public String viewInbox( HttpServletRequest request , Model model , @PathVariable( "page" ) String sPage ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int page; + try { + page = Integer.parseInt( sPage ); + } catch ( NumberFormatException e ) { + page = 0; + } + + MessageBoxView view = this.viewMessageBox( true , this.getSession( AdminSession.class , request ) , page ); + return this.render( model , "internal" , "en" , "messageBox" , view ); + } + + + @RequestMapping( "/inbox-from-{id}" ) + public String viewInboxFrom( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + id = 0; + } + + MessageBoxView view = this.viewMessageBoxFrom( true , this.getSession( AdminSession.class , request ) , id ); + return this.render( model , "internal" , "en" , "messageBox" , view ); + } + + + @RequestMapping( "/outbox" ) + public String viewOutbox( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + MessageBoxView view = this.viewMessageBox( false , this.getSession( AdminSession.class , request ) , 0 ); + return this.render( model , "internal" , "en" , "messageBox" , view ); + } + + + @RequestMapping( "/outbox-{page}" ) + public String viewOutbox( HttpServletRequest request , Model model , @PathVariable( "page" ) String sPage ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int page; + try { + page = Integer.parseInt( sPage ); + } catch ( NumberFormatException e ) { + page = 0; + } + + MessageBoxView view = this.viewMessageBox( false , this.getSession( AdminSession.class , request ) , page ); + return this.render( model , "internal" , "en" , "messageBox" , view ); + } + + + @RequestMapping( "/outbox-from-{id}" ) + public String viewOutboxFrom( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + id = 0; + } + + MessageBoxView view = this.viewMessageBoxFrom( false , this.getSession( AdminSession.class , request ) , id ); + return this.render( model , "internal" , "en" , "messageBox" , view ); + } + + + private MessageBoxView viewMessageBox( boolean inbox , AdminSession aSession , int page ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + GetMessagesResponse mResponse = aSession.getMessages( inbox ); + MessageBoxView view = new MessageBoxView( mResponse.getAdmin( ) , inbox ); + List< MessageListEntry > messages = mResponse.getMessages( ); + + // Handle paging + messages = this.setPage( view , messages , page ); + this.prepareMessages( view , messages ); + + return view; + } + + + private MessageBoxView viewMessageBoxFrom( boolean inbox , AdminSession pSession , long fromId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + GetMessagesResponse mResponse = pSession.getMessages( inbox ); + MessageBoxView view = new MessageBoxView( mResponse.getAdmin( ) , inbox ); + List< MessageListEntry > messages = mResponse.getMessages( ); + int page = 0; + int nSeen = -1; + for ( MessageListEntry e : messages ) { + nSeen++; + if ( e.getId( ) != fromId ) { + continue; + } + page = ( nSeen - nSeen % MessagesPages.perPage ) / MessagesPages.perPage; + break; + } + + // Handle paging + messages = this.setPage( view , messages , page ); + this.prepareMessages( view , messages ); + + return view; + } + + + private void prepareMessages( MessageBoxView view , List< MessageListEntry > messages ) + { + for ( MessageListEntry message : messages ) { + message.setTitle( this.formatter.cleanMessage( message.getTitle( ) ) ); + view.addMessage( message ); + } + } + + + private List< MessageListEntry > setPage( MessageBoxView view , List< MessageListEntry > messages , int page ) + { + int nMessages = messages.size( ); + int mod = nMessages % MessagesPages.perPage; + int nPages = ( nMessages - mod ) / MessagesPages.perPage + ( mod > 0 ? 1 : 0 ); + if ( page < 0 ) { + page = 0; + } else if ( page >= nPages ) { + page = nPages - 1; + } + if ( !messages.isEmpty( ) ) { + messages = messages.subList( page * MessagesPages.perPage , Math.min( ( page + 1 ) * MessagesPages.perPage , + nMessages ) ); + } + + view.setPages( nPages ); + view.setcPage( page ); + return messages; + } + + + @RequestMapping( "/inbox-message-{id}" ) + public String viewInboxMessage( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.viewMessage( request , model , sId , true ); + } + + + @RequestMapping( "/outbox-message-{id}" ) + public String viewOutboxMessage( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.viewMessage( request , model , sId , false ); + } + + + private String viewMessage( HttpServletRequest request , Model model , String sId , boolean inbox ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long id; + try { + id = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + AdminSession aSession = this.getSession( AdminSession.class , request ); + ReadMessageResponse response = aSession.readMessage( inbox , id ); + Message message = response.getMessage( ); + if ( message == null ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + boolean internal = ( message.getType( ) == MessageType.INTERNAL ); + message.setTitle( this.formatter.cleanMessage( message.getTitle( ) ) ); + message.setContents( this.formatter.formatMessage( message.getContents( ) , internal ) ); + + return this.render( model , "internal" , "en" , "message" , response ); + } + + + @RequestMapping( value = "/messages.action" , method = RequestMethod.POST ) + public String mbAction( HttpServletRequest request , Model model , @RequestParam( "inbox" ) String sInbox , + @RequestParam( "page" ) String sPage , @RequestParam( "target" ) String sTarget , + @RequestParam( "action" ) String action , + @RequestParam( value = "selection" , required = false ) String[] sSelection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + boolean inbox = "1".equals( sInbox ); + if ( !inbox ) { + action = "d"; + } + + boolean useSelected = "0".equals( sTarget ); + long selection[]; + if ( useSelected ) { + List< Long > rSel = new LinkedList< Long >( ); + if ( sSelection != null ) { + for ( String sItem : sSelection ) { + Long value; + try { + value = Long.parseLong( sItem ); + } catch ( NumberFormatException e ) { + continue; + } + rSel.add( value ); + } + + selection = new long[ rSel.size( ) ]; + int i = 0; + for ( Long value : rSel ) { + selection[ i++ ] = value; + } + } else { + selection = new long[ 0 ]; + } + } else { + selection = null; + } + + AdminSession aSession = this.getSession( AdminSession.class , request ); + if ( selection == null || selection.length > 0 ) { + if ( "d".equals( action ) ) { + aSession.deleteMessages( inbox , selection ); + } else if ( "r".equals( action ) ) { + aSession.markRead( selection ); + } else if ( "u".equals( action ) ) { + aSession.markUnread( selection ); + } + } + + int page; + try { + page = Integer.parseInt( sPage ); + } catch ( NumberFormatException e ) { + page = 0; + } + return this.redirect( ( inbox ? "inbox" : "outbox" ) + "-" + page ); + } + + + @RequestMapping( value = "/message.action" , method = RequestMethod.POST ) + public String msgAction( HttpServletRequest request , Model model , @RequestParam( "inbox" ) String sInbox , + @RequestParam( "id" ) String sId , @RequestParam( "next" ) String sNext , + @RequestParam( value = "delete" , required = false ) String delete , + @RequestParam( value = "reply" , required = false ) String reply ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + boolean inbox = "1".equals( sInbox ); + + long id; + try { + id = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + AdminSession aSession = this.getSession( AdminSession.class , request ); + if ( delete != null ) { + aSession.deleteMessages( inbox , new long[] { + id + } ); + + try { + id = Long.parseLong( sNext ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + return this.redirect( ( inbox ? "inbox" : "outbox" ) + "-message-" + id ); + } else if ( reply != null ) { + ComposeMessageResponse response; + response = aSession.replyTo( inbox , id ); + return this.showWriter( model , response ); + } + return this.redirect( inbox ? "messages" : "outbox" ); + } + + + @RequestMapping( "/compose-message" ) + public String composeNew( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminSession aSession = this.getSession( AdminSession.class , request ); + return this.render( model , "internal" , "en" , "messageWriter" , aSession.initNewMessage( ) ); + } + + + @RequestMapping( "/msg-empire-{id}" ) + public String messageEmpire( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.newMessageTo( request , model , MessageType.EMPIRE , sId ); + } + + + @RequestMapping( "/msg-admin-{id}" ) + public String messageAdmin( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.newMessageTo( request , model , MessageType.ADMINISTRATOR , sId ); + } + + + @RequestMapping( value = "/send-message.action" , method = RequestMethod.POST ) + public String sendMessage( HttpServletRequest request , Model model , @RequestParam( "toType" ) String sToType , + @RequestParam( "toName" ) String toName , @RequestParam( "title" ) String title , + @RequestParam( "contents" ) String contents , + @RequestParam( value = "rtInbox" , required = false ) String sRtInbox , + @RequestParam( value = "rtId" , required = false ) String sRtId , + @RequestParam( value = "cancel" , required = false ) String sCancel ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + // Handle cancellation + if ( sCancel != null ) { + return this.cancelSendRedirect( sRtInbox , sRtId ); + } + + // Get message type + MessageType type; + try { + type = MessageType.valueOf( sToType ); + } catch ( IllegalArgumentException e ) { + type = MessageType.INTERNAL; + } + if ( type == MessageType.INTERNAL ) { + type = MessageType.EMPIRE; + } + + AdminSession aSession = this.getSession( AdminSession.class , request ); + ComposeMessageResponse response; + if ( sRtInbox == null || sRtId == null ) { + response = aSession.sendMessage( type , toName , title , contents ); + } else { + boolean inbox = "1".equals( sRtInbox ); + long rtId; + try { + rtId = Long.parseLong( sRtId ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + response = aSession.sendReply( inbox , rtId , type , toName , title , contents ); + } + + if ( !response.isError( ) ) { + return this.cancelSendRedirect( sRtInbox , sRtId ); + } + return this.showWriter( model , response ); + } + + + private String newMessageTo( HttpServletRequest request , Model model , MessageType type , String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "compose-message" ); + } + + ComposeMessageResponse response; + response = this.getSession( AdminSession.class , request ).messageTo( type , id ); + return this.showWriter( model , response ); + } + + + private String showWriter( Model model , ComposeMessageResponse response ) + { + if ( response.getReplyTo( ) != null ) { + Message message = response.getReplyTo( ); + message.setTitle( this.formatter.cleanMessage( message.getTitle( ) ) ); + message.setContents( this.formatter.formatMessage( message.getContents( ) , false ) ); + } + return this.render( model , "internal" , "en" , "messageWriter" , response ); + } + + + private String cancelSendRedirect( String sRtInbox , String sRtId ) + { + if ( sRtInbox == null || sRtId == null ) { + return this.redirect( "messages" ); + } + + boolean inbox = "1".equals( sRtInbox ); + long rtId; + try { + rtId = Long.parseLong( sRtId ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + return this.redirect( ( inbox ? "inbox" : "outbox" ) + "-message-" + rtId ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/NamesPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/NamesPages.java new file mode 100644 index 0000000..0d1ad44 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/NamesPages.java @@ -0,0 +1,107 @@ +package com.deepclone.lw.web.admin; + + +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.naming.*; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class NamesPages + extends PageControllerBase +{ + + @RequestMapping( "/names" ) + public String listNameTypes( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + NamesSummaryResponse response = this.getSession( AdminSession.class , request ).getNameSummary( ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "namesSummary" , response ); + } + + + @RequestMapping( "/names-{type}" ) + public String listNames( HttpServletRequest request , Model model , @PathVariable( "type" ) String sType ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + NameType type; + try { + type = NameType.valueOf( sType.toUpperCase( ).replace( "-" , "_" ) ); + } catch ( IllegalArgumentException e ) { + return this.redirect( "names" ); + } + + GetNamesResponse response = this.getSession( AdminSession.class , request ).getNames( type ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "names" , response ); + } + + + @RequestMapping( value = "/names-{type}.action" , method = RequestMethod.POST ) + public String namesAction( HttpServletRequest request , Model model , @PathVariable( "type" ) String sType , + @RequestParam( "action" ) String sAction , @RequestParam( value = "ids" , required = false ) String[] sIds ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + // Parse type + NameType type; + try { + type = NameType.valueOf( sType.toUpperCase( ).replace( "-" , "_" ) ); + } catch ( IllegalArgumentException e ) { + return this.redirect( "names" ); + } + + // Parse action + NameAction action; + try { + action = NameAction.valueOf( sAction ); + } catch ( IllegalArgumentException e ) { + return this.redirect( "names-" + type.toString( ).toLowerCase( ).replace( "_" , "-" ) ); + } + + // Parse identifiers + List< Integer > lIds = new LinkedList< Integer >( ); + if ( sIds != null ) { + for ( String s : sIds ) { + try { + lIds.add( Integer.parseInt( s ) ); + } catch ( NumberFormatException e ) { + // EMPTY + } + } + } + if ( lIds.isEmpty( ) ) { + return this.redirect( "names-" + type.toString( ).toLowerCase( ).replace( "_" , "-" ) ); + } + int[] ids = new int[ lIds.size( ) ]; + int i = 0; + for ( Integer v : lIds ) { + ids[ i++ ] = v.intValue( ); + } + + this.getSession( AdminSession.class , request ).namesAction( type , action , ids ); + return this.redirect( "names-" + type.toString( ).toLowerCase( ).replace( "_" , "-" ) ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/PasswordPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/PasswordPages.java new file mode 100644 index 0000000..1d2726e --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/PasswordPages.java @@ -0,0 +1,51 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.SetPasswordResponse; +import com.deepclone.lw.cmd.admin.SetPasswordResponse.PasswordChangeStatus; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "login" ) +public class PasswordPages + extends PageControllerBase +{ + + @RequestMapping( "/change-password" ) + public String changePassword( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminSession aSession = this.getSession( AdminSession.class , request ); + return this.render( model , "internal" , "en" , "changePassword" , aSession.noOp( ) ); + } + + + @RequestMapping( value = "/change-password.action" , method = RequestMethod.POST ) + public String changePassword( HttpServletRequest request , Model model , @RequestParam( "current" ) String current , + @RequestParam( "password" ) String pass1 , @RequestParam( "passwordConfirm" ) String pass2 ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminSession aSession = this.getSession( AdminSession.class , request ); + SetPasswordResponse response = aSession.changePassword( current , pass1 , pass2 ); + if ( !response.isAuthError( ) && response.getPasswordError( ) == PasswordChangeStatus.OK ) { + return this.redirect( "admin-session" ); + } + + return this.render( model , "internal" , "en" , "changePassword" , response ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/PreferencesPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/PreferencesPages.java new file mode 100644 index 0000000..b4fd39c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/PreferencesPages.java @@ -0,0 +1,48 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.prefs.PrefDefaultsResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class PreferencesPages + extends PageControllerBase +{ + + @RequestMapping( "/prefs" ) + public String listPrefDefaults( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PrefDefaultsResponse response = this.getSession( AdminSession.class , request ).getPrefDefaults( ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "preferences" , response ); + } + + + @RequestMapping( value = "/prefs.action" , method = RequestMethod.POST ) + public String setPrefDefault( HttpServletRequest request , Model model , @RequestParam( "pref" ) String pref , + @RequestParam( "value" ) String value ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.getSession( AdminSession.class , request ).setPrefDefault( pref , value ); + return this.redirect( "prefs" ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SessionPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SessionPages.java new file mode 100644 index 0000000..1537b9c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SessionPages.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.ClientSessionReference; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "login" ) +public class SessionPages + extends PageControllerBase +{ + @RequestMapping( "/admin-session" ) + public String login( HttpServletRequest request , Model model ) + { + ClientSessionReference cReference = (ClientSessionReference) request.getSession( ).getAttribute( "sReference" ); + String type = cReference.getReference( ).extra; + if ( "pass".equals( type ) ) { + return this.redirect( "change-password" ); + } + + return this.redirect( "main" ); + } + + + @RequestMapping( "/main" ) + public String main( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminSession session = this.getSession( AdminSession.class , request ); + return this.render( model , "internal" , "en" , "main" , session.getOverview( ) ); + } + + + @RequestMapping( value = "/logout.action" ) + public String validation( HttpServletRequest request , Model model ) + throws SessionServerException , SessionException + { + this.getSession( AdminSession.class , request ).terminate( ); + return this.redirect( "login" ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SpamPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SpamPages.java new file mode 100644 index 0000000..e9a41c1 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SpamPages.java @@ -0,0 +1,89 @@ +package com.deepclone.lw.web.admin; + + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.msgs.MessageFormatter; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "admin-session" , subType = "main" ) +public class SpamPages + extends PageControllerBase +{ + + private MessageFormatter formatter; + + + @Autowired( required = true ) + public void setFormatter( MessageFormatter formatter ) + { + this.formatter = formatter; + } + + + @RequestMapping( "/send-spam" ) + public String sendSpam( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminResponse response = this.getSession( AdminSession.class , request ).noOp( Privileges.SPAM ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + + return this.render( model , "internal" , "en" , "spam" , response ); + } + + + @RequestMapping( value = "/send-spam.action" , method = RequestMethod.POST ) + public String sendSpam( HttpServletRequest request , Model model , @RequestParam( "title" ) String title , + @RequestParam( "body" ) String body , @RequestParam( value = "preview" , required = false ) String preview ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + boolean tError , bError; + title = title.trim( ); + body = body.trim( ); + tError = ( title.length( ) < 5 || title.length( ) > 64 ); + bError = ( body.length( ) < 10 ); + + AdminResponse response; + if ( ( tError || bError || preview != null ) ) { + response = this.getSession( AdminSession.class , request ).noOp( Privileges.SPAM ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + } else { + this.getSession( AdminSession.class , request ).sendSpam( title , body ); + return this.redirect( "send-spam" ); + } + + Map< String , Object > data = new HashMap< String , Object >( ); + data.put( "admin" , response.getAdmin( ) ); + data.put( "title" , title ); + data.put( "body" , body ); + data.put( "preview" , this.formatter.formatMessage( body , false ) ); + data.put( "titleError" , (Boolean) tError ); + data.put( "bodyError" , (Boolean) bError ); + + return this.render( model , "internal" , "en" , "spam" , data ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SuperUserPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SuperUserPages.java new file mode 100644 index 0000000..479dadb --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/SuperUserPages.java @@ -0,0 +1,186 @@ +package com.deepclone.lw.web.admin; + + +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.AdminResponse; +import com.deepclone.lw.cmd.admin.adata.Privileges; +import com.deepclone.lw.cmd.admin.su.AddAdministratorResponse; +import com.deepclone.lw.cmd.admin.su.ListAdministratorsResponse; +import com.deepclone.lw.cmd.admin.su.ViewAdministratorResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class SuperUserPages + extends PageControllerBase +{ + + @RequestMapping( "/admins" ) + public String listAdministrators( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ListAdministratorsResponse response = this.getSession( AdminSession.class , request ).listAdmins( ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "admins" , response ); + } + + + @RequestMapping( "/add-admin" ) + public String addAdministrator( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminResponse response = this.getSession( AdminSession.class , request ).noOp( Privileges.SUPER ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "addAdmin" , response ); + } + + + @RequestMapping( value = "/add-admin.action" , method = RequestMethod.POST ) + public String addAdministrator( HttpServletRequest request , Model model , + @RequestParam( "address" ) String address , @RequestParam( "name" ) String name , + @RequestParam( value = "privileges" , required = false ) String[] sPrivs ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + List< Privileges > privs = this.getPrivileges( sPrivs ); + AddAdministratorResponse response; + response = this.getSession( AdminSession.class , request ).addAdmin( address , name , privs ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( !response.isError( ) ) { + return this.redirect( "admins" ); + } + + return this.render( model , "internal" , "en" , "addAdmin" , response ); + } + + + @RequestMapping( "/admin-{id}" ) + public String viewAdministrator( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "admins" ); + } + + ViewAdministratorResponse response = this.getSession( AdminSession.class , request ).viewAdministrator( id ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getView( ) == null ) { + return this.redirect( "admins" ); + } + return this.render( model , "internal" , "en" , "viewAdmin" , response ); + } + + + @RequestMapping( "/reset-admin-{id}.action" ) + public String resetAdministrator( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "admins" ); + } + + ViewAdministratorResponse response = this.getSession( AdminSession.class , request ).viewAdministrator( id ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getView( ) == null || response.getView( ).getPrivileges( ).isEmpty( ) ) { + return this.redirect( "admins" ); + } + return this.render( model , "internal" , "en" , "resetAdmin" , response ); + } + + + @RequestMapping( value = "/do-reset-admin-{id}.action" , method = RequestMethod.POST ) + public String confirmResetAdministrator( HttpServletRequest request , Model model , + @PathVariable( "id" ) String sId , @RequestParam( value = "cancel" , required = false ) String sCancel ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "admins" ); + } + + if ( sCancel != null ) { + return this.redirect( "admin-" + id ); + } + + ViewAdministratorResponse response = this.getSession( AdminSession.class , request ).resetAdministrator( id ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getView( ) == null ) { + return this.redirect( "admins" ); + } + return this.redirect( "admin-" + id ); + } + + + @RequestMapping( value = "/admin-privileges-{id}.action" , method = RequestMethod.POST ) + public String setPrivileges( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId , + @RequestParam( value = "privileges" , required = false ) String[] sPrivs ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "admins" ); + } + + List< Privileges > privs = this.getPrivileges( sPrivs ); + ViewAdministratorResponse response; + response = this.getSession( AdminSession.class , request ).setAdminPrivileges( id , privs ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getView( ) == null ) { + return this.redirect( "admins" ); + } + return this.redirect( "admin-" + id ); + } + + + private List< Privileges > getPrivileges( String[] sPrivs ) + { + List< Privileges > privs = new LinkedList< Privileges >( ); + if ( sPrivs != null ) { + for ( String sPriv : sPrivs ) { + try { + privs.add( Privileges.valueOf( sPriv ) ); + } catch ( IllegalArgumentException e ) { + // EMPTY + } + } + } + return privs; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/TickerPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/TickerPages.java new file mode 100644 index 0000000..09dbb13 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/TickerPages.java @@ -0,0 +1,101 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.tick.TickerStatusResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class TickerPages + extends PageControllerBase +{ + + @RequestMapping( "/ticker" ) + public String viewStatus( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + TickerStatusResponse response = this.getSession( AdminSession.class , request ).getTickerStatus( ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "ticker" , response ); + } + + + @RequestMapping( "/toggle-ticker.action" ) + public String toggleTicker( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.getSession( AdminSession.class , request ).toggleTicker( ); + return this.redirect( "ticker" ); + } + + + @RequestMapping( "/start-ticker-task-{id}.action" ) + public String startTask( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.setTickerTaskStatus( request , sId , true ); + } + + + @RequestMapping( "/stop-ticker-task-{id}.action" ) + public String stopTask( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.setTickerTaskStatus( request , sId , false ); + } + + + private String setTickerTaskStatus( HttpServletRequest request , String sId , boolean run ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "ticker" ); + } + this.getSession( AdminSession.class , request ).setTickerTaskStatus( id , run ); + return this.redirect( "ticker" ); + } + + + @RequestMapping( value = "/set-ticker-task-{id}.action" , method = RequestMethod.POST ) + public String setTaskDelay( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId , + @RequestParam( "delay" ) String sDelay , @RequestParam( "multiplier" ) String sMultiplier ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + long delay , multiplier; + try { + id = Integer.parseInt( sId ); + delay = Long.parseLong( sDelay ); + multiplier = Long.parseLong( sMultiplier ); + } catch ( NumberFormatException e ) { + return this.redirect( "ticker" ); + } + delay *= multiplier; + if ( delay <= 0 ) { + return this.redirect( "ticker" ); + } + this.getSession( AdminSession.class , request ).setTickerTaskStatus( id , delay ); + return this.redirect( "ticker" ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/UsersPages.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/UsersPages.java new file mode 100644 index 0000000..def95b1 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/UsersPages.java @@ -0,0 +1,144 @@ +package com.deepclone.lw.web.admin; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import com.deepclone.lw.cmd.admin.users.AccountStatus; +import com.deepclone.lw.cmd.admin.users.ListAccountsResponse; +import com.deepclone.lw.cmd.admin.users.ListSessionsResponse; +import com.deepclone.lw.cmd.admin.users.ViewAccountResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.AdminSession; + + + +@Controller +@SessionRequirement( value = true , subType = "main" , redirectTo = "admin-session" ) +public class UsersPages + extends PageControllerBase +{ + + @RequestMapping( "/users" ) + public String listUsers( HttpServletRequest request , Model model , + @RequestParam( value = "online" , required = false ) String sOnline ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AdminSession aSession = this.getSession( AdminSession.class , request ); + ListAccountsResponse list; + if ( "1".equals( sOnline ) ) { + list = aSession.listOnlineUsers( ); + } else { + list = aSession.listUsers( ); + } + if ( !list.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + + return this.render( model , "internal" , "en" , "users" , list ); + } + + + @RequestMapping( "/users-by-status" ) + public String listUsers( HttpServletRequest request , Model model , @RequestParam( "status" ) String sStatus , + @RequestParam( value = "online" , required = false ) String sOnline ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + AccountStatus status; + try { + status = AccountStatus.valueOf( sStatus ); + } catch ( IllegalArgumentException e ) { + return this.redirect( "users" + ( "1".equals( sOnline ) ? "?online=1" : "" ) ); + } + + AdminSession aSession = this.getSession( AdminSession.class , request ); + ListAccountsResponse list; + if ( "1".equals( sOnline ) ) { + list = aSession.listOnlineUsers( status ); + } else { + list = aSession.listUsers( status ); + } + if ( !list.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } + return this.render( model , "internal" , "en" , "users" , list ); + } + + + @RequestMapping( "/user-{id}" ) + public String viewUser( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "users" ); + } + + ViewAccountResponse response = this.getSession( AdminSession.class , request ).viewUser( id ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getAccount( ) == null ) { + return this.redirect( "users" ); + } + return this.render( model , "internal" , "en" , "user" , response ); + } + + + @RequestMapping( "/user-{id}-sessions" ) + public String viewUserSessions( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "users" ); + } + + ListSessionsResponse response = this.getSession( AdminSession.class , request ).viewUserSessions( id ); + if ( !response.isPrivilegeOk( ) ) { + return this.redirect( "main" ); + } else if ( response.getAccount( ) == null ) { + return this.redirect( "users" ); + } + return this.render( model , "internal" , "en" , "userSessions" , response ); + } + + + @RequestMapping( value = "/user-{id}.action" , method = RequestMethod.POST ) + public String grantCredits( HttpServletRequest request , Model model , @PathVariable( "id" ) String sId , + @RequestParam( "credits" ) String sCredits ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "users" ); + } + + int credits; + try { + credits = Integer.parseInt( sCredits ); + } catch ( NumberFormatException e ) { + credits = 0; + } + if ( credits > 0 ) { + this.getSession( AdminSession.class , request ).giveCredits( id , credits ); + } + return this.redirect( "user-" + id ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/i18ne/LanguageExport.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/i18ne/LanguageExport.java new file mode 100644 index 0000000..1e14932 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/i18ne/LanguageExport.java @@ -0,0 +1,28 @@ +package com.deepclone.lw.web.admin.i18ne; + + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; +import com.thoughtworks.xstream.annotations.XStreamImplicit; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "language" ) +public class LanguageExport + implements Serializable +{ + @XStreamAsAttribute + public String id; + + @XStreamAsAttribute + public String name; + + @XStreamImplicit + public List< StringExport > strings = new LinkedList< StringExport >( ); + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/i18ne/StringExport.java b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/i18ne/StringExport.java new file mode 100644 index 0000000..76785c0 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/java/com/deepclone/lw/web/admin/i18ne/StringExport.java @@ -0,0 +1,21 @@ +package com.deepclone.lw.web.admin.i18ne; + + +import java.io.Serializable; + +import com.thoughtworks.xstream.annotations.XStreamAlias; +import com.thoughtworks.xstream.annotations.XStreamAsAttribute; + + + +@SuppressWarnings( "serial" ) +@XStreamAlias( "inline-string" ) +public class StringExport + implements Serializable +{ + @XStreamAsAttribute + public String id; + + public String value; + +} diff --git a/legacyworlds-web/legacyworlds-web-admin/src/main/resources/log4j.properties b/legacyworlds-web/legacyworlds-web-admin/src/main/resources/log4j.properties new file mode 100644 index 0000000..774c437 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-admin/src/main/resources/log4j.properties @@ -0,0 +1,5 @@ +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n +log4j.rootLogger=warn, stdout \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-beans/.classpath b/legacyworlds-web/legacyworlds-web-beans/.classpath new file mode 100644 index 0000000..7c3d14f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/.classpath @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-beans/.project b/legacyworlds-web/legacyworlds-web-beans/.project new file mode 100644 index 0000000..5702a99 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/.project @@ -0,0 +1,23 @@ + + + legacyworlds-web-beans + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + + diff --git a/legacyworlds-web/legacyworlds-web-beans/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-web/legacyworlds-web-beans/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..34724f2 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,6 @@ +#Fri Apr 16 07:54:29 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-web/legacyworlds-web-beans/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-web/legacyworlds-web-beans/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..b3bba2f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Fri Apr 16 07:54:27 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-web/legacyworlds-web-beans/pom.xml b/legacyworlds-web/legacyworlds-web-beans/pom.xml new file mode 100644 index 0000000..5560487 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/pom.xml @@ -0,0 +1,70 @@ + + 4.0.0 + + legacyworlds-web + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-web-beans + 5.99.1 + Legacy Worlds common web beans + Module for common web-related beans. + jar + + + + com.deepclone.lw + legacyworlds-session + ${project.version} + + + com.deepclone.lw + legacyworlds-utils + ${project.version} + + + + org.springframework + spring-core + ${org.springframework.version} + + + org.springframework + spring-context + ${org.springframework.version} + + + org.springframework + spring-webmvc + ${org.springframework.version} + + + + log4j + log4j + ${log4j.version} + + + + commons-dbcp + commons-dbcp + ${commons.dbcp.version} + + + + cglib + cglib + ${cglib.version} + + + + javax.servlet + servlet-api + 2.5 + provided + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/IEContentTypeBean.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/IEContentTypeBean.java new file mode 100644 index 0000000..69da9f9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/IEContentTypeBean.java @@ -0,0 +1,26 @@ +package com.deepclone.lw.web.beans.intercept; + + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + + + +public class IEContentTypeBean + extends HandlerInterceptorAdapter +{ + + @Override + public void postHandle( HttpServletRequest request , HttpServletResponse response , Object handler , + ModelAndView modelAndView ) + { + String userAgent = request.getHeader( "User-Agent" ); + if ( userAgent.contains( "MSIE" ) + && ( response.getContentType( ) == null || response.getContentType( ).startsWith( "application/xhtml+xml" ) ) ) { + response.setHeader( "Content-Type" , "text/html" ); + } + } +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/LanguageInterceptorBean.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/LanguageInterceptorBean.java new file mode 100644 index 0000000..f818348 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/LanguageInterceptorBean.java @@ -0,0 +1,159 @@ +package com.deepclone.lw.web.beans.intercept; + + +import java.io.IOException; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import com.deepclone.lw.cmd.MaintenanceResponse; +import com.deepclone.lw.cmd.ext.ListLanguagesResponse; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.session.ClientSessionReference; +import com.deepclone.lw.web.beans.session.SessionClient; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.csess.ExternalSession; + + + +public class LanguageInterceptorBean + extends HandlerInterceptorAdapter + +{ + + private final Logger logger = Logger.getLogger( SessionInterceptorBean.class ); + private SessionClient client; + + + @Autowired( required = true ) + public void setSessionClient( SessionClient client ) + { + this.client = client; + } + + + @Override + public boolean preHandle( HttpServletRequest request , HttpServletResponse response , Object handler ) + throws IOException + { + HttpSession session = request.getSession( ); + String language = (String) session.getAttribute( "language" ); + + if ( language != null ) { + return true; + } + + this.logger.debug( "no language configured, trying to look it up" ); + + ExternalSession eSession; + CommandResponse cResponse; + ClientSessionReference sReference = new ClientSessionReference( null ); + try { + InetAddress addr = InetAddress.getByName( request.getRemoteAddr( ) ); + eSession = this.client.getSession( sReference , ExternalSession.class , addr ); + cResponse = eSession.listLanguages( ); + } catch ( SessionException e ) { + this.logger.error( "session error while initialising session language" ); + throw new RuntimeException( e ); + } catch ( SessionServerException e ) { + this.logger.warn( "server offline while initialising session language, defaulting" ); + session.setAttribute( "language" , "en" ); + return true; + } catch ( SessionMaintenanceException e ) { + this.logger.warn( "server under maintenance while initialising session language, defaulting" ); + session.setAttribute( "language" , "en" ); + return true; + } + + if ( cResponse instanceof MaintenanceResponse ) { + this.logger.warn( "server under maintenance while initialising session language, defaulting" ); + session.setAttribute( "language" , "en" ); + return true; + } + + ListLanguagesResponse languages = (ListLanguagesResponse) cResponse; + String accept = request.getHeader( "Accept-Language" ); + if ( accept == null ) { + this.logger.info( "Accept-Language not found, defaulting" ); + session.setAttribute( "language" , "en" ); + return true; + } + + Set< String > supported = new HashSet< String >( ); + for ( ListLanguagesResponse.Language l : languages.getLanguages( ) ) { + supported.add( l.getId( ).toLowerCase( ) ); + this.logger.trace( "supported language code '" + l.getId( ) + "'" ); + } + + List< String > lAccept = this.makeLangList( accept.replaceAll( "\\s+" , "" ) ); + for ( String lId : lAccept ) { + this.logger.debug( "accepted language code '" + lId + "'" ); + if ( supported.contains( lId.toLowerCase( ) ) ) { + this.logger.info( "using language " + lId ); + session.setAttribute( "language" , lId ); + return true; + } + } + + this.logger.info( "no language found in Accept-Language, defaulting" ); + session.setAttribute( "language" , "en" ); + return true; + } + + + private List< String > makeLangList( String acceptString ) + { + List< Double > qValues = new ArrayList< Double >( ); + Map< Double , Set< String > > found = new HashMap< Double , Set< String > >( ); + + for ( String part : acceptString.split( "," ) ) { + + Double qValue; + String language; + if ( part.contains( ";q=" ) ) { + try { + String r[] = part.split( ";q=" ); + language = r[ 0 ]; + qValue = Double.parseDouble( r[ 1 ] ); + } catch ( NumberFormatException e ) { + continue; + } + } else { + qValue = 1.0; + language = part; + } + + Set< String > accepts = found.get( qValue ); + if ( accepts == null ) { + accepts = new HashSet< String >( ); + qValues.add( qValue ); + found.put( qValue , accepts ); + } + accepts.add( language ); + } + + Collections.sort( qValues ); + Collections.reverse( qValues ); + List< String > result = new LinkedList< String >( ); + for ( Double v : qValues ) { + result.addAll( found.get( v ) ); + } + return result; + } +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/SessionInterceptorBean.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/SessionInterceptorBean.java new file mode 100644 index 0000000..cdcf33e --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/SessionInterceptorBean.java @@ -0,0 +1,59 @@ +package com.deepclone.lw.web.beans.intercept; + + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.log4j.Logger; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import com.deepclone.lw.web.beans.session.ClientSessionReference; + + + +public class SessionInterceptorBean + extends HandlerInterceptorAdapter +{ + + private final Logger logger = Logger.getLogger( SessionInterceptorBean.class ); + + + @Override + public boolean preHandle( HttpServletRequest request , HttpServletResponse response , Object handler ) + throws IOException + { + HttpSession session = request.getSession( ); + ClientSessionReference sReference = (ClientSessionReference) session.getAttribute( "sReference" ); + if ( sReference == null ) { + sReference = new ClientSessionReference( null ); + session.setAttribute( "sReference" , sReference ); + } + + Class< ? > handlerType = handler.getClass( ); + SessionRequirement requirement = handlerType.getAnnotation( SessionRequirement.class ); + if ( requirement == null ) { + this.logger.debug( "no session requirement" ); + return true; + } + + if ( ( requirement.value( ) && sReference.isNull( ) ) || ( !requirement.value( ) && !sReference.isNull( ) ) ) { + this.logger.debug( "requirement fail, redirecting to /" + requirement.redirectTo( ) ); + response.sendRedirect( requirement.redirectTo( ) ); + return false; + } + if ( requirement.value( ) && requirement.subType( ).length == 1 ) { + String rType = requirement.subType( )[ 0 ]; + if ( !rType.equals( sReference.getReference( ).extra ) ) { + this.logger.debug( "sub-type requirement fail, redirecting to /" + requirement.redirectTo( ) ); + response.sendRedirect( requirement.redirectTo( ) ); + return false; + } + } + this.logger.debug( "session requirement satisfied" ); + + return true; + } +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/SessionRequirement.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/SessionRequirement.java new file mode 100644 index 0000000..371ee4b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/intercept/SessionRequirement.java @@ -0,0 +1,24 @@ +package com.deepclone.lw.web.beans.intercept; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + + +@Retention( RetentionPolicy.RUNTIME ) +@Target( ElementType.TYPE ) +public @interface SessionRequirement +{ + + public boolean value( ); + + + public String[] subType( ) default { }; + + + public String redirectTo( ); + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/msgs/MessageFormatter.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/msgs/MessageFormatter.java new file mode 100644 index 0000000..6dead0e --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/msgs/MessageFormatter.java @@ -0,0 +1,10 @@ +package com.deepclone.lw.web.beans.msgs; + + +public interface MessageFormatter +{ + public String cleanMessage( String message ); + + public String formatMessage( String message , boolean internal ); + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/msgs/MessageFormatterBean.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/msgs/MessageFormatterBean.java new file mode 100644 index 0000000..0184ae2 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/msgs/MessageFormatterBean.java @@ -0,0 +1,129 @@ +package com.deepclone.lw.web.beans.msgs; + + +import java.util.regex.Pattern; + + + +public class MessageFormatterBean + implements MessageFormatter +{ + private final Pattern planet = Pattern.compile( "\\{\\{planet:(\\d+) ([^\\}]+)\\}\\}" ); + private final Pattern empire = Pattern.compile( "\\{\\{empire:(\\d+) ([^\\}]+)\\}\\}" ); + private final Pattern battle = Pattern.compile( "\\{\\{battle:(\\d+) ([^\\}]+)\\}\\}" ); + private final Pattern bug = Pattern.compile( "\\{\\{bug:(\\d+)\\}\\}" ); + + + public String cleanMessage( String message ) + { + message = message.trim( ); + + StringBuilder repLine = new StringBuilder( ); + for ( Character c : message.toCharArray( ) ) { + int nVal = Character.codePointAt( new char[] { + c + } , 0 ); + if ( Character.isISOControl( nVal ) ) { + continue; + } + + switch ( c ) { + case '<': + repLine.append( "<" ); + continue; + case '>': + repLine.append( ">" ); + continue; + case '&': + repLine.append( "&" ); + continue; + case '\'': + repLine.append( "'" ); + continue; + case '"': + repLine.append( """ ); + continue; + } + if ( nVal < 128 ) { + repLine.append( c ); + } else { + repLine.append( "&#" ).append( nVal ).append( ";" ); + } + } + message = repLine.toString( ); + return message; + } + + + @Override + public String formatMessage( String message , boolean internal ) + { + StringBuilder result = new StringBuilder( ); + boolean inList = false; + boolean prevEmpty = true; + for ( String line : message.split( "\\n" ) ) { + line = this.cleanMessage( line ); + + if ( line.equals( "" ) ) { + if ( prevEmpty ) { + continue; + } + if ( inList ) { + result.append( "" ); + } else { + result.append( "

" ); + } + result.append( "

 

" ); + prevEmpty = true; + inList = false; + continue; + } + + if ( line.charAt( 0 ) == '*' ) { + if ( !inList ) { + if ( !prevEmpty ) { + result.append( "

" ); + } + result.append( "
    " ); + inList = true; + } + result.append( "
  • " ).append( line.substring( 1 ) ).append( "
  • " ); + } else { + if ( prevEmpty ) { + result.append( "

    " ); + } else if ( inList ) { + result.append( "

" ); + inList = false; + } else { + result.append( "
" ); + } + result.append( line ); + } + prevEmpty = false; + } + + if ( !prevEmpty ) { + if ( inList ) { + result.append( "" ); + } else { + result.append( "

" ); + } + } + + if ( !internal ) { + return result.toString( ); + } + return this.applyInternals( result.toString( ) ); + } + + + private String applyInternals( String message ) + { + message = planet.matcher( message ).replaceAll( "$2" ); + message = empire.matcher( message ).replaceAll( "$2" ); + message = battle.matcher( message ).replaceAll( "$2" ); + message = bug.matcher( message ).replaceAll( "#$1" ); + return message; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/ClientSessionReference.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/ClientSessionReference.java new file mode 100644 index 0000000..09ab219 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/ClientSessionReference.java @@ -0,0 +1,47 @@ +package com.deepclone.lw.web.beans.session; + + +import java.io.Serializable; + +import com.deepclone.lw.session.SessionReference; + + + +public class ClientSessionReference + implements Serializable +{ + + private static final long serialVersionUID = 1L; + private SessionReference reference; + + + public ClientSessionReference( SessionReference reference ) + { + this.setReference( reference ); + } + + + public void setReference( SessionReference reference ) + { + this.reference = reference; + } + + + public SessionReference getReference( ) + { + return this.reference; + } + + + public boolean isNull( ) + { + return this.reference == null; + } + + + public void clear( ) + { + this.reference = null; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/MaintenanceStatus.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/MaintenanceStatus.java new file mode 100644 index 0000000..cdf1a04 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/MaintenanceStatus.java @@ -0,0 +1,15 @@ +package com.deepclone.lw.web.beans.session; + + +import com.deepclone.lw.cmd.MaintenanceResponse; + + + +public interface MaintenanceStatus +{ + + public void storeStatus( MaintenanceResponse response ); + + public MaintenanceResponse getStatus( ); + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/MaintenanceStatusBean.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/MaintenanceStatusBean.java new file mode 100644 index 0000000..194dc9a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/MaintenanceStatusBean.java @@ -0,0 +1,32 @@ +package com.deepclone.lw.web.beans.session; + + +import org.apache.log4j.Logger; + +import com.deepclone.lw.cmd.MaintenanceResponse; + + + +public class MaintenanceStatusBean + implements MaintenanceStatus +{ + private final Logger logger = Logger.getLogger( MaintenanceStatusBean.class ); + private MaintenanceResponse maintenance = null; + + + @Override + synchronized public void storeStatus( MaintenanceResponse response ) + { + this.logger.debug( "Setting maintenance status response: " + response ); + this.maintenance = response; + } + + + @Override + synchronized public MaintenanceResponse getStatus( ) + { + this.logger.debug( "Reading latest maintenance status response: " + this.maintenance ); + return this.maintenance; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/Session.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/Session.java new file mode 100644 index 0000000..b826f25 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/Session.java @@ -0,0 +1,103 @@ +package com.deepclone.lw.web.beans.session; + + +import com.deepclone.lw.cmd.MaintenanceResponse; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionException; + + + +public abstract class Session +{ + + private static final long serialVersionUID = 1L; + private ClientSessionReference reference; + private SessionClient sClient; + + + void initialise( SessionClient client , ClientSessionReference ref ) + { + this.sClient = client; + this.reference = ref; + } + + + public final boolean isActive( ) + { + return !this.reference.isNull( ); + } + + + public boolean authenticate( String identifier , String secret ) + throws SessionException , SessionServerException + { + try { + this.sClient.authenticate( this.reference , identifier , secret ); + } catch ( SessionException e ) { + this.handleSessionException( e ); + } catch ( SessionServerException e ) { + this.reference.clear( ); + throw e; + } + + if ( this.reference.isNull( ) ) { + return false; + } + return this.reference.getReference( ).authenticated; + } + + + public void terminate( ) + throws SessionServerException , SessionException + { + try { + this.sClient.terminate( this.reference ); + } catch ( SessionServerException e ) { + throw e; + } catch ( SessionException e ) { + this.handleSessionException( e ); + } + } + + + public final String getSessionSubType( ) + { + try { + return this.reference.getReference( ).extra; + } catch ( NullPointerException e ) { + return null; + } + } + + + protected CommandResponse execute( Command command ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + CommandResponse response = null; + try { + response = this.sClient.execute( this.reference , command ); + } catch ( SessionServerException e ) { + this.reference.clear( ); + throw e; + } catch ( SessionException e ) { + this.handleSessionException( e ); + } + + if ( response instanceof MaintenanceResponse ) { + throw new SessionMaintenanceException( (MaintenanceResponse) response ); + } + return response; + } + + + protected void handleSessionException( SessionException e ) + throws SessionException + { + if ( !e.isSessionKept( ) ) { + this.reference.clear( ); + } + throw e; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionClient.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionClient.java new file mode 100644 index 0000000..ed1b446 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionClient.java @@ -0,0 +1,33 @@ +package com.deepclone.lw.web.beans.session; + + +import java.net.InetAddress; + +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionException; + + + +public interface SessionClient +{ + + public < T extends Session > T getSession( ClientSessionReference reference , Class< T > type , InetAddress ip ) + throws SessionException , SessionServerException; + + + public < T extends Session > T restoreSession( ClientSessionReference session , Class< T > type ); + + + public void authenticate( ClientSessionReference session , String identifier , String secret ) + throws SessionException , SessionServerException; + + + public CommandResponse execute( ClientSessionReference reference , Command command ) + throws SessionServerException , SessionException; + + + public void terminate( ClientSessionReference reference ) + throws SessionServerException , SessionException; + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionClientBean.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionClientBean.java new file mode 100644 index 0000000..8ad80d9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionClientBean.java @@ -0,0 +1,165 @@ +package com.deepclone.lw.web.beans.session; + + +import java.net.InetAddress; + +import org.apache.log4j.Logger; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.remoting.RemoteAccessException; + +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionAccessor; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.session.SessionReference; +import com.deepclone.lw.session.SessionResponse; +import com.deepclone.lw.utils.DigestHelper; + + + +public class SessionClientBean + implements SessionClient , ApplicationContextAware +{ + private Logger logger = Logger.getLogger( SessionClient.class ); + private String sessionService = "sessionSrv"; + private ApplicationContext appContext; + + + public void setSessionService( String name ) + { + this.sessionService = name; + } + + + @Override + public void setApplicationContext( ApplicationContext applicationContext ) + throws BeansException + { + this.appContext = applicationContext; + } + + + private SessionAccessor getSessionService( ) + throws SessionServerException + { + try { + return (SessionAccessor) this.appContext.getBean( this.sessionService ); + } catch ( BeanCreationException e ) { + this.logger.error( "Could not connect to session manager" , e.getCause( ) ); + throw new SessionServerException( e.getCause( ) ); + } + } + + + private < T extends Session > T makeSession( ClientSessionReference sRef , Class< T > type ) + { + T session; + try { + session = type.newInstance( ); + } catch ( Exception e ) { + this.logger.error( "Session creation failed" , e ); + throw new RuntimeException( e ); + } + session.initialise( this , sRef ); + return session; + } + + + @Override + public < T extends Session > T getSession( ClientSessionReference session , Class< T > type , InetAddress ip ) + throws SessionException , SessionServerException + { + if ( !type.isAnnotationPresent( SessionType.class ) ) { + throw new RuntimeException( "missing SessionType annotation on " + type ); + } + + SessionType t = type.getAnnotation( SessionType.class ); + SessionAccessor sAcc = this.getSessionService( ); + SessionReference sRef; + try { + sRef = sAcc.create( t.value( ) , "web" , ip ); + } catch ( RemoteAccessException e ) { + this.logger.error( "Could not create session" , e ); + throw new SessionServerException( e ); + } + + session.setReference( sRef ); + return this.makeSession( session , type ); + } + + + @Override + public < T extends Session > T restoreSession( ClientSessionReference session , Class< T > type ) + { + if ( session.isNull( ) ) { + return null; + } + + if ( !type.isAnnotationPresent( SessionType.class ) ) { + throw new RuntimeException( "missing SessionType annotation on " + type ); + } + + SessionType t = type.getAnnotation( SessionType.class ); + if ( !t.value( ).equals( session.getReference( ).type ) ) { + throw new RuntimeException( "session type mismatch" ); + } + + return this.makeSession( session , type ); + } + + + @Override + public void authenticate( ClientSessionReference session , String identifier , String secret ) + throws SessionException , SessionServerException + { + String challenge = session.getReference( ).extra; + String sha1 = DigestHelper.digest( "sha-1" , challenge + " " + DigestHelper.digest( "sha-1" , secret ) ); + String md5 = DigestHelper.digest( "md5" , challenge + " " + DigestHelper.digest( "md5" , secret ) ); + + SessionAccessor sAcc = this.getSessionService( ); + SessionReference ref; + try { + ref = sAcc.authenticate( session.getReference( ).identifier , identifier , sha1 , md5 ); + } catch ( RemoteAccessException e ) { + this.logger.error( "Could not authenticate session" , e ); + throw new SessionServerException( e ); + } + session.setReference( ref ); + } + + + @Override + public CommandResponse execute( ClientSessionReference reference , Command command ) + throws SessionServerException , SessionException + { + SessionAccessor sAcc = this.getSessionService( ); + SessionResponse sRep; + try { + sRep = sAcc.executeCommand( reference.getReference( ).identifier , command ); + } catch ( RemoteAccessException e ) { + this.logger.error( "Could not execute command" , e ); + throw new SessionServerException( e ); + } + reference.setReference( sRep.session ); + return sRep.data; + } + + + @Override + public void terminate( ClientSessionReference reference ) + throws SessionServerException , SessionException + { + try { + this.getSessionService( ).terminate( reference.getReference( ).identifier ); + } catch ( RemoteAccessException e ) { + this.logger.error( "Could not terminate session" , e ); + throw new SessionServerException( e ); + } finally { + reference.clear( ); + } + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionMaintenanceException.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionMaintenanceException.java new file mode 100644 index 0000000..4643128 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionMaintenanceException.java @@ -0,0 +1,27 @@ +package com.deepclone.lw.web.beans.session; + + +import com.deepclone.lw.cmd.MaintenanceResponse; + + + +public class SessionMaintenanceException + extends Exception +{ + + private static final long serialVersionUID = 1L; + private final MaintenanceResponse maintenance; + + + public SessionMaintenanceException( MaintenanceResponse data ) + { + this.maintenance = data; + } + + + public MaintenanceResponse getMaintenance( ) + { + return maintenance; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionServerException.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionServerException.java new file mode 100644 index 0000000..94c06d6 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionServerException.java @@ -0,0 +1,16 @@ +package com.deepclone.lw.web.beans.session; + + +public class SessionServerException + extends Exception +{ + + private static final long serialVersionUID = 1L; + + + public SessionServerException( Throwable cause ) + { + super( "could not reach session server" , cause ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionType.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionType.java new file mode 100644 index 0000000..23bc649 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/session/SessionType.java @@ -0,0 +1,18 @@ +package com.deepclone.lw.web.beans.session; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + + +@Retention( RetentionPolicy.RUNTIME ) +@Target( ElementType.TYPE ) +public @interface SessionType +{ + + public String value( ); + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/BugTrackerBase.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/BugTrackerBase.java new file mode 100644 index 0000000..0827c92 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/BugTrackerBase.java @@ -0,0 +1,99 @@ +package com.deepclone.lw.web.beans.view; + + +import java.io.Serializable; + +import com.deepclone.lw.cmd.bt.data.BugStatus; + + + +public abstract class BugTrackerBase + extends PageControllerBase +{ + + @SuppressWarnings( "serial" ) + public static class BugQuery + implements Serializable + { + public final BugStatus status; + public final boolean ownOnly; + public final long first; + + + BugQuery( BugStatus status , boolean ownOnly , long first ) + { + this.status = status; + this.ownOnly = ownOnly; + this.first = first; + } + + + public BugStatus getStatus( ) + { + return status; + } + + + public boolean isOwnOnly( ) + { + return ownOnly; + } + + + public long getFirst( ) + { + return first; + } + + } + + + protected final BugQuery getBugQuery( String sStatus , String sOwn , String sFirst ) + { + BugQuery query; + + // Get status + BugStatus status; + if ( sStatus == null ) { + status = null; + } else { + try { + status = BugStatus.valueOf( sStatus ); + } catch ( IllegalArgumentException e ) { + status = null; + } + } + + // Own reports only? + boolean ownOnly = ( sOwn != null && "1".equals( sOwn ) ); + + // First report displayed + long first; + if ( sFirst == null ) { + first = 0; + } else { + try { + first = Long.parseLong( sFirst ); + } catch ( NumberFormatException e ) { + first = 0; + } + } + + query = new BugQuery( status , ownOnly , first ); + return query; + } + + + protected String makeGetParams( BugQuery query ) + { + String rTo = "?status="; + if ( query.status == null ) { + rTo += "x"; + } else { + rTo += query.status.toString( ); + } + rTo += "&own=" + ( query.ownOnly ? "1" : "0" ) + "&first=" + query.first; + return rTo; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/Page.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/Page.java new file mode 100644 index 0000000..096b08c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/Page.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.web.beans.view; + + +import java.io.Serializable; + + + +public class Page + implements Serializable +{ + + private static final long serialVersionUID = 1L; + + private String type; + + private String language; + + private Serializable data; + + + public Page( String name , String language ) + { + this.type = name; + this.language = language; + } + + + public Page( String name , String language , Serializable data ) + { + this.type = name; + this.language = language; + this.data = data; + } + + + public String getDataType( ) + { + if ( this.data == null ) { + return "null"; + } + return this.data.getClass( ).getSimpleName( ); + } + + + public String getLanguage( ) + { + return this.language; + } + + + public Object getData( ) + { + return this.data; + } + + + public String getType( ) + { + return this.type; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/PageControllerBase.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/PageControllerBase.java new file mode 100644 index 0000000..c5fe5ef --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/beans/view/PageControllerBase.java @@ -0,0 +1,163 @@ +package com.deepclone.lw.web.beans.view; + + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.ui.Model; + +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.session.CommandResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.session.ClientSessionReference; +import com.deepclone.lw.web.beans.session.Session; +import com.deepclone.lw.web.beans.session.SessionClient; +import com.deepclone.lw.web.beans.session.SessionServerException; + + + +public abstract class PageControllerBase +{ + + protected SessionClient client; + + + @Autowired( required = true ) + public void setSessionClient( SessionClient client ) + { + this.client = client; + } + + + protected String render( Model model , String template , String language ) + { + return this.render( model , template , new Page( null , language ) ); + } + + + protected String render( Model model , String template , String language , String subPage ) + { + return this.render( model , template , new Page( subPage , language ) ); + } + + + protected String render( Model model , String template , String language , CommandResponse data ) + { + return this.render( model , template , new Page( null , language , data ) ); + } + + + protected String render( Model model , String template , String language , String subPage , CommandResponse data ) + { + return this.render( model , template , new Page( subPage , language , data ) ); + } + + + protected String renderMap( Model model , String template , String language , String subPage , Object... data ) + { + HashMap< String , Serializable > map = new HashMap< String , Serializable >( ); + for ( int i = 0 ; i < data.length / 2 ; i++ ) { + map.put( (String) data[ i * 2 ] , (Serializable) data[ i * 2 + 1 ] ); + } + return this.render( model , template , new Page( subPage , language , map ) ); + } + + + protected String renderStatic( Model model , String template , String language , String name ) + { + return this.render( model , template , new Page( "static" , language , name ) ); + } + + + protected String renderStatic( Model model , String template , String language , GameResponseBase gameData , + String name ) + { + return this.renderMap( model , template , language , "static" , "page" , gameData.getPage( ) , "name" , name ); + } + + + protected String render( Model model , String template , Page page ) + { + model.addAttribute( "container" , template ); + model.addAttribute( "language" , page.getLanguage( ) ); + model.addAttribute( "type" , page.getType( ) ); + model.addAttribute( "data" , page.getData( ) ); + model.addAttribute( "dataType" , page.getDataType( ) ); + return "ROOT"; + } + + + protected String render( Model model , String template , String language , String type , Map< String , Object > data ) + { + model.addAttribute( "container" , template ); + model.addAttribute( "language" , language ); + model.addAttribute( "type" , type ); + model.addAttribute( "data" , data ); + model.addAttribute( "dataType" , "map" ); + return "ROOT"; + } + + + protected String redirect( String to ) + { + return "redirect:" + to; + } + + + protected final InetAddress getAddress( HttpServletRequest request ) + { + InetAddress address; + try { + address = InetAddress.getByName( request.getRemoteAddr( ) ); + } catch ( UnknownHostException e ) { + throw new RuntimeException( e ); + } + return address; + } + + + protected final ClientSessionReference getSessionReference( HttpServletRequest request ) + { + return (ClientSessionReference) request.getSession( ).getAttribute( "sReference" ); + } + + + protected < T extends Session > T createTemporarySession( Class< T > type , HttpServletRequest request ) + throws SessionException , SessionServerException + { + return this.client.getSession( new ClientSessionReference( null ) , type , this.getAddress( request ) ); + } + + + protected < T extends Session > T initSession( Class< T > type , HttpServletRequest request ) + throws SessionException , SessionServerException + { + return this.client.getSession( this.getSessionReference( request ) , type , this.getAddress( request ) ); + } + + + protected < T extends Session > T getSession( Class< T > type , HttpServletRequest request ) + { + return this.client.restoreSession( this.getSessionReference( request ) , type ); + } + + + protected void clearSession( HttpServletRequest request ) + { + this.getSessionReference( request ).clear( ); + } + + + @SuppressWarnings( "unchecked" ) + protected Map< String , Object > getInput( HttpServletRequest request ) + { + return (Map< String , Object >) request.getParameterMap( ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/AdminSession.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/AdminSession.java new file mode 100644 index 0000000..2f89e3e --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/AdminSession.java @@ -0,0 +1,542 @@ +package com.deepclone.lw.web.csess; + + +import java.util.List; + +import com.deepclone.lw.cmd.CreateAuthChallengeCommand; +import com.deepclone.lw.cmd.CreateAuthChallengeResponse; +import com.deepclone.lw.cmd.admin.*; +import com.deepclone.lw.cmd.admin.adata.*; +import com.deepclone.lw.cmd.admin.bans.*; +import com.deepclone.lw.cmd.admin.bt.*; +import com.deepclone.lw.cmd.admin.constants.*; +import com.deepclone.lw.cmd.admin.i18n.*; +import com.deepclone.lw.cmd.admin.logs.*; +import com.deepclone.lw.cmd.admin.mntm.*; +import com.deepclone.lw.cmd.admin.msg.*; +import com.deepclone.lw.cmd.admin.naming.*; +import com.deepclone.lw.cmd.admin.prefs.*; +import com.deepclone.lw.cmd.admin.su.*; +import com.deepclone.lw.cmd.admin.tick.*; +import com.deepclone.lw.cmd.admin.users.*; +import com.deepclone.lw.cmd.bt.*; +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.utils.DigestHelper; +import com.deepclone.lw.web.beans.session.Session; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.session.SessionType; + + + +@SessionType( "admin" ) +public class AdminSession + extends Session +{ + + /* Common commands */ + + public AdminOverviewResponse getOverview( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AdminOverviewResponse) this.execute( new AdminOverviewCommand( ) ); + } + + + public AdminResponse noOp( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AdminResponse) this.execute( new NoOperationCommand( ) ); + } + + + public AdminResponse noOp( Privileges privilege ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AdminResponse) this.execute( new NoOperationCommand( privilege ) ); + } + + + public SetPasswordResponse changePassword( String current , String password , String passwordConfirm ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + String challenge = ( (CreateAuthChallengeResponse) this.execute( new CreateAuthChallengeCommand( ) ) ) + .getChallenge( ); + + String sha1 , md5; + sha1 = DigestHelper.digest( "sha-1" , challenge + " " + DigestHelper.digest( "sha-1" , current ) ); + md5 = DigestHelper.digest( "md5" , challenge + " " + DigestHelper.digest( "md5" , current ) ); + + return (SetPasswordResponse) this.execute( new SetPasswordCommand( sha1 , md5 , password , passwordConfirm ) ); + } + + + /* Constants administration */ + + public GetConstantsResponse getConstants( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetConstantsResponse) this.execute( new GetConstantsCommand( ) ); + } + + + public SetConstantResponse setConstant( String name , double value ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (SetConstantResponse) this.execute( new SetConstantCommand( name , value ) ); + } + + + /* Administrators administration */ + + public ListAdministratorsResponse listAdmins( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListAdministratorsResponse) this.execute( new ListAdministratorsCommand( ) ); + } + + + public AddAdministratorResponse addAdmin( String address , String name , List< Privileges > privs ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AddAdministratorResponse) this.execute( new AddAdministratorCommand( address , name , privs ) ); + } + + + public ViewAdministratorResponse viewAdministrator( int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewAdministratorResponse) this.execute( new ViewAdministratorCommand( id ) ); + } + + + public ViewAdministratorResponse resetAdministrator( int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewAdministratorResponse) this.execute( new ResetAdminPasswordCommand( id ) ); + } + + + public ViewAdministratorResponse setAdminPrivileges( int id , List< Privileges > privs ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewAdministratorResponse) this.execute( new SetPrivilegesCommand( id , privs ) ); + } + + + /* I18N administration */ + + public ViewLanguagesResponse listLanguages( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewLanguagesResponse) this.execute( new ViewLanguagesCommand( ) ); + } + + + public GetLanguageResponse getLanguage( String language ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetLanguageResponse) this.execute( new GetLanguageCommand( language ) ); + } + + + public ChangeLanguageResponse setLanguageName( String language , String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ChangeLanguageResponse) this.execute( new ChangeLanguageCommand( language , name ) ); + } + + + public SetStringResponse setTranslation( String language , String string , String value ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (SetStringResponse) this.execute( new SetStringCommand( language , string , value ) ); + } + + + /* Names */ + + public NamesSummaryResponse getNameSummary( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (NamesSummaryResponse) this.execute( new NamesSummaryCommand( ) ); + } + + + public GetNamesResponse getNames( NameType type ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetNamesResponse) this.execute( new GetNamesCommand( type ) ); + } + + + public void namesAction( NameType type , NameAction action , int[] ids ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new NamesActionCommand( type , action , ids ) ); + } + + + /* Banhammer */ + + public BansSummaryResponse getBansSummary( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (BansSummaryResponse) this.execute( new BansSummaryCommand( ) ); + } + + + public ListBansResponse getBans( BanType type ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListBansResponse) this.execute( new ListBansCommand( type ) ); + } + + + public RequestBanResponse requestBan( String user , boolean empire , String reason ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (RequestBanResponse) this.execute( new RequestBanCommand( user , empire , reason ) ); + } + + + public RejectBanResponse rejectBan( int id , String reason ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (RejectBanResponse) this.execute( new RejectBanCommand( id , reason ) ); + } + + + public void confirmBan( int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new ConfirmBanCommand( id ) ); + } + + + public void liftBan( int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new LiftBanCommand( id ) ); + } + + + /* Ticker */ + + public TickerStatusResponse getTickerStatus( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (TickerStatusResponse) this.execute( new TickerStatusCommand( ) ); + } + + + public void toggleTicker( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new ToggleTickerCommand( ) ); + } + + + public void setTickerTaskStatus( int task , boolean run ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new SetTaskStatusCommand( task , run ) ); + } + + + public void setTickerTaskStatus( int task , long delay ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new SetTaskStatusCommand( task , delay ) ); + } + + + /* Logs */ + + public ViewLogResponse viewLog( LogType logType , int first , int pageSize , LogLevel logLevel , String component , + boolean excOnly ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewLogResponse) this.execute( new ViewLogCommand( logType , first , pageSize , logLevel , component , + excOnly ) ); + } + + + public GetEntryResponse getLogEntry( long id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetEntryResponse) this.execute( new GetEntryCommand( id ) ); + } + + + /* Spam! */ + + public AdminResponse sendSpam( String title , String body ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AdminResponse) this.execute( new SendSpamCommand( title , body ) ); + } + + + /* Messages */ + + public GetMessagesResponse getMessages( boolean inbox ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetMessagesResponse) this.execute( new GetMessagesCommand( inbox ) ); + } + + + public ReadMessageResponse readMessage( boolean inbox , long id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ReadMessageResponse) this.execute( new ReadMessageCommand( inbox , id ) ); + } + + + public void deleteMessages( boolean inbox , long[] selection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new MessageBoxCommand( inbox , selection ) ); + } + + + public void markRead( long[] selection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new MessageBoxCommand( selection , true ) ); + } + + + public void markUnread( long[] selection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new MessageBoxCommand( selection , false ) ); + } + + + public ComposeMessageResponse initNewMessage( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ComposeMessageResponse) this.execute( PrepareMessageCommand.newMessage( ) ); + } + + + public ComposeMessageResponse replyTo( boolean inbox , long id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ComposeMessageResponse) this.execute( new PrepareMessageCommand( id , inbox ) ); + } + + + public ComposeMessageResponse messageTo( MessageType type , int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ComposeMessageResponse) this.execute( PrepareMessageCommand.newMessageTo( type , id ) ); + } + + + public ComposeMessageResponse sendMessage( MessageType type , String toName , String title , String contents ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ComposeMessageCommand command = new ComposeMessageCommand( ); + command.setType( type ); + command.setTarget( toName ); + command.setSubject( title ); + command.setContents( contents ); + return (ComposeMessageResponse) this.execute( command ); + } + + + public ComposeMessageResponse sendReply( boolean inbox , long rtId , MessageType type , String toName , + String title , String contents ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ComposeMessageCommand command = new ComposeMessageCommand( inbox , rtId ); + command.setType( type ); + command.setTarget( toName ); + command.setSubject( title ); + command.setContents( contents ); + return (ComposeMessageResponse) this.execute( command ); + } + + + /* Users */ + + public ListAccountsResponse listUsers( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListAccountsResponse) this.execute( new ListAccountsCommand( ) ); + } + + + public ListAccountsResponse listOnlineUsers( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListAccountsResponse) this.execute( new ListAccountsCommand( null , true ) ); + } + + + public ListAccountsResponse listUsers( AccountStatus status ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListAccountsResponse) this.execute( new ListAccountsCommand( status ) ); + } + + + public ListAccountsResponse listOnlineUsers( AccountStatus status ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListAccountsResponse) this.execute( new ListAccountsCommand( status , true ) ); + } + + + public ViewAccountResponse viewUser( int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewAccountResponse) this.execute( new ViewAccountCommand( id ) ); + } + + + public ListSessionsResponse viewUserSessions( int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListSessionsResponse) this.execute( new ListSessionsCommand( id ) ); + } + + + public void giveCredits( int id , int credits ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new GiveCreditsCommand( id , credits ) ); + } + + + /* Default preferences */ + + public PrefDefaultsResponse getPrefDefaults( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (PrefDefaultsResponse) this.execute( new GetPrefDefaultsCommand( ) ); + } + + + public void setPrefDefault( String pref , String value ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new SetPrefDefaultCommand( pref , value ) ); + } + + + /* Bug tracking system */ + + public BugsSummaryResponse getBugsSummary( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (BugsSummaryResponse) this.execute( new BugsSummaryCommand( ) ); + } + + + public ListBugsResponse listBugs( BugStatus status , boolean ownOnly , long first , int count ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListBugsResponse) this.execute( new ListBugsCommand( status , ownOnly , first , count ) ); + } + + + public ReportBugResponse reportBug( String title , String description , boolean publicReport ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ReportBugResponse) this.execute( new ReportBugCommand( title , description , publicReport ) ); + } + + + public ViewBugResponse getBugReport( long bugId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewBugResponse) this.execute( new ViewBugCommand( bugId ) ); + } + + + public PostCommentResponse postBugComment( long bugId , String comment , boolean publicComment ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (PostCommentResponse) this.execute( new PostCommentCommand( bugId , comment , publicComment ) ); + } + + + public void moderateBugComment( long commentId , boolean validate ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new ModerateCommentCommand( commentId , validate ) ); + } + + + public void validateReport( long bugId , BugStatus newStatus , boolean visible , int grantCredits , boolean snapshot ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new ValidateReportCommand( bugId , newStatus , visible , grantCredits , snapshot ) ); + + } + + + public void setReportStatus( long bugId , BugStatus newStatus ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new ReportStatusCommand( bugId , newStatus ) ); + } + + + public void toggleReportVisibility( long bugId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new ReportVisibilityCommand( bugId ) ); + } + + + public MergeReportsResponse mergeReports( long bugId , long mergeId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (MergeReportsResponse) this.execute( new MergeReportsCommand( bugId , mergeId ) ); + } + + + public GetSnapshotResponse getSnapshot( long bugId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetSnapshotResponse) this.execute( new GetSnapshotCommand( bugId ) ); + } + + + /* Maintenance mode */ + + public MaintenanceStatusResponse getMaintenanceStatus( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (MaintenanceStatusResponse) this.execute( new MaintenanceStatusCommand( ) ); + } + + + public MaintenanceChangeResponse enableMaintenance( String reason , int duration ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (MaintenanceChangeResponse) this.execute( new EnableMaintenanceCommand( reason , duration ) ); + } + + + public void extendMaintenance( int duration ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new ExtendMaintenanceCommand( duration ) ); + } + + + public void endMaintenance( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new EndMaintenanceCommand( ) ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/ExternalSession.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/ExternalSession.java new file mode 100644 index 0000000..f899790 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/ExternalSession.java @@ -0,0 +1,68 @@ +package com.deepclone.lw.web.csess; + + +import com.deepclone.lw.cmd.ext.*; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.session.Session; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.session.SessionType; + + + +@SessionType( "ext" ) +public class ExternalSession + extends Session +{ + + public ListLanguagesResponse listLanguages( ) + throws SessionServerException , SessionMaintenanceException + { + Command ll = new ListLanguagesCommand( ); + try { + return (ListLanguagesResponse) this.execute( ll ); + } catch ( SessionException se ) { + throw new RuntimeException( se ); + } + } + + + public CreateAccountResponse createAccount( String mail , String mailConfirm , String password , + String passwordConfirm , String language ) + throws SessionServerException , SessionMaintenanceException + { + Command command = new CreateAccountCommand( mail , mailConfirm , password , passwordConfirm , language ); + try { + return (CreateAccountResponse) this.execute( command ); + } catch ( SessionException se ) { + throw new RuntimeException( se ); + } + } + + + public RequestPasswordRecoveryResponse requestPasswordRecovery( String mail ) + throws SessionServerException , SessionMaintenanceException + { + Command command = new RequestPasswordRecoveryCommand( mail ); + try { + return (RequestPasswordRecoveryResponse) this.execute( command ); + } catch ( SessionException se ) { + throw new RuntimeException( se ); + } + } + + + public ConfirmPasswordRecoveryResponse confirmPasswordRecovery( String mail , String token , String password , + String passwordConfirm ) + throws SessionServerException , SessionMaintenanceException + { + Command command = new ConfirmPasswordRecoveryCommand( mail , token , password , passwordConfirm ); + try { + return (ConfirmPasswordRecoveryResponse) this.execute( command ); + } catch ( SessionException se ) { + throw new RuntimeException( se ); + } + } + +} diff --git a/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/PlayerSession.java b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/PlayerSession.java new file mode 100644 index 0000000..1cc1607 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-beans/src/main/java/com/deepclone/lw/web/csess/PlayerSession.java @@ -0,0 +1,578 @@ +package com.deepclone.lw.web.csess; + + +import java.util.Map; + +import com.deepclone.lw.cmd.CreateAuthChallengeCommand; +import com.deepclone.lw.cmd.CreateAuthChallengeResponse; +import com.deepclone.lw.cmd.bt.*; +import com.deepclone.lw.cmd.bt.data.BugStatus; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.player.*; +import com.deepclone.lw.cmd.player.account.*; +import com.deepclone.lw.cmd.player.alliances.*; +import com.deepclone.lw.cmd.player.battles.*; +import com.deepclone.lw.cmd.player.bt.*; +import com.deepclone.lw.cmd.player.elist.*; +import com.deepclone.lw.cmd.player.fleets.*; +import com.deepclone.lw.cmd.player.gdata.*; +import com.deepclone.lw.cmd.player.planets.*; +import com.deepclone.lw.cmd.player.msgs.*; +import com.deepclone.lw.session.Command; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.utils.DigestHelper; +import com.deepclone.lw.web.beans.session.*; + + + +@SessionType( "player" ) +public class PlayerSession + extends Session +{ + + /* General & account management commands */ + + public String getLanguage( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Command command = new GetLanguageCommand( ); + return ( (GetLanguageResponse) this.execute( command ) ).getLanguage( ); + } + + + public AccountValidationResponse startValidation( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AccountValidationResponse) this.execute( new AccountValidationCommand( ) ); + } + + + public AccountValidationResponse validate( String token , String empire , String planet ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Command command = new AccountValidationCommand( token , empire , planet ); + return (AccountValidationResponse) this.execute( command ); + } + + + public AccountReactivationResponse reactivate( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AccountReactivationResponse) this.execute( new AccountReactivationCommand( ) ); + } + + + public BanDetailsResponse getBanDetails( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (BanDetailsResponse) this.execute( new BanDetailsCommand( ) ); + } + + + /* Empire commands */ + + public EmpireResponse getOverview( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (EmpireResponse) this.execute( new OverviewCommand( ) ); + } + + + public EmpireResponse implementTechnology( int technology ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (EmpireResponse) this.execute( new ImplementTechCommand( technology ) ); + } + + + /* Planet list */ + + public ListPlanetsResponse listPlanets( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListPlanetsResponse) this.execute( new ListPlanetsCommand( ) ); + } + + + /* Map */ + + public ViewMapResponse viewMap( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewMapResponse) this.execute( new ViewMapCommand( ) ); + } + + + public ViewMapResponse viewMap( int x , int y , MapSize size ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewMapResponse) this.execute( new ViewMapCommand( x , y , size ) ); + } + + + /* Planet commands */ + + public ViewPlanetResponse getPlanetView( int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewPlanetResponse) this.execute( new ViewPlanetCommand( id ) ); + } + + + public ViewPlanetResponse constructBuildings( int planetId , int type , int amount ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Command cmd = new BuildingActionCommand( planetId , type , amount , false ); + return (ViewPlanetResponse) this.execute( cmd ); + } + + + public ViewPlanetResponse destroyBuildings( int planetId , int type , int amount ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Command cmd = new BuildingActionCommand( planetId , type , amount , true ); + return (ViewPlanetResponse) this.execute( cmd ); + } + + + public ViewPlanetResponse buildShips( int planetId , int type , int amount ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Command cmd = new BuildShipsCommand( planetId , type , amount ); + return (ViewPlanetResponse) this.execute( cmd ); + } + + + public ViewPlanetResponse flushQueue( int planetId , boolean military ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Command cmd = new FlushQueueCommand( planetId , military ); + return (ViewPlanetResponse) this.execute( cmd ); + } + + + public ViewPlanetResponse rename( int planetId , String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewPlanetResponse) this.execute( new RenamePlanetCommand( planetId , name ) ); + } + + + public ViewPlanetResponse abandon( int planetId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewPlanetResponse) this.execute( new AbandonPlanetCommand( planetId , false ) ); + } + + + public ViewPlanetResponse cancelAbandon( int planetId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewPlanetResponse) this.execute( new AbandonPlanetCommand( planetId , true ) ); + } + + + /* Alliance commands */ + + public AllianceStatusResponse getAllianceStatus( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new AllianceStatusCommand( ) ); + } + + + public AllianceStatusResponse viewAlliance( String tag ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new ViewAllianceCommand( tag ) ); + } + + + public AllianceStatusResponse joinAlliance( String tag ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new JoinAllianceCommand( tag ) ); + } + + + public AllianceStatusResponse cancelJoinAlliance( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new CancelJoinCommand( ) ); + } + + + public AllianceStatusResponse createAlliance( String tag , String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new CreateAllianceCommand( tag , name ) ); + } + + + public AllianceStatusResponse manageRequests( boolean accept , int[] members ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new ManageRequestsCommand( members , accept ) ); + } + + + public AllianceStatusResponse kickMembers( int[] members ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new KickMembersCommand( members ) ); + } + + + public AllianceStatusResponse transferLeadership( int to ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new TransferLeadershipCommand( to ) ); + } + + + public AllianceStatusResponse leaveAlliance( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (AllianceStatusResponse) this.execute( new LeaveAllianceCommand( ) ); + } + + + /* Enemy list */ + + public EnemyListResponse getEnemyList( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (EnemyListResponse) this.execute( new EnemyListCommand( ) ); + } + + + public EnemyListResponse addEnemy( boolean alliance , String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (EnemyListResponse) this.execute( new AddEnemyCommand( alliance , name ) ); + } + + + public EnemyListResponse removeEnemies( boolean alliance , int[] ids ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (EnemyListResponse) this.execute( new RemoveEnemiesCommand( alliance , ids ) ); + } + + + /* Fleets */ + + public ViewFleetsResponse getFleets( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewFleetsResponse) this.execute( new ViewFleetsCommand( ) ); + } + + + public MoveFleetsResponse moveFleets( long[] ids ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (MoveFleetsResponse) this.execute( new MoveFleetsCommand( ids ) ); + } + + + public MoveFleetsResponse moveFleets( long[] ids , String destination , boolean attack ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (MoveFleetsResponse) this.execute( new MoveFleetsCommand( ids , destination , attack ) ); + } + + + public SetFleetsModeResponse setFleetsMode( long[] ids , boolean attack , boolean forReal ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (SetFleetsModeResponse) this.execute( new SetFleetsModeCommand( ids , attack , forReal ) ); + } + + + public RenameFleetsResponse renameFleets( long[] ids ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (RenameFleetsResponse) this.execute( new RenameFleetsCommand( ids ) ); + } + + + public RenameFleetsResponse renameFleets( long[] ids , String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (RenameFleetsResponse) this.execute( new RenameFleetsCommand( ids , name ) ); + } + + + public SplitFleetResponse splitFleet( long id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (SplitFleetResponse) this.execute( new SplitFleetCommand( id ) ); + } + + + public SplitFleetResponse splitFleet( long id , Map< Integer , Integer > ships , int nFleets , String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (SplitFleetResponse) this.execute( new SplitFleetCommand( id , ships , nFleets , name ) ); + } + + + public DisbandFleetsResponse disbandFleets( long[] ids , boolean confirm ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (DisbandFleetsResponse) this.execute( new DisbandFleetsCommand( ids , confirm ) ); + } + + + public MergeFleetsResponse mergeFleets( long[] ids ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (MergeFleetsResponse) this.execute( new MergeFleetsCommand( ids ) ); + } + + + /* Account management */ + + public GetAccountResponse getAccount( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetAccountResponse) this.execute( new GetAccountCommand( ) ); + } + + + public void setLanguage( String language ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new SetLanguageCommand( language ) ); + } + + + public String createAuthenticationChallenge( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return ( (CreateAuthChallengeResponse) this.execute( new CreateAuthChallengeCommand( ) ) ).getChallenge( ); + } + + + public SetPasswordResponse setPassword( String currentPassword , String challenge , String newPass1 , + String newPass2 ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + String sha1 , md5; + sha1 = DigestHelper.digest( "sha-1" , challenge + " " + DigestHelper.digest( "sha-1" , currentPassword ) ); + md5 = DigestHelper.digest( "md5" , challenge + " " + DigestHelper.digest( "md5" , currentPassword ) ); + + return (SetPasswordResponse) this.execute( new SetPasswordCommand( sha1 , md5 , newPass1 , newPass2 ) ); + } + + + public SetAddressResponse setAddress( String currentPassword , String challenge , String newAddr1 , String newAddr2 ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + String sha1 , md5; + sha1 = DigestHelper.digest( "sha-1" , challenge + " " + DigestHelper.digest( "sha-1" , currentPassword ) ); + md5 = DigestHelper.digest( "md5" , challenge + " " + DigestHelper.digest( "md5" , currentPassword ) ); + + return (SetAddressResponse) this.execute( new SetAddressCommand( sha1 , md5 , newAddr1 , newAddr2 ) ); + } + + + public ValidateSetAddressResponse cancelAddressChange( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ValidateSetAddressResponse) this.execute( new ValidateSetAddressCommand( ) ); + } + + + public ValidateSetAddressResponse confirmAddressChange( String code ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ValidateSetAddressResponse) this.execute( new ValidateSetAddressCommand( code ) ); + } + + + public void loadDefaultPreferences( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new SetPreferencesCommand( ) ); + } + + + public void setPreferences( Map< String , String > prefs ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new SetPreferencesCommand( prefs ) ); + } + + + public void setQuit( String reason ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new QuitGameCommand( reason ) ); + } + + + public void cancelQuit( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new CancelQuitCommand( ) ); + } + + + public void toggleVacation( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new ToggleVacationCommand( ) ); + } + + + /* Battles */ + + public GetBattleResponse getBattle( long battle ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetBattleResponse) this.execute( new GetBattleCommand( battle ) ); + } + + + public GetBattleResponse getBattle( long battle , long tick ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetBattleResponse) this.execute( new GetBattleCommand( battle , tick ) ); + } + + + public ListBattlesResponse getBattles( int page ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListBattlesResponse) this.execute( new ListBattlesCommand( page ) ); + } + + + public GetNewPlanetResponse getNewPlanet( String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetNewPlanetResponse) this.execute( new GetNewPlanetCommand( name ) ); + } + + + /* Messages */ + + public GetMessagesResponse getMessages( boolean inbox ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (GetMessagesResponse) this.execute( new GetMessagesCommand( inbox ) ); + } + + + public ReadMessageResponse readMessage( boolean inbox , long id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ReadMessageResponse) this.execute( new ReadMessageCommand( inbox , id ) ); + } + + + public void deleteMessages( boolean inbox , long[] selection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new MessageBoxCommand( inbox , selection ) ); + } + + + public void markRead( long[] selection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new MessageBoxCommand( selection , true ) ); + } + + + public void markUnread( long[] selection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.execute( new MessageBoxCommand( selection , false ) ); + } + + + public ComposeMessageResponse initNewMessage( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ComposeMessageResponse) this.execute( PrepareMessageCommand.newMessage( ) ); + } + + + public ComposeMessageResponse messageTo( MessageType messageType , int id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ComposeMessageResponse) this.execute( PrepareMessageCommand.newMessageTo( messageType , id ) ); + } + + + public ComposeMessageResponse sendMessage( MessageType type , String toName , String title , String contents ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ComposeMessageCommand command = new ComposeMessageCommand( ); + command.setType( type ); + command.setTarget( toName ); + command.setSubject( title ); + command.setContents( contents ); + return (ComposeMessageResponse) this.execute( command ); + } + + + public ComposeMessageResponse sendReply( boolean inbox , long rtId , MessageType type , String toName , + String title , String contents ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ComposeMessageCommand command = new ComposeMessageCommand( inbox , rtId ); + command.setType( type ); + command.setTarget( toName ); + command.setSubject( title ); + command.setContents( contents ); + return (ComposeMessageResponse) this.execute( command ); + } + + + public ComposeMessageResponse replyTo( boolean inbox , long id ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ComposeMessageResponse) this.execute( new PrepareMessageCommand( id , inbox ) ); + } + + + public ListTargetsResponse listMessageTargets( ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListTargetsResponse) this.execute( new ListTargetsCommand( ) ); + } + + + /* Bug tracking system */ + + public ListBugsResponse listBugs( BugStatus status , boolean ownOnly , long first , int count ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ListBugsResponse) this.execute( new ListBugsCommand( status , ownOnly , first , count ) ); + } + + + public ReportBugResponse reportBug( String title , String description ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ReportBugResponse) this.execute( new ReportBugCommand( title , description ) ); + } + + + public ViewBugResponse getBugReport( long bugId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (ViewBugResponse) this.execute( new ViewBugCommand( bugId ) ); + } + + + public PostCommentResponse postBugComment( long bugId , String comment ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return (PostCommentResponse) this.execute( new PostCommentCommand( bugId , comment ) ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/.classpath b/legacyworlds-web/legacyworlds-web-main/.classpath new file mode 100644 index 0000000..3f554db --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.classpath @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-main/.project b/legacyworlds-web/legacyworlds-web-main/.project new file mode 100644 index 0000000..348118f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.project @@ -0,0 +1,37 @@ + + + legacyworlds-web-main + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/legacyworlds-web/legacyworlds-web-main/.settings/.jsdtscope b/legacyworlds-web/legacyworlds-web-main/.settings/.jsdtscope new file mode 100644 index 0000000..bbb8e68 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.settings/.jsdtscope @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.jdt.core.prefs b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..30a3c16 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,8 @@ +#Thu Apr 15 19:50:22 CEST 2010 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.common.component b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..9c506c0 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.common.component @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.common.project.facet.core.xml b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..9680654 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.jsdt.ui.superType.container b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.jsdt.ui.superType.name b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/.settings/org.maven.ide.eclipse.prefs b/legacyworlds-web/legacyworlds-web-main/.settings/org.maven.ide.eclipse.prefs new file mode 100644 index 0000000..a40fb0f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/.settings/org.maven.ide.eclipse.prefs @@ -0,0 +1,9 @@ +#Thu Apr 15 18:52:28 CEST 2010 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/META-INF/MANIFEST.MF b/legacyworlds-web/legacyworlds-web-main/WebContent/META-INF/MANIFEST.MF new file mode 100644 index 0000000..5e94951 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/ROOT.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/ROOT.ftl new file mode 100644 index 0000000..a6c8975 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/ROOT.ftl @@ -0,0 +1,13 @@ +<#setting url_escaping_charset='UTF-8'> +<#setting number_format='computer'> +<#include "/version.ftl"> +<#include "/layout/columns.ftl"> +<#include "/layout/datatable.ftl"> +<#include "/layout/fields.ftl"> +<#include "/layout/form.ftl"> +<#include "/layout/happiness.ftl"> +<#include "/layout/lists.ftl"> +<#include "/layout/tabs.ftl"> +<#include "${language}/containers/${container}.ftl" /> +<#include "${language}/types/${type}.ftl" /> +<@render /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/chat.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/chat.ftl new file mode 100644 index 0000000..28deee5 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/chat.ftl @@ -0,0 +1,28 @@ +<#include "../game.ftl"> +<#macro page title hidePlanets=false> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ +
+

${title?xhtml}

+
+ +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/external.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/external.ftl new file mode 100644 index 0000000..5f9e1ef --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/external.ftl @@ -0,0 +1,44 @@ +<#macro page title> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ + Legacy Worlds Beta 6 <@version/> +
current version: <@full_version/>
+
${title?xhtml}
+ + +
+
+
+ E-mail address:
+ Password:
+ Forgot your password? + +
+
+
+ + + Scope + Rules + Register + +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/game.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/game.ftl new file mode 100644 index 0000000..3d07f3f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/game.ftl @@ -0,0 +1,70 @@ +<#include "../game.ftl"> +<#macro page title hidePlanets=false> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ Legacy Worlds Beta 6 <@version/> +
<@abbr_gt/>: <@game_time record=data.page.gameTime /> / <@abbr_st/>: ${data.page.serverTime?string("yyyy-MM-dd HH:mm:ss ZZZZZ")}
+ + +
+

${title?xhtml}

+

 

+ <#if !hidePlanets> + <#if data.page.planets?size == 0> +

Get new planet

+ <#else> +

Jump to planet: + <#list data.page.planets as planet> + ${planet.name?xhtml} + +

+ + +
+ +
+ ${data.page.empire} + <#if data.page.alliance?has_content> + [${data.page.alliance}] +
+ ${data.page.cash?string(",##0")} <@abbr_bgc/>
+ <#if data.page.special?has_content> + + <#switch data.page.special> + <#case 'v'>ON VACATION<#break> + <#case 's'>ENTERING VACATION<#break> + <#case 'q'>QUITTING<#break> + + + +
+ Account - Log out +
+ + Planets + Fleets + Map + Alliance + Enemy list + Messages + Bug tracker + +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/offline.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/offline.ftl new file mode 100644 index 0000000..37af005 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/offline.ftl @@ -0,0 +1,27 @@ +<#macro page title> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ + Legacy Worlds Beta 6 <@version/> +
current version: <@full_version/>
+
${title?xhtml}
+ +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/restricted.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/restricted.ftl new file mode 100644 index 0000000..6f5efb8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/containers/restricted.ftl @@ -0,0 +1,33 @@ +<#macro page title> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ + Legacy Worlds Beta 6 <@version/> +
current version: <@full_version/>
+
${title?xhtml}
+ + +
+


+ Log out +
+ +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/game.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/game.ftl new file mode 100644 index 0000000..f9518eb --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/game.ftl @@ -0,0 +1,66 @@ +<#macro game_time record> + <#if record.years == 1> + 1 year, + <#elseif record.years gt 1 > + ${record.years?string(",##0")} years, + + <#if record.weeks == 1> + 1 week, + <#elseif record.weeks gt 1 > + ${record.weeks?string} weeks, + + <#if record.days == 1> + 1 day + <#elseif record.days gt 1 > + ${record.days?string} days, + <#else> + first day, + + ${record.hours?string("00")}:00 + +<#macro game_duration record> + <#if record.years == 1> + 1 year + <#elseif record.years gt 1 > + ${record.years?string(",##0")} years + + <#if record.weeks == 1> + 1 week + <#elseif record.weeks gt 1 > + ${record.weeks?string} weeks + + <#if record.days == 1> + 1 day + <#elseif record.days gt 1 > + ${record.days?string} days + + <#if record.hours == 1> + 1 hour + <#elseif record.hours gt 1 > + ${record.hours?string} hours + + +<#macro rl_duration rTime> + <#local rlDays = (rTime / 1440)?floor> + <#local rlHours = ((rTime - rlDays * 1440) / 60)?floor> + <#local rlMinutes = (rTime - rlDays * 1440 - rlHours * 60)> + <#if rlDays gt 0> + <#if rlDays = 1>1 day<#else>${rlDays} days + + <#if rlHours gt 0> + <#if rlHours = 1>1 hour<#else>${rlHours} hours + + <#if rlMinutes gt 0> + <#if rlMinutes = 1>1 minute<#else>${rlMinutes} minutes + + +<#macro duration rTime gTime> + <#if data.page.useRLTime> + <@rl_duration rTime=rTime /> + <#else> + <@game_duration record=gTime /> + + +<#macro abbr_bgc>bgc +<#macro abbr_st>ST +<#macro abbr_gt>GT \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/home.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/home.ftl new file mode 100644 index 0000000..a9dedfb --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/home.ftl @@ -0,0 +1,28 @@ +<@page title="Legacy Worlds Beta 6 - Milestone 1"> +

+ Welcome to the first milestone release for Legacy Worlds' Beta 6. +

+

 

+

+ This is not a complete game. In fact, most of Beta 5's advanced features have been left out. + However, it is a good starting point for the development of Beta 6. The complete list of features + included in this release can be found on the Scope page. +

+

 

+

+ You will find more information about the game itself on the Rules page. It's + basically the same old thing: build stuff, kill people using the aforementioned stuff. Only the + details have changed. +

+

 

+

+ Now - this is a bit unusual, but because the real goal of this release is to test the system itself, + you are encouraged to create multiple accounts. +

+

 

+

+ While this version may be played independently from Beta 5, it doesn't feature forums (although a bug + reporting system has been included); it is therefore recommended that you + join Beta 5 anyway. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/loggedOut.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/loggedOut.ftl new file mode 100644 index 0000000..6f77200 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/loggedOut.ftl @@ -0,0 +1,8 @@ +<@page title="Logged out"> +

+ You have been logged out of Legacy Worlds. +

+

+ Thanks for playing! +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/loginFailed.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/loginFailed.ftl new file mode 100644 index 0000000..8a70011 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/loginFailed.ftl @@ -0,0 +1,8 @@ +<@page title="Invalid credentials"> +

+ The e-mail address and password you entered do not match any existing account. +

+

+ Please try again. If you have forgotten your password, you may use the password recovery utility. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/noSession.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/noSession.ftl new file mode 100644 index 0000000..3b1b72b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/noSession.ftl @@ -0,0 +1,8 @@ +<@page title="Logged out automatically"> +

+ Your session has expired, and you've been logged out of Legacy Worlds. +

+

+ You need to log in again. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/passwordRecoveryOk.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/passwordRecoveryOk.ftl new file mode 100644 index 0000000..a41c2d4 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/passwordRecoveryOk.ftl @@ -0,0 +1,8 @@ +<@page title="Password Recovery Successful"> +

+ Your password recovery request has been successfully processed. +

+

+ You may now log in with the new password you have just set. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/reactivate.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/reactivate.ftl new file mode 100644 index 0000000..f83bebc --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/reactivate.ftl @@ -0,0 +1,11 @@ +<@page title="Account disabled"> +

+ Your account is currently disabled. +

+

+ You can either leave it as it is by logging out or choose to re-activate it. +

+

+ Please note that your email address must still be valid if you want to re-activate your account. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/rules.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/rules.ftl new file mode 100644 index 0000000..92ade38 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/rules.ftl @@ -0,0 +1,113 @@ +<@page title="Rules of the game"> +

General

+

+ The whole game is based on per-minute updates. Because these updates are computed depending on when the game + server was started, they may happen at any time. +

+

+ Because of this, a game time is provided. It corresponds to the amount of updates that were computed. + One "hour" of game time corresponds to an update and, generally speaking, a minute of real-world time. +

+

+ No real attempts at balancing the game were made. It is therefore quite likely that some aspects of the rules + will not work as expected. +

+

 

+ +

Money & research

+

+ Income is mostly provided by an empire's population. While income and upkeep are displayed for 24h of real-world time, + an empire's cash reserve will increase (or decrease) continuously. The optional Generic assembly line building + provides additional income. +

+

+ Populations also generate research points, which are used to update an empire's research progress. When a + technology reaches 100% of its required research points, it needs to be implemented, which costs + money. +

+

+ Two sets of three technologies are available: civilian technologies provide new buildings, while + military technologies provide new ships. +

+

+ If an empire's cash reserve reach 0 because of a high upkeep, its fleets will begin to degrade. If it does not + own any fleets, then its planet's buildings start to degrade. +

+

+ It is however possible for an empire to reach 0 because of buildings and ships construction. In this case, + no damage will be inflicted, but construction will be slowed down. +

+

 

+ +

Planet management

+

+ Two types of buildings are available without any technology: ship parts factories (which allow ships to be built) + and defence turrets (which provide stationary defences to your planets). +

+

+ Buildings construction or destruction are not immediate. The speed at which buildings are constructed or destroyed + depend on a planet's population. When building, the monetary cost of buildings is taken from the empire's reserves + at every update. +

+

+ Destroying buildings is much faster than constructing them; in addition, a small proportion of the building's cost + is added back to the empire's cash reserves once the building is destroyed. +

+

+ A planet's happiness is determined by three factors: the amount of jobs provided by the planet's buildings relative + to the planet's population, the stationary defences' power and the amount of planets owned by the empire. +

+

+ Happiness does not change immediately when something affects it. The change is progressive, and its speed depend + on its amplitude and on the planet's total population. +

+

+ When a planet's happiness is below 25%, its citizen go on strike, which reduces the planet's income, production and + defences. +

+

+ Population growth is directly proportional to the planet's happiness. +

+

 

+ +

Fleets and ships

+

+ Ships are constructed on planets using the same principle as buildings. However, their construction speed is determined + by the planet's military production. +

+

+ Ships have two characteristics: their power, which determine how effective they are in battle, and their + orbit-to-orbit flight time, which determines their speed and the various penalties which may be inflicted + on a fleet (redirection, redeployment, etc). +

+

+ A fleet's power is the sum of each of its ships' power. Its orbit-to-orbit flight time is determined by the slowest + ship in the fleet. +

+

+ Only fleets that have the available status may be moved, split, or merged. In addition, fleets that have + the deploying status do not inflict damage in battle (they do however receive damage). All fleets may be + renamed, disbanded, or switched between offensive and defensive modes, whatever their status is. +

+

 

+ +

Battles

+

+ A battle starts whenever an attacking fleet is present on a planet, and end when all attacking fleets are gone / have + been destroyed, or when all defensive fleets and planetary defences are gone / have been destroyed. In the latter case, + the attacker with the biggest fleet takes control of the planet at the next update. +

+

+ Battles are updated every minute. Therefore, there are no "battle reports"; instead, a history of the battle and + the events that occured during the battle are provided. +

+

+ A battle's intensity starts at a low level, slowly increasing over time until it reaches full intensity. It determines how + much damage is dealt. +

+

+ Battle damage on both buildings and ships accumulates over time. It is not possible to repair ships or buildings. +

+

 

+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/scope.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/scope.ftl new file mode 100644 index 0000000..0f7ee32 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/static/scope.ftl @@ -0,0 +1,56 @@ +<@page title="Scope of this milestone"> +

+ This milestone consists mostly in writing the game's engine and most of the common + administrative functionalities. Because of this, the game itself + is pretty limited, and so is the interface. +

+

 

+ +

Game server

+

+ The stand-alone game server runs independently of any interface and is responsible for + all administrative and game functionalities. This release concentrates on: +

+
    +
  • system basics - logging, run-time access to game-related "constants", + internationalisation, communications with user interfaces,
  • +
  • accounts - from registration to preferences to inactivity management,
  • +
  • naming system - the names of all in-game entities (empires and planets + in this release) are managed through the same sub-system,
  • +
  • bug tracking system - because it will not be possible to include forums + until much further in the game's development cycle, the bug-tracking system is an essential + tool,
  • +
  • scheduler - because ticks still need to run, sometimes.
  • +
+

 

+ +

Server administration

+

+ Server administration is one of the most important areas for this release, although most + people will (hopefully) never get to see it. It is implemented as a separate user interface + accessing the server through its external communication interface. The administration interface + includes: +

+
    +
  • privilege system (not all administrators are equal),
  • +
  • account management,
  • +
  • game parameters access,
  • +
  • bug tracker administration,
  • +
  • names validation,
  • +
  • log viewer,
  • +
  • automated error reports.
  • +
+

 

+ +

Game and interface

+

+ While the game does not bring anything really new, it is based on a per-minute update system. + Its interface is probably not really appropriate, as Beta 5's external layout is a bit cramped + when it comes to displaying all required in-game information; it is however temporary. +

+

+ This release is available in two languages - English and French - as the internationalisation + system needs to be tested. However, it is extremely likely that future milestone releases will + only be available in English. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/account.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/account.ftl new file mode 100644 index 0000000..2fa1826 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/account.ftl @@ -0,0 +1,220 @@ +<#macro render_preference pref> + <#switch pref.type> + <#case 'BOOLEAN'> + <@form_select label=pref.name name=pref.id id="pref-${pref.id}"> + <@form_option value="0" text="No" selected=( pref.value != "1" )/> + <@form_option value="1" text="Yes" selected=( pref.value == "1" )/> + + <#break> + <#case 'INTEGER'> + <#case 'STRING'> + <@form_text label=pref.name name=pref.id id="pref-${pref.id}" value=pref.value /> + <#break> + <#case 'CHOICE'> + <@form_select label=pref.name name=pref.id id="pref-${pref.id}"> + <#list pref.choices as choice> + <@form_option value=choice.value text=choice.display selected=( pref.value == choice.value )/> + + + <#break> + + <#if pref.description?has_content> + <@form_extra>${pref.description?xhtml} + + +<#macro render_prefs_category category> + <@form_part title=category.name /> + <#list category.preferences as p> + <@render_preference pref=p /> + + +<#macro render> +<@page title="Account"> + <@tabs> + + <@tab id="prefs" title="Preferences"> + <@form name="prefs-form" action="set-preferences" hash="prefs"> + <#list data.account.preferences as c> + <@render_prefs_category category=c /> + + <@form_extended_submit label="Change preferences"> + <@ff_submit label="Defaults" name="load-default-preferences" /> + + + + + <@tab id="basics" title="Identity"> + <@form name="lang-form" action="set-language" hash="basics"> + <@form_part title="Account language" /> + <@form_select name="language" label="Language"> + <#list data.account.supportedLanguages.languages as lang> + <@form_option text=lang.name value=lang.id selected=(lang.id == data.account.language) /> + + + <@form_submit label="Update" /> + + + <@form name="pwd-form" action="set-password" hash="basics"> + <@form_part title="Change password" /> + <#if data.authError!false> + <@form_error>Incorrect password + + <@form_pwd label="Current password" name="current" /> + <#switch data.passwordError!""> + <#case "EMPTY"> + <@form_error>Empty password. + <#break> + <#case "TOO_WEAK"> + <@form_error>This password is too weak. + <#break> + <#case "MISMATCH"> + <@form_error>Password field and confirmation field do not match. + <#break> + <#case "PROHIBITED"> + <@form_error>You are not allowed to use this password here. + <#break> + <#default> + <@form_extra>At least 6 characters, containing both text and numbers. Bonus points for special characters, spaces, and extremely long passwords. + + <@form_pwd label="Password" name="password" /> + <@form_pwd label="Password (confirm)" name="passwordConfirm" /> + <@form_submit label="Update" /> + + + <#if data.account.mailChange?has_content> + <#local mc = data.account.mailChange> + <#if mc.used> + <@form name="mail-form" action="set-address" hash="basics"> + <@form_part title="Change e-mail address" /> + + Current address: + ${data.account.address?xhtml} + + <@form_extra> + You will be able to request an e-mail address change at ${mc.until?string("HH:mm:ss (ZZZZZ)")}. + + + <#else> + <@form name="mail-form" action="confirm-set-address" hash="basics"> + <@form_part title="Change e-mail address" /> + + Current address: + ${data.account.address?xhtml} + + <@form_extra> + You are changing your address to ${mc.newAddress?xhtml}.
+ Your request will expire at ${mc.until?string("HH:mm (ZZZZZ)")}. + + <#if data.codeError!false> + <@form_error>Incorrect confirmation code + + <@form_text name="code" id="mail-confirmation-code" value="${data.code!}" maxLength=64 label="Confirmation code" /> + <@form_extended_submit label="Change address"> + <@ff_submit label="Cancel" name="cancel-set-address" /> + + + + <#else> + <@form name="mail-form" action="set-address" hash="basics"> + <@form_part title="Change e-mail address" /> + <#if data.mailAuthError!false> + <@form_error>Incorrect password + + + Current address: + ${data.account.address?xhtml} + + <@form_pwd label="Current password" name="password" id="current-2" /> + <#switch data.mailError!""> + <#case "EMPTY"> + <@form_error>Empty e-mail address. + <#break> + <#case "INVALID"> + <@form_error>Invalid e-mail address. + <#break> + <#case "IN_USE"> + <@form_error>This e-mail address is already associated with an account. + <#break> + <#case "SEND_FAIL"> + <@form_error>Unable to send confirmation code to this address. + <#break> + <#case "MISMATCH"> + <@form_error>E-mail address field and confirmation field do not match. + <#break> + <#default> + <@form_extra>The e-mail address MUST exist. + + <@form_text label="E-mail address" maxLength=128 name="mail" value=data.mail! /> + <@form_text label="E-mail address (confirm)" maxLength=128 name="mailConfirm" value=data.mail! /> + <@form_submit label="Update" /> + + + + + <@tab id="status" title="Status"> + <@form name="game-credits" action="no-action" hash="status"> + <@form_part title="Game credits" /> + + Game credits: + ${data.account.gameCredits?string(',##0')} + + <@form_extra> + Game credits cannot be used at this time. They will however be accumulated + throughout the LWB6 development cycle. You obtain them by reporting bugs. + + + + <@form name="vacation-form" action="toggle-vacation" hash="status"> + <@form_part title="Vacation mode" /> + + Vacation credits: + ${data.account.vacCredits?string(',##0')} + + + Maximal duration: + + <#if data.account.vacTime?has_content> + approximately <@game_duration record=data.account.vacTime /> + <#else> + less than an hour + + + + <#if data.account.vacStart?has_content> + + Vacation start: + ${data.account.vacStart?string("HH:mm (yyyy-MM-dd ZZZZZ)")} + + <#if data.page.special == 'v'> + <@form_submit label="Exit vacation mode" /> + <#else> + <@form_submit label="Cancel vacation mode" /> + + <#elseif !data.page.special?has_content && data.account.vacTime?has_content> + <@form_submit label="Enter vacation mode" /> + + + + <#if !data.page.special?has_content> + <@form name="quit-form" action="quit" hash="status"> + <@form_part title="Quit game" /> + <@form_extra> + If you click the button below, your account will be disabled after 24 hours. You will be able to re-enable it for the next 6 months, after which it will be deleted. + + <@form_text label="Reason for quitting (optional)" name="reason" value="" /> + <@form_submit label="Quit game" /> + + <#elseif data.page.special == 'q'> + <@form name="quit-form" action="cancel-quit" hash="status"> + <@form_part title="Quit game" /> + <@form_extra> + Your account will be disabled at ${data.account.quitGame?string("HH:mm (yyyy-MM-dd ZZZZZ)")}. + + <@form_submit label="Cancel" /> + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/alliance.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/alliance.ftl new file mode 100644 index 0000000..c0c8dd7 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/alliance.ftl @@ -0,0 +1,268 @@ +<#macro show_alliance alliance> + <@dt_main> + <@dt_entry title="Tag">${alliance.tag?xhtml} + <@dt_entry title="Name">${alliance.name?xhtml} + <@dt_entry title="Leader">${alliance.leaderName?xhtml} + <@dt_entry title="Planets">${alliance.planets?string(",##0")} + <@dt_entry title="">Send message + + +<#macro alliance_info_tab> + + <@tab id="info" title="Other alliances"> + + <@form action="alliance-info" name="alliance-info" hash="info"> + <@form_text name="tag" id="ai-tag" label="Alliance tag" value=data.requested! maxLength=5 /> + <@form_submit label="Get information" /> + + + <#if data.info?has_content> + <@show_alliance alliance=data.info /> + + + + + +<#macro alliance_creation_tab> + + <#if data.creation?has_content> + <#assign tag = data.creation.tag!> + <#assign tagError = data.creation.tagError!> + <#assign name = data.creation.name!> + <#assign nameError = data.creation.nameError!> + <#else> + <#assign tag = ""> + <#assign tagError = ""> + <#assign name = ""> + <#assign nameError = ""> + + + <@tab id="create-alliance" title="Create"> + <@form action="create-alliance" name="create-alliance" hash="create-alliance"> + <#switch tagError> + <#case "EMPTY"><@form_error>Please specify your alliance's tag.<#break> + <#case "INVALID"><@form_error>This tag is invalid.<#break> + <#case "UNAVAILABLE"><@form_error>This tag is used by another alliance. + + <@form_text name="tag" id="ca-tag" label="Alliance tag" value=tag maxLength=5 /> + + <#switch nameError> + <#case "EMPTY"><@form_error>Please specify your alliance's name.<#break> + <#case "INVALID"><@form_error>This name is invalid.<#break> + + <@form_text name="name" id="ca-name" label="Alliance name" value=name maxLength=5 /> + + <@form_submit label="Create an alliance" /> + + + + +<#macro alliance_join_tab> + + <@tab id="join-alliance" title="Join"> + <@form action="join-alliance" name="join-alliance" hash="join-alliance"> + <#if data.joinFailure?has_content> + <@form_error>Alliance not found. + + <@form_text name="tag" id="ja-tag" label="Alliance tag" value=data.joinFailure! maxLength=5 /> + <@form_submit label="Join this alliance" /> + + + + +<#macro no_alliance> + + <#if data.page.special! != 'v'> + <@alliance_join_tab /> + <@alliance_creation_tab /> + + + +<#macro alliance_joining_tab> + + <@tab id="join-alliance" title="Request sent"> + <@lineform action="cancel-join" hash="join-alliance"> + A request to join ${alliance.main.tag?xhtml} has been sent. + <#if data.page.special! != 'v'> + <@ff_submit label="Cancel" /> + + + <@show_alliance alliance=alliance.main /> + + + +<#macro alliance_planets pList> + <@tab id="planets" title="Planets"> + + <#if pList?size == 0> +

There are no planets in the alliance.

+ <#return> + + + <@listview> + <@lv_line headers=true> + <@lv_column width=80 centered=true>Coordinates + <@lv_column width=150>Planet + <@lv_column width=150>Owner + + + <#list pList as planet> + <#if planet.battle> + <#local bStart = ""> + <#local bEnd = ""> + <#else> + <#local bStart = " "> + <#local bEnd = " "> + + + <@lv_line> + <@lv_column centered=true>${bStart}(${planet.x},${planet.y};${planet.orbit})${bEnd} + <@lv_column>${bStart}${planet.name?xhtml}${bEnd} + <@lv_column>${bStart}${planet.owner?xhtml}${bEnd} + + + <#if planet.battle> + <@lv_line> +   + + Military situation: + ${planet.defence?string(",##0")} + vs. + ${planet.attack?string(",##0")} + + + + + + + + +<#macro alliance_members mList isLeader empty=""> + + <#if mList?size == 0 && empty != ""> +

${empty?xhtml}

+ <#return> + + + <@listview> + <@lv_line headers=true> + <#if isLeader && data.page.special! != 'v'> + <@lv_column width=40 centered=true>  + + <@lv_column width="x">Empire + + + <#list mList as member> + <@lv_line> + <#if isLeader && data.page.special! != 'v'> + <@lv_column centered=true> + <#if member.name == data.page.empire> +   + <#else> + + + + + <@lv_column> + <#if member.name == data.page.empire> + ${member.name?xhtml} + <#else> + ${member.name?xhtml} + + + + + + + +<#macro alliance_member_page> + <#local leader = alliance.leader?has_content> + + <@tab id="in-alliance" title="Alliance"> + <@lineform action="leave-alliance" hash="join-alliance"> + You are + <#if alliance.leader?has_content> + the leader + <#else> + a member + + of ${alliance.main.tag?xhtml}. + <#if data.page.special! != 'v'> + <@ff_submit label="Leave alliance" /> + + + <@show_alliance alliance=alliance.main /> + + + <@alliance_planets pList=alliance.member.planets /> + + <@tab id="members" title="Members"> + <#if leader && alliance.member.members?size gt 1 && data.page.special! != 'v'> +
+ + <@alliance_members mList=alliance.member.members isLeader=leader /> + <#if leader && alliance.member.members?size gt 1 && data.page.special! != 'v'> +
+
+ <@ff_submit label="Kick selected members" /> +
+
+
+ + <@lineform action="transfer-leadership" hash="members"> + Transfer leadership to + <@ff_select id="leadership" name="leadership"> + <#list alliance.member.members as member> + <#if member.name != data.page.empire> + <@form_option value=member.id text=member.name /> + + + + <@ff_submit label="Confirm" /> + + + + + <#if leader> + <@tab id="requests" title="Requests"> + <#if alliance.leader.requests?size gt 0 && data.page.special! != 'v'> +
+ + <@alliance_members mList=alliance.leader.requests isLeader=true empty="No pending requests" /> + <#if alliance.leader.requests?size gt 0 && data.page.special! != 'v'> +
+
+ <@ff_select id="requests-select" name="action"> + <@form_option value="1" text="Accept" /> + <@form_option value="0" text="Reject" /> + selected applicants + <@ff_submit label="Confirm" /> +
+
+
+ + + + + +<#macro render> +<@page title="Alliance"> + + <#assign alliance = data.alliance> + <@tabs> + + <#if alliance.main?has_content> + <#if alliance.member?has_content> + <@alliance_member_page /> + <#else> + <@alliance_joining_tab /> + + <#else> + <@no_alliance /> + + <@alliance_info_tab /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/banned.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/banned.ftl new file mode 100644 index 0000000..b143398 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/banned.ftl @@ -0,0 +1,12 @@ +<#macro render> +<@page title="You've been banned"> +

You did it. You got yourself banned. Nice work.

+ <@dt_main> + <@dt_entry width=200 title="Ban date/time">${data.banTime?string("yyyy-MM-dd HH:mm:ss")} + <@dt_entry width=200 title="Reason for the ban">${data.banReason?xhtml} + + <#if data.redeemable> +

Your empire has not been deleted yet. You may appeal the ban by sending an email to the staff within 48h.

+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/battle.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/battle.ftl new file mode 100644 index 0000000..f749a23 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/battle.ftl @@ -0,0 +1,261 @@ +<#macro render_header desc> +
+ At ${desc.location.name?xhtml} + (${desc.x},${desc.y};${desc.orbit}) +
+ +<#macro render_navigation id disp> +
+ + + + + + + +
+ <#if disp.previous?has_content> + + + << + <#if disp.previous?has_content> + + + + <@ff_select id="view-battle-tick" name="tick" style="width:470px"> + <#list disp.all as viewable> + <@form_option value="${viewable.ticks?string('#')}" selected=(viewable.ticks == disp.current.ticks)><@game_time record=viewable.gameTime /> + + + <@ff_submit label="Go" style="width:40px" /> + + <#if disp.next?has_content> + + + >> + <#if disp.next?has_content> + + + + >>> +
+
+ +<#macro render_list_entry mode record type> + +   + buildings<#else>ships">  +   + + <#nested> + + ${record.cPower?string(',##0')} + ${record.lPower?string(',##0')} + + <#list record.ships as shipType> + +   + ${shipType.name} + ${shipType.cAmount?string(',##0')} + ${shipType.lAmount?string(',##0')} + + + +<#macro render_protagonist mode record> + <#if record.ships?has_content> + <@render_list_entry mode=mode record=record type="empire"> + <#if record.player.id = 0 || mode = "own"> + ${record.player.name?xhtml} + <#else> + ${record.player.name?xhtml} + + + + +<#macro render_planet mode record> + <@render_list_entry mode=mode record=record type="planet">( planet ) + +<#macro render_protagonists mode source> + <#if source.players?size = 0> + <#return> + + +   +   + <#if mode == "allied">Allied<#else>Hostile forces + ${source.cPower?string(',##0')} + ${source.lPower?string(',##0')} + + <#list source.ships as shipType> + +   + ${shipType.name} + ${shipType.cAmount?string(',##0')} + ${shipType.lAmount?string(',##0')} + + + <#list source.players as pRecord> + <@render_protagonist mode=mode record=pRecord /> + + +<#macro render_fleets fData> + <@listview> + Forces + <@lv_line headers=true> +   +   +   +   +   + <@lv_column width=100 centered=true>Current + <@lv_column width=100 centered=true>Lost + + <@render_protagonist mode="own" record=fData.own /> + <#if fData.planet.relation == "OWN"> + <@render_planet mode="own" record=fData.planet /> + + <@render_protagonists mode="allied" source=fData.friendly /> + <#if fData.planet.relation == "ALLIED"> + <@render_planet mode="allied" record=fData.planet /> + + <@render_protagonists mode="enemy" source=fData.hostile /> + <#if fData.planet.relation == "ENEMY"> + <@render_planet mode="enemy" record=fData.planet /> + + Click "*" and "+" to toggle ships/buildings and forces display. + + +<#macro render_event_items items> + <#list items as item> + <@lv_line> +   + ${item.name} + ${item.cAmount?string(",##0")} + + + +<#macro render_event event> + <#switch event.type> + <#case "RENAME"> + <@lv_line> + Planet renamed to ${event.name} + + <#break> + <#case "SWITCH"> + <@lv_line> + + <#if event.name = data.page.empire> + We have switched to <#if event.hostile>attack<#else>defence. + <#else> + ${event.name} has switched mode and is now <#if event.hostile>hostile<#else>friendly. + + + + <#break> + <#case "BUILD"> + <@lv_line> + + <#if event.planet> + New buildings have been constructed on the planet. + <#elseif event.name = data.page.empire> + Our new fleets have been deployed. + <#else> + <#if event.hostile>Hostile<#else>Friendly fleets belonging to ${event.name} have been deployed. + + + + <@render_event_items items=event.ships /> + <#break> + <#case "DEPART"> + <@lv_line> + + <#if event.name = data.page.empire> + Our fleets have left orbit. + <#else> + <#if event.hostile>Hostile<#else>Friendly fleets belonging to ${event.name} have left orbit. + + + + <@render_event_items items=event.ships /> + <#break> + <#case "ARRIVE"> + <@lv_line> + + <#if event.name = data.page.empire> + Our fleets have joined the battle. + <#else> + <#if event.hostile>Hostile<#else>Friendly fleets belonging to ${event.name} have joined the battle. + + + + <@render_event_items items=event.ships /> + <#break> + <#case "DESTROY"> + <@lv_line> + + <#if event.planet> + Buildings have been destroyed on the planet. + <#elseif event.name = data.page.empire> + Our fleets have been disbanded. + <#else> + <#if event.hostile>Hostile<#else>Friendly fleets belonging to ${event.name} have been disbanded. + + + + <@render_event_items items=event.ships /> + <#break> + <#default> + <@lv_line> + + Missing event type "${event.type}" (this is a bug) + + + <#break> + + +<#macro render_history hData> + <#if hData?size = 0> + <#return> + + <@listview> + History + <@lv_line headers=true> +   +   +   + + <#list hData as hInterval> + <#if hInterval.end?has_content> + <#if hInterval.battleEnds> + Battle ended at <@game_time record=hInterval.end.gameTime /> + <#else> + No more fleets at this location + +   + + <#list hInterval.entries as atTick> + <@game_time record=atTick.time.gameTime />: + <#list atTick.events as event> + <@render_event event=event /> + +   + + <#if hInterval.battleBegins> + Battle started at <@game_time record=hInterval.begin.gameTime /> + + + + +<#macro render> +<#local bDescription = data.battle.description> +<#local bDisplay = data.battle.display> +<@page title="Battle #${bDescription.id?string(',##0')} at ${bDescription.location.name}"> + + <@render_header desc=bDescription /> + <@render_navigation id=bDescription.id disp=bDisplay /> +

 

+ <@render_fleets fData=data.battle.ships /> + <@render_history hData=data.battle.history /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/battles.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/battles.ftl new file mode 100644 index 0000000..0c39c6c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/battles.ftl @@ -0,0 +1,62 @@ +<#macro render_battles battles page pages> + <#if pages gt 1> + + + + + + +
+ <#if page gt 0> + + + << + <#if page gt 0> + + + + Page ${page + 1} / ${pages} + + <#if page lt pages - 1> + + + >> + <#if page lt pages - 1> + + +
+ + <@listview> + <@lv_line headers=true> + <@lv_column width=60 centered=true># + <@lv_column width="x">Location + <@lv_column width=80 centered=true>  + <@lv_column width=125 centered=true>Joined + <@lv_column width=125 centered=true>Finished + + <#list battles as battle> + <@lv_line> + <@lv_column centered=true>${battle.id?string(',##0')} + <@lv_column>${battle.location.name?xhtml} + <@lv_column centered=true>(${battle.x},${battle.y};${battle.orbit}) + <@lv_column centered=true><@game_time record=battle.first.gameTime /> + <@lv_column centered=true> + <#if battle.last?has_content> + <@game_time record=battle.last.gameTime /> + <#else> + In progress + + + + + + +<#macro render> +<@page title="Battles"> + <#if data.pages == 0> +

We have not taken part in any battle

+ <#else> + <@render_battles battles=data.list page=data.currentPage pages=data.pages /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsList.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsList.ftl new file mode 100644 index 0000000..e206f0d --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsList.ftl @@ -0,0 +1,136 @@ +<#include "bugsTabs.ftl"> +<#macro render_navigation current count total qString> + + + + + + +
+ <#if current gt 0> + + + << + <#if current gt 0> + + + + <#if total gt 1> + ${total?string(',##0')} entries found. + <#elseif total = 1> + 1 entry found. + <#else> + No entries found. + + + <#if current lt total - count> + + + >> + <#if current lt total - count> + + +
+ +<#macro render> +<#if data.ownOnly> + <#local ownOnly = "1"> +<#else> + <#local ownOnly = "0"> + +<#local qString = "status=${data.status!'x'}&own=${ownOnly}" > +<@page title="Bug tracker"> + <#-- Tabs --> + <@bugTabs selected="bugsList" qString="${qString}&first=${data.first}" /> + + <#-- Selection --> +
+
+ + +
+ List + <@ff_select id="sel-own" name="own"> + <@form_option value="0">all + <@form_option value="1" selected=(data.ownOnly)>my own + + reports with the following status: + <@ff_select id="sel-stat" name="status"> + <@form_option value="x">(indifferent) + <@form_option value="PENDING" selected=((data.status!"") = 'PENDING')>pending validation + <@form_option value="OPEN" selected=((data.status!"") = 'OPEN')>being handled + <@form_option value="RESOLVED" selected=((data.status!"") = 'RESOLVED')>fixed + <@form_option value="WONT_FIX" selected=((data.status!"") = 'WONT_FIX')>won't fix + <@form_option value="NOT_A_BUG" selected=((data.status!"") = 'NOT_A_BUG')>not a bug + + <@ff_submit label="Search" /> +
+
+
+ + <#-- Navigation --> + <@render_navigation current=data.first count=data.count total=data.entries qString=qString /> + + <#-- List of bugs --> + <#if data.reports?size gt 0> + <@listview> + + <@lv_line headers=true> + <@lv_column centered=true width=60># + <@lv_column width="x">Title + <#if !( data.status?has_content )> + <@lv_column width=130 centered=true>Status + + <@lv_column width=150 centered=true>Last update + + + <#list data.reports as report> + + <#if !data.ownOnly && report.initialSubmitter.userId?has_content && !report.initialSubmitter.admin && report.initialSubmitter.name = data.page.empire> + <#local eClass="own-fleet"> + <#else> + <#local eClass=""> + + + <@lv_line class=eClass> + <@lv_column centered=true>${report.reportId?string(",##0")} + <@lv_column>${report.title} + <#if !( data.status?has_content )> + <@lv_column centered=true><@bugStatus status=report.status /> + + <@lv_column centered=true> + <#if report.updated> + + + ${report.lastUpdate?string("yyyy-MM-dd HH:mm:ss")} + <#if report.updated> + + + + + <@lv_line class=eClass> + <#if data.status?has_content> + + <#else> + + +   + <@lv_column centered=true> + by + <#if report.latestSubmitter.admin> + + + ${report.latestSubmitter.name} + <#if report.latestSubmitter.admin> + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsReport.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsReport.ftl new file mode 100644 index 0000000..0dc7272 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsReport.ftl @@ -0,0 +1,57 @@ +<#include "bugsTabs.ftl"> +<#macro render> +<#if data.query.ownOnly> + <#local ownOnly = "1"> +<#else> + <#local ownOnly = "0"> + +<#local qString = "status=${data.query.status!'x'}&own=${ownOnly}" > +<@page title="Report bug"> + <@bugTabs selected="bugsReport" qString="${qString}&first=${data.query.first}" /> + +

READ THIS BEFORE REPORTING BUGS

+

+ So, you've found something that doesn't work or that seems to be behaving in an unexpected manner. + Nice, that's the reason why this version has been made public. +

+

+ However, are you sure that what you have found is really a bug? If you'd been playing Beta 5 in + the past, there are many things that no longer work in the same way. Make sure you've read the + rules and milestone information first. +

+

+ Once you've read this documentation and haven't found any clue related to your problem, well, + it's either a bug or something missing in these pages. In any case, it should be reported. + Use the form below for that. Make sure the title is as clear as possible + (it should indicate the nature of the problem) and that the description is as thorough as you + can make it. +

+

+ Thanks for helping! +

+ + <@form action="report-bug" hash="report-form"> + + + + + + + <#switch data.titleError!""> + <#case "EMPTY"><@form_error>Please specify the report's title<#break> + <#case "INVALID"><@form_error>Title should be at least 10 characters long<#break> + + <@form_text label="Title" name="title" value=data.title!"" maxLength=127 /> + + <#switch data.descriptionError!""> + <#case "EMPTY"><@form_error>Please specify the bug's description<#break> + <#case "INVALID"><@form_error>Description should be at least 30 characters long<#break> + + <@form_text label="Description" name="description" value=data.description!"" multiline=true maxLength=10 /> + + <@form_submit label="Post bug report" /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsTabs.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsTabs.ftl new file mode 100644 index 0000000..e047ca7 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsTabs.ftl @@ -0,0 +1,18 @@ +<#macro bugTab href title selected> + ${title} + +<#macro bugTabs selected qString> +
+ <@bugTab href="bugtrack?${qString}" title="List bugs" selected=( selected = 'bugsList' ) /> + <@bugTab href="report-bug?${qString}" title="Report bug" selected=( selected = 'bugsReport' ) /> +
+ +<#macro bugStatus status> + <#switch status> + <#case "PENDING">pending validation<#break> + <#case "OPEN">being handled<#break> + <#case "RESOLVED">fixed<#break> + <#case "WONT_FIX">won't fix<#break> + <#case "NOT_A_BUG">not a bug<#break> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsView.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsView.ftl new file mode 100644 index 0000000..0fea18b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/bugsView.ftl @@ -0,0 +1,124 @@ +<#include "bugsTabs.ftl" /> +<#macro render_submitter s> + <#if s.admin> + + <#elseif s.userId?has_content && s.name = data.page.empire> + + + ${s.name?xhtml} + <#if s.admin || ( s.userId?has_content && s.name = data.page.empire )> + + + +<#macro render_event e> +
+ ${e.timestamp?string("yyyy-MM-dd HH:mm:ss")} - <@render_submitter s=e.submitter /> + <#nested> +
+ +<#macro render_report_event e> + <@render_event e=e> + posted bug report #${e.id?string(",##0")} + +

${e.title}

+
+ ${e.contents} +
+ +<#macro render_status_event e> + <@render_event e=e> + set the report's status to <@bugStatus status=e.status /> + + +<#macro render_visibility_event e> + <@render_event e=e> + set the report's visibility to <#if e.visible>public<#else>private + + +<#macro render_merge_event e> + <@render_event e=e> + merged current bug report with bug report #${e.mergedId?string(",##0")} + + +<#macro render_comment_event e> + <@render_event e=e> + posted a comment + <#if !e.visible> + (moderation pending) + + +
+ ${e.contents} +
+ +<#macro render> +<#if data.query.ownOnly> + <#local ownOnly = "1"> +<#else> + <#local ownOnly = "0"> + +<#local qString = "status=${data.query.status!'x'}&own=${ownOnly}" > +<@page title="Bug #${data.report.reportId?string(',##0')} - ${data.report.title}" hidePlanets=true> + <#-- Tabs --> + <@bugTabs selected="" qString="${qString}&first=${data.query.first}" /> + + <#-- Bug info --> + <@dt_main> + <@dt_entry title="Status"><@bugStatus status=data.report.status /> + <@dt_entry title="Public"><#if data.report.visible>Yes<#else>No + <@dt_entry title="Initially reported"> + ${data.report.posted?string("yyyy-MM-dd HH:mm:ss")} + by <@render_submitter s=data.report.initialSubmitter /> + + <@dt_entry title="Latest update"> + ${data.report.lastUpdate?string("yyyy-MM-dd HH:mm:ss")} + by <@render_submitter s=data.report.latestSubmitter /> + + + + <#-- List events --> + <#local mayPost = false> + <#list data.events as event> +
+ <#local mayPost = ( mayPost || ( !event.submitter.admin && event.submitter.userId?has_content && event.submitter.name = data.page.empire ) )> + <#switch event.type> + <#case 'INIT'> + <@render_report_event e=event /> + <#break> + <#case 'STATUS'> + <@render_status_event e=event /> + <#break> + <#case 'COMMENT'> + <@render_comment_event e=event /> + <#break> + <#case 'VISIBILITY'> + <@render_visibility_event e=event /> + <#break> + <#case 'MERGE'> + <@render_merge_event e=event /> + <#break> + + + + <#-- Comment form --> + <#if mayPost && ( data.report.status = 'OPEN' || data.report.status = 'PENDING' )> +
+ <@form action="bug-${data.report.reportId}-comment" hash="post-comment"> + + + + + + + + <#switch data.commentError!""> + <#case "EMPTY"><@form_error>You should type a comment before posting a comment.<#break> + <#case "INVALID"><@form_error>Comments must be at least 30 characters long.<#break> + + <@form_text label="New comment" name="comment" multiline=true maxLength=6 value=data.comment!"" /> + <@form_submit label="Post comment" /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/chat.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/chat.ftl new file mode 100644 index 0000000..f62c595 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/chat.ftl @@ -0,0 +1,27 @@ +<#macro render> +<@page title="Legacy Worlds chat"> + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/enemies.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/enemies.ftl new file mode 100644 index 0000000..3dc1fa9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/enemies.ftl @@ -0,0 +1,98 @@ +<#macro enemy_tab eList alliances> + + <#if alliances> + <#local tabId = "alliances"> + <#local addAction = "alliance"> + <#local tabTitle = "Alliances"> + <#local emptyText = "No enemy alliances."> + <#local nameLen = 5> + <#if data.alliance?has_content & data.alliance> + <#local error = data.error> + <#local defName = data.name> + + <#else> + <#local tabId = "empires"> + <#local addAction = "empire"> + <#local tabTitle = "Empires"> + <#local emptyText = "No enemy empires."> + <#local nameLen = 20> + <#if data.alliance?has_content & !data.alliance> + <#local error = data.error> + <#local defName = data.name> + + + + <@tab id=tabId title=tabTitle> + + <#if eList?size == 0> +

${emptyText}

+ <#else> +
+ <@listview> + <@lv_line headers=true> + <#if data.page.special! != 'v'> + <@lv_column width=40 centered=true>  + + <@lv_column width="x">${tabTitle} + + + <#list eList as enemy> + <@lv_line> + <#if data.page.special! != 'v'> + <@lv_column centered=true> + + <@lv_column> + <#if alliances>[<#else>${enemy.name?xhtml}<#if alliances>] + + + + + <#if data.page.special! != 'v'> +
+
+ <@ff_submit label="Remove selected enemies" /> +
+
+ +
+ + + <#if data.page.special! != 'v'> + <#if error?has_content> + <@standalone_error> + <#switch error> + <#case "INVALID"><#if alliances>Alliance<#else>Empire not found.<#break> + <#case "BANNED"> + <#if alliances> + Feeling Mordred-ish today, are we? + <#else> + There's a medical term for that - schizophrenia. + + <#break> + <#case "UNAVAILABLE"> + This <#if alliances>alliance<#else>empire is already in your enemy list. + <#break> + + + + <@lineform action="add-enemy-${addAction}" hash=tabId> + New enemy: <@ff_text id="name-${addAction}" name="name" value=defName! maxLength=nameLen size=(nameLen+1) /> + <@ff_submit label="Add" /> + + + + + + +<#macro render> +<@page title="Enemy list"> + + <@tabs> + + <@enemy_tab eList=data.empires alliances=false /> + <@enemy_tab eList=data.alliances alliances=true /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/fleets.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/fleets.ftl new file mode 100644 index 0000000..1833cf9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/fleets.ftl @@ -0,0 +1,261 @@ +<#macro render_fleet_ships rType id ships> + + + + + + + <#list ships as ship> + + + + + + +
Ship classQuantityPower
${ship.name}${ship.amount?string(',##0')}${ship.power?string(',##0')}
+ +<#macro render_static_fleet_details rType fleet> + +   + +
+ <@render_fleet_ships rType="own-fleet" id=fleet.id ships=fleet.ships /> +
+
+ <@dt_main> + <#if fleet.status != 'AVAILABLE'> + <@dt_entry title="Penalty"> + <@duration rTime=fleet.penalty gTime=fleet.gamePenalty /> + + + <@dt_entry abbr="OOFT" title="Orbit-to-orbit flight time"> + <@duration rTime=fleet.flightTime gTime=fleet.gameFlightTime /> + + +
+ + + +<#macro render_fleets_at location owners> + <#list owners as owner> + <#switch owner.relation> + <#case 'OWN'> + <#local rType = 'own-fleet'> + <#local mode = location.attacking > + <#break> + <#case 'ALLIED'> + <#local rType = 'allied-fleet'> + <#local mode = location.attacking > + <#break> + <#case 'ENEMY'> + <#local rType = 'enemy-fleet'> + <#local mode = ! location.attacking > + <#break> + + <#list owner.fleets as fleet> + + + <#if owner.relation == 'OWN' && data.page.special! != 'v'> + + <#else> +   + + + + <#if fleet.name?has_content && fleet.name != ""> + ${fleet.name?xhtml} + <#else> + (unnamed fleet) + + + + <#if owner.relation = 'OWN'> + ${owner.name?xhtml} + <#else> + ${owner.name?xhtml} + + + + <#if mode>A<#else>D + + ${fleet.power?string(',##0')} + + <#if fleet.status == 'AVAILABLE'> + AVL + <#else> + <#switch fleet.status> + <#case 'DEPLOYING'>DPL<#break> + <#case 'REDEPLOYING'>RDP<#break> + + + + + <@render_static_fleet_details rType=rType fleet=fleet /> + + + +<#macro render_static_fleets locations> + <#list locations as location> + + + + + + + + + + + <#if location.onVacation!false> + + <#elseif location.battle?has_content && location.battle.hostile gt 0> + + +
${location.name?xhtml}${location.name?xhtml} (${location.x},${location.y};${location.orbit})Population: ${location.population?string(",##0")} + <#if location.attacking> + + <#elseif location.own> + + <#else> + + + Defence: ${location.defence?string(",##0")} + +
+ <#if location.fleetOwners?size == 0> +

No fleets at this location.

+ <#else> + + + + + + + + + + <@render_fleets_at location=location owners=location.fleetOwners /> +
 Fleet nameOwnerMPS
+ +
Vacation mode enabled
+ Battle - ${location.battle.friendly?string(',##0')} vs. ${location.battle.hostile?string(',##0')} - + Details +
+ + +<#macro render_moving_fleet_details fleet> + +   + +
+ <@render_fleet_ships rType="own-fleet" id=fleet.id ships=fleet.ships /> +
+
+ <@dt_main> + <@dt_entry title="Source">${fleet.source.name?xhtml} + <@dt_entry title="Status"> + <#if fleet.status == 'AVAILABLE'> + AVL + <#else> + RDR - + <@duration rTime=fleet.penalty gTime=fleet.gamePenalty /> + + + <@dt_entry title="Time to target"><@duration rTime=fleet.timeLeft gTime=fleet.gameTimeLeft /> + <@dt_entry title="Coordinates">(${fleet.currentX?string("0.00")};${fleet.currentY?string("0.00")}) + <@dt_entry title="Nearest planet"> + <#if fleet.nearest?has_content> + ${fleet.nearest.name?xhtml} + <#else> + in outer space + + + <@dt_entry abbr="OOFT" title="Orbit-to-orbit flight time"> + <@duration rTime=fleet.flightTime gTime=fleet.gameFlightTime /> + + +
+ + + +<#macro render_moving_fleet fleet> + + + <#if data.page.special! != 'v'> + + <#else> +   + + + + <#if fleet.name?has_content && fleet.name != ""> + ${fleet.name?xhtml} + <#else> + (unnamed fleet) + + + + <#if fleet.attacking>A<#else>D + + ${fleet.power?string(',##0')} + <@duration rTime=fleet.eta gTime=fleet.gameEta /> + ${fleet.destination.name?xhtml} + + <@render_moving_fleet_details fleet=fleet /> + +<#macro render_moving_fleets fleets> + <#if fleets?size != 0> + + + + + + + +
Moving fleets
+ + + + + + + + + + <#list fleets as fleet> + <@render_moving_fleet fleet=fleet /> + +
 Fleet nameMPETADestination
+
+ + +<#macro render> +<@page title="Fleets"> + <#local locations = data.fleets.locations> + <#local mFleets = data.fleets.moving> + <#if locations?size == 0 && mFleets?size == 0> +

You do not own any fleets or planets.

+ <#else> +
Click a fleet's name to see composition and details
+
+ <@render_static_fleets locations=locations /> + <@render_moving_fleets fleets=mFleets /> + <#if data.page.special! != 'v'> +
+ +   + +   + + +   + + +   + +
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/fleetsCommand.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/fleetsCommand.ftl new file mode 100644 index 0000000..0c19219 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/fleetsCommand.ftl @@ -0,0 +1,137 @@ +<#macro render_fleet fleet> + + + <#if fleet.name?has_content && fleet.name != ""> + ${fleet.name?xhtml} + <#else> + (unnamed fleet) + + + ${fleet.power?string(',##0')} + <@duration rTime=fleet.flightTime gTime=fleet.gameFlightTime /> + + <#switch fleet.status> + <#case 'DEPLOYING'>DPL<#break> + <#case 'REDEPLOYING'>RDP<#break> + <#case 'REDIRECTING'>RDP<#break> + <#case 'AVAILABLE'>AVL<#break> + + + + (${fleet.x?string("0.00")};${fleet.y?string("0.00")})
+ <#if fleet.nearest?has_content> + <#if fleet.atPlanet>At<#else>Near + ${fleet.nearest.name?xhtml} + <#else> + In outer space + + + +<#macro render_selected_fleets fleets> +

Selected fleets

+ + + + + + + + + + <#list fleets as fleet> + + <@render_fleet fleet=fleet /> + + +
 NamePFTSLocation
+ +<#macro render_move_fleets> +

New orders

+ <#if data.error> + <@standalone_error>This planet does not exist. + +

+ Move selected fleets to + <@ff_text name="destination" id="destination" value="${data.destination!?xhtml}" maxLength=20 size=21 /> + for + <@ff_select name="mode" id="mode"> + <@form_option text="defence" selected=( !data.mode!false ) value="0" /> + <@form_option text="attack" selected=( data.mode!false ) value="1" /> + +   + <@ff_submit label="Ok" /> + <@ff_submit label="Cancel" name="cancel" /> +

+ +<#macro render_rename_fleets> +

Rename fleets

+ <#if data.error> + <@standalone_error>This name is invalid. + +

+ Rename selected fleets to + <@ff_text name="name" id="name" value="${data.name!?xhtml}" maxLength=40 size=21 /> +   + <@ff_submit label="Ok" /> + <@ff_submit label="Cancel" name="cancel" /> +

+ +<#macro render_set_fleets_mode> +

Set fleets mode

+

+ Assign selected fleets to + <#if data.attack>attack<#else>defence? +   + <@ff_submit label="Yes" /> + <@ff_submit label="No" name="cancel" /> +

+ + +<#macro render_disband_fleets> +

Disband fleets

+

+ Are you sure? +   + <@ff_submit label="Yes" /> + <@ff_submit label="No" name="cancel" /> +

+ +<#macro render> +<#switch dataType> + <#case 'MoveFleetsResponse'> + <#local title="Move fleets"> + <#local action="move-fleets.action"> + <#break> + <#case 'RenameFleetsResponse'> + <#local title="Rename fleets"> + <#local action="rename-fleets.action"> + <#break> + <#case 'SetFleetsModeResponse'> + <#local title="Set fleets mode"> + <#local action="set-fleets-mode.action"> + <#break> + <#case 'DisbandFleetsResponse'> + <#local title="Disband fleets"> + <#local action="disband-fleets.action"> + <#break> + +<@page title=title> +
+ <@render_selected_fleets fleets=data.fleets /> + <#switch dataType> + <#case 'MoveFleetsResponse'> + <@render_move_fleets /> + <#break> + <#case 'RenameFleetsResponse'> + <@render_rename_fleets /> + <#break> + <#case 'SetFleetsModeResponse'> + <@render_set_fleets_mode /> + <#break> + <#case 'DisbandFleetsResponse'> + <@render_disband_fleets /> + <#break> + +
+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/getNewPlanet.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/getNewPlanet.ftl new file mode 100644 index 0000000..4534ee5 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/getNewPlanet.ftl @@ -0,0 +1,17 @@ +<#macro render> +<@page title="Get new planet"> +

Hordes of drooling barbarians invaded your empire, slaughtering your women and raping your cattle?

+

Well, fear no more! You will be able to get a brand new planet.

+

Please note that doing this will disband your fleets.

+ <@form action="get-planet" name="get-planet"> + <#switch data.error!> + <#case "EMPTY"><@form_error>Please select a planet name.<#break> + <#case "INVALID"><@form_error>Invalid planet name.<#break> + <#case "UNAVAILABLE"><@form_error>This planet name is unavailable.<#break> + <#case "BANNED"><@form_error>This planet name has been banned.<#break> + + <@form_text name="name" label="New planet's name" value=data.name! /> + <@form_submit label="Get planet" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/maintenance.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/maintenance.ftl new file mode 100644 index 0000000..0b3dcd7 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/maintenance.ftl @@ -0,0 +1,16 @@ +<#macro render><@page title="Server under maintenance"> + <@dt_main title="The server is currently under maintenance."> + <@dt_entry title="Maintenance mode activated">${data.start?string("yyyy-MM-dd HH:mm")} + <@dt_entry title="Current server time">${data.current?string("yyyy-MM-dd HH:mm")} + <@dt_entry title="Planned end of maintenance"> + <#if data.late> + + + ${data.end?string("yyyy-MM-dd HH:mm")} + <#if data.late> + + + + <@dt_entry title="Reason">${data.reason?xhtml} + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/map.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/map.ftl new file mode 100644 index 0000000..0e33d71 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/map.ftl @@ -0,0 +1,83 @@ +<#macro render_system system tags> + + <#list system.planets as planet> + <#if tags> + <#if planet.tag?has_content> + <#assign vName = "[${planet.tag}]"> + <#else> + <#assign vName = "N/A"> + + <#else> + <#assign vName = planet.name> + + <#if planet.tag?has_content> + <#assign vTitle = " [${planet.tag}]" > + <#else> + <#assign vTitle = "" > + + <#if planet.relation?has_content> + <#switch planet.relation> + <#case "OWN"> + <#assign lStyle = "class='own-planet'" > + <#break> + <#case "ALLIED"> + <#assign lStyle = "class='allied-planet'" > + <#break> + <#case "ENEMY"> + <#assign lStyle = "class='enemy-planet'" > + <#break> + + <#elseif planet.tag?has_content> + <#assign lStyle = "class='other-planet'" > + <#else> + <#assign lStyle = "" > + + + + + +<#macro render_map size systems tags> + + + <#list systems as row> + + <#list row as system> + <#if system?has_content> + <@render_system system=system tags=tags /> + <#else> + + + + + + +
(unexplored)
+ +<#macro render> +<@page title="Map"> + + <@lineform action="move-map"> + Coordinates: ( <@ff_text name="x" id="x" maxLength=4 size=5 value=data.x?string /> ; + <@ff_text name="y" id="y" maxLength=4 size=5 value=data.y?string /> ) + Size: <@ff_select id="sz" name="sz"> + <#list data.sizes as size> + <@form_option text=size value=size_index selected=( size_index == data.sizeOrdinal ) /> + + + <@ff_submit label="Centre map" /> + + + <@tabs> + <@tab id="names" title="Planets"> + <@render_map size=data.sizeOrdinal systems=data.systems tags=false /> + + <@tab id="alliances" title="Alliances"> + <@render_map size=data.sizeOrdinal systems=data.systems tags=true /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/message.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/message.ftl new file mode 100644 index 0000000..c1f7cd8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/message.ftl @@ -0,0 +1,115 @@ +<#macro render_navigation message inbox> + <#if inbox> + <#local link="inbox-message-"> + <#else> + <#local link="outbox-message-"> + + + + + + + +
+ <#if message.previous?has_content> + + + << + <#if message.previous?has_content> + + + + <#if inbox> + Received messages + <#else> + Sent messages + + + <#if message.next?has_content> + + + >> + <#if message.next?has_content> + + +
+ +<#macro render> +<#if data.inbox> + <#local title="Received messages"> + <#local timeTtl="Received"> +<#else> + <#local title="Sent messages"> + <#local timeTtl="Sent"> + +<#switch data.message.type> + <#case 'INTERNAL'> + <#local mColor="#ffffaf"> + <#break> + <#case 'ADMINISTRATOR'> + <#local mColor="#ffafaf"> + <#break> + <#case 'ALLIANCE'> + <#local mColor="#afafff"> + <#break> + <#case 'EMPIRE'> + <#local mColor="#afafaf"> + <#break> + +<@page title=title> + <@render_navigation message=data.message inbox=data.inbox /> + + <@dt_main> + <@dt_entry width=100 title="From"> + <#if data.inbox> + + + ${data.message.sender!} + <#if data.inbox> + + + + <@dt_entry width=100 title="To"> + <#if !data.inbox> + + + ${data.message.receiver!} + <#if !data.inbox> + + + + <@dt_entry width=100 title=timeTtl> + <@abbr_gt />: <@game_time record=data.message.gameTime /> / <@abbr_st />: ${data.message.time?string("yyyy-MM-dd HH:mm:ss")} + + <#if data.message.unread> + <@dt_entry width=100 title="">New! + + + + <@listview><@lv_line headers=true>  + +

${data.message.title}

+
+ ${data.message.contents} +
+ + <@listview><@lv_line headers=true>  + <@lineform action="message"> + + + <#if data.message.previous?has_content> + <#local afterDelete = data.message.previous> + <#elseif data.message.next?has_content> + <#local afterDelete = data.message.next> + <#else> + <#local afterDelete = "x"> + + + <@ff_submit label="Delete message" name="delete" /> + <#if data.inbox && data.message.type != 'INTERNAL'> + <@ff_submit label="Compose reply" name="reply" /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageBox.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageBox.ftl new file mode 100644 index 0000000..8b9db23 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageBox.ftl @@ -0,0 +1,125 @@ +<#include "messageTabs.ftl" /> +<#macro render_navigation current total inbox> + <#if inbox> + <#local link="inbox-"> + <#else> + <#local link="outbox-"> + + + + + + + +
+ <#if current gt 0> + + + << + <#if current gt 0> + + + + <#if total gt 0> + Page ${current + 1} / ${total} + <#elseif inbox> + No messages received. + <#else> + No messages sent. + + + <#if current lt total - 1> + + + >> + <#if current lt total - 1> + + +
+ +<#macro render> +<#if data.inbox> + <#local title="Received messages"> + <#local tab="inbox"> +<#else> + <#local title="Sent messages"> + <#local tab="outbox"> + +<@page title=title> + <@messageTabs selected=tab /> + <@render_navigation current=data.cPage total=data.pages inbox=data.inbox /> + <#if data.messages?size gt 0> +
+
+ + +
+ <@listview> + + <@lv_line headers=true> + <@lv_column width=16 centered=true>  + <@lv_column width="x">Subject + <@lv_column width=150 centered=true><#if data.inbox>From<#else>To + <@lv_column width=150 centered=true><#if data.inbox>Received<#else>Sent + + + <#list data.messages as message> + <#switch message.type> + <#case 'INTERNAL'> + <#local mType="int-msg"> + <#break> + <#case 'ADMINISTRATOR'> + <#local mType="admin-msg"> + <#break> + <#case 'ALLIANCE'> + <#local mType="alliance-msg"> + <#break> + <#case 'EMPIRE'> + <#local mType="empire-msg"> + <#break> + + <#if ! message.read> + <#local mType = "${mType} unread-msg"> + + + <@lv_line class=mType> + <@lv_column centered=true> + + + <@lv_column>${message.title} + <@lv_column centered=true>${message.sender!} + <@lv_column centered=true>${message.time?string("yyyy-MM-dd HH:mm:ss")} + + + + + <#if data.inbox> +
+ With + <@ff_select name="target" id="target"> + <@form_option value="0">selected + <@form_option value="1">all + + messages: + <@ff_select name="action" id="action"> + <@form_option value="r">mark as read + <@form_option value="u">mark as unread + <@form_option value="d">delete + + <@ff_submit label="Go" /> +
+ <#else> +
+ + Delete + <@ff_select name="target" id="target"> + <@form_option value="0">selected + <@form_option value="1">all + + messages <@ff_submit label="Go" /> +
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageTabs.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageTabs.ftl new file mode 100644 index 0000000..bfb7ecf --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageTabs.ftl @@ -0,0 +1,11 @@ +<#macro messageTab href title selected=false eClass=""> + ${title} + +<#macro messageTabs selected> +
+ <@messageTab href="messages" title="Received" selected=( selected = 'inbox' ) /> + <@messageTab href="outbox" title="Sent" selected=( selected = 'outbox' ) /> + <@messageTab href="compose-message" title="Compose" selected=( selected = 'compose' ) /> + <@messageTab href="chat" title="Chat" eClass="open-chat-button" /> +
+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageTargets.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageTargets.ftl new file mode 100644 index 0000000..78b1c96 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageTargets.ftl @@ -0,0 +1,62 @@ +<#include "messageTabs.ftl" /> +<#macro render> +<@page title="Recipients"> + <@messageTabs selected="compose" /> + + <@tabs> + + <#if data.empires?size gt 0> + <@tab id="empires" title="Empires"> + + <#list data.empires as empire> + <#if empire_index % 3 == 0> + + <#if empire_index % 3 == 2> + + <#if data.empires?size % 3 == 1> + + <#elseif data.empires?size % 3 == 2> + + +
+ <#else> + + + ${empire.name?xhtml}
  
 
+ + + + <#if data.alliances?size gt 0> + <@tab id="alliances" title="Alliances"> + <@listview> + <#list data.alliances as alliance> + <@lv_line> + [${alliance.tag?xhtml}]   + ${alliance.name} + + + + + + + <#if data.admins?size gt 0> + <@tab id="admins" title="Administrators"> + <@listview> + <#list data.admins as admin> + <@lv_line> + ${admin.name?xhtml}   + + <#list admin.privileges as priv> + ${priv} + + + +   + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageWriter.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageWriter.ftl new file mode 100644 index 0000000..4499f4f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/messageWriter.ftl @@ -0,0 +1,82 @@ +<#include "messageTabs.ftl" /> +<#macro render> +<#if data.replyTo?has_content> + <#local title="Reply to message"> +<#else> + <#local title="Compose new message"> + +<@page title=title> + <@messageTabs selected="compose" /> + +
+
+ <#if data.replyTo?has_content> + + + + + + <#if data.timingError> + <@form_error>Not so fast! Wait a few seconds before trying again. + + + <#-- Message recipient --> + <#if data.targetError> + <@form_error>Message recipient not found. + + <@form_select label="Recipient type" name="toType"> + <@form_option value="EMPIRE" selected=( data.messageType = 'EMPIRE' )>Empire + <@form_option value="ALLIANCE" selected=( data.messageType = 'ALLIANCE' )>Alliance + <@form_option value="ADMINISTRATOR" selected=( data.messageType = 'ADMINISTRATOR' )>Administrator + + <@form_text label="Recipient name" name="toName" maxLength=48 value=data.target /> + <#if (data.target == "")> + + + + <#-- Subject --> + <#if data.titleError> + <@form_error>Subject is too short (min.: 2 characters) + + <@form_text label="Subject" name="title" maxLength=64 value=data.title /> + + <#-- Body --> + <#if data.contentsError> + <@form_error>Contents are too short (min.: 2 characters) + + <@form_text label="Contents" name="contents" value=data.contents multiline=true maxLength=10 /> + + <@form_extended_submit label="Send message"> + <@ff_submit label="Cancel" name="cancel" /> + +
 Select from list...
+ +
+
+ + <#-- Original message --> + <#if data.replyTo?has_content> + <@listview><@lv_line headers=true>  + <@dt_main> + <@dt_entry width=100 title="">Original message: + <@dt_entry width=100 title="From"> + ${data.replyTo.sender!} + + <@dt_entry width=100 title="To"> + ${data.replyTo.receiver!} + + <@dt_entry width=100 title="Received"> + <@abbr_gt />: <@game_time record=data.replyTo.gameTime /> / <@abbr_st />: ${data.replyTo.time?string("yyyy-MM-dd HH:mm:ss")} + + + + <@listview><@lv_line headers=true>  + +

${data.replyTo.title}

+
+ ${data.replyTo.contents} +
+ + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/offline.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/offline.ftl new file mode 100644 index 0000000..772290b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/offline.ftl @@ -0,0 +1,9 @@ +<#macro render><@page title="Server off-line"> +

The game server could not be reached.

+

+ It may be under maintenance, or it may have crashed. In any case, the staff will receive a notification of the problem. +

+

+ Sorry for the inconvenience. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/overview.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/overview.ftl new file mode 100644 index 0000000..af04b79 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/overview.ftl @@ -0,0 +1,118 @@ +<#macro render> +<@page title="Empire"> + + <#assign ov = data.overview > + <#assign rs = data.research > + + <@tabs> + + <@tab id="overview" title="Overview"> + <@left_column> + + <#assign nplanets = data.page.planets?size> + <@dt_main title="Fleets & planets"> + <@dt_entry title="Number of planets">${nplanets?string(",##0")} + <@dt_entry title="Total population">${ov.population?string(",##0")} + <@dt_entry title="Average happiness"><@happiness value=data.overview.avgHappiness /> + <@dt_entry title="Total fleet power">${ov.fleetPower?string(",##0")} + + + <@dt_main title="Battles"> + <#if data.battles?size gt 0> + <@dt_status>We are involved in the following battle(s): + <#list data.battles as battle> + <@dt_status>${battle.location.name?xhtml} + (${battle.x},${battle.y};${battle.orbit}) + + <#else> + <@dt_status>We are not involved in any battle at the moment. + + <@dt_status> + View all battles + + + + + + <@right_column> + + <@dt_main title="Money"> + <@dt_entry title="Cash reserves">${data.page.cash?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Planet income">${ov.planetIncome?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Planet upkeep">${ov.planetUpkeep?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Fleet upkeep">${ov.fleetUpkeep?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Investments">${ov.investment?string(",##0")} <@abbr_bgc/> + + + <@dt_main title="Messages"> + <@dt_status> + <#if ov.newMessages == 0> + No new messages. + <#elseif ov.newMessages == 1> + You have a new message. + <#else> + You have ${ov.newMessages} new messages. + + + <@dt_status> + Compose a message + + + + + + + <@tab id="research" title="Research"> + <#if rs?size == 0> +

Our scientists are still settling in.

+ + <#list rs as research> +
+

${research.name?xhtml}

+

${research.description?xhtml}

+ + <@left_column> + <#if research.implemented?size == 0> +

No usable technologies.

+ <#else> + <@dt_main> + <#list research.implemented as tech> + <@dt_status> + ${tech.name?xhtml} +
${tech.description?xhtml}
+ + + + + + + <#if research.current?has_content> + <@right_column> + <@dt_main> + <@dt_status> + Current research: ${research.current.name?xhtml} +

+ ${research.current.description?xhtml} +

+ + <@dt_entry title="Progress">${research.current.researched}% + <#if research.current.cost?has_content> + <@dt_entry title="Cost">${research.current.cost?string(",##0")} <@abbr_bgc/> + <#if data.page.cash gte research.current.cost && data.page.special! != 'v'> + <@dt_status>
+
<@ff_submit label="Implement technology" />
+
+ + + + + + +
+ + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/passwordRecovery.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/passwordRecovery.ftl new file mode 100644 index 0000000..f18054c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/passwordRecovery.ftl @@ -0,0 +1,69 @@ +<#macro render> +<@page title="Password recovery"> + <@tabs> + + <@tab title="Request password recovery" id="request-recovery"> + <#if data.sent?has_content> +

An email has been sent to your address, ${data.mail?xhtml}

+

It contains a one-time authentication code you can use to change your password.

+

The authentication code will expire in one hour, and you will not be able to request another code until it expires.

+ <#else> + + <@form name="req-pwd-recovery" action="request-password-recovery"> + <#switch data.status!> + <#case "INVALID_INPUT"> + <@form_error>Invalid e-mail address. + <#break> + <#case "ACCOUNT_NOT_FOUND"> + <@form_error>Unknown e-mail address. + <#break> + <#case "ACCOUNT_STATUS"> + <@form_error>The account's status prevents password recovery. + <#break> + <#case "RECOVERY_IN_PROGRESS"> + <@form_error>A password recovery request has been made within the last hour. + <#break> + <#case "MAIL_ERROR"> + <@form_error>Unable to send e-mail. + <#break> + + <@form_text label="E-mail address" name="mail" id="req-mail" value=data.mail! maxLength=128 /> + <@form_submit label="Request password recovery" extraClass="" /> + + + + + + <@tab id="confirm-recovery" title="Confirm password recovery"> + <@form name="conf-pwd-recovery" action="confirm-password-recovery" hash="confirm-recovery"> + <#switch data.cStatus!> + <#case "INVALID_MAIL"> + <@form_error>Invalid e-mail address. + <#break> + <#case "NOT_FOUND"> + <@form_error>Unknown e-mail address or code. + <#break> + <#case "ACCOUNT_STATUS"> + <@form_error>The account's status prevents password recovery. + <#break> + <#case "WEAK_PASSWORD"> + <@form_error>New password too weak. + <#break> + <#case "MISMATCH_PASSWORD"> + <@form_error>Password and password confirmation did not match. + <#break> + <#case "PROHIBITED"> + <@form_error>You may not use this password. + <#break> + + <@form_text label="E-mail address" name="mail" id="conf-mail" value=data.cMail! maxLength=128 /> + <@form_text label="Confirmation code" name="code" id="conf-code" value=data.cCode! maxLength=64 /> + <@form_pwd label="New password" name="password" id="conf-pwd1" /> + <@form_pwd label="Confirm new password" name="passwordConfirm" id="conf-pwd2" /> + <@form_submit label="Set new password" /> + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/planet.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/planet.ftl new file mode 100644 index 0000000..f32d709 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/planet.ftl @@ -0,0 +1,329 @@ +<#macro render> +<#if ! data.basic?has_content> +<@page title="Planet not found"> +

This planet does not exist.

+ +<#return> + +<@page title="Planet ${data.basic.name}"> + <#if data.ownershipError> + <@standalone_error>Unfortunately, we no longer control this planet. + + + <@tabs> + + <@tab id="general" title="General"> +
+
+ ${data.basic.name?xhtml} +
+ + <@left_column width=250> + <@dt_main> + <@dt_entry title="Coordinates">(${data.basic.x},${data.basic.y};${data.basic.orbit}) + <#if data.basic.alliance?has_content> + <@dt_entry title="Alliance">${data.basic.alliance} + <#else> + <@dt_blank /> + + + <#if data.orbit?has_content> + <@dt_entry title="Population">${data.orbit.population?string(",##0")} + <@dt_entry title="Stationary defence">${data.orbit.defencePoints?string(",##0")} + + + <#if data.own?has_content> + <@dt_entry title="Happiness"><@happiness value=data.own.happiness /> <@happiness_change value=data.own.hChange /> + <@dt_entry title="Income">${data.own.income?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Upkeep">${data.own.upkeep?string(",##0")} <@abbr_bgc/> + + + + + <@right_column width=250> + <#if data.orbit?has_content> + <@dt_main> + + <#if data.orbit.ownFleet gt 0> + <@dt_entry title="Own fleet power">${data.orbit.ownFleet?string(",##0")} + <#else> + <@dt_blank /> + + + <#if data.orbit.friendlyFleet gt 0> + <@dt_entry title="Friendly fleet power">${data.orbit.friendlyFleet?string(",##0")} + <#else> + <@dt_blank /> + + + <#if data.orbit.hostileFleet gt 0> + <@dt_entry title="Hostile fleet power">${data.orbit.hostileFleet?string(",##0")} + <#else> + <@dt_blank /> + + + <#if data.orbit.battle?has_content> + <@dt_entry title="">View battle + <#else> + <@dt_blank /> + + + <@dt_blank /><@dt_blank /><@dt_blank /><@dt_blank /><@dt_blank /> + + + + +
+ + <#if data.own?has_content> + <#if data.own.status.renamePossible && data.page.special! != 'v'> + <#switch data.renameError!> + <#case "EMPTY"><@standalone_error>Please specify a name.<#break> + <#case "INVALID"><@standalone_error>Invalid planet name.<#break> + <#case "UNAVAILABLE"><@standalone_error>This planet name already exists.<#break> + <#case "BANNED"><@standalone_error>This name is banned.<#break> + + <@lineform action="planet-${data.id}-rename" name="rename" hash="general"> + <#if data.renamingTo?has_content> + <#assign newName = data.renamingTo!> + + Rename planet to <@ff_text name="name" id="rename-name" maxLength=20 size=21 value=newName! /> + <@ff_submit label="Rename planet" /> + + + + <#if data.own.status.abandonPossible && data.page.special! != 'v'> + <@lineform action="planet-${data.id}-abandon" name="abandon" hash="general"> + <@ff_submit label="Abandon planet" /> + + <#elseif data.own.status.abandonTime gt 0> + <@lineform action="planet-${data.id}-cancel-abandon" name="abandon" hash="general"> + Abandoning planet in <@duration rTime=data.own.status.abandonTime gTime=data.own.status.abandonGameTime /> +   + <#if data.page.special! != 'v'> + <@ff_submit label="Cancel" /> + + + + + + + + <#if data.orbit?has_content> + + <#if data.orbit.buildings?size gt 0 || data.own?has_content> + <@tab id="buildings" title="Buildings"> + + <#if data.orbit.buildings?size gt 0> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Building + <@lv_column width=50 centered=true>Amount + <#if data.own?has_content> + <@lv_column width=150 centered=true>Production + <@lv_column width=50 centered=true>Jobs + <@lv_column width=100 centered=true>Upkeep + + + + <#list data.orbit.buildings as building> + <@lv_line> + <@lv_column> + ${building.name?xhtml} + <#if data.own?has_content> +
${building.description?xhtml}
+ + + <@lv_column centered=true>${building.amount?string(",##0")} + <#if data.own?has_content> + <@lv_column centered=true> + ${building.output?string(",##0")} + <#switch building.produces> + <#case "CASH">ind. production<#break> + <#case "DEF">defence<#break> + <#case "WORK">mil. output<#break> + <#case "POP">growth<#break> + + + <@lv_column centered=true>${building.jobs?string(",##0")} + <@lv_column centered=true>${building.upkeep?string(",##0")} <@abbr_bgc/> + + + + + <#else> + <@dt_main><@dt_status>No buildings on this planet. + + + <#if data.own?has_content> + <#if data.page.special! != 'v'> + <#if data.own.civQueue.appendPossible> + <@lineform name="build-civ" action="planet-${data.id}-build-civ" hash="buildings"> + Build <@ff_text name="amount" id="civ-build-amount" size=5 maxLength=4 value="" /> + <@ff_select name="type" id="civ-build-type"> + <@form_option value="0" text="(building type)" /> + <#list data.own.bBuildings as building> + <@form_option value=building.id text=building.name /> + + + <@ff_submit label="Add to queue" /> + +
+ <#list data.own.bBuildings as building> +
+ <@dt_main> + <@dt_status>${building.description?xhtml} + <@dt_entry title="Cost">${building.cost?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Upkeep">${building.upkeep?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Time to build"> + <#if building.time?has_content> + <@duration rTime=building.time gTime=building.gameTime /> + <#else> + N/A + + + <@dt_entry title="Jobs">${building.workers?string(",##0")} + <@dt_entry title="Production">${building.output?string(",##0")} + <#switch building.prodType> + <#case "CASH">ind. production<#break> + <#case "DEF">defence<#break> + <#case "WORK">mil. output<#break> + <#case "POP">growth<#break> + + + +
+ +
+ + <#if data.orbit.buildings?size gt 0> + <#if data.destructionFailed!false> + <@standalone_error>Trying to destroy too many buildings + + <@lineform name="destroy" action="planet-${data.id}-destroy" hash="buildings"> + Destroy <@ff_text name="amount" id="civ-destroy-amount" size=5 maxLength=4 value="" /> + <@ff_select name="type" id="civ-destroy-type"> + <@form_option value="0" text="(building type)" /> + <#list data.orbit.buildings as building> + <@form_option value=building.id text=building.name /> + + + <@ff_submit label="Add to queue" /> + + + + + + <#if data.own.civQueue.items?size gt 0> + <#if data.page.special! != 'v'> + <@lineform name="flush-civ-queue" action="planet-${data.id}-flush-civ" hash="buildings"> + Remove all items from the build queue (investments will be lost) + <@ff_submit label="Flush" /> + + + + <@listview> + <@lv_line headers=true> + <@lv_column width=80 centered=true>Amount + <@lv_column width="x">Nature + <@lv_column width=200 centered=true>Time + <@lv_column width=70 centered=true>Investment + + <#list data.own.civQueue.items as qItem> + <@lv_line> + <@lv_column centered=true>${qItem.amount?string(",##0")} + <@lv_column>${qItem.name} <#if qItem.destroy>(destruction)<#else>(construction) + <@lv_column centered=true> + <#if qItem.timeLeft?has_content> + <@duration rTime=qItem.timeLeft gTime=qItem.gameTimeLeft /> + <#else> + N/A + + + <@lv_column centered=true>${qItem.invested?string(",##0")} <@abbr_bgc/> + + + + + + + + + + <#if data.own?has_content> + <@tab id="ships" title="Shipyards"> + <#if data.page.special! != 'v'> + <#if data.own.milQueue.appendPossible> + <@lineform name="build-mil" action="planet-${data.id}-build-mil" hash="ships"> + Build <@ff_text name="amount" id="mil-build-amount" size=5 maxLength=4 value="" /> + <@ff_select name="type" id="mil-build-type"> + <@form_option value="0" text="(ship type)" /> + <#list data.own.bShips as ship> + <@form_option value=ship.id text=ship.name /> + + + <@ff_submit label="Add to queue" /> + +
+ <#list data.own.bShips as ship> +
+ <@dt_main> + <@dt_status>${ship.description?xhtml} + <@dt_entry title="Cost">${ship.cost?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Upkeep">${ship.upkeep?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Time to build"> + <#if ship.time?has_content> + <@duration rTime=ship.time gTime=ship.gameTime /> + <#else> + N/A + + + <@dt_entry title="Power">${ship.power?string(",##0")} + <@dt_entry abbr="OOFT" title="Orbit-to-orbit flight time"> + <@duration rTime=ship.flightTime gTime=ship.gameFlightTime /> + + +
+ +
+ + + + <#if data.own.milQueue.items?size gt 0> + <#if data.page.special! != 'v'> + <@lineform name="flush-mil-queue" action="planet-${data.id}-flush-mil" hash="ships"> + Remove all items from the build queue (investments will be lost) + <@ff_submit label="Flush" /> + + + + <@listview> + <@lv_line headers=true> + <@lv_column width=80 centered=true>Amount + <@lv_column width="x">Ship + <@lv_column width=200 centered=true>Time + <@lv_column width=70 centered=true>Investment + + <#list data.own.milQueue.items as qItem> + <@lv_line> + <@lv_column centered=true>${qItem.amount?string(",##0")} + <@lv_column>${qItem.name} + <@lv_column centered=true> + <#if qItem.timeLeft?has_content> + <@duration rTime=qItem.timeLeft gTime=qItem.gameTimeLeft /> + <#else> + N/A + + + <@lv_column centered=true>${qItem.invested?string(",##0")} <@abbr_bgc/> + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/planets.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/planets.ftl new file mode 100644 index 0000000..0321889 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/planets.ftl @@ -0,0 +1,167 @@ +<#macro render> +<@page title="Planets"> + <#assign pl = data.planets> + <#if pl?size == 0> +

We no longer own any planet.

+

Get a new planet?

+ <#else> + + <@tabs> + + <@tab id="general" title="General"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Name + <@lv_column width=90 centered=true>Coordinates + <@lv_column width=90 centered=true>Happiness + <@lv_column width=90 right=true>Population + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column centered=true>(${planet.x},${planet.y};${planet.orbit}) + <@lv_column centered=true><@happiness value=planet.happiness /> + <@lv_column right=true>${planet.population?string(",##0")} + + + + + + <@tab id="eco" title="Economy"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Name + <@lv_column width=110 right=true>Income + <@lv_column width=110 right=true>Upkeep + <@lv_column width=110 right=true>Profit + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column right=true>${planet.income?string(",##0")} <@abbr_bgc /> + <@lv_column right=true>${planet.upkeep?string(",##0")} <@abbr_bgc /> + <@lv_column right=true> + <#if planet.upkeep gt planet.income> + + + ${( planet.income - planet.upkeep )?string(",##0")} <@abbr_bgc /> + <#if planet.upkeep gt planet.income> + + + + + + + + + <@tab id="prod" title="Production"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Name + <@lv_column width=90 right=true>Military + <@lv_column width=90 right=true>Industrial + <@lv_column width=90 right=true>Growth inc. + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column right=true>${planet.militaryProduction?string(",##0")} + <@lv_column right=true>${planet.industrialProduction?string(",##0")} + <@lv_column right=true>${planet.growthProduction?string(",##0")} + + + + + + <@tab id="cons" title="Construction"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Name + <@lv_column width=200 centered=true>Current queue item + <@lv_column width=90 right=true>Investment + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column centered=true> + <#if planet.civAmount = 0> + N/A + <#else> + ${planet.civAmount?string(",##0")}x + ${planet.civName?xhtml} + <#if planet.civDestroy> + (destruction) + <#else> + (construction) + + + + <@lv_column right=true>${planet.civInvestment?string(",##0")} <@abbr_bgc /> + + + + + + <@tab id="ships" title="Shipyards"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Name + <@lv_column width=200 centered=true>Current queue item + <@lv_column width=90 right=true>Investment + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column centered=true> + <#if planet.milAmount = 0> + N/A + <#else> + ${planet.milAmount?string(",##0")}x + ${planet.milName?xhtml} + + + <@lv_column right=true>${planet.milInvestment?string(",##0")} <@abbr_bgc /> + + + + + + <@tab id="mil" title="Military"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Name + <@lv_column width=90 right=true>Stationary + <@lv_column width=90 right=true>Own fleets + <@lv_column width=90 right=true>Friendly + <@lv_column width=90 right=true>Hostile + + + <#list pl as planet> + <@lv_line> + <@lv_column> + <#if planet.battle?has_content> + + + ${planet.name?xhtml} + <#if planet.battle?has_content> + + + + <@lv_column right=true>${planet.fpStatic?string(",##0")} + <@lv_column right=true>${planet.fpOwn?string(",##0")} + <@lv_column right=true>${planet.fpFriendly?string(",##0")} + <@lv_column right=true>${planet.fpHostile?string(",##0")} + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/reactivation.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/reactivation.ftl new file mode 100644 index 0000000..803d61b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/reactivation.ftl @@ -0,0 +1,24 @@ +<#macro render> +<#if data.success> +<@page title="Account re-activation"> +

+ Your account was successfully re-activated. The confirmation code was sent to ${data.address}. +

+

+ One you've received this e-mail, please proceed to the confirmation page. +

+ +<#else> +<@page title="Account re-activation failed"> +

+ An error occurred while trying to send an e-mail to your address, ${data.address}. +

+

+ If your address is still valid, you might want to wait a bit and then try again. +

+

+ Or the server might be on crack, in which case you should drop the staff a line. +

+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/register.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/register.ftl new file mode 100644 index 0000000..bbbdb14 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/register.ftl @@ -0,0 +1,56 @@ +<#macro render> +<@page title="Register"> + <@form name="register" action="register"> + <#switch data.mailError!""> + <#case "EMPTY"> + <@form_error>Empty e-mail address. + <#break> + <#case "INVALID"> + <@form_error>Invalid e-mail address. + <#break> + <#case "IN_USE"> + <@form_error>This e-mail address is already associated with an account. + <#break> + <#case "SEND_FAIL"> + <@form_error>Unable to send confirmation code to this address. + <#break> + <#case "MISMATCH"> + <@form_error>E-mail address field and confirmation field do not match. + <#break> + <#default> + <@form_extra>The e-mail address MUST exist. + + <@form_text label="E-mail address" maxLength=128 name="mail" value=data.mail! /> + <@form_text label="E-mail address (confirm)" maxLength=128 name="mailConfirm" value=data.mail! /> + + <#switch data.passwordError!""> + <#case "EMPTY"> + <@form_error>Empty password. + <#break> + <#case "TOO_WEAK"> + <@form_error>This password is too weak. + <#break> + <#case "MISMATCH"> + <@form_error>Password field and confirmation field do not match. + <#break> + <#default> + <@form_extra>At least 6 characters, containing both text and numbers. Bonus points for special characters, spaces, and extremely long passwords. + + <@form_pwd label="Password" name="password" /> + <@form_pwd label="Password (confirm)" name="passwordConfirm" /> + + <@form_select name="language" label="Language"> + <#if dataType == "ListLanguagesResponse"> + <#assign lList = data.languages> + <#else> + <#assign lList = data.supportedLanguages.languages> + + <#list lList as lang> + <@form_option text=lang.name value=lang.id selected=(lang.id == language) /> + + + + <@form_submit label="Register" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/registered.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/registered.ftl new file mode 100644 index 0000000..a32d101 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/registered.ftl @@ -0,0 +1,13 @@ +<#macro render> +<@page title="Accound created"> +

+ Your account has been successfully created. +

+

+ An e-mail containing its confirmation code has been sent to your address, ${data.mail?xhtml}. +

+

+ Once you have received it, you will be able to log in and confirm your account. +

+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/splitFleet.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/splitFleet.ftl new file mode 100644 index 0000000..b469677 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/splitFleet.ftl @@ -0,0 +1,40 @@ +<#macro render> +<@page title="Split fleet"> +
+
+ + <#if data.shipsError> + <@standalone_error>Invalid amount(s) of ships or resulting fleets + + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Ship type + <@lv_column width=150>Initial amount + <@lv_column width=150>Amount in new fleet + + <#list data.ships as ships> + <@lv_line headers> + <@lv_column>${ships.name} + <@lv_column>${ships.amount?string(",##0")} + <@lv_column> + <@ff_text name="ships_${ships.id}" id="ships-${ships.id}" value=ships.selectedAmount /> + + + + + <#if data.nameError> + <@standalone_error>Invalid fleet name. + +

+ Create + <@ff_text name="nFleets" id="n-fleets" value=data.nFleets size=3 maxLength=2 /> + new fleet(s) named + <@ff_text name="name" id="name" value=data.name size=20 maxLength=40 /> +   + <@ff_submit label="Ok" /> + <@ff_submit label="Cancel" name="cancel" /> +

+
+
+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/static.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/static.ftl new file mode 100644 index 0000000..cbf01c8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/static.ftl @@ -0,0 +1 @@ +<#macro render><#if dataType == "HashMap"><#include "../static/${data.name}.ftl" /><#else><#include "../static/${data}.ftl" /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/validation.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/validation.ftl new file mode 100644 index 0000000..9a01b54 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/en/types/validation.ftl @@ -0,0 +1,50 @@ +<#macro render> +<@page title="Account validation"> + <@form action="validation" name="validation"> + <@form_extra> + Before you can proceed any further, you need to validate your account using the confirmation code that was e-mailed to you.
+ You will also be able to select the names of your empire and first planet. + + + <#if data.wrongToken> + <@form_error>Incorrect confirmation code. + + <@form_text label="Confirmation code" value=data.token! name="token" maxLength=64 /> + + <#switch data.empireError!> + <#case "EMPTY"><@form_error>Please select an empire name.<#break> + <#case "INVALID"><@form_error>Invalid empire name.<#break> + <#case "UNAVAILABLE"><@form_error>This empire name is unavailable.<#break> + <#case "BANNED"><@form_error>This empire name has been banned.<#break> + + + <#if data.previousEmpires?size == 0> + <@form_text label="Empire name" value=data.empire! name="empire" maxLength=20 /> + + <#else> + <@form_select name="old" label="Re-use empire name"> + <#list data.previousEmpires as oldName> + <@form_option text=oldName selected=( oldName == data.empire! ) /> + + + + <@form_extra>Leave this blank if you want to re-use a previous empire name. + <#if ! data.previousEmpires?seq_contains(data.empire!)> + <#assign empValue = data.empire!> + + <@form_text name="empire" label="New empire name" value=empValue! maxLength=20 /> + + + + <#switch data.planetError!> + <#case "EMPTY"><@form_error>Please select a planet name.<#break> + <#case "INVALID"><@form_error>Invalid planet name.<#break> + <#case "UNAVAILABLE"><@form_error>This planet name is unavailable.<#break> + <#case "BANNED"><@form_error>This planet name has been banned.<#break> + + <@form_text name="planet" label="Planet name" value=data.planet! maxLength=20 /> + + <@form_submit label="Join the game" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/chat.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/chat.ftl new file mode 100644 index 0000000..28deee5 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/chat.ftl @@ -0,0 +1,28 @@ +<#include "../game.ftl"> +<#macro page title hidePlanets=false> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ +
+

${title?xhtml}

+
+ +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/external.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/external.ftl new file mode 100644 index 0000000..040e9d7 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/external.ftl @@ -0,0 +1,44 @@ +<#macro page title> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ + Legacy Worlds Beta 6 <@version/> +
version courante : <@full_version/>
+
${title?xhtml}
+ + +
+
+
+ Adresse e-mail :
+ Mot de passe :
+ Mot de passe oubliƩ ? + +
+
+
+ + + PortĆ©e + RĆØgles + Inscription + +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/game.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/game.ftl new file mode 100644 index 0000000..2f8e922 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/game.ftl @@ -0,0 +1,70 @@ +<#include "../game.ftl"> +<#macro page title hidePlanets=false> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ Legacy Worlds Beta 6 <@version/> +
<@abbr_gt/>: <@game_time record=data.page.gameTime /> / <@abbr_st/>: ${data.page.serverTime?string("yyyy-MM-dd HH:mm:ss ZZZZZ")}
+ + +
+

${title?xhtml}

+ <#if !hidePlanets> +

 

+ <#if data.page.planets?size == 0> +

Obtenir une nouvelle planĆØte

+ <#else> +

Aller Ć  la planĆØte: + <#list data.page.planets as planet> + ${planet.name?xhtml} + +

+ + +
+ +
+ ${data.page.empire} + <#if data.page.alliance?has_content> + [${data.page.alliance}] +
+ ${data.page.cash?string(",##0")} <@abbr_bgc/>
+ <#if data.page.special?has_content> + + <#switch data.page.special> + <#case 'v'>EN VACANCES<#break> + <#case 's'>PRELIMINAIRES AUX VACANCES<#break> + <#case 'q'>EN TRAIN D'ABANDONNER<#break> + + + +
+ Compte - DĆ©connexion +
+ + PlanĆØtes + Flottes + Carte + Alliance + Listes d'ennemis + Messages + Suivi des bugs + +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/offline.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/offline.ftl new file mode 100644 index 0000000..9261f58 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/offline.ftl @@ -0,0 +1,27 @@ +<#macro page title> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ + Legacy Worlds Beta 6 <@version/> +
Version courante : <@full_version/>
+
${title?xhtml}
+ +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/restricted.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/restricted.ftl new file mode 100644 index 0000000..7f1db1a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/containers/restricted.ftl @@ -0,0 +1,33 @@ +<#macro page title> + + + + + Legacy Worlds Beta 6 <@version/> - ${title?xhtml} + + + + + +
+
+ + Legacy Worlds Beta 6 <@version/> +
Version courante : <@full_version/>
+
${title?xhtml}
+ + + + +
<#nested>
+
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/game.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/game.ftl new file mode 100644 index 0000000..81e8aa9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/game.ftl @@ -0,0 +1,66 @@ +<#macro game_time record> + <#if record.years == 1> + 1 an, + <#elseif record.years gt 1 > + ${record.years?string(",##0")} ans, + + <#if record.weeks == 1> + 1 semaine, + <#elseif record.weeks gt 1 > + ${record.weeks?string} semaines, + + <#if record.days == 1> + 1 jour + <#elseif record.days gt 1 > + ${record.days?string} jours, + <#else> + premier jour, + + ${record.hours?string("00")}:00 + +<#macro game_duration record> + <#if record.years == 1> + 1 an + <#elseif record.years gt 1 > + ${record.years?string(",##0")} ans + + <#if record.weeks == 1> + 1 semaine + <#elseif record.weeks gt 1 > + ${record.weeks?string} semaines + + <#if record.days == 1> + 1 jour + <#elseif record.days gt 1 > + ${record.days?string} jours + + <#if record.hours == 1> + 1 heure + <#elseif record.hours gt 1 > + ${record.hours?string} heures + + +<#macro rl_duration rTime> + <#local rlDays = (rTime / 1440)?floor> + <#local rlHours = ((rTime - rlDays * 1440) / 60)?floor> + <#local rlMinutes = (rTime - rlDays * 1440 - rlHours * 60)> + <#if rlDays gt 0> + <#if rlDays = 1>1 jour<#else>${rlDays} jours + + <#if rlHours gt 0> + <#if rlHours = 1>1 heure<#else>${rlHours} heures + + <#if rlMinutes gt 0> + <#if rlMinutes = 1>1 minute<#else>${rlMinutes} minutes + + +<#macro duration rTime gTime> + <#if data.page.useRLTime> + <@rl_duration rTime=rTime /> + <#else> + <@game_duration record=gTime /> + + +<#macro abbr_bgc>mcg +<#macro abbr_st>TS +<#macro abbr_gt>TJ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/home.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/home.ftl new file mode 100644 index 0000000..d23fb64 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/home.ftl @@ -0,0 +1,26 @@ +<@page title="Legacy Worlds Beta 6 - Jalon 1"> +

+ Bienvenue sur le premier jalon de la Beta 6 de Legacy Worls. +

+

 

+

+ Ceci n'est pas un jeu complet. En fait, la plupart des fonctionnalitĆ©s avancĆ©es de la Beta 5 ont Ć©tĆ© laissĆ©es de cĆ“tĆ©. + Mais il s'agit d'un bon point de dĆ©part pour le dĆ©veloppement de la Beta 6. La liste complĆØte des fonctionnalitĆ©s incluses dans cette version + peut ĆŖtre trouvĆ©e sur la page PortĆ©e. +

+

 

+

+ Vous trouverez plus d'informations sur le jeu lui-mĆŖme sur la page RĆØgles. Il s'agit basiquement + de ce dont vous avez l'habitude : contruire des choses, tuer des gens aux moyens des choses susnommĆ©es. Seuls les dĆ©tails ont changĆ©. +

+

 

+

+ Maintenant - c'est un peu inhabituel, mais puisque le but rĆ©el de cette version est de tester le systĆØme lui-mĆŖme, vous ĆŖtes encouragĆ©s Ć  crĆ©er + des comptes multiples. +

+

 

+

+ Bien que cette version puisse ĆŖtre jouĆ©e indĆ©pendamment de la Beta 5, elle ne dispose pas de forums (bien qu'un systĆØme + de rapport de bugs ait Ć©tĆ© inclus) ; il est donc recommandĆ© que vous joigniez la Beta 5 quoi qu'il en soit. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/loggedOut.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/loggedOut.ftl new file mode 100644 index 0000000..3218bb1 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/loggedOut.ftl @@ -0,0 +1,8 @@ +<@page title="DƩconnectƩ"> +

+ Vous avez ƩtƩ dƩconnectƩ de Legacy Worlds. +

+

+ Merci d'avoir jouƩ! +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/loginFailed.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/loginFailed.ftl new file mode 100644 index 0000000..f7be93d --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/loginFailed.ftl @@ -0,0 +1,8 @@ +<@page title="IdentitƩ invalide"> +

+ L'adresse e-mail et le mot de passe que vous avez entrƩs ne correspondent Ơ aucun compte existant. +

+

+ Veuillez rƩessayer. Si vous avez oubliƩ votre mot de passe, vous pouvez utiliser le service de rƩcupƩration de mot de passe. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/noSession.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/noSession.ftl new file mode 100644 index 0000000..0ac7423 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/noSession.ftl @@ -0,0 +1,8 @@ +<@page title="Automatiquement dƩconnectƩ"> +

+ Votre session a expirƩ et vous avez ƩtƩ dƩconnectƩ de Legacy Worlds. +

+

+ Vous devez vous reconnecter. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/passwordRecoveryOk.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/passwordRecoveryOk.ftl new file mode 100644 index 0000000..9e7693a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/passwordRecoveryOk.ftl @@ -0,0 +1,8 @@ +<@page title="RƩcupƩration de mot de passe rƩussie"> +

+ Votre demande de rĆ©cupĆ©ration de mot de passe a Ć©tĆ© traitĆ©e avec succĆØs. +

+

+ Vous pouvez maintenant vous connecter avec le mot de passe que vous venez de dƩfinir. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/reactivate.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/reactivate.ftl new file mode 100644 index 0000000..e55163d --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/reactivate.ftl @@ -0,0 +1,11 @@ +<@page title="Compte dƩsactivƩ"> +

+ Votre compte est actuellement dƩsactivƩ. +

+

+ Vous pouvez soit le laisser tel quel en vous dƩconnectant ou choisir de le rƩactiver. +

+

+ Veuillez noter que votre adresse e-mail doit toujours ĆŖtre valide si vous voulez rĆ©activer votre compte. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/rules.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/rules.ftl new file mode 100644 index 0000000..ed40d85 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/rules.ftl @@ -0,0 +1,116 @@ +<@page title="RĆØgles du jeu"> +

GƩnƩral

+

+ L'ensemble du jeu est basĆ© sur des mises Ć  jour toutes les minutes. Comme ces mises Ć  jour sont calculĆ©es en fonction du moment + oĆ¹ le serveur du jeu a dĆ©marrĆ©, elles peuvent intervenir Ć  tout moment. +

+

+ C'est pour cela qu'un temps du jeu est dƩfini. Il correspond Ơ la quantitƩ de mises Ơ jour qui ont ƩtƩ calculƩes. + Une "heure" de temps du jeu correspond Ơ une mise Ơ jour et, en gƩnƩral, Ơ une minute en temps du monde rƩel. +

+

+ Aucune vraie tentative pour atteindre un jeu Ć©quilibrĆ© n'a Ć©tĆ© fait. Il est donc trĆØs possible que certains aspects + des rĆØgles fonctionnent pas comme prĆ©vu. +

+

 

+ +

Finances & recherche

+

+ Les bĆ©nĆ©fices sont majoritairement produits par la population d'un empire. Alors que les bĆ©nĆ©fices et charges sont affichĆ©s + pour une durĆ©e de 24h en temps du monde rĆ©el, les rĆ©serves financiĆØres d'un empire augmentent (ou diminuent) en continu. + Les bĆ¢timents optionnels nommĆ©s Ligne de production gĆ©nĆ©rique apportent un revenu supplĆ©mentaire. +

+

+ La population gĆ©nĆØre aussi des points de recherche qui sont utilisĆ©s pour mettre Ć  jour les progrĆØs scientifiques d'un empire. + Quand une technologie atteint 100% de ses points de recherche requis, elle doit ĆŖtre appliquĆ©e, ce qui coĆ»te de l'argent. +

+

+ Deux jeux de trois technologies sont disponibles : les technologies civiles donnent accĆØs Ć  de nouveaux bĆ¢timents, + alors que les technologies militaires fournissent de nouveau types de vaisseaux. +

+

+ Si les rĆ©serves financiĆØres d'un empire atteignent 0 Ć  cause de charges trop Ć©levĆ©es, ses flottes vont commencer Ć  se + dĆ©grader. S'il ne possĆØde pas de flottes, alors ce sont les bĆ¢timents de ses planĆØtes qui commencent Ć  se dĆ©grader. +

+

+ Il est par contre possible qu'un empire atteigne 0 Ć  cause de la construction de bĆ¢timents ou vaisseaux. Dans ce cas, aucun + dommage ne sera infligĆ©, mais la construction sera ralentie. +

+

 

+ +

Gestion de planĆØte

+

+ Deux types de bĆ¢timents sont disponibles sans aucune technologie : les fabriques de piĆØces de vaisseaux (qui permettent la + construction de vaisseaux) et les tourelles dĆ©fensives (qui fournissent une dĆ©fense statique Ć  vos planĆØtes). +

+

+ La construction et la destruction de bĆ¢timents ne sont pas immĆ©diates. La vitesse Ć  laquelle les bĆ¢timents sont construits + ou dĆ©truits dĆ©pend de la population de la planĆØte considĆ©rĆ©e. Pendant la construction, le coĆ»t financier des bĆ¢timents + est prĆ©levĆ© dans les rĆ©serves de l'empire Ć  chaque mise Ć  jour. +

+

+ DĆ©truire des bĆ¢timents est bien plus rapide que les construire ; de plus, une petite partie du coĆ»t du bĆ¢timent est + restituĆ©e aux rĆ©serves financiĆØres de l'empire une fois que le bĆ¢timent a Ć©tĆ© dĆ©truit. +

+

+ La satisfaction d'une planĆØte est dĆ©terminĆ©e par trois facteurs : le nombre d'emplois fournis par les bĆ¢timents de la planĆØte + par rapport Ć  la population de la planĆØte, la puissance des dĆ©fenses statiques et la quantitĆ© de planĆØtes + possĆ©dĆ©es par l'empire. +

+

+ La satisfaction ne change pas immĆ©diatement quand un Ć©vĆ©nement l'affecte. L'Ć©volution est progressive et sa vitesse + dĆ©pend de son amplitude et de la population totale de la planĆØte. +

+

+ Quand la satisfaction d'une planĆØte est infĆ©rieure Ć  25%, ses habitants se mettent en grĆØve, ce qui rĆ©duit les bĆ©nĆ©fices, + la production et les dĆ©fenses de la planĆØte. +

+

+ La croissance de la population est directement proportionnelle Ć  la satisfaction de la planĆØte. +

+

 

+ +

Flottes et vaisseaux

+

+ Les vaisseaux sont construite sur les planĆØtes selon les mĆŖmes principes que les bĆ¢timents. Par contre, leur vitesse + de construction est dĆ©terminĆ©e par la production militaire de la planĆØte. +

+

+ Les vaisseaux ont deux caractĆ©ristiques : leur puissance, qui dĆ©termine leur efficacitĆ© au combat, et leur + temps de vol orbite-Ć -orbite, qui dĆ©termine leur vitesse et les diffĆ©rentes pĆ©nalitĆ©s qui peuvent ĆŖtre + infligĆ©es Ć  une flottes (redirection, redĆ©ploiement, etc.). +

+

+ La puissance d'une flotte correspond Ơ la somme des puissances des vaisseaux qui la composent. Son temps de vol orbite-Ơ-orbite + est dƩterminƩ par le vaisseau le plus lent de la flotte. +

+

+ Seules les flottes dont le statut est disponible peuvent ĆŖtre dĆ©placĆ©es, divisĆ©es ou fusionnĆ©es. En + complĆ©ment, les flottes dont le statut est dĆ©ploiement initial n'infligent pas de dommages pendant les + combats (par contre, elles peuvent ĆŖtre endommagĆ©es). Toutes les flottes peuvent ĆŖtre renommĆ©es, dissoutes ou + passĆ©es d'un mode Ć  l'autre (entre attaque et dĆ©fense), quel que soit leur statut. +

+

 

+ +

Batailles

+

+ Une bataille commence Ć  partir du moment une flotte offensive est prĆ©sente sur une planĆØte, et se termine quand toutes + les flottes offensives sont parties / ont Ć©tĆ© dĆ©truites, ou quand toutes les flottes dĆ©fensives et dĆ©fenses planĆ©taires + sont parties / ont Ć©tĆ© dĆ©truites. Dans ce dernier cas, l'attaquant dont la flotte est la plus puissante prend contrĆ“le + de la planĆØte Ć  la mise Ć  jour suivante. +

+

+ Les batailles sont mises Ơ jour toutes les minutes. En consƩquence, il n'y a pas de "rapports de bataille" ; Ơ la place, + un historique de la bataille et des ƩvƩnements qui ont eu lieu pendant la bataille est fourni. +

+

+ L'intensitƩ d'une bataille commence Ơ un faible niveau, augmentant progressivement au cours du temps jusqu'Ơ atteindre + l'intensitƩ maximale. Cette intensitƩ dƩtermine la quantitƩ de dommages infligƩs. +

+

+ Les dommages dus aux combats qui sont infligĆ©s que ce soit aux bĆ¢timents ou aux vaisseaux s'accumulent au cours du temps. + Il n'est pas possible de rĆ©parer vaisseaux ou bĆ¢timents. +

+

 

+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/scope.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/scope.ftl new file mode 100644 index 0000000..39a4f58 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/static/scope.ftl @@ -0,0 +1,58 @@ +<@page title="PortƩe de ce jalon"> +

+ Ce jalon consiste majoritairement en l'Ć©criture du moteur du jeu et des fonctionnalitĆ©s + administratives de base. De ce fait, le jeu lui-mĆŖme est trĆØs limitĆ©, + de mĆŖme que l'interface. +

+

 

+ +

Serveur du jeu

+

+ Le serveur du jeu tourne indƩpendamment de toute interface et est en charge de toutes les + fonctionnalitƩs administratives et de jeu. Cette version est focalisƩe sur : +

+
    +
  • bases systĆØme - enregistrement de fichiers journal, accĆØs en cours d'exĆ©cution + Ć  des "constantes" liĆ©es au jeu, internationalisation, communications avec les interfaces utilisateur,
  • +
  • comptes - depuis l'enregistrement jusqu'aux prĆ©fĆ©rences et Ć  la gestion de l'inactivitĆ©,
  • +
  • systĆØme de nommage - les noms de toutes les entitĆ©s au sein du jeu (empires et + planĆØtes dans cette version) sont gĆ©rĆ©es par le mĆŖme sous-systĆØme,
  • +
  • systĆØme de suivi des bugs - parce qu'il ne sera pas possible d'inclure de forums avant + d'ĆŖtre bien plus loin dans le cycle de dĆ©veloppement du jeu, le systĆØme de suivi des bugs est un outil + essentiel,
  • +
  • ordonnanceur - parce que les mises Ć  jour ont quand mĆŖme besoin d'ĆŖtre d'ĆŖtre calculĆ©es, + parfois.
  • +
+

 

+ +

Administration du serveur

+

+ L'administration du serveur est l'une des composantes principales de cette version, bien que + la plupart des gens ne la verront (on peut l'espĆ©rer) jamais. Elle est implantĆ©e comme une + interface utilisateur sĆ©parĆ©e qui accĆØde au serveur par son interface de communication externe. + L'interface d'administration inclut : +

+
    +
  • systĆØme de droits (tous les administrateurs ne sont pas Ć©gaux),
  • +
  • gestion des comptes,
  • +
  • accĆØs aux paramĆØtres du jeu,
  • +
  • administration du suivi des bugs,
  • +
  • validation de noms,
  • +
  • affichage des fichiers journal,
  • +
  • rapports d'erreurs automatisĆ©s.
  • +
+

 

+ +

Jeu et interface

+

+ Bien que je jeu n'apporte rien de rĆ©ellement nouveau, il est basĆ© sur un systĆØme de mise Ć  + jour Ć  la minute. Son interface n'est probablement pas appropriĆ©e, du fait que la disposition + de l'interface externe de la Beta 5 est un peu restreinte quand il s'agit d'afficher toutes + les informations requises au sein du jeu. Cette interface est quoi qu'il en soit temporaire. +

+

+ Cette version est disponible en deux langues - anglais et franƧais - parce que le systĆØme + d'internationalisation a besoin d'ĆŖtre testĆ©. Mais il est extrĆŖmement probable que les futurs + jalons ne seront disponibles qu'en anglais. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/account.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/account.ftl new file mode 100644 index 0000000..6f1f622 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/account.ftl @@ -0,0 +1,220 @@ +<#macro render_preference pref> + <#switch pref.type> + <#case 'BOOLEAN'> + <@form_select label=pref.name name=pref.id id="pref-${pref.id}"> + <@form_option value="0" text="Non" selected=( pref.value != "1" )/> + <@form_option value="1" text="Oui" selected=( pref.value == "1" )/> + + <#break> + <#case 'INTEGER'> + <#case 'STRING'> + <@form_text label=pref.name name=pref.id id="pref-${pref.id}" value=pref.value /> + <#break> + <#case 'CHOICE'> + <@form_select label=pref.name name=pref.id id="pref-${pref.id}"> + <#list pref.choices as choice> + <@form_option value=choice.value text=choice.display selected=( pref.value == choice.value )/> + + + <#break> + + <#if pref.description?has_content> + <@form_extra>${pref.description?xhtml} + + +<#macro render_prefs_category category> + <@form_part title=category.name /> + <#list category.preferences as p> + <@render_preference pref=p /> + + +<#macro render> +<@page title="Compte"> + <@tabs> + + <@tab id="prefs" title="PrĆ©fĆ©rences"> + <@form name="prefs-form" action="set-preferences" hash="prefs"> + <#list data.account.preferences as c> + <@render_prefs_category category=c /> + + <@form_extended_submit label="Changer les prĆ©fĆ©rences"> + <@ff_submit label="DĆ©fauts" name="load-default-preferences" /> + + + + + <@tab id="basics" title="IdentitĆ©"> + <@form name="lang-form" action="set-language" hash="basics"> + <@form_part title="Langue du compte" /> + <@form_select name="language" label="Langue "> + <#list data.account.supportedLanguages.languages as lang> + <@form_option text=lang.name value=lang.id selected=(lang.id == data.account.language) /> + + + <@form_submit label="Mettre Ć  jour" /> + + + <@form name="pwd-form" action="set-password" hash="basics"> + <@form_part title="Changement de mot de passe" /> + <#if data.authError!false> + <@form_error>Mot de passe incorrect + + <@form_pwd label="Mot de passe actuel " name="current" /> + <#switch data.passwordError!""> + <#case "EMPTY"> + <@form_error>Mot de passe vide. + <#break> + <#case "TOO_WEAK"> + <@form_error>Ce mot de passe est trop faible. + <#break> + <#case "MISMATCH"> + <@form_error>Le mot de passe et sa confirmation ne sont pas identiques. + <#break> + <#case "PROHIBITED"> + <@form_error>Vous ne pouvez pas utiliser ce mot de passe ici. + <#break> + <#default> + <@form_extra>Au moins 6 caractĆØres, incluant Ć  la fois des lettres et des chiffres. Bonus pour les caractĆØres spĆ©ciaux, les espaces et les mots de passe extrĆØmement longs. + + <@form_pwd label="Mot de passe " name="password" /> + <@form_pwd label="Mot de passe (confirmation) " name="passwordConfirm" /> + <@form_submit label="Mettre Ć  jour" /> + + + <#if data.account.mailChange?has_content> + <#local mc = data.account.mailChange> + <#if mc.used> + <@form name="mail-form" action="set-address" hash="basics"> + <@form_part title="Changement d'adresse e-mail" /> + + Adresse actuelle : + ${data.account.address?xhtml} + + <@form_extra> + Vous pourrez demander un changement d'adresse e-mail Ć  ${mc.until?string("HH:mm:ss (ZZZZZ)")}. + + + <#else> + <@form name="mail-form" action="confirm-set-address" hash="basics"> + <@form_part title="Changement d'adresse e-mail" /> + + Adresse actuelle : + ${data.account.address?xhtml} + + <@form_extra> + Vous ĆŖtes en train de demander un changement d'adresse e-mail pour ${mc.newAddress?xhtml}.
+ Votre requĆŖte va expirer Ć  ${mc.until?string("HH:mm (ZZZZZ)")}. + + <#if data.codeError!false> + <@form_error>Code de confirmation erronĆ© + + <@form_text name="code" id="mail-confirmation-code" value="${data.code!}" maxLength=64 label="Code de confirmation" /> + <@form_extended_submit label="Changer d'adresse"> + <@ff_submit label="Annuler" name="cancel-set-address" /> + + + + <#else> + <@form name="mail-form" action="set-address" hash="basics"> + <@form_part title="Changement d'adresse e-mail" /> + <#if data.mailAuthError!false> + <@form_error>Mot de pase erronĆ© + + + Current address: + ${data.account.address?xhtml} + + <@form_pwd label="Mot de passe actuel " name="password" id="current-2" /> + <#switch data.mailError!""> + <#case "EMPTY"> + <@form_error>Adresse e-mail vide. + <#break> + <#case "INVALID"> + <@form_error>Adresse e-mail invalide. + <#break> + <#case "IN_USE"> + <@form_error>Cette adresse e-mail est dĆ©jĆ  associĆ©e Ć  un compte. + <#break> + <#case "SEND_FAIL"> + <@form_error>Impossible d'envoyer un code de confirmation Ć  cette adresse. + <#break> + <#case "MISMATCH"> + <@form_error>L'adresse e-mail et sa confirmation ne sont pas identiques. + <#break> + <#default> + <@form_extra>L'adresse e-mail DOIT exister. + + <@form_text label="Adresse e-mail " maxLength=128 name="mail" value=data.mail! /> + <@form_text label="Adresse e-mail (confirmation) " maxLength=128 name="mailConfirm" value=data.mail! /> + <@form_submit label="Mettre Ć  jour" /> + + + + + <@tab id="status" title="Statut"> + <@form name="game-credits" action="no-action" hash="status"> + <@form_part title="CrĆ©dits de jeu" /> + + CrĆ©dits de jeu: + ${data.account.gameCredits?string(',##0')} + + <@form_extra> + Les crĆ©dits de jeu ne peuvent pas ĆŖtre utilisĆ©s actuellement. Par contre, ils seront accumulĆ©s au cours du cycle de dĆ©veloppement de LWB6. + Vous les obtenez en rapportant des bugs. + + + + <@form name="vacation-form" action="toggle-vacation" hash="status"> + <@form_part title="Mode vacances" /> + + CrĆ©dits de vacances : + ${data.account.vacCredits?string(',##0')} + + + DurĆ©e maximale : + + <#if data.account.vacTime?has_content> + approximativement <@game_duration record=data.account.vacTime /> + <#else> + moins d'une heure + + + + <#if data.account.vacStart?has_content> + + DĆ©but de vacances : + ${data.account.vacStart?string("HH:mm (yyyy-MM-dd ZZZZZ)")} + + <#if data.page.special == 'v'> + <@form_submit label="Quitter le mode vacances" /> + <#else> + <@form_submit label="Annuler le mode vacances" /> + + <#elseif !data.page.special?has_content && data.account.vacTime?has_content> + <@form_submit label="Entrer en mode vacances" /> + + + + <#if !data.page.special?has_content> + <@form name="quit-form" action="quit" hash="status"> + <@form_part title="Quitter le jeu" /> + <@form_extra> + Si vous cliquez le bouton ci-dessous, votre compte sera dĆ©sactivĆ© aprĆØs un dĆ©lai de 24h. Vous pourrez le rĆ©activer pendant les 6 prochains mois, dĆ©lai aprĆØs lequel il sera supprimĆ©. + + <@form_text label="Raison de quitter (optionel) " name="reason" value="" /> + <@form_submit label="Quitter le jeu" /> + + <#elseif data.page.special == 'q'> + <@form name="quit-form" action="cancel-quit" hash="status"> + <@form_part title="Quitter le jeu" /> + <@form_extra> + Votre compte sera dĆ©sactivĆ© Ć  ${data.account.quitGame?string("HH:mm (yyyy-MM-dd ZZZZZ)")}. + + <@form_submit label="Annuler" /> + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/alliance.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/alliance.ftl new file mode 100644 index 0000000..8cbb99c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/alliance.ftl @@ -0,0 +1,268 @@ +<#macro show_alliance alliance> + <@dt_main> + <@dt_entry title="Tag ">${alliance.tag?xhtml} + <@dt_entry title="Nom ">${alliance.name?xhtml} + <@dt_entry title="Dirigeant ">${alliance.leaderName?xhtml} + <@dt_entry title="PlanĆØtes ">${alliance.planets?string(",##0")} + <@dt_entry title="">Envoyer un message + + +<#macro alliance_info_tab> + + <@tab id="info" title="Autres alliances"> + + <@form action="alliance-info" name="alliance-info" hash="info"> + <@form_text name="tag" id="ai-tag" label="Tag de l'alliance" value=data.requested! maxLength=5 /> + <@form_submit label="Obtenir les informations" /> + + + <#if data.info?has_content> + <@show_alliance alliance=data.info /> + + + + + +<#macro alliance_creation_tab> + + <#if data.creation?has_content> + <#assign tag = data.creation.tag!> + <#assign tagError = data.creation.tagError!> + <#assign name = data.creation.name!> + <#assign nameError = data.creation.nameError!> + <#else> + <#assign tag = ""> + <#assign tagError = ""> + <#assign name = ""> + <#assign nameError = ""> + + + <@tab id="create-alliance" title="CrĆ©er"> + <@form action="create-alliance" name="create-alliance" hash="create-alliance"> + <#switch tagError> + <#case "EMPTY"><@form_error>Veuillez indiquer le tag de votre alliance.<#break> + <#case "INVALID"><@form_error>Ce tag est invalide.<#break> + <#case "UNAVAILABLE"><@form_error>Ce tag est utilisĆ© par une autre alliance. + + <@form_text name="tag" id="ca-tag" label="Tag de l'alliance " value=tag maxLength=5 /> + + <#switch nameError> + <#case "EMPTY"><@form_error>Veuillez spĆ©cifier le nom de votre alliance.<#break> + <#case "INVALID"><@form_error>Ce nom est invalide.<#break> + + <@form_text name="name" id="ca-name" label="Nom de l'alliance " value=name maxLength=5 /> + + <@form_submit label="CrĆ©er une alliance" /> + + + + +<#macro alliance_join_tab> + + <@tab id="join-alliance" title="Rejoindre"> + <@form action="join-alliance" name="join-alliance" hash="join-alliance"> + <#if data.joinFailure?has_content> + <@form_error>Alliance non trouvĆ©e. + + <@form_text name="tag" id="ja-tag" label="Tag de l'alliance" value=data.joinFailure! maxLength=5 /> + <@form_submit label="Rejoindre cette alliance" /> + + + + +<#macro no_alliance> + + <#if data.page.special! != 'v'> + <@alliance_join_tab /> + <@alliance_creation_tab /> + + + +<#macro alliance_joining_tab> + + <@tab id="join-alliance" title="RequĆŖte envoyĆ©e"> + <@lineform action="cancel-join" hash="join-alliance"> + Une requĆŖte pour rejoindre ${alliance.main.tag?xhtml} a Ć©tĆ© envoyĆ©e. + <#if data.page.special! != 'v'> + <@ff_submit label="Annuler" /> + + + <@show_alliance alliance=alliance.main /> + + + +<#macro alliance_planets pList> + <@tab id="planets" title="PlanĆØtes"> + + <#if pList?size == 0> +

Il n'y a pas de planĆØtes dans cette alliance.

+ <#return> + + + <@listview> + <@lv_line headers=true> + <@lv_column width=80 centered=true>CoordonnĆ©es + <@lv_column width=150>PlanĆØtes + <@lv_column width=150>PropriĆ©taire + + + <#list pList as planet> + <#if planet.battle> + <#local bStart = ""> + <#local bEnd = ""> + <#else> + <#local bStart = " "> + <#local bEnd = " "> + + + <@lv_line> + <@lv_column centered=true>${bStart}(${planet.x},${planet.y};${planet.orbit})${bEnd} + <@lv_column>${bStart}${planet.name?xhtml}${bEnd} + <@lv_column>${bStart}${planet.owner?xhtml}${bEnd} + + + <#if planet.battle> + <@lv_line> +   + + Situation militaire: + ${planet.defence?string(",##0")} + contre + ${planet.attack?string(",##0")} + + + + + + + + +<#macro alliance_members mList isLeader empty=""> + + <#if mList?size == 0 && empty != ""> +

${empty?xhtml}

+ <#return> + + + <@listview> + <@lv_line headers=true> + <#if isLeader && data.page.special! != 'v'> + <@lv_column width=40 centered=true>  + + <@lv_column width="x">Empire + + + <#list mList as member> + <@lv_line> + <#if isLeader && data.page.special! != 'v'> + <@lv_column centered=true> + <#if member.name == data.page.empire> +   + <#else> + + + + + <@lv_column> + <#if member.name == data.page.empire> + ${member.name?xhtml} + <#else> + ${member.name?xhtml} + + + + + + + +<#macro alliance_member_page> + <#local leader = alliance.leader?has_content> + + <@tab id="in-alliance" title="Alliance"> + <@lineform action="leave-alliance" hash="join-alliance"> + Vous ĆŖtes + <#if alliance.leader?has_content> + le dirigeant + <#else> + un membre + + de ${alliance.main.tag?xhtml}. + <#if data.page.special! != 'v'> + <@ff_submit label="Quitter l'alliance" /> + + + <@show_alliance alliance=alliance.main /> + + + <@alliance_planets pList=alliance.member.planets /> + + <@tab id="members" title="Members"> + <#if leader && alliance.member.members?size gt 1 && data.page.special! != 'v'> +
+ + <@alliance_members mList=alliance.member.members isLeader=leader /> + <#if leader && alliance.member.members?size gt 1 && data.page.special! != 'v'> +
+
+ <@ff_submit label="Exclure les membres sƩlectionnƩs" /> +
+
+
+ + <@lineform action="transfer-leadership" hash="members"> + TrasnfĆ©rer la direction Ć  + <@ff_select id="leadership" name="leadership"> + <#list alliance.member.members as member> + <#if member.name != data.page.empire> + <@form_option value=member.id text=member.name /> + + + + <@ff_submit label="Confirmation" /> + + + + + <#if leader> + <@tab id="requests" title="RequĆŖtes"> + <#if alliance.leader.requests?size gt 0 && data.page.special! != 'v'> +
+ + <@alliance_members mList=alliance.leader.requests isLeader=true empty="Aucune requĆŖte en suspens" /> + <#if alliance.leader.requests?size gt 0 && data.page.special! != 'v'> +
+
+ <@ff_select id="requests-select" name="action"> + <@form_option value="1" text="Accepter" /> + <@form_option value="0" text="Rejecter" /> + postulants sƩlectionnƩs + <@ff_submit label="Confirmation" /> +
+
+
+ + + + + +<#macro render> +<@page title="Alliance"> + + <#assign alliance = data.alliance> + <@tabs> + + <#if alliance.main?has_content> + <#if alliance.member?has_content> + <@alliance_member_page /> + <#else> + <@alliance_joining_tab /> + + <#else> + <@no_alliance /> + + <@alliance_info_tab /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/banned.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/banned.ftl new file mode 100644 index 0000000..c098592 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/banned.ftl @@ -0,0 +1,12 @@ +<#macro render> +<@page title="Vous avez ƩtƩ banni"> +

Vous avez rƩussi. Vous avez ƩtƩ banni. Bien jouƩ.

+ <@dt_main> + <@dt_entry width=200 title="Date/Heure du bannissement ">${data.banTime?string("yyyy-MM-dd HH:mm:ss")} + <@dt_entry width=200 title="Raison du bannissement ">${data.banReason?xhtml} + + <#if data.redeemable> +

Votre empire n'a pas encore ƩtƩ supprimƩ. Vous pouvez faire appel de ce bannissement en envoyant un e-mail Ơ the staff dans un dƩlai de 48h.

+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/battle.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/battle.ftl new file mode 100644 index 0000000..69236c1 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/battle.ftl @@ -0,0 +1,261 @@ +<#macro render_header desc> +
+ At ${desc.location.name?xhtml} + (${desc.x},${desc.y};${desc.orbit}) +
+ +<#macro render_navigation id disp> +
+ + + + + + + +
+ <#if disp.previous?has_content> + + + << + <#if disp.previous?has_content> + + + + <@ff_select id="view-battle-tick" name="tick" style="width:470px"> + <#list disp.all as viewable> + <@form_option value="${viewable.ticks?string('#')}" selected=(viewable.ticks == disp.current.ticks)><@game_time record=viewable.gameTime /> + + + <@ff_submit label="Voir" style="width:40px" /> + + <#if disp.next?has_content> + + + >> + <#if disp.next?has_content> + + + + >>> +
+
+ +<#macro render_list_entry mode record type> + +   + les bĆ¢timents<#else>les vaisseaux">  +   + + <#nested> + + ${record.cPower?string(',##0')} + ${record.lPower?string(',##0')} + + <#list record.ships as shipType> + +   + ${shipType.name} + ${shipType.cAmount?string(',##0')} + ${shipType.lAmount?string(',##0')} + + + +<#macro render_protagonist mode record> + <#if record.ships?has_content> + <@render_list_entry mode=mode record=record type="empire"> + <#if record.player.id = 0 || mode = "own"> + ${record.player.name?xhtml} + <#else> + ${record.player.name?xhtml} + + + + +<#macro render_planet mode record> + <@render_list_entry mode=mode record=record type="planet">( planĆØte ) + +<#macro render_protagonists mode source> + <#if source.players?size = 0> + <#return> + + +   +   + Forces <#if mode == "allied">AlliĆ©es<#else>Hostiles + ${source.cPower?string(',##0')} + ${source.lPower?string(',##0')} + + <#list source.ships as shipType> + +   + ${shipType.name} + ${shipType.cAmount?string(',##0')} + ${shipType.lAmount?string(',##0')} + + + <#list source.players as pRecord> + <@render_protagonist mode=mode record=pRecord /> + + +<#macro render_fleets fData> + <@listview> + Forces + <@lv_line headers=true> +   +   +   +   +   + <@lv_column width=100 centered=true>Actuelles + <@lv_column width=100 centered=true>DĆ©truites + + <@render_protagonist mode="own" record=fData.own /> + <#if fData.planet.relation == "OWN"> + <@render_planet mode="own" record=fData.planet /> + + <@render_protagonists mode="allied" source=fData.friendly /> + <#if fData.planet.relation == "ALLIED"> + <@render_planet mode="allied" record=fData.planet /> + + <@render_protagonists mode="enemy" source=fData.hostile /> + <#if fData.planet.relation == "ENEMY"> + <@render_planet mode="enemy" record=fData.planet /> + + Cliquer "*" et "+" pour Ć©tendre les affichages de vaisseaux/bĆ¢timents. + + +<#macro render_event_items items> + <#list items as item> + <@lv_line> +   + ${item.name} + ${item.cAmount?string(",##0")} + + + +<#macro render_event event> + <#switch event.type> + <#case "RENAME"> + <@lv_line> + PlanĆØte renommĆ©e en ${event.name} + + <#break> + <#case "SWITCH"> + <@lv_line> + + <#if event.name = data.page.empire> + Nous sommes passĆ©s en <#if event.hostile>attaque<#else>dĆ©fense. + <#else> + ${event.name} a changĆ© de mode et est maintenant <#if event.hostile>hostile<#else>dans notre camp. + + + + <#break> + <#case "BUILD"> + <@lv_line> + + <#if event.planet> + De nouveau bĆ¢timents ont Ć©tĆ© construits sur la planĆØte. + <#elseif event.name = data.page.empire> + Nos nouvelles flottes ont Ć©tĆ© dĆ©ployĆ©es. + <#else> + Des flottes <#if event.hostile>Hostiles<#else>AlliĆ©es appartenant Ć  ${event.name} ont Ć©tĆ© dĆ©ployĆ©es. + + + + <@render_event_items items=event.ships /> + <#break> + <#case "DEPART"> + <@lv_line> + + <#if event.name = data.page.empire> + Nos flottes ont quittĆ© l'orbite. + <#else> + Des flottes <#if event.hostile>Hostiles<#else>AlliĆ©es appartemant Ć  ${event.name} ont quittĆ© l'orbite. + + + + <@render_event_items items=event.ships /> + <#break> + <#case "ARRIVE"> + <@lv_line> + + <#if event.name = data.page.empire> + Nos flottes se sont jointes Ć  la bataille. + <#else> + Des flottes <#if event.hostile>Hostiles<#else>AlliĆ©es appartenant Ć  ${event.name} se sont jointes Ć  la bataille. + + + + <@render_event_items items=event.ships /> + <#break> + <#case "DESTROY"> + <@lv_line> + + <#if event.planet> + Des bĆ¢timents ont Ć©tĆ© dĆ©truits sur la planĆØte. + <#elseif event.name = data.page.empire> + Nos flottes ont Ć©tĆ© dissoutes. + <#else> + Des flottes <#if event.hostile>Hostiles<#else>AlliĆ©es appartenant Ć  ${event.name} ont Ć©tĆ© dissoutes. + + + + <@render_event_items items=event.ships /> + <#break> + <#default> + <@lv_line> + + Type d'Ć©vĆ©nement manquant "${event.type}" (ceci est un bug) + + + <#break> + + +<#macro render_history hData> + <#if hData?size = 0> + <#return> + + <@listview> + Historique + <@lv_line headers=true> +   +   +   + + <#list hData as hInterval> + <#if hInterval.end?has_content> + <#if hInterval.battleEnds> + La bataille s'est terminĆ©e Ć  <@game_time record=hInterval.end.gameTime /> + <#else> + Plus de flottes Ć  cet endroit + +   + + <#list hInterval.entries as atTick> + <@game_time record=atTick.time.gameTime />: + <#list atTick.events as event> + <@render_event event=event /> + +   + + <#if hInterval.battleBegins> + La bataille a commencĆ© Ć  <@game_time record=hInterval.begin.gameTime /> + + + + +<#macro render> +<#local bDescription = data.battle.description> +<#local bDisplay = data.battle.display> +<@page title="Battle #${bDescription.id?string(',##0')} at ${bDescription.location.name}"> + + <@render_header desc=bDescription /> + <@render_navigation id=bDescription.id disp=bDisplay /> +

 

+ <@render_fleets fData=data.battle.ships /> + <@render_history hData=data.battle.history /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/battles.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/battles.ftl new file mode 100644 index 0000000..1cd3e7c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/battles.ftl @@ -0,0 +1,62 @@ +<#macro render_battles battles page pages> + <#if pages gt 1> + + + + + + +
+ <#if page gt 0> + + + << + <#if page gt 0> + + + + Page ${page + 1} / ${pages} + + <#if page lt pages - 1> + + + >> + <#if page lt pages - 1> + + +
+ + <@listview> + <@lv_line headers=true> + <@lv_column width=60 centered=true># + <@lv_column width="x">Localisation + <@lv_column width=80 centered=true>  + <@lv_column width=125 centered=true>Rejointe + <@lv_column width=125 centered=true>TerminĆ©e + + <#list battles as battle> + <@lv_line> + <@lv_column centered=true>${battle.id?string(',##0')} + <@lv_column>${battle.location.name?xhtml} + <@lv_column centered=true>(${battle.x},${battle.y};${battle.orbit}) + <@lv_column centered=true><@game_time record=battle.first.gameTime /> + <@lv_column centered=true> + <#if battle.last?has_content> + <@game_time record=battle.last.gameTime /> + <#else> + En cours + + + + + + +<#macro render> +<@page title="Batailles"> + <#if data.pages == 0> +

Nous n'avons pris part Ć  aucune bataille

+ <#else> + <@render_battles battles=data.list page=data.currentPage pages=data.pages /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsList.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsList.ftl new file mode 100644 index 0000000..c964038 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsList.ftl @@ -0,0 +1,136 @@ +<#include "bugsTabs.ftl"> +<#macro render_navigation current count total qString> + + + + + + +
+ <#if current gt 0> + + + << + <#if current gt 0> + + + + <#if total gt 1> + ${total?string(',##0')} entrƩes trouvƩes. + <#elseif total = 1> + 1 entrƩe trouvƩe. + <#else> + Aucune entrƩe trouvƩe. + + + <#if current lt total - count> + + + >> + <#if current lt total - count> + + +
+ +<#macro render> +<#if data.ownOnly> + <#local ownOnly = "1"> +<#else> + <#local ownOnly = "0"> + +<#local qString = "status=${data.status!'x'}&own=${ownOnly}" > +<@page title="Suivi des bugs"> + <#-- Tabs --> + <@bugTabs selected="bugsList" qString="${qString}&first=${data.first}" /> + + <#-- Selection --> +
+
+ + +
+ Lister + <@ff_select id="sel-own" name="own"> + <@form_option value="0">tous les + <@form_option value="1" selected=(data.ownOnly)>mes + + rapports dont le statut est : + <@ff_select id="sel-stat" name="status"> + <@form_option value="x">(indiffƩrent) + <@form_option value="PENDING" selected=((data.status!"") = 'PENDING')>en attente de validation + <@form_option value="OPEN" selected=((data.status!"") = 'OPEN')>en cours de traitement + <@form_option value="RESOLVED" selected=((data.status!"") = 'RESOLVED')>rƩsolu + <@form_option value="WONT_FIX" selected=((data.status!"") = 'WONT_FIX')>ne sera pas rƩsolu + <@form_option value="NOT_A_BUG" selected=((data.status!"") = 'NOT_A_BUG')>pas un bug + + <@ff_submit label="Rechercher" /> +
+
+
+ + <#-- Navigation --> + <@render_navigation current=data.first count=data.count total=data.entries qString=qString /> + + <#-- List of bugs --> + <#if data.reports?size gt 0> + <@listview> + + <@lv_line headers=true> + <@lv_column centered=true width=60># + <@lv_column width="x">Titre + <#if !( data.status?has_content )> + <@lv_column width=130 centered=true>Statut + + <@lv_column width=150 centered=true>DerniĆØre mise Ć  jour + + + <#list data.reports as report> + + <#if !data.ownOnly && report.initialSubmitter.userId?has_content && !report.initialSubmitter.admin && report.initialSubmitter.name = data.page.empire> + <#local eClass="own-fleet"> + <#else> + <#local eClass=""> + + + <@lv_line class=eClass> + <@lv_column centered=true>${report.reportId?string(",##0")} + <@lv_column>${report.title} + <#if !( data.status?has_content )> + <@lv_column centered=true><@bugStatus status=report.status /> + + <@lv_column centered=true> + <#if report.updated> + + + ${report.lastUpdate?string("yyyy-MM-dd HH:mm:ss")} + <#if report.updated> + + + + + <@lv_line class=eClass> + <#if data.status?has_content> + + <#else> + + +   + <@lv_column centered=true> + par + <#if report.latestSubmitter.admin> + + + ${report.latestSubmitter.name} + <#if report.latestSubmitter.admin> + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsReport.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsReport.ftl new file mode 100644 index 0000000..df9adab --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsReport.ftl @@ -0,0 +1,62 @@ +<#include "bugsTabs.ftl"> +<#macro render> +<#if data.query.ownOnly> + <#local ownOnly = "1"> +<#else> + <#local ownOnly = "0"> + +<#local qString = "status=${data.query.status!'x'}&own=${ownOnly}" > +<@page title="Rapporter un bug"> + <@bugTabs selected="bugsReport" qString="${qString}&first=${data.query.first}" /> + +

LISEZ CECI AVANT DE RAPPORTER UN BUG

+

+ Or donc, vous avez dĆ©couvert quelque chose qui ne fonctionne pas ou qui semble se comporter + incorrectement. TrĆØs bien - c'est la raison pour laquelle cette version est publique. +

+

+ Cependant, ĆŖtes-vous sĆ»r qu'il s'agit bel et bien d'un bug? Si vous avez jouĆ© Ć  la Beta 5, beaucoup + de choses ont changĆ© et ne se comportent plus de la mĆŖme maniĆØre. Assurez-vous tout d'abord d'avoir + consultĆ© les rĆØgles du jeu ainsi que les informations concernant la + portĆ©e de ce jalon. +

+

+ Une fois que vous avez lu cette documentation, si vous n'avez rien trouvĆ© qui semble se rapporter + Ć  votre problĆØme, hĆ© bien, il s'agit d'un vrai bug ou bien de quelque chose qui a Ć©tĆ© omis dans la doc. + Dans tous les cas, ce problĆØme devrait ĆŖtre rapportĆ© en utilisant le formulaire ci-dessous. + Utilisez un titre aussi clair que possible (il devrait indiquer la nature du problĆØme) + et Ć©crivez une description aussi prĆ©cise que vous le pouvez. +

+

+ Il est prĆ©fĆ©rable que ce rapport soit Ć©crit en Anglais, afin d'ĆŖtre lisible par tous les membres + de l'Ć©quipe, mais ce n'est pas obligatoire. +

+

+ Merci pour votre aide! +

+ + <@form action="report-bug"> + + + + + + + <#switch data.titleError!""> + <#case "EMPTY"><@form_error>Veuillez spĆ©cifier le titre du rapport<#break> + <#case "INVALID"><@form_error>Le titre doit comprendre au moins 10 caractĆØres<#break> + + <@form_text label="Titre " name="title" value=data.title!"" maxLength=127 /> + + <#switch data.descriptionError!""> + <#case "EMPTY"><@form_error>Veuillez spĆ©cifier la description du bug<#break> + <#case "INVALID"><@form_error>La description doit comprendre au moins 30 caractĆØres<#break> + + <@form_text label="Description " name="description" value=data.description!"" multiline=true maxLength=10 /> + + <@form_submit label="Poster le rapport de bug" /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsTabs.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsTabs.ftl new file mode 100644 index 0000000..b5d7633 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsTabs.ftl @@ -0,0 +1,18 @@ +<#macro bugTab href title selected> + ${title} + +<#macro bugTabs selected qString> +
+ <@bugTab href="bugtrack?${qString}" title="Lister les bugs" selected=( selected = 'bugsList' ) /> + <@bugTab href="report-bug?${qString}" title="Rapporter un bug" selected=( selected = 'bugsReport' ) /> +
+ +<#macro bugStatus status> + <#switch status> + <#case "PENDING">en attende de validation<#break> + <#case "OPEN">en cours de traitement<#break> + <#case "RESOLVED">rƩsolu<#break> + <#case "WONT_FIX">ne sera pas rƩsolu<#break> + <#case "NOT_A_BUG">pas un bug<#break> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsView.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsView.ftl new file mode 100644 index 0000000..5937a63 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/bugsView.ftl @@ -0,0 +1,124 @@ +<#include "bugsTabs.ftl" /> +<#macro render_submitter s> + <#if s.admin> + + <#elseif s.userId?has_content && s.name = data.page.empire> + + + ${s.name?xhtml} + <#if s.admin || ( s.userId?has_content && s.name = data.page.empire )> + + + +<#macro render_event e> +
+ ${e.timestamp?string("yyyy-MM-dd HH:mm:ss")} - <@render_submitter s=e.submitter /> + <#nested> +
+ +<#macro render_report_event e> + <@render_event e=e> + a postƩ un rapport de bug #${e.id?string(",##0")} + +

${e.title}

+
+ ${e.contents} +
+ +<#macro render_status_event e> + <@render_event e=e> + a changƩ le statut du rapport en <@bugStatus status=e.status /> + + +<#macro render_visibility_event e> + <@render_event e=e> + a mis la visibilitƩ du rapport Ơ <#if e.visible>public<#else>privƩ + + +<#macro render_merge_event e> + <@render_event e=e> + a fusionnƩ le rapport de bug courant avec le rapport de bug #${e.mergedId?string(",##0")} + + +<#macro render_comment_event e> + <@render_event e=e> + a postƩ un commentaire + <#if !e.visible> + (en attente de modƩration) + + +
+ ${e.contents} +
+ +<#macro render> +<#if data.query.ownOnly> + <#local ownOnly = "1"> +<#else> + <#local ownOnly = "0"> + +<#local qString = "status=${data.query.status!'x'}&own=${ownOnly}" > +<@page title="Bug #${data.report.reportId?string(',##0')} - ${data.report.title}" hidePlanets=true> + <#-- Tabs --> + <@bugTabs selected="" qString="${qString}&first=${data.query.first}" /> + + <#-- Bug info --> + <@dt_main> + <@dt_entry title="Statut "><@bugStatus status=data.report.status /> + <@dt_entry title="Public "><#if data.report.visible>Oui<#else>Non + <@dt_entry title="RapportĆ© initialement le "> + ${data.report.posted?string("yyyy-MM-dd HH:mm:ss")} + par <@render_submitter s=data.report.initialSubmitter /> + + <@dt_entry title="DerniĆØre mise Ć  jour le "> + ${data.report.lastUpdate?string("yyyy-MM-dd HH:mm:ss")} + par <@render_submitter s=data.report.latestSubmitter /> + + + + <#-- List events --> + <#local mayPost = false> + <#list data.events as event> +
+ <#local mayPost = ( mayPost || ( !event.submitter.admin && event.submitter.userId?has_content && event.submitter.name = data.page.empire ) )> + <#switch event.type> + <#case 'INIT'> + <@render_report_event e=event /> + <#break> + <#case 'STATUS'> + <@render_status_event e=event /> + <#break> + <#case 'COMMENT'> + <@render_comment_event e=event /> + <#break> + <#case 'VISIBILITY'> + <@render_visibility_event e=event /> + <#break> + <#case 'MERGE'> + <@render_merge_event e=event /> + <#break> + + + + <#-- Comment form --> + <#if mayPost && ( data.report.status = 'OPEN' || data.report.status = 'PENDING' )> +
+ <@form action="bug-${data.report.reportId}-comment" hash="post-comment"> + + + + + + + + <#switch data.commentError!""> + <#case "EMPTY"><@form_error>Vous devriez Ć©crire le commentaire avant de le poster.<#break> + <#case "INVALID"><@form_error>Les commentaires doivent compter au moins 30 caractĆØres.<#break> + + <@form_text label="Nouveau commentaire " name="comment" multiline=true maxLength=6 value=data.comment!"" /> + <@form_submit label="Poster le commentaire" /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/chat.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/chat.ftl new file mode 100644 index 0000000..52708bf --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/chat.ftl @@ -0,0 +1,28 @@ +<#macro render> +<@page title="Legacy Worlds - Discussion"> + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/enemies.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/enemies.ftl new file mode 100644 index 0000000..0c98924 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/enemies.ftl @@ -0,0 +1,92 @@ +<#macro enemy_tab eList alliances> + + <#if alliances> + <#local tabId = "alliances"> + <#local addAction = "alliance"> + <#local tabTitle = "Alliances"> + <#local emptyText = "Aucune alliance ennemie."> + <#local nameLen = 5> + <#if data.alliance?has_content & data.alliance> + <#local error = data.error> + <#local defName = data.name> + + <#else> + <#local tabId = "empires"> + <#local addAction = "empire"> + <#local tabTitle = "Empires"> + <#local emptyText = "Aucun empire ennemi."> + <#local nameLen = 20> + <#if data.alliance?has_content & !data.alliance> + <#local error = data.error> + <#local defName = data.name> + + + + <@tab id=tabId title=tabTitle> + + <#if eList?size == 0> +

${emptyText}

+ <#else> +
+ <@listview> + <@lv_line headers=true> + <@lv_column width=40 centered=true>  + <@lv_column width="x">${tabTitle} + + + <#list eList as enemy> + <@lv_line> + <@lv_column centered=true> + <@lv_column> + <#if alliances>[<#else>${enemy.name?xhtml}<#if alliances>] + + + + +
+
+ <@ff_submit label="Supprimer les ennemis sƩlectionnƩs" /> +
+
+
+ + + <#if data.page.special! != 'v'> + <#if error?has_content> + <@standalone_error> + <#switch error> + <#case "INVALID"><#if alliances>Alliance<#else>Empire non trouvƩ.<#break> + <#case "BANNED"> + <#if alliances> + Petite trahison entre amis ? + <#else> + Il y a un terme mƩdical pour Ƨa - schizophrƩnie. + + <#break> + <#case "UNAVAILABLE"> + <#if alliances>Cette alliance<#else>Cet empire est dƩjƠ dans votre liste d'ennemis. + <#break> + + + + <@lineform action="add-enemy-${addAction}" hash=tabId> + Nouvel ennemi: <@ff_text id="name-${addAction}" name="name" value=defName! maxLength=nameLen size=(nameLen+1) /> + <@ff_submit label="Ajouter" /> + + + + + + +<#macro render> +<@page title="Liste d'ennemis"> + + <@tabs> + + <@enemy_tab eList=data.empires alliances=false /> + <@enemy_tab eList=data.alliances alliances=true /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/fleets.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/fleets.ftl new file mode 100644 index 0000000..016cdaf --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/fleets.ftl @@ -0,0 +1,261 @@ +<#macro render_fleet_ships rType id ships> + + + + + + + <#list ships as ship> + + + + + + +
Classe de vaisseauxQuantitƩPuissance
${ship.name}${ship.amount?string(',##0')}${ship.power?string(',##0')}
+ +<#macro render_static_fleet_details rType fleet> + +   + +
+ <@render_fleet_ships rType="own-fleet" id=fleet.id ships=fleet.ships /> +
+
+ <@dt_main> + <#if fleet.status != 'AVAILABLE'> + <@dt_entry title="PƩnalitƩ"> + <@duration rTime=fleet.penalty gTime=fleet.gamePenalty /> + + + <@dt_entry abbr="TVOO " title="Temps de vol d'orbite-Ơ-orbite"> + <@duration rTime=fleet.flightTime gTime=fleet.gameFlightTime /> + + +
+ + + +<#macro render_fleets_at location owners> + <#list owners as owner> + <#switch owner.relation> + <#case 'OWN'> + <#local rType = 'own-fleet'> + <#local mode = location.attacking > + <#break> + <#case 'ALLIED'> + <#local rType = 'allied-fleet'> + <#local mode = location.attacking > + <#break> + <#case 'ENEMY'> + <#local rType = 'enemy-fleet'> + <#local mode = ! location.attacking > + <#break> + + <#list owner.fleets as fleet> + + + <#if owner.relation == 'OWN' && data.page.special! != 'v'> + + <#else> +   + + + + <#if fleet.name?has_content && fleet.name != ""> + ${fleet.name?xhtml} + <#else> + (flotte sans nom) + + + + <#if owner.relation = 'OWN'> + ${owner.name?xhtml} + <#else> + ${owner.name?xhtml} + + + + <#if mode>A<#else>D + + ${fleet.power?string(',##0')} + + <#if fleet.status == 'AVAILABLE'> + DIS + <#else> + <#switch fleet.status> + <#case 'DEPLOYING'>DPL<#break> + <#case 'REDEPLOYING'>RDP<#break> + + + + + <@render_static_fleet_details rType=rType fleet=fleet /> + + + +<#macro render_static_fleets locations> + <#list locations as location> + + + + + + + + + + + <#if location.onVacation!false> + + <#elseif location.battle?has_content && location.battle.hostile gt 0> + + +
${location.name?xhtml}${location.name?xhtml} (${location.x},${location.y};${location.orbit})Population : ${location.population?string(",##0")} + <#if location.attacking> + + <#elseif location.own> + + <#else> + + + DĆ©fense : ${location.defence?string(",##0")} + +
+ <#if location.fleetOwners?size == 0> +

Aucune flotte Ć  cet endroit.

+ <#else> + + + + + + + + + + <@render_fleets_at location=location owners=location.fleetOwners /> +
 Nom de la flottePropriĆ©taireMPS
+ +
Mode vacances activƩ
+ Bataille - ${location.battle.friendly?string(',##0')} contre ${location.battle.hostile?string(',##0')} - + DĆ©tails +
+ + +<#macro render_moving_fleet_details fleet> + +   + +
+ <@render_fleet_ships rType="own-fleet" id=fleet.id ships=fleet.ships /> +
+
+ <@dt_main> + <@dt_entry title="Origine ">${fleet.source.name?xhtml} + <@dt_entry title="Statut "> + <#if fleet.status == 'AVAILABLE'> + DIS + <#else> + RDR - + <@duration rTime=fleet.penalty gTime=fleet.gamePenalty /> + + + <@dt_entry title="Temps jusqu'Ć  la destionation "><@duration rTime=fleet.timeLeft gTime=fleet.gameTimeLeft /> + <@dt_entry title="CoordonnĆ©es ">(${fleet.currentX?string("0.00")};${fleet.currentY?string("0.00")}) + <@dt_entry title="PlanĆØte la plus proche "> + <#if fleet.nearest?has_content> + ${fleet.nearest.name?xhtml} + <#else> + dans l'espace profond + + + <@dt_entry abbr="TVOO " title="Temps de vol d'orbite-Ć -orbite"> + <@duration rTime=fleet.flightTime gTime=fleet.gameFlightTime /> + + +
+ + + +<#macro render_moving_fleet fleet> + + + <#if data.page.special! != 'v'> + + <#else> +   + + + + <#if fleet.name?has_content && fleet.name != ""> + ${fleet.name?xhtml} + <#else> + (flotte sans nom) + + + + <#if fleet.attacking>A<#else>D + + ${fleet.power?string(',##0')} + <@duration rTime=fleet.eta gTime=fleet.gameEta /> + ${fleet.destination.name?xhtml} + + <@render_moving_fleet_details fleet=fleet /> + +<#macro render_moving_fleets fleets> + <#if fleets?size != 0> + + + + + + + +
Flottes en mouvement
+ + + + + + + + + + <#list fleets as fleet> + <@render_moving_fleet fleet=fleet /> + +
 Nom de la flotteMPTEADestination
+
+ + +<#macro render> +<@page title="Flottes"> + <#local locations = data.fleets.locations> + <#local mFleets = data.fleets.moving> + <#if locations?size == 0 && mFleets?size == 0> +

Vous ne possĆ©dez ni flottes ni planĆØtes.

+ <#else> +
Cliquez sur le nom d'un flotte pour voir sa compsition et autres dƩtails la concernant
+
+ <@render_static_fleets locations=locations /> + <@render_moving_fleets fleets=mFleets /> + <#if data.page.special! != 'v'> +
+ +   + +   + + +   + + +   + +
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/fleetsCommand.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/fleetsCommand.ftl new file mode 100644 index 0000000..7543fca --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/fleetsCommand.ftl @@ -0,0 +1,137 @@ +<#macro render_fleet fleet> + + + <#if fleet.name?has_content && fleet.name != ""> + ${fleet.name?xhtml} + <#else> + (flotte sans nom) + + + ${fleet.power?string(',##0')} + <@duration rTime=fleet.flightTime gTime=fleet.gameFlightTime /> + + <#switch fleet.status> + <#case 'DEPLOYING'>DPL<#break> + <#case 'REDEPLOYING'>RDP<#break> + <#case 'REDIRECTING'>RDP<#break> + <#case 'AVAILABLE'>DIS<#break> + + + + (${fleet.x?string("0.00")};${fleet.y?string("0.00")})
+ <#if fleet.nearest?has_content> + <#if fleet.atPlanet>ƀ<#else>PrĆØs de + ${fleet.nearest.name?xhtml} + <#else> + Dans l'espace profond + + + +<#macro render_selected_fleets fleets> +

Flottes sƩlectionnƩes

+ + + + + + + + + + <#list fleets as fleet> + + <@render_fleet fleet=fleet /> + + +
 NomPTVSLocalisation
+ +<#macro render_move_fleets> +

Nouveaux ordres

+ <#if data.error> + <@standalone_error>Cette planĆØte n'existe pas. + +

+ Diriger les flottes sĆ©lectionnĆ©es vers + <@ff_text name="destination" id="destination" value="${data.destination!?xhtml}" maxLength=20 size=21 /> + en + <@ff_select name="mode" id="mode"> + <@form_option text="dĆ©fense" selected=( !data.mode!false ) value="0" /> + <@form_option text="attaque" selected=( data.mode!false ) value="1" /> + +   + <@ff_submit label="Ok" /> + <@ff_submit label="Annuler" name="cancel" /> +

+ +<#macro render_rename_fleets> +

Renommer les flottes

+ <#if data.error> + <@standalone_error>Ce nom est invalide. + +

+ Renommer les flottes sĆ©lectionnĆ©es en + <@ff_text name="name" id="name" value="${data.name!?xhtml}" maxLength=40 size=21 /> +   + <@ff_submit label="Ok" /> + <@ff_submit label="Annuler" name="cancel" /> +

+ +<#macro render_set_fleets_mode> +

DĆ©finir le mode des flottes

+

+ Mettre les flottes sĆ©lectionnĆ©es en + <#if data.attack>attaque<#else>dĆ©fense? +   + <@ff_submit label="Oui" /> + <@ff_submit label="Non" name="cancel" /> +

+ + +<#macro render_disband_fleets> +

Dissudre les flottes

+

+ Ɗtes-vous sĆ»r? +   + <@ff_submit label="Oui" /> + <@ff_submit label="Non" name="cancel" /> +

+ +<#macro render> +<#switch dataType> + <#case 'MoveFleetsResponse'> + <#local title="DĆ©placer les flottes"> + <#local action="move-fleets.action"> + <#break> + <#case 'RenameFleetsResponse'> + <#local title="Renommer les flottes"> + <#local action="rename-fleets.action"> + <#break> + <#case 'SetFleetsModeResponse'> + <#local title="DĆ©finir le mode des flottes"> + <#local action="set-fleets-mode.action"> + <#break> + <#case 'DisbandFleetsResponse'> + <#local title="Dissoudre les flottes"> + <#local action="disband-fleets.action"> + <#break> + +<@page title=title> +
+ <@render_selected_fleets fleets=data.fleets /> + <#switch dataType> + <#case 'MoveFleetsResponse'> + <@render_move_fleets /> + <#break> + <#case 'RenameFleetsResponse'> + <@render_rename_fleets /> + <#break> + <#case 'SetFleetsModeResponse'> + <@render_set_fleets_mode /> + <#break> + <#case 'DisbandFleetsResponse'> + <@render_disband_fleets /> + <#break> + +
+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/getNewPlanet.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/getNewPlanet.ftl new file mode 100644 index 0000000..d1e336c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/getNewPlanet.ftl @@ -0,0 +1,17 @@ +<#macro render> +<@page title="Obtenir une nouvelle planĆØte"> +

Des hordes de barbares Ơ la bouche Ʃcumante ont envahi votre empire, massacrant vos femmes et violant votre bƩtail ?

+

Eh bien, n'ayez plus peur ! Vous pourrez recevoir une nouvelle planĆØte flambant neuve.

+

Please note that doing this will disband your fleets.

+ <@form action="get-planet" name="get-planet"> + <#switch data.error!> + <#case "EMPTY"><@form_error>Veuillez sĆ©lectionner un nom de planĆØte.<#break> + <#case "INVALID"><@form_error>Nom de planĆØte invalide.<#break> + <#case "UNAVAILABLE"><@form_error>Ce nom de planĆØte n'est pas disponible.<#break> + <#case "BANNED"><@form_error>Ce nom de planĆØte a Ć©tĆ© banni.<#break> + + <@form_text name="name" label="Nom de la nouvelle planĆØte " value=data.name! /> + <@form_submit label="Obtenir la planĆØte" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/maintenance.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/maintenance.ftl new file mode 100644 index 0000000..41cffba --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/maintenance.ftl @@ -0,0 +1,16 @@ +<#macro render><@page title="Serveur en cours de maintenance"> + <@dt_main title="Le serveur est en cours de maintenance."> + <@dt_entry title="DĆ©but de la maintenance">${data.start?string("yyyy-MM-dd HH:mm")} + <@dt_entry title="Temps serveur actuel">${data.current?string("yyyy-MM-dd HH:mm")} + <@dt_entry title="Fin prĆ©vue de l'opĆ©ration"> + <#if data.late> + + + ${data.end?string("yyyy-MM-dd HH:mm")} + <#if data.late> + + + + <@dt_entry title="Raison">${data.reason?xhtml} + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/map.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/map.ftl new file mode 100644 index 0000000..6150e35 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/map.ftl @@ -0,0 +1,83 @@ +<#macro render_system system tags> + + <#list system.planets as planet> + <#if tags> + <#if planet.tag?has_content> + <#assign vName = "[${planet.tag}]"> + <#else> + <#assign vName = "N/A"> + + <#else> + <#assign vName = planet.name> + + <#if planet.tag?has_content> + <#assign vTitle = " [${planet.tag}]" > + <#else> + <#assign vTitle = "" > + + <#if planet.relation?has_content> + <#switch planet.relation> + <#case "OWN"> + <#assign lStyle = "class='own-planet'" > + <#break> + <#case "ALLIED"> + <#assign lStyle = "class='allied-planet'" > + <#break> + <#case "ENEMY"> + <#assign lStyle = "class='enemy-planet'" > + <#break> + + <#elseif planet.tag?has_content> + <#assign lStyle = "class='other-planet'" > + <#else> + <#assign lStyle = "" > + + + + + +<#macro render_map size systems tags> + + + <#list systems as row> + + <#list row as system> + <#if system?has_content> + <@render_system system=system tags=tags /> + <#else> + + + + + + +
(inexplorƩ)
+ +<#macro render> +<@page title="Carte"> + + <@lineform action="move-map"> + CoordonnĆ©es : ( <@ff_text name="x" id="x" maxLength=4 size=5 value=data.x?string /> ; + <@ff_text name="y" id="y" maxLength=4 size=5 value=data.y?string /> ) + Taille : <@ff_select id="sz" name="sz"> + <#list data.sizes as size> + <@form_option text=size value=size_index selected=( size_index == data.sizeOrdinal ) /> + + + <@ff_submit label="Centrer la carte" /> + + + <@tabs> + <@tab id="names" title="PlanĆØtes"> + <@render_map size=data.sizeOrdinal systems=data.systems tags=false /> + + <@tab id="alliances" title="Alliances"> + <@render_map size=data.sizeOrdinal systems=data.systems tags=true /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/message.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/message.ftl new file mode 100644 index 0000000..016c466 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/message.ftl @@ -0,0 +1,115 @@ +<#macro render_navigation message inbox> + <#if inbox> + <#local link="inbox-message-"> + <#else> + <#local link="outbox-message-"> + + + + + + + +
+ <#if message.previous?has_content> + + + << + <#if message.previous?has_content> + + + + <#if inbox> + Messages reƧus + <#else> + Messages envoyƩs + + + <#if message.next?has_content> + + + >> + <#if message.next?has_content> + + +
+ +<#macro render> +<#if data.inbox> + <#local title="Messages reƧus"> + <#local timeTtl="ReƧu le "> +<#else> + <#local title="Messages envoyĆ©s"> + <#local timeTtl="EnvoyĆ© le "> + +<#switch data.message.type> + <#case 'INTERNAL'> + <#local mColor="#ffffaf"> + <#break> + <#case 'ADMINISTRATOR'> + <#local mColor="#ffafaf"> + <#break> + <#case 'ALLIANCE'> + <#local mColor="#afafff"> + <#break> + <#case 'EMPIRE'> + <#local mColor="#afafaf"> + <#break> + +<@page title=title> + <@render_navigation message=data.message inbox=data.inbox /> + + <@dt_main> + <@dt_entry width=100 title="De "> + <#if data.inbox> + + + ${data.message.sender!} + <#if data.inbox> + + + + <@dt_entry width=100 title="ƀ "> + <#if !data.inbox> + + + ${data.message.receiver!} + <#if !data.inbox> + + + + <@dt_entry width=100 title=timeTtl> + <@abbr_gt />: <@game_time record=data.message.gameTime /> / <@abbr_st />: ${data.message.time?string("yyyy-MM-dd HH:mm:ss")} + + <#if data.message.unread> + <@dt_entry width=100 title="">Nouveau! + + + + <@listview><@lv_line headers=true>  + +

${data.message.title}

+
+ ${data.message.contents} +
+ + <@listview><@lv_line headers=true>  + <@lineform action="message"> + + + <#if data.message.previous?has_content> + <#local afterDelete = data.message.previous> + <#elseif data.message.next?has_content> + <#local afterDelete = data.message.next> + <#else> + <#local afterDelete = "x"> + + + <@ff_submit label="Supprimer le message" name="delete" /> + <#if data.inbox && data.message.type != 'INTERNAL'> + <@ff_submit label="Ɖcrire une rĆ©ponse" name="reply" /> + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageBox.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageBox.ftl new file mode 100644 index 0000000..1125a86 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageBox.ftl @@ -0,0 +1,124 @@ +<#include "messageTabs.ftl" /> +<#macro render_navigation current total inbox> + <#if inbox> + <#local link="inbox-"> + <#else> + <#local link="outbox-"> + + + + + + + +
+ <#if current gt 0> + + + << + <#if current gt 0> + + + + <#if total gt 0> + Page ${current + 1} / ${total} + <#elseif inbox> + Aucun message reƧu. + <#else> + Aucun message envoyƩ. + + + <#if current lt total - 1> + + + >> + <#if current lt total - 1> + + +
+ +<#macro render> +<#if data.inbox> + <#local title="Messages reƧus"> + <#local tab="inbox"> +<#else> + <#local title="Messages envoyƩs"> + <#local tab="outbox"> + +<@page title=title> + <@messageTabs selected=tab /> + <@render_navigation current=data.cPage total=data.pages inbox=data.inbox /> + <#if data.messages?size gt 0> +
+
+ + +
+ <@listview> + + <@lv_line headers=true> + <@lv_column width=16 centered=true>  + <@lv_column width="x">Sujet + <@lv_column width=150 centered=true><#if data.inbox>De<#else>ƀ + <@lv_column width=150 centered=true><#if data.inbox>ReƧu le<#else>EnvoyĆ© le + + + <#list data.messages as message> + <#switch message.type> + <#case 'INTERNAL'> + <#local mType="int-msg"> + <#break> + <#case 'ADMINISTRATOR'> + <#local mType="admin-msg"> + <#break> + <#case 'ALLIANCE'> + <#local mType="alliance-msg"> + <#break> + <#case 'EMPIRE'> + <#local mType="empire-msg"> + <#break> + + <#if ! message.read> + <#local mType = "${mType} unread-msg"> + + + <@lv_line class=mType> + <@lv_column centered=true> + + + <@lv_column>${message.title} + <@lv_column centered=true>${message.sender!} + <@lv_column centered=true>${message.time?string("yyyy-MM-dd HH:mm:ss")} + + + + + <#if data.inbox> +
+ <@ff_select name="action" id="action"> + <@form_option value="r">Marquer comme lus + <@form_option value="u">Marquer comme non lus + <@form_option value="d">Supprimer + + + <@ff_select name="target" id="target"> + <@form_option value="0">les messages sƩlectionnƩs + <@form_option value="1">tous les messages + + <@ff_submit label="Appliquer" /> +
+ <#else> +
+ + Supprimer + <@ff_select name="target" id="target"> + <@form_option value="0">les messages sƩlectionnƩs + <@form_option value="1">tous les messages + + <@ff_submit label="Appliquer" /> +
+ +
+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageTabs.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageTabs.ftl new file mode 100644 index 0000000..d98b6dc --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageTabs.ftl @@ -0,0 +1,11 @@ +<#macro messageTab href title selected=false eClass=""> + ${title} + +<#macro messageTabs selected> +
+ <@messageTab href="messages" title="ReƧus" selected=( selected = 'inbox' ) /> + <@messageTab href="outbox" title="EnvoyĆ©s" selected=( selected = 'outbox' ) /> + <@messageTab href="compose-message" title="Ɖcrire" selected=( selected = 'compose' ) /> + <@messageTab href="chat" title="Disussion" eClass="open-chat-button" /> +
+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageTargets.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageTargets.ftl new file mode 100644 index 0000000..7b4508f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageTargets.ftl @@ -0,0 +1,62 @@ +<#include "messageTabs.ftl" /> +<#macro render> +<@page title="Destinataires"> + <@messageTabs selected="compose" /> + + <@tabs> + + <#if data.empires?size gt 0> + <@tab id="empires" title="Empires"> + + <#list data.empires as empire> + <#if empire_index % 3 == 0> + + <#if empire_index % 3 == 2> + + <#if data.empires?size % 3 == 1> + + <#elseif data.empires?size % 3 == 2> + + +
+ <#else> + + + ${empire.name?xhtml}
  
 
+ + + + <#if data.alliances?size gt 0> + <@tab id="alliances" title="Alliances"> + <@listview> + <#list data.alliances as alliance> + <@lv_line> + [${alliance.tag?xhtml}]   + ${alliance.name} + + + + + + + <#if data.admins?size gt 0> + <@tab id="admins" title="Administrateurs"> + <@listview> + <#list data.admins as admin> + <@lv_line> + ${admin.name?xhtml}   + + <#list admin.privileges as priv> + ${priv} + + + +   + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageWriter.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageWriter.ftl new file mode 100644 index 0000000..c72a2bb --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/messageWriter.ftl @@ -0,0 +1,82 @@ +<#include "messageTabs.ftl" /> +<#macro render> +<#if data.replyTo?has_content> + <#local title="RĆ©pondre au message"> +<#else> + <#local title="Ɖcrire un nouveau message"> + +<@page title=title> + <@messageTabs selected="compose" /> + +
+
+ <#if data.replyTo?has_content> + + + + + + <#if data.timingError> + <@form_error>Pas si vite ! Attendez quelques secondes avant d'essayer Ć  nouveau. + + + <#-- Message recipient --> + <#if data.targetError> + <@form_error>Destinataire du message non trouvĆ©. + + <@form_select label="Type de destinataire " name="toType"> + <@form_option value="EMPIRE" selected=( data.messageType = 'EMPIRE' )>Empire + <@form_option value="ALLIANCE" selected=( data.messageType = 'ALLIANCE' )>Alliance + <@form_option value="ADMINISTRATOR" selected=( data.messageType = 'ADMINISTRATOR' )>Administrateur + + <@form_text label="Nom du destinataire " name="toName" maxLength=48 value=data.target /> + <#if (data.target == "")> + + + + <#-- Subject --> + <#if data.titleError> + <@form_error>Le sujet est trop court (min.: 2 caractĆØres) + + <@form_text label="Sujet " name="title" maxLength=64 value=data.title /> + + <#-- Body --> + <#if data.contentsError> + <@form_error>Le corps du message est trop court (min.: 2 caractĆØres) + + <@form_text label="Corps du message " name="contents" value=data.contents multiline=true maxLength=10 /> + + <@form_extended_submit label="Envoyer le message"> + <@ff_submit label="Annuler" name="cancel" /> + +
 SĆ©lectionner depuis la liste...
+ +
+
+ + <#-- Original message --> + <#if data.replyTo?has_content> + <@listview><@lv_line headers=true>  + <@dt_main> + <@dt_entry width=100 title="">Message d'origine : + <@dt_entry width=100 title="De "> + ${data.replyTo.sender!} + + <@dt_entry width=100 title="ƀ "> + ${data.replyTo.receiver!} + + <@dt_entry width=100 title="ReƧu le "> + <@abbr_gt />: <@game_time record=data.replyTo.gameTime /> / <@abbr_st />: ${data.replyTo.time?string("yyyy-MM-dd HH:mm:ss")} + + + + <@listview><@lv_line headers=true>  + +

${data.replyTo.title}

+
+ ${data.replyTo.contents} +
+ + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/offline.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/offline.ftl new file mode 100644 index 0000000..3f4d4c2 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/offline.ftl @@ -0,0 +1,9 @@ +<#macro render><@page title="Serveur hors ligne"> +

Le serveur du jeu n'a pas pu ĆŖtre contactĆ©.

+

+ Il peut ĆŖtre en cours de maintenance ou il a pu planter. Dans tous les cas, une alerte a Ć©tĆ© transmise Ć  l'Ć©quipe d'administration. +

+

+ DƩsolƩs pour les troubles occasionnƩs. +

+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/overview.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/overview.ftl new file mode 100644 index 0000000..919f8e9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/overview.ftl @@ -0,0 +1,118 @@ +<#macro render> +<@page title="Empire"> + + <#assign ov = data.overview > + <#assign rs = data.research > + + <@tabs> + + <@tab id="overview" title="RĆ©sumĆ©"> + <@left_column> + + <#assign nplanets = data.page.planets?size> + <@dt_main title="Flottes & PlanĆØtes"> + <@dt_entry title="Nombre de planĆØtes ">${nplanets?string(",##0")} + <@dt_entry title="Population totale ">${ov.population?string(",##0")} + <@dt_entry title="Satisfaction moyenne "><@happiness value=data.overview.avgHappiness /> + <@dt_entry title="Puissance de flotte totale ">${ov.fleetPower?string(",##0")} + + + <@dt_main title="Batailles"> + <#if data.battles?size gt 0> + <@dt_status>Nous sommes impliquĆ©s dans les batailles suivantes: + <#list data.battles as battle> + <@dt_status>${battle.location.name?xhtml} + (${battle.x},${battle.y};${battle.orbit}) + + <#else> + <@dt_status>Nous ne sommes impliquĆ©s dans aucune bataille. + + <@dt_status> + Toutes les batailles + + + + + + <@right_column> + + <@dt_main title="Finances"> + <@dt_entry title="RĆ©serves financiĆØres ">${data.page.cash?string(",##0")} <@abbr_bgc/> + <@dt_entry title="BĆ©nĆ©fice planĆ©taire ">${ov.planetIncome?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Charges planĆØtaires ">${ov.planetUpkeep?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Charges des flottes ">${ov.fleetUpkeep?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Investissements ">${ov.investment?string(",##0")} <@abbr_bgc/> + + + <@dt_main title="Messages"> + <@dt_status> + <#if ov.newMessages == 0> + Aucun nouveau message. + <#elseif ov.newMessages == 1> + Vous avez un nouveau message. + <#else> + Vous avez ${ov.newMessages} nouveaux messages. + + + <@dt_status> + Ecrire message + + + + + + + <@tab id="research" title="Recherche"> + <#if rs?size == 0> +

Nos scientifiques sont encore en train de s'installer.

+ + <#list rs as research> +
+

${research.name?xhtml}

+

${research.description?xhtml}

+ + <@left_column> + <#if research.implemented?size == 0> +

Aucune technologie utilisable.

+ <#else> + <@dt_main> + <#list research.implemented as tech> + <@dt_status> + ${tech.name?xhtml} +
${tech.description?xhtml}
+ + + + + + + <#if research.current?has_content> + <@right_column> + <@dt_main> + <@dt_status> + Recherche actuelle : ${research.current.name?xhtml} +

+ ${research.current.description?xhtml} +

+ + <@dt_entry title="Progression">${research.current.researched}% + <#if research.current.cost?has_content> + <@dt_entry title="Coƻt">${research.current.cost?string(",##0")} <@abbr_bgc/> + <#if data.page.cash gte research.current.cost && data.page.special! != 'v'> + <@dt_status>
+
<@ff_submit label="Appliquer la technologie" />
+
+ + + + + + +
+ + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/passwordRecovery.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/passwordRecovery.ftl new file mode 100644 index 0000000..4236933 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/passwordRecovery.ftl @@ -0,0 +1,69 @@ +<#macro render> +<@page title="RƩcupƩration de mot de passe"> + <@tabs> + + <@tab title="Demande de rƩcupƩration de mot de passe" id="request-recovery"> + <#if data.sent?has_content> +

Un e-mail vous a ƩtƩ envoyƩ Ơ votre adresse, ${data.mail?xhtml}

+

Il contient un code d'authetification Ć  usage unique que vous devez utiliser pour changer votre mot de passe.

+

Le code d'authentification va expirer dans une heure, et vous ne pourrez pas demander un autre code jusqu'Ơ ce qu'il ait expirƩ.

+ <#else> + + <@form name="req-pwd-recovery" action="request-password-recovery"> + <#switch data.status!> + <#case "INVALID_INPUT"> + <@form_error>Adresse e-mail invalide. + <#break> + <#case "ACCOUNT_NOT_FOUND"> + <@form_error>Adresse e-mail inconnue. + <#break> + <#case "ACCOUNT_STATUS"> + <@form_error>L'Ć©tat du compte ne permet pas la rĆ©cupĆ©ration de mot de passe. + <#break> + <#case "RECOVERY_IN_PROGRESS"> + <@form_error>Une demande de rĆ©cupĆ©ration de mot de passe a Ć©tĆ© fait au cours de la derniĆØre heure. + <#break> + <#case "MAIL_ERROR"> + <@form_error>Incapable d'envoyer un e-mail. + <#break> + + <@form_text label="Adresse e-mail" name="mail" id="req-mail" value=data.mail! maxLength=128 /> + <@form_submit label="Demander la rĆ©cupĆ©ration de mot de passe" extraClass="" /> + + + + + + <@tab id="confirm-recovery" title="Confirmer la rĆ©cupĆ©ration de mot de passe"> + <@form name="conf-pwd-recovery" action="confirm-password-recovery" hash="confirm-recovery"> + <#switch data.cStatus!> + <#case "INVALID_MAIL"> + <@form_error>Adresse e-mail invalide. + <#break> + <#case "NOT_FOUND"> + <@form_error>Code ou adresse e-mail inconnu. + <#break> + <#case "ACCOUNT_STATUS"> + <@form_error>L'Ć©tat du compte ne permet pas la rĆ©cupĆ©ration de mot de passe. + <#break> + <#case "WEAK_PASSWORD"> + <@form_error>Nouveau mot de passe trop faible. + <#break> + <#case "MISMATCH_PASSWORD"> + <@form_error>Le mot de passe et sa confirmation ne sont pas identiques. + <#break> + <#case "PROHIBITED"> + <@form_error>Vous ne pouvez pas utiliser ce mot de passe. + <#break> + + <@form_text label="Adresse e-mail" name="mail" id="conf-mail" value=data.cMail! maxLength=128 /> + <@form_text label="Code de confirmation" name="code" id="conf-code" value=data.cCode! maxLength=64 /> + <@form_pwd label="Nouveau mot de passe" name="password" id="conf-pwd1" /> + <@form_pwd label="Confirmation du nouveau mot de passe" name="passwordConfirm" id="conf-pwd2" /> + <@form_submit label="DĆ©finir le nouveau mot de passe" /> + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/planet.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/planet.ftl new file mode 100644 index 0000000..1aed9bf --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/planet.ftl @@ -0,0 +1,329 @@ +<#macro render> +<#if ! data.basic?has_content> +<@page title="PlanĆØte non trouvĆ©e"> +

Cette planĆØte n'existe pas.

+ +<#return> + +<@page title="PlanĆØte ${data.basic.name}"> + <#if data.ownershipError> + <@standalone_error>Malheureusement, nous ne controllons plus cette planĆØte. + + + <@tabs> + + <@tab id="general" title="GĆ©nĆ©ral"> +
+
+ ${data.basic.name?xhtml} +
+ + <@left_column width=250> + <@dt_main> + <@dt_entry title="CoordonnƩes ">(${data.basic.x},${data.basic.y};${data.basic.orbit}) + <#if data.basic.alliance?has_content> + <@dt_entry title="Alliance ">${data.basic.alliance} + <#else> + <@dt_blank /> + + + <#if data.orbit?has_content> + <@dt_entry title="Population ">${data.orbit.population?string(",##0")} + <@dt_entry title="DƩfense statique ">${data.orbit.defencePoints?string(",##0")} + + + <#if data.own?has_content> + <@dt_entry title="Satisfaction "><@happiness value=data.own.happiness /> <@happiness_change value=data.own.hChange /> + <@dt_entry title="BƩnƩfice ">${data.own.income?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Charges ">${data.own.upkeep?string(",##0")} <@abbr_bgc/> + + + + + <@right_column width=250> + <#if data.orbit?has_content> + <@dt_main> + + <#if data.orbit.ownFleet gt 0> + <@dt_entry title="Puissance de flotte propre ">${data.orbit.ownFleet?string(",##0")} + <#else> + <@dt_blank /> + + + <#if data.orbit.friendlyFleet gt 0> + <@dt_entry title="Puissance de flotte alliƩe ">${data.orbit.friendlyFleet?string(",##0")} + <#else> + <@dt_blank /> + + + <#if data.orbit.hostileFleet gt 0> + <@dt_entry title="Puissance de flotte hostile">${data.orbit.hostileFleet?string(",##0")} + <#else> + <@dt_blank /> + + + <#if data.orbit.battle?has_content> + <@dt_entry title="">Voir la bataille + <#else> + <@dt_blank /> + + + <@dt_blank /><@dt_blank /><@dt_blank /><@dt_blank /><@dt_blank /> + + + + +
+ + <#if data.own?has_content> + <#if data.own.status.renamePossible && data.page.special! != 'v'> + <#switch data.renameError!> + <#case "EMPTY"><@standalone_error>Veuillez spĆ©cifier un nom.<#break> + <#case "INVALID"><@standalone_error>Nom de planĆØte invalide.<#break> + <#case "UNAVAILABLE"><@standalone_error>Ce nom de planĆØte existe dĆ©jĆ .<#break> + <#case "BANNED"><@standalone_error>Ce nom a Ć©tĆ© banni.<#break> + + <@lineform action="planet-${data.id}-rename" name="rename" hash="general"> + <#if data.renamingTo?has_content> + <#assign newName = data.renamingTo!> + + Renommer la planĆØte en <@ff_text name="name" id="rename-name" maxLength=20 size=21 value=newName! /> + <@ff_submit label="Renommer la planĆØte" /> + + + + <#if data.own.status.abandonPossible && data.page.special! != 'v'> + <@lineform action="planet-${data.id}-abandon" name="abandon" hash="general"> + <@ff_submit label="Abandonner la planĆØte" /> + + <#elseif data.own.status.abandonTime gt 0> + <@lineform action="planet-${data.id}-cancel-abandon" name="abandon" hash="general"> + Abandon de la planĆØte dans <@duration rTime=data.own.status.abandonTime gTime=data.own.status.abandonGameTime /> +   + <#if data.page.special! != 'v'> + <@ff_submit label="Annuler" /> + + + + + + + + <#if data.orbit?has_content> + + <#if data.orbit.buildings?size gt 0 || data.own?has_content> + <@tab id="buildings" title="BĆ¢timents"> + + <#if data.orbit.buildings?size gt 0> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">BĆ¢timent + <@lv_column width=50 centered=true>Nombre + <#if data.own?has_content> + <@lv_column width=150 centered=true>Production + <@lv_column width=50 centered=true>Emplois + <@lv_column width=100 centered=true>Charges + + + + <#list data.orbit.buildings as building> + <@lv_line> + <@lv_column> + ${building.name?xhtml} + <#if data.own?has_content> +
${building.description?xhtml}
+ + + <@lv_column centered=true>${building.amount?string(",##0")} + <#if data.own?has_content> + <@lv_column centered=true> + ${building.output?string(",##0")} + <#switch building.produces> + <#case "CASH">production ind.<#break> + <#case "DEF">dĆ©fense<#break> + <#case "WORK">production mil.<#break> + <#case "POP">croissance<#break> + + + <@lv_column centered=true>${building.jobs?string(",##0")} + <@lv_column centered=true>${building.upkeep?string(",##0")} <@abbr_bgc/> + + + + + <#else> + <@dt_main><@dt_status>Aucun bĆ¢timent sur cette planĆØte. + + + <#if data.own?has_content> + <#if data.page.special! != 'v'> + <#if data.own.civQueue.appendPossible> + <@lineform name="build-civ" action="planet-${data.id}-build-civ" hash="buildings"> + Construire <@ff_text name="amount" id="civ-build-amount" size=5 maxLength=4 value="" /> + <@ff_select name="type" id="civ-build-type"> + <@form_option value="0" text="(type de bĆ¢timent)" /> + <#list data.own.bBuildings as building> + <@form_option value=building.id text=building.name /> + + + <@ff_submit label="Ajouter Ć  la liste" /> + +
+ <#list data.own.bBuildings as building> +
+ <@dt_main> + <@dt_status>${building.description?xhtml} + <@dt_entry title="Coƻt ">${building.cost?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Charges ">${building.upkeep?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Temps de construction "> + <#if building.time?has_content> + <@duration rTime=building.time gTime=building.gameTime /> + <#else> + N/A + + + <@dt_entry title="Emplois ">${building.workers?string(",##0")} + <@dt_entry title="Production ">${building.output?string(",##0")} + <#switch building.prodType> + <#case "CASH">production ind.<#break> + <#case "DEF">dƩfense<#break> + <#case "WORK">production mil.<#break> + <#case "POP">croissance<#break> + + + +
+ +
+ + <#if data.orbit.buildings?size gt 0> + <#if data.destructionFailed!false> + <@standalone_error>Tentative de destruction d'un trop grand nombre de bĆ¢timents + + <@lineform name="destroy" action="planet-${data.id}-destroy" hash="buildings"> + DĆ©truire <@ff_text name="amount" id="civ-destroy-amount" size=5 maxLength=4 value="" /> + <@ff_select name="type" id="civ-destroy-type"> + <@form_option value="0" text="(type de bĆ¢timent)" /> + <#list data.orbit.buildings as building> + <@form_option value=building.id text=building.name /> + + + <@ff_submit label="Ajouter Ć  la liste" /> + + + + + + <#if data.own.civQueue.items?size gt 0> + <#if data.page.special! != 'v'> + <@lineform name="flush-civ-queue" action="planet-${data.id}-flush-civ" hash="buildings"> + Retirer tous les Ć©lĆ©ments de la liste de construction (les investissements seront perdus) + <@ff_submit label="Vider" /> + + + + <@listview> + <@lv_line headers=true> + <@lv_column width=80 centered=true>Nombre + <@lv_column width="x">Nature + <@lv_column width=200 centered=true>Temps + <@lv_column width=70 centered=true>Investissement + + <#list data.own.civQueue.items as qItem> + <@lv_line> + <@lv_column centered=true>${qItem.amount?string(",##0")} + <@lv_column>${qItem.name} <#if qItem.destroy>(destruction)<#else>(construction) + <@lv_column centered=true> + <#if qItem.timeLeft?has_content> + <@duration rTime=qItem.timeLeft gTime=qItem.gameTimeLeft /> + <#else> + N/A + + + <@lv_column centered=true>${qItem.invested?string(",##0")} <@abbr_bgc/> + + + + + + + + + + <#if data.own?has_content> + <@tab id="ships" title="Chantiers navals"> + <#if data.page.special! != 'v'> + <#if data.own.milQueue.appendPossible> + <@lineform name="build-mil" action="planet-${data.id}-build-mil" hash="ships"> + Construire <@ff_text name="amount" id="mil-build-amount" size=5 maxLength=4 value="" /> + <@ff_select name="type" id="mil-build-type"> + <@form_option value="0" text="(type de vaisseau)" /> + <#list data.own.bShips as ship> + <@form_option value=ship.id text=ship.name /> + + + <@ff_submit label="Ajouter Ć  la liste" /> + +
+ <#list data.own.bShips as ship> +
+ <@dt_main> + <@dt_status>${ship.description?xhtml} + <@dt_entry title="Coƻt ">${ship.cost?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Charges ">${ship.upkeep?string(",##0")} <@abbr_bgc/> + <@dt_entry title="Temps de Construction "> + <#if ship.time?has_content> + <@duration rTime=ship.time gTime=ship.gameTime /> + <#else> + N/A + + + <@dt_entry title="Puissance ">${ship.power?string(",##0")} + <@dt_entry abbr="TVOO " title="Temps de vol orbite-Ơ-orbite"> + <@duration rTime=ship.flightTime gTime=ship.gameFlightTime /> + + +
+ +
+ + + + <#if data.own.milQueue.items?size gt 0> + <#if data.page.special! != 'v'> + <@lineform name="flush-mil-queue" action="planet-${data.id}-flush-mil" hash="ships"> + Retirer tous les Ć©lĆ©ments de la liste de construction (les investissements seront perdus) + <@ff_submit label="Vider" /> + + + + <@listview> + <@lv_line headers=true> + <@lv_column width=80 centered=true>Nombre + <@lv_column width="x">Vaisseau + <@lv_column width=200 centered=true>Temps + <@lv_column width=70 centered=true>Investissement + + <#list data.own.milQueue.items as qItem> + <@lv_line> + <@lv_column centered=true>${qItem.amount?string(",##0")} + <@lv_column>${qItem.name} + <@lv_column centered=true> + <#if qItem.timeLeft?has_content> + <@duration rTime=qItem.timeLeft gTime=qItem.gameTimeLeft /> + <#else> + N/A + + + <@lv_column centered=true>${qItem.invested?string(",##0")} <@abbr_bgc/> + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/planets.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/planets.ftl new file mode 100644 index 0000000..e8fb997 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/planets.ftl @@ -0,0 +1,167 @@ +<#macro render> +<@page title="PlanĆØtes"> + <#assign pl = data.planets> + <#if pl?size == 0> +

Nous ne possĆ©dons plus aucune planĆØte.

+

Obtenir une nouvelle planĆØte ?

+ <#else> + + <@tabs> + + <@tab id="general" title="GĆ©nĆ©ral"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Nom + <@lv_column width=90 centered=true>CoordonnĆ©es + <@lv_column width=90 centered=true>Satisfaction + <@lv_column width=90 right=true>Population + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column centered=true>(${planet.x},${planet.y};${planet.orbit}) + <@lv_column centered=true><@happiness value=planet.happiness /> + <@lv_column right=true>${planet.population?string(",##0")} + + + + + + <@tab id="eco" title="Ɖconomie"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Nom + <@lv_column width=110 right=true>BĆ©nĆ©fice + <@lv_column width=110 right=true>Charges + <@lv_column width=110 right=true>Revenu + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column right=true>${planet.income?string(",##0")} <@abbr_bgc /> + <@lv_column right=true>${planet.upkeep?string(",##0")} <@abbr_bgc /> + <@lv_column right=true> + <#if planet.upkeep gt planet.income> + + + ${( planet.income - planet.upkeep )?string(",##0")} <@abbr_bgc /> + <#if planet.upkeep gt planet.income> + + + + + + + + + <@tab id="prod" title="Production"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Nom + <@lv_column width=90 right=true>Militaire + <@lv_column width=90 right=true>Industriel + <@lv_column width=120 right=true>Aug. Croissance + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column right=true>${planet.militaryProduction?string(",##0")} + <@lv_column right=true>${planet.industrialProduction?string(",##0")} + <@lv_column right=true>${planet.growthProduction?string(",##0")} + + + + + + <@tab id="cons" title="Construction"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Nom + <@lv_column width=200 centered=true>Item actuellement produit + <@lv_column width=90 right=true>Investissement + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column centered=true> + <#if planet.civAmount = 0> + N/A + <#else> + ${planet.civAmount?string(",##0")}x + ${planet.civName?xhtml} + <#if planet.civDestroy> + (destruction) + <#else> + (construction) + + + + <@lv_column right=true>${planet.civInvestment?string(",##0")} <@abbr_bgc /> + + + + + + <@tab id="ships" title="Chantiers navals"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Nom + <@lv_column width=200 centered=true>Item actuellement produit + <@lv_column width=90 right=true>Investissement + + + <#list pl as planet> + <@lv_line> + <@lv_column>${planet.name?xhtml} + <@lv_column centered=true> + <#if planet.milAmount = 0> + N/A + <#else> + ${planet.milAmount?string(",##0")}x + ${planet.milName?xhtml} + + + <@lv_column right=true>${planet.milInvestment?string(",##0")} <@abbr_bgc /> + + + + + + <@tab id="mil" title="Militaire"> + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Nom + <@lv_column width=90 right=true>Stationnaire + <@lv_column width=110 right=true>Flottes propres + <@lv_column width=90 right=true>AlliĆ©es + <@lv_column width=90 right=true>Hostiles + + + <#list pl as planet> + <@lv_line> + <@lv_column> + <#if planet.battle?has_content> + + + ${planet.name?xhtml} + <#if planet.battle?has_content> + + + + <@lv_column right=true>${planet.fpStatic?string(",##0")} + <@lv_column right=true>${planet.fpOwn?string(",##0")} + <@lv_column right=true>${planet.fpFriendly?string(",##0")} + <@lv_column right=true>${planet.fpHostile?string(",##0")} + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/reactivation.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/reactivation.ftl new file mode 100644 index 0000000..db56988 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/reactivation.ftl @@ -0,0 +1,24 @@ +<#macro render> +<#if data.success> +<@page title="rĆ©activation de compte"> +

+ Votre compte a Ć©tĆ© rĆ©activĆ© avec succĆØs. Le conde de confirmation a Ć©tĆ© envoyĆ© Ć  ${data.address}. +

+

+ Une fois que vous avez reƧu cet e-mail, veuillez aller sur la page de confirmation. +

+ +<#else> +<@page title="Erreur de rƩactivation de compte"> +

+ Une erreur a eu lieu lors de l'envoi d'un e-mail Ć  votre adresse, ${data.address}. +

+

+ Si votre adresse est toujours valide, vous pouvez envisager d'attendre un peu et d'essayer Ć  nouveau. +

+

+ Ou le serveur est peut-ĆŖtre sous acide, auquel cas vous devriez informer l'Ć©quipe d'administration. +

+ + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/register.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/register.ftl new file mode 100644 index 0000000..32a4c93 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/register.ftl @@ -0,0 +1,56 @@ +<#macro render> +<@page title="Enregistrement"> + <@form name="register" action="register"> + <#switch data.mailError!""> + <#case "EMPTY"> + <@form_error>Adresse e-mail vide. + <#break> + <#case "INVALID"> + <@form_error>Adresse e-mail invalide. + <#break> + <#case "IN_USE"> + <@form_error>Cette adresse e-mail est dĆ©jĆ  associĆ©e Ć  un compte. + <#break> + <#case "SEND_FAIL"> + <@form_error>Impossible d'envoyer le code de confirmation Ć  cette adresse. + <#break> + <#case "MISMATCH"> + <@form_error>L'adresse e-mail et sa confirmation ne sont pas identiques. + <#break> + <#default> + <@form_extra>L'adresse e-mail DOIT exister. + + <@form_text label="Adresse e-mail" maxLength=128 name="mail" value=data.mail! /> + <@form_text label="Adresse e-mail (confirmation)" maxLength=128 name="mailConfirm" value=data.mail! /> + + <#switch data.passwordError!""> + <#case "EMPTY"> + <@form_error>Mot de passe vide. + <#break> + <#case "TOO_WEAK"> + <@form_error>Cet mot de passe est trop faible. + <#break> + <#case "MISMATCH"> + <@form_error>Le mot de passe et sa confirmation ne sont pas identiques. + <#break> + <#default> + <@form_extra>Au moins 6 catactĆØres, contenant Ć  la fois des lettres et des chiffres. Points bonus pour les caractĆØres spĆ©ciaux, les espaces et les mots de passe extrĆØmement longs. + + <@form_pwd label="Mot de passe" name="password" /> + <@form_pwd label="Mot de passe (confirmation)" name="passwordConfirm" /> + + <@form_select name="language" label="Langue"> + <#if dataType == "ListLanguagesResponse"> + <#assign lList = data.languages> + <#else> + <#assign lList = data.supportedLanguages.languages> + + <#list lList as lang> + <@form_option text=lang.name value=lang.id selected=(lang.id == language) /> + + + + <@form_submit label="S'enregistrer" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/registered.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/registered.ftl new file mode 100644 index 0000000..456884a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/registered.ftl @@ -0,0 +1,13 @@ +<#macro render> +<@page title="Compte crĆ©Ć©"> +

+ Votre compte a Ć©tĆ© crĆ©Ć© avec succĆØs. +

+

+ Un e-mail contenant son code de confirmation a ƩtƩ envoyƩ Ơ votre adresse, ${data.mail?xhtml}. +

+

+ Une fois que vous l'aurez reƧu, vous serez en mesure de vous connecter et de confirmer votre compte. +

+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/splitFleet.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/splitFleet.ftl new file mode 100644 index 0000000..d213195 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/splitFleet.ftl @@ -0,0 +1,40 @@ +<#macro render> +<@page title="Diviser la flotte"> +
+
+ + <#if data.shipsError> + <@standalone_error>Nombre de vaisseaux ou de flottes rƩsultantes invalides + + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Type de vaisseaux + <@lv_column width=150>Nombre initial + <@lv_column width=150>Nombre dans la nouvelle flotte + + <#list data.ships as ships> + <@lv_line headers> + <@lv_column>${ships.name} + <@lv_column>${ships.amount?string(",##0")} + <@lv_column> + <@ff_text name="ships_${ships.id}" id="ships-${ships.id}" value=ships.selectedAmount /> + + + + + <#if data.nameError> + <@standalone_error>Nom de flotte invalide. + +

+ CrĆ©er + <@ff_text name="nFleets" id="n-fleets" value=data.nFleets size=3 maxLength=2 /> + nouvelle(s) flotte(s) nommĆ©e(s) + <@ff_text name="name" id="name" value=data.name size=20 maxLength=40 /> +   + <@ff_submit label="Ok" /> + <@ff_submit label="Annuler" name="cancel" /> +

+
+
+ + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/static.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/static.ftl new file mode 100644 index 0000000..cbf01c8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/static.ftl @@ -0,0 +1 @@ +<#macro render><#if dataType == "HashMap"><#include "../static/${data.name}.ftl" /><#else><#include "../static/${data}.ftl" /> \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/validation.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/validation.ftl new file mode 100644 index 0000000..683d0f4 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/fr/types/validation.ftl @@ -0,0 +1,50 @@ +<#macro render> +<@page title="Validation de compte"> + <@form action="validation" name="validation"> + <@form_extra> + Avant d'aller plus loin, vous devez valider votre compte en utilisant le code de confirmation qui vous a ƩtƩ envoyƩ par e-mail.
+ Vous pouvez aussi choisir le nom de votre empire et de votre premiĆØre planĆØte. + + + <#if data.wrongToken> + <@form_error>Code ds confirmation incorrect. + + <@form_text label="Code de confirmation" value=data.token! name="token" maxLength=64 /> + + <#switch data.empireError!> + <#case "EMPTY"><@form_error>Veuillez choisir un nom d'empire.<#break> + <#case "INVALID"><@form_error>Nom d'empire invalide.<#break> + <#case "UNAVAILABLE"><@form_error>Ce nom d'empire n'est pas disponible.<#break> + <#case "BANNED"><@form_error>Ce nom d'empire a Ć©tĆ© banni.<#break> + + + <#if data.previousEmpires?size == 0> + <@form_text label="Nom d'empire" value=data.empire! name="empire" maxLength=20 /> + + <#else> + <@form_select name="old" label="RĆ©utiliser un nom d'empire"> + <#list data.previousEmpires as oldName> + <@form_option text=oldName selected=( oldName == data.empire! ) /> + + + + <@form_extra>Laissez ce champ vide si vous voulez rĆ©utiliser un ancien nom d'empire. + <#if ! data.previousEmpires?seq_contains(data.empire!)> + <#assign empValue = data.empire!> + + <@form_text name="empire" label="Nouveau nom d'empire" value=empValue! maxLength=20 /> + + + + <#switch data.planetError!> + <#case "EMPTY"><@form_error>Veuillez choisir un nom de planĆØte.<#break> + <#case "INVALID"><@form_error>Nom de planĆØte invalide.<#break> + <#case "UNAVAILABLE"><@form_error>Ce nom de planĆØte n'est pas disponible.<#break> + <#case "BANNED"><@form_error>Ce nom de planĆØte a Ć©tĆ© banni.<#break> + + <@form_text name="planet" label="Nom de planĆØte" value=data.planet! maxLength=20 /> + + <@form_submit label="Entrer dans le jeu" /> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/columns.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/columns.ftl new file mode 100644 index 0000000..6d79301 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/columns.ftl @@ -0,0 +1,18 @@ +<#macro left_column width=0> + <#if width gt 0> +
+ <#else> +
+ + <#nested> +
+ +<#macro right_column width=0> + <#if width gt 0> +
+ <#else> +
+ + <#nested> +
+ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/datatable.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/datatable.ftl new file mode 100644 index 0000000..e02f8e8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/datatable.ftl @@ -0,0 +1,20 @@ +<#macro dt_main title=""> + + <#if title != ""> + + + <#nested> +
${title}
+ +<#macro dt_entry title abbr="" width=0> + + style="width: ${width}px"><#if title == ""> <#else><#if abbr != "">${abbr?xhtml}<#else>${title?xhtml}: + <#nested> + + +<#macro dt_blank> +   + +<#macro dt_status> + <#nested> + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/fields.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/fields.ftl new file mode 100644 index 0000000..63dcdcd --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/fields.ftl @@ -0,0 +1,20 @@ +<#macro ff_text name value id="" maxLength=0 size=0> + maxlength="${maxLength?string}" <#if size gt 0>size="${size?string}" /> + +<#macro ff_pwd id name> + + +<#macro ff_select id name style=""> + + +<#macro ff_checkbox id name value checked=false> + checked="checked" /> + +<#macro form_option text="" selected=false value=""> + value="${value?xhtml}"<#if selected> selected="selected"><#if text == ""><#nested><#else>${text?xhtml} + +<#macro ff_submit label extraClass="" name="" style=""> + name="${name?xhtml}" type="submit" value="${label?xhtml}" <#if style != "">style="${style}" /> + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/form.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/form.ftl new file mode 100644 index 0000000..4544473 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/form.ftl @@ -0,0 +1,98 @@ +<#macro form action name="" hash=""> +
+
#${hash?url}" method="post"> + + <#nested> +
+
+
+ +<#macro form_field_line label id> + + + <#nested> + + +<#macro form_text label name value id="" maxLength=0 multiline=false> + <#if id = ""> + <#local id = name> + + <@form_field_line label=label id=id> + <#if multiline> + + <#else> + <@ff_text id=id name=name maxLength=maxLenth value=value /> + + + +<#macro form_checkbox label name value id="" checked=false> + <#if id = ""> + <#local id = name> + + <@form_field_line label=label id=id> + <@ff_checkbox id=id name=name value=value checked=checked /> + + +<#macro form_pwd label name id=""> + <#if id = ""> + <#local id = name> + + <@form_field_line label=label id=id> + <@ff_pwd id=id name=name /> + + +<#macro form_select label name id=""> + <#if id = ""> + <#local id = name> + + <@form_field_line label=label id=id> + <@ff_select id=id name=name> + <#nested> + + + +<#macro form_part title> + + ${title} + + +<#macro form_extra> + + <#nested> + + +<#macro form_error> + + <#nested> + + +<#macro standalone_error> +
+ + + + +
<#nested>
+
+ +<#macro form_submit label extraClass=""> + +   + <@ff_submit label=label extraClass=extraClass /> + + +<#macro form_extended_submit label extraClass=""> + +   + <@ff_submit label=label extraClass=extraClass /><#nested /> + + +<#macro lineform action name="" hash=""> +
+
#${hash?url}" method="post"> + + +
<#nested>
+
+
+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/happiness.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/happiness.ftl new file mode 100644 index 0000000..ada6ca6 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/happiness.ftl @@ -0,0 +1,20 @@ +<#macro happiness value> + <#if value lt 26> + <#assign colour = "#ffafaf"> + <#elseif value lt 51> + <#assign colour = "#ffffaf"> + <#elseif value lt 76> + <#assign colour = "#afafff"> + <#else> + <#assign colour = "#afffaf"> + + ${value}% + +<#macro happiness_change value> + <#switch data.own.hChange> + <#case -2>--<#break> + <#case -1>-<#break> + <#case 1>+<#break> + <#case 2>++<#break> + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/lists.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/lists.ftl new file mode 100644 index 0000000..798342a --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/lists.ftl @@ -0,0 +1,25 @@ +<#macro listview> + + <#nested> +
+ +<#macro lv_line headers=false class=""> + class="${class}<#if headers>headers"<#elseif headers> class="headers"> + <#nested> + + +<#macro lv_column width=0 centered=false right=false> + <#if width?is_string> + + <#nested> + + <#elseif width gt 0> + + <#nested> + + <#else> + + <#nested> + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/tabs.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/tabs.ftl new file mode 100644 index 0000000..b1ab861 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/layout/tabs.ftl @@ -0,0 +1,13 @@ +<#macro tabs> +
+ <#nested> +
+ +<#macro tab id title> +
+

${title?xhtml}

+
+ <#nested> +
+
+ \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/version.ftl b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/version.ftl new file mode 100644 index 0000000..c9406cf --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/fm/version.ftl @@ -0,0 +1,2 @@ +<#macro version>Milestone 1 +<#macro full_version>Beta 6 milestone 1 (5.99.1) \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/main-servlet.xml b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/main-servlet.xml new file mode 100644 index 0000000..25ea52b --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/main-servlet.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/web.xml b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/web.xml new file mode 100644 index 0000000..19183e1 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/WEB-INF/web.xml @@ -0,0 +1,83 @@ + + + + legacyworlds-web-main + + + charsetFilter + org.springframework.web.filter.CharacterEncodingFilter + + encoding + UTF-8 + + + forceEncoding + 1 + + + + + charsetFilter + /* + + + + main + org.springframework.web.servlet.DispatcherServlet + 1 + + + + pass-through + org.apache.catalina.servlets.DefaultServlet + 1 + + + + pass-through + *.js + + + + pass-through + *.css + + + + pass-through + *.jpg + + + + pass-through + *.png + + + + pass-through + *.gif + + + pass-through + *.cab + + + pass-through + *.jar + + + pass-through + *.lng + + + pass-through + *.class + + + + main + / + + + diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/css/main.css b/legacyworlds-web/legacyworlds-web-main/WebContent/css/main.css new file mode 100644 index 0000000..48ff3b4 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/css/main.css @@ -0,0 +1,842 @@ +/* General appearance */ +* { + font-family: Arial, sans-serif; + font-size: 10pt; + padding: 0px; + margin: 0px; + color: white; + scrollbar-face-color: #1f1f1f; + scrollbar-highlight-color: #1f1f1f; + scrollbar-3dlight-color: #3f3f3f; + scrollbar-darkshadow-color: #3f3f3f; + scrollbar-shadow-color: #1f1f1f; + scrollbar-arrow-color: #afafaf; + scrollbar-track-color: #1f1f1f; +} + +h1 { + font-size: 16pt +} + +h2 { + font-size: 14pt +} + +h3 { + font-size: 12pt +} + +h4 { + font-size: 11pt +} + +h5 { + font-size: 11pt +} + +h6 { + font-size: 10pt +} + +body { + background-color: #000; + color: #888; + overflow: auto; +} + +/* Page layout */ +#extframe { + position: absolute; + top: 50%; + left: 0px; + width: 100%; + height: 1px +} + +.internal { + margin-left: -475px; + position: absolute; + left: 50%; + width: 950px; +} + +#intframe { + top: -280px; + height: 560px; + background-image: url(../img/background.jpg); + background-repeat: no-repeat; +} + +/* Footer (DCD link) */ +#footer { + top: 280px; + text-align: center; + font-size: 8pt; + font-style: italic; + padding: 2px 0 0 0; +} + +#footer a,#footer a:visited { + font-size: 8pt; + text-decoration: none; + color: white; +} + +#footer a:hover { + text-decoration: underline; +} + +/* "Home" button */ +#hbutton { + display: block; + position: absolute; + top: 12px; + left: 10px; + width: 272px; + height: 90px; + background-color: transparent; +} + +#hbutton span { + display: none; +} + +/* Current version text */ +#version { + position: absolute; + top: 89px; + left: 299px; + width: 640px; + height: 22px; + font-size: 10pt; + text-align: center; + font-style: italic; + font-weight: bold; +} + +/* Log-in/player info box */ +#lbox { + position: absolute; + top: 9px; + left: 699px; + width: 230px; + height: 60px; + text-align: right; + font-size: 10pt; +} + +#lbox a { + color: white; + text-decoration: none; + font-style: italic; +} + +#lbox a:hover { + text-decoration: underline; +} + +/* Menu and buttons */ +a.mbutton { + display: block; + position: absolute; + height: 21px; + width: 250px; + left: 14px; + padding: 18px 0px; + background-repeat: no-repeat; + border-style: none; + border-width: 0px; + font-weight: bold; + text-align: center; + text-decoration: none; + color: #ddd; + background-position: 0px 0px; + font-size: 12pt; +} + +a.mbutton:hover { + color: white; + background-position: 0px -57px; +} + +a#b0 { + top: 136px; + background-image: url(../img/button-0.png); +} + +a#b1 { + top: 193px; + background-image: url(../img/button-1.png); +} + +a#b2 { + top: 250px; + background-image: url(../img/button-2.png); +} + +a#b3 { + top: 307px; + background-image: url(../img/button-3.png); +} + +a#b4 { + top: 364px; + background-image: url(../img/button-4.png); +} + +a#b5 { + top: 421px; + background-image: url(../img/button-5.png); +} + +a#b6 { + top: 478px; + background-image: url(../img/button-6.png); +} + +/* Content frame */ +.cframe { + position: absolute; + left: 299px; + top: 117px; + width: 637px; + height: 426px; + overflow: auto; + background-color: transparent; + color: white; +} + +.cframe.full-width { + left: 15px; + width: 921px; +} + +.cframe.offline { + height: 279px; + top: 264px; + overflow: hidden; +} + +.cframe p { + color: #CCCCCC; +} + +.cframe ul,.cframe ol { + margin: 0px 0px 0px 20px; + padding: 0px 0px 0px 10px; +} + +.cframe li { + margin: 0px 0px 0px 20px; + padding: 0px 0px 0px 0px; +} + +/* Text in the content frame */ +.cframe ul { + list-style-type: square; +} + +.cframe li { + font-size: 10pt; +} + +.cframe li:first-letter { + font-size: 11pt; + font-weight: bold; +} + +.cframe p { + margin: 5px 10px 5px 30px; + text-align: justify; + text-indent: 10px; + font-size: 10pt; +} + +.cframe p:first-letter { + font-size: 11pt; + font-weight: bold; +} + +/* Tabs */ +.tab-buttons { + width: 100%; + text-align: center; + margin: 0 0 5px 0; + padding: 5px 0 0 0; + height: 20px; +} + +a.tab-button { + padding: 4px; + margin: 1px 0 0 5px; + background-color: #3f3f3f; + border: 1px solid #7f7f7f; + text-decoration: none; + font-style: normal; +} + +a.tab-button:hover { + background-color: #4f4f4f; + border-color: #8f8f8f; +} + +a.tab-button.selected-tab,a.tab-button.selected-tab:hover { + background-color: #7f7f7f; + border-color: white; +} + +/* Top/centered layer (title, planet links) */ +div.top-centered { + position: absolute; + left: 330px; + width: 320px; + top: 10px; + height: 50px; + text-align: center; +} + +#tc-title { + font-weight: bold; + font-size: 13pt; + text-align: center; +} + +div#tc-title { + top: 30px; + height: 30px; +} + +span.special-info { + color: red; + font-weight: bold; +} + +/* Forms */ +.form-container { + width: 509px; + margin: 0 64px; +} + +.full-width .form-container { + width: 793px; + margin: 0 64px; +} + +.form-container table { + width: 509px; + table-layout: fixed; +} + +.full-width .form-container table { + width: 793px; +} + +.form-field th,.form-submit th { + text-align: right; + vertical-align: middle; + height: 16px; + width: 200px; + padding: 4px; + font-weight: normal; +} + +.form-field td { + padding: 1px 2px 1px 0px; +} + +.form-submit td { + padding: 10px 0px 30px 0px; +} + +.form-part th { + padding: 30px 0 0 0; +} + +.form-submit .input { + padding: 5px 20px; +} + +.form-submit .input:hover { + padding: 5px 20px; + border-color: #dfdfdf; + background-color: #7f7f7f; +} + +.form-extra td { + padding: 4px 0px 0px 100px; + text-align: justify; +} + +.form-field .input { + width: 100%; + height: 20px; +} + +.form-error td { + font-size: 11pt; + color: white; + background-color: red; + font-weight: bold; + margin: 2px 0px; + padding: 5px; +} + +.input { + border-style: solid; + border-width: 1px; + border-color: #afafaf; + background-color: #3f3f3f; + color: white; + font-size: 10pt; + margin: 1px 0px +} + +/* Data display */ +.data-table { + width: 100%; + margin: 0 0 10px 0; +} + +.data-table th { + text-align: right; + padding: 2px 10px 2px 0px; + font-weight: normal; + color: #cccccc; + width: 50%; +} + +.data-table th.title { + text-align: center; + padding: 0px 0px 5px 0px; + font-weight: bold; + font-size: 12pt; + color: white; +} + +.data-table td.status { + text-align: center; + color: #cccccc; +} + +/* List display */ +.list-view { + width: 573px; + margin: 0 32px 20px 32px; + border-collapse: collapse; +} + +.list-view th,.list-view td { + padding: 0; + margin: 0; + vertical-align: top; +} + +.list-view .headers th { + border-style: solid; + border-color: white; + border-width: 0 0 1px 0; +} + +.list-view td { + color: #cccccc; +} + +/* Column layout */ +.column { + width: 310px +} + +.left-column { + float: left +} + +.right-column { + padding: 0 0 0 310px; +} + +/* Misc */ +div.auto-hide { + padding: 2px 0px 5px 20px; +} + +/* Map */ +table.map { + border: 1px solid white; + border-collapse: collapse +} + +.map td { + border: 1px solid white; + vertical-align: top +} + +.map img { + display: block; + float: left; + border: 0; + padding: 0; + margin: 0; + border: 0 +} + +.map a { + display: block; + text-decoration: none +} + +.map a.own-planet { + color: #afffaf; +} + +.map a.allied-planet { + color: #afafff; +} + +.map a.other-planet { + color: #ffffaf; +} + +.map a.enemy-planet { + color: #ffafaf; +} + +.map-empty div { + text-align: center; + font-style: italic +} + +div.map-invert { + cursor: pointer; +} + +.map div.map-invert a,.map div.map-invert a.own-planet,.map div.map-invert a.allied-planet,.map div.map-invert a.other-planet + { + color: black +} + +div.map-bg-none { + background-color: #cccccc +} + +div.map-bg-allied { + background-color: #afafff +} + +div.map-bg-own { + background-color: #afffaf +} + +div.map-bg-other { + background-color: #ffffaf +} + +div.map-bg-enemy { + background-color: #ffafaf +} + +/* Map - 3x3 */ +.map-0 { + width: 540px; + height: 540px; + margin: 0 49px 0 48px; +} + +.map-0 * { + font-size: 9pt +} + +.map-0 tr { + height: 180px +} + +.map-0 td { + width: 180px +} + +.map-0 div.map-planet { + height: 36px; + width: 100% +} + +.map-0 img { + height: 36px; + width: 36px +} + +.map-0 a { + padding: 10px 0 0 41px +} + +.map-0 .map-empty div { + padding: 82px 0 0 0; +} + +/* Map - 5x5 */ +.map-1 { + width: 600px; + height: 600px; + margin: 0 19px 0 18px; +} + +.map-1 * { + font-size: 6pt +} + +.map-1 tr { + height: 120px +} + +.map-1 td { + width: 120px +} + +.map-1 div.map-planet { + height: 24px; + width: 100% +} + +.map-1 img { + height: 24px; + width: 24px +} + +.map-1 a { + padding: 7px 0 0 27px +} + +.map-1 .map-empty div { + padding: 54px 0 0 0; +} + +/* Map - 7x7 */ +.map-2 { + width: 595px; + height: 595px; + margin: 0 22px 0 22px; +} + +.map-2 * { + font-size: 4pt +} + +.map-2 tr { + height: 85px +} + +.map-2 td { + width: 85px +} + +.map-2 div.map-planet { + height: 17px; + width: 100% +} + +.map-2 img { + height: 17px; + width: 17px +} + +.map-2 a { + padding: 5px 0 0 19px +} + +.map-2 .map-empty div { + padding: 37px 0 0 0; +} + +/* Fleets */ +table.fleets-planet,table.fleets-moving { + border: 1px solid white; + border-collapse: collapse; + margin: 0 0 20px 5px; + width: 610px; +} + +table.selected-fleets { + border: 1px solid white; + border-collapse: collapse; + margin: 10px 0 20px 15px; + width: 600px; +} + +table.fleets-planet td { + border: 1px solid white; +} + +table.fleets-planet td.pic { + width: 32px; + height: 32px; +} + +table.fleets-planet td.planet-data { + width: 150px; + text-align: center; +} + +table.fleets-planet th.planet-name { + text-align: left; + font-weight: normal; + padding: 0 0 0 5px; +} + +table.fleets-planet p { + padding: 8px 0px; + margin: 0; + text-align: center; +} + +table.fleets-list { + width: 100%; + padding: 0; + margin: 0; + border-style: none; + border-collapse: collapse; +} + +table.fleets-list td,table.selected-fleets td { + border-style: none; + vertical-align: top; + padding: 2px 0px; +} + +table.fleets-moving th.mv-header { + border-style: solid; + border-width: 0px 0px 1px 0px; + border-color: white; + height: 32px; +} + +table.fleets-list th,table.selected-fleets th { + font-weight: bold; + border-style: solid; + border-width: 0px 0px 1px 0px; + border-color: white; +} + +table.fleets-list table.data-table th { + text-align: right; + padding: 2px 10px 2px 0px; + font-weight: normal; + color: #cccccc; + width: 40%; + border-style: none; +} + +table.fleets-list .selector,table.selected-fleets .selector { + width: 20px; + text-align: center; +} + +table.fleets-list .name,table.selected-fleets .name { + text-align: left; +} + +table.fleets-list .owner { + text-align: left; + width: 120px; +} + +table.fleets-list .mode { + text-align: center; + width: 20px; +} + +table.fleets-list .power,table.selected-fleets .power { + text-align: right; + width: 80px; +} + +table.fleets-list .fltime,table.selected-fleets .fltime { + text-align: right; + width: 80px; +} + +table.fleets-list .status { + text-align: center; + width: 80px; +} + +table.fleets-moving .timeleft { + text-align: right; + width: 160px; +} + +table.fleets-moving .destination { + text-align: right; + width: 160px; +} + +table.selected-fleets .status { + text-align: center; + width: 60px; +} + +table.selected-fleets .cloc { + text-align: left; + width: 190px; +} + +.list-view .own-fleet,.list-view .own-fleet *,.own-fleet,.own-fleet * { + color: #afffaf; +} + +.list-view .allied-fleet,.list-view .allied-fleet *,.allied-fleet,.allied-fleet * + { + color: #afafff; +} + +.list-view .enemy-fleet,.list-view .enemy-fleet *,.enemy-fleet,.enemy-fleet * + { + color: #ffafaf; +} + +.fleet-ships table { + margin: 0 0 5px 28px; + width: 300px; + border-collapse: collapse; +} + +.fleet-ships table.data-table { + margin: 0 0 5px 0; + width: 280px; +} + +.fleet-ships .ships-type { + text-align: left; +} + +.fleet-ships .ships-amount { + text-align: center; + width: 60px; +} + +.fleet-ships .ships-power { + text-align: right; + width: 120px; +} + +#fleet-actions { + text-align: center; +} + +/* Messages */ +tr.unread-msg * { + font-weight: bold; +} + +tr.int-msg * { + color: #ffffaf; +} + +tr.admin-msg * { + color: #ffafaf; +} + +tr.alliance-msg * { + color: #afafff; +} + +tr.empire-msg * { + color: #afafaf; +} \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/background.jpg b/legacyworlds-web/legacyworlds-web-main/WebContent/img/background.jpg new file mode 100644 index 0000000..b5bd6df Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/background.jpg differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-0.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-0.png new file mode 100644 index 0000000..ed18c52 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-0.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-1.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-1.png new file mode 100644 index 0000000..c62487e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-1.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-2.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-2.png new file mode 100644 index 0000000..2ffec4f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-2.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-3.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-3.png new file mode 100644 index 0000000..f35a722 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-3.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-4.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-4.png new file mode 100644 index 0000000..e2c9548 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-4.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-5.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-5.png new file mode 100644 index 0000000..92560ea Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-5.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-6.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-6.png new file mode 100644 index 0000000..81a8a92 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/button-6.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/1.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/1.png new file mode 100644 index 0000000..9e84247 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/1.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/10.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/10.png new file mode 100644 index 0000000..9b8f882 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/10.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/100.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/100.png new file mode 100644 index 0000000..70bc763 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/100.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/101.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/101.png new file mode 100644 index 0000000..c5f7f29 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/101.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/102.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/102.png new file mode 100644 index 0000000..366189f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/102.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/103.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/103.png new file mode 100644 index 0000000..5b56992 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/103.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/104.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/104.png new file mode 100644 index 0000000..3c552b4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/104.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/105.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/105.png new file mode 100644 index 0000000..a8b71f3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/105.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/106.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/106.png new file mode 100644 index 0000000..4679153 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/106.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/107.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/107.png new file mode 100644 index 0000000..76a6f3d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/107.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/108.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/108.png new file mode 100644 index 0000000..61791f5 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/108.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/109.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/109.png new file mode 100644 index 0000000..1ae572d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/109.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/11.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/11.png new file mode 100644 index 0000000..4202fc0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/11.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/110.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/110.png new file mode 100644 index 0000000..0d63171 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/110.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/111.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/111.png new file mode 100644 index 0000000..88e6837 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/111.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/112.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/112.png new file mode 100644 index 0000000..9d91574 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/112.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/113.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/113.png new file mode 100644 index 0000000..f3b9820 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/113.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/114.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/114.png new file mode 100644 index 0000000..2e19dd7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/114.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/115.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/115.png new file mode 100644 index 0000000..38a979b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/115.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/116.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/116.png new file mode 100644 index 0000000..8582abd Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/116.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/117.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/117.png new file mode 100644 index 0000000..de6b366 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/117.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/118.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/118.png new file mode 100644 index 0000000..9ae10c0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/118.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/119.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/119.png new file mode 100644 index 0000000..9add564 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/119.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/12.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/12.png new file mode 100644 index 0000000..b0843c2 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/12.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/120.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/120.png new file mode 100644 index 0000000..8ea8b2f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/120.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/121.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/121.png new file mode 100644 index 0000000..01f1ce1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/121.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/122.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/122.png new file mode 100644 index 0000000..da8e53c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/122.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/123.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/123.png new file mode 100644 index 0000000..1250a13 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/123.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/124.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/124.png new file mode 100644 index 0000000..b0cb288 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/124.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/125.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/125.png new file mode 100644 index 0000000..a185f0d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/125.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/126.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/126.png new file mode 100644 index 0000000..6bbc86d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/126.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/127.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/127.png new file mode 100644 index 0000000..2c4b0a8 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/127.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/128.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/128.png new file mode 100644 index 0000000..fce67de Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/128.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/129.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/129.png new file mode 100644 index 0000000..e627ec1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/129.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/13.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/13.png new file mode 100644 index 0000000..e07462f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/13.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/130.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/130.png new file mode 100644 index 0000000..ae53781 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/130.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/131.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/131.png new file mode 100644 index 0000000..4ab8594 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/131.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/132.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/132.png new file mode 100644 index 0000000..180622b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/132.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/133.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/133.png new file mode 100644 index 0000000..418b6f3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/133.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/134.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/134.png new file mode 100644 index 0000000..d41ef7e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/134.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/135.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/135.png new file mode 100644 index 0000000..d7e8013 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/135.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/136.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/136.png new file mode 100644 index 0000000..1b51e59 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/136.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/137.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/137.png new file mode 100644 index 0000000..c0edc0b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/137.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/138.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/138.png new file mode 100644 index 0000000..cd77ced Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/138.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/139.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/139.png new file mode 100644 index 0000000..998ab03 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/139.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/14.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/14.png new file mode 100644 index 0000000..e98fc4f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/14.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/140.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/140.png new file mode 100644 index 0000000..015410c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/140.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/141.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/141.png new file mode 100644 index 0000000..a1d4417 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/141.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/142.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/142.png new file mode 100644 index 0000000..c7c8341 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/142.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/143.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/143.png new file mode 100644 index 0000000..546f24a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/143.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/144.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/144.png new file mode 100644 index 0000000..cb2790c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/144.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/145.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/145.png new file mode 100644 index 0000000..8a86754 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/145.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/146.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/146.png new file mode 100644 index 0000000..cfe0dd5 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/146.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/147.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/147.png new file mode 100644 index 0000000..43f094a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/147.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/148.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/148.png new file mode 100644 index 0000000..c261e2b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/148.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/149.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/149.png new file mode 100644 index 0000000..9edd595 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/149.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/15.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/15.png new file mode 100644 index 0000000..a8d0d26 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/15.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/150.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/150.png new file mode 100644 index 0000000..603a845 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/150.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/151.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/151.png new file mode 100644 index 0000000..47124e7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/151.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/152.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/152.png new file mode 100644 index 0000000..7dbb280 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/152.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/153.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/153.png new file mode 100644 index 0000000..65f55bb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/153.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/154.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/154.png new file mode 100644 index 0000000..9f2b218 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/154.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/155.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/155.png new file mode 100644 index 0000000..750f17c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/155.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/156.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/156.png new file mode 100644 index 0000000..ded097c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/156.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/157.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/157.png new file mode 100644 index 0000000..76c989c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/157.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/158.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/158.png new file mode 100644 index 0000000..826f4f2 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/158.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/159.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/159.png new file mode 100644 index 0000000..5974acb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/159.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/16.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/16.png new file mode 100644 index 0000000..b83418e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/16.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/160.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/160.png new file mode 100644 index 0000000..30b2dc4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/160.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/161.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/161.png new file mode 100644 index 0000000..b3c3569 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/161.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/162.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/162.png new file mode 100644 index 0000000..f3f0c09 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/162.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/163.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/163.png new file mode 100644 index 0000000..4c5bc15 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/163.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/164.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/164.png new file mode 100644 index 0000000..0981a60 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/164.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/165.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/165.png new file mode 100644 index 0000000..492f117 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/165.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/166.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/166.png new file mode 100644 index 0000000..fdba9ae Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/166.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/167.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/167.png new file mode 100644 index 0000000..a7d8ff3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/167.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/168.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/168.png new file mode 100644 index 0000000..97709e5 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/168.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/169.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/169.png new file mode 100644 index 0000000..cb313f3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/169.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/17.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/17.png new file mode 100644 index 0000000..0c26343 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/17.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/170.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/170.png new file mode 100644 index 0000000..d472b3c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/170.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/171.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/171.png new file mode 100644 index 0000000..9eaac00 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/171.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/172.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/172.png new file mode 100644 index 0000000..e7dc960 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/172.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/173.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/173.png new file mode 100644 index 0000000..7b04ab2 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/173.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/174.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/174.png new file mode 100644 index 0000000..ccb2d21 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/174.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/175.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/175.png new file mode 100644 index 0000000..bb0f060 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/175.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/176.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/176.png new file mode 100644 index 0000000..ae52c58 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/176.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/177.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/177.png new file mode 100644 index 0000000..147a9b4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/177.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/178.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/178.png new file mode 100644 index 0000000..2280107 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/178.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/179.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/179.png new file mode 100644 index 0000000..1e200b4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/179.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/18.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/18.png new file mode 100644 index 0000000..b393de6 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/18.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/180.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/180.png new file mode 100644 index 0000000..83e5870 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/180.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/181.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/181.png new file mode 100644 index 0000000..9c5844f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/181.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/182.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/182.png new file mode 100644 index 0000000..2ff36ef Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/182.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/183.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/183.png new file mode 100644 index 0000000..fcca910 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/183.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/184.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/184.png new file mode 100644 index 0000000..b9e334b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/184.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/185.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/185.png new file mode 100644 index 0000000..0c75c00 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/185.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/186.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/186.png new file mode 100644 index 0000000..9962e62 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/186.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/187.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/187.png new file mode 100644 index 0000000..00e0b90 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/187.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/188.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/188.png new file mode 100644 index 0000000..40474e7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/188.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/189.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/189.png new file mode 100644 index 0000000..2fc4c72 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/189.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/19.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/19.png new file mode 100644 index 0000000..1e705a9 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/19.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/190.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/190.png new file mode 100644 index 0000000..b5c512e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/190.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/191.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/191.png new file mode 100644 index 0000000..767d115 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/191.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/192.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/192.png new file mode 100644 index 0000000..37acfc3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/192.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/193.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/193.png new file mode 100644 index 0000000..ed16ee1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/193.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/194.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/194.png new file mode 100644 index 0000000..a6f550c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/194.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/195.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/195.png new file mode 100644 index 0000000..8b250d2 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/195.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/196.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/196.png new file mode 100644 index 0000000..c0bf525 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/196.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/197.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/197.png new file mode 100644 index 0000000..d5f2e89 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/197.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/198.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/198.png new file mode 100644 index 0000000..1a81778 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/198.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/199.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/199.png new file mode 100644 index 0000000..eeede15 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/199.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/2.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/2.png new file mode 100644 index 0000000..caf6884 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/2.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/20.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/20.png new file mode 100644 index 0000000..9bc29fb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/20.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/200.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/200.png new file mode 100644 index 0000000..2f48d6b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/200.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/21.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/21.png new file mode 100644 index 0000000..4f7b1b0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/21.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/22.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/22.png new file mode 100644 index 0000000..fff6611 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/22.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/23.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/23.png new file mode 100644 index 0000000..2a7eda7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/23.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/24.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/24.png new file mode 100644 index 0000000..2f876cb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/24.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/25.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/25.png new file mode 100644 index 0000000..65b029b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/25.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/26.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/26.png new file mode 100644 index 0000000..00e4b11 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/26.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/27.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/27.png new file mode 100644 index 0000000..f620162 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/27.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/28.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/28.png new file mode 100644 index 0000000..75d8c86 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/28.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/29.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/29.png new file mode 100644 index 0000000..5586111 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/29.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/3.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/3.png new file mode 100644 index 0000000..c7b9fb9 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/3.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/30.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/30.png new file mode 100644 index 0000000..723e9ef Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/30.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/31.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/31.png new file mode 100644 index 0000000..9e15ac7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/31.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/32.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/32.png new file mode 100644 index 0000000..f9287d2 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/32.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/33.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/33.png new file mode 100644 index 0000000..1fde464 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/33.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/34.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/34.png new file mode 100644 index 0000000..6988d42 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/34.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/35.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/35.png new file mode 100644 index 0000000..2a81b13 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/35.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/36.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/36.png new file mode 100644 index 0000000..6b4adbc Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/36.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/37.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/37.png new file mode 100644 index 0000000..16f60f3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/37.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/38.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/38.png new file mode 100644 index 0000000..6debeb8 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/38.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/39.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/39.png new file mode 100644 index 0000000..964fe14 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/39.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/4.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/4.png new file mode 100644 index 0000000..46b0e5c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/4.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/40.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/40.png new file mode 100644 index 0000000..c2480c7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/40.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/41.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/41.png new file mode 100644 index 0000000..acd14c2 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/41.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/42.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/42.png new file mode 100644 index 0000000..d4fa026 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/42.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/43.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/43.png new file mode 100644 index 0000000..ece9874 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/43.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/44.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/44.png new file mode 100644 index 0000000..07fd355 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/44.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/45.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/45.png new file mode 100644 index 0000000..78ccc25 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/45.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/46.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/46.png new file mode 100644 index 0000000..2c7c6a5 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/46.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/47.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/47.png new file mode 100644 index 0000000..dd1e194 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/47.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/48.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/48.png new file mode 100644 index 0000000..8e5b01b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/48.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/49.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/49.png new file mode 100644 index 0000000..c86f932 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/49.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/5.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/5.png new file mode 100644 index 0000000..9e3bf68 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/5.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/50.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/50.png new file mode 100644 index 0000000..a0f392f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/50.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/51.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/51.png new file mode 100644 index 0000000..6d056eb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/51.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/52.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/52.png new file mode 100644 index 0000000..df0d701 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/52.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/53.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/53.png new file mode 100644 index 0000000..8ea54fe Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/53.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/54.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/54.png new file mode 100644 index 0000000..30b3366 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/54.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/55.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/55.png new file mode 100644 index 0000000..d3712e0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/55.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/56.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/56.png new file mode 100644 index 0000000..fc65431 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/56.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/57.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/57.png new file mode 100644 index 0000000..dd3e029 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/57.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/58.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/58.png new file mode 100644 index 0000000..c280dc3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/58.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/59.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/59.png new file mode 100644 index 0000000..dfc3b8c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/59.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/6.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/6.png new file mode 100644 index 0000000..217bc24 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/6.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/60.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/60.png new file mode 100644 index 0000000..5d01b90 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/60.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/61.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/61.png new file mode 100644 index 0000000..53eac80 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/61.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/62.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/62.png new file mode 100644 index 0000000..29d6c09 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/62.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/63.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/63.png new file mode 100644 index 0000000..ce61a99 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/63.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/64.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/64.png new file mode 100644 index 0000000..0616418 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/64.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/65.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/65.png new file mode 100644 index 0000000..0faeed9 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/65.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/66.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/66.png new file mode 100644 index 0000000..c2dcedb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/66.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/67.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/67.png new file mode 100644 index 0000000..5d513c1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/67.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/68.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/68.png new file mode 100644 index 0000000..6e6f723 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/68.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/69.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/69.png new file mode 100644 index 0000000..60400d4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/69.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/7.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/7.png new file mode 100644 index 0000000..1c1d0e0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/7.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/70.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/70.png new file mode 100644 index 0000000..15401cb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/70.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/71.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/71.png new file mode 100644 index 0000000..dce3117 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/71.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/72.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/72.png new file mode 100644 index 0000000..af8f6af Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/72.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/73.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/73.png new file mode 100644 index 0000000..e4b9fc0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/73.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/74.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/74.png new file mode 100644 index 0000000..a530c79 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/74.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/75.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/75.png new file mode 100644 index 0000000..40c95eb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/75.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/76.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/76.png new file mode 100644 index 0000000..fbf7a61 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/76.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/77.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/77.png new file mode 100644 index 0000000..93fc440 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/77.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/78.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/78.png new file mode 100644 index 0000000..3720b72 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/78.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/79.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/79.png new file mode 100644 index 0000000..12ce480 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/79.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/8.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/8.png new file mode 100644 index 0000000..cc2caf3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/8.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/80.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/80.png new file mode 100644 index 0000000..369f8ff Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/80.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/81.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/81.png new file mode 100644 index 0000000..f65732b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/81.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/82.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/82.png new file mode 100644 index 0000000..69ddbc1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/82.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/83.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/83.png new file mode 100644 index 0000000..7ee06b0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/83.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/84.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/84.png new file mode 100644 index 0000000..3c7cbab Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/84.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/85.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/85.png new file mode 100644 index 0000000..f1bad9a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/85.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/86.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/86.png new file mode 100644 index 0000000..11b6478 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/86.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/87.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/87.png new file mode 100644 index 0000000..9134845 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/87.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/88.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/88.png new file mode 100644 index 0000000..d7c4a65 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/88.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/89.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/89.png new file mode 100644 index 0000000..6741796 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/89.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/9.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/9.png new file mode 100644 index 0000000..eeaae8d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/9.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/90.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/90.png new file mode 100644 index 0000000..ebda7fb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/90.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/91.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/91.png new file mode 100644 index 0000000..c7d661e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/91.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/92.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/92.png new file mode 100644 index 0000000..12a88e6 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/92.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/93.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/93.png new file mode 100644 index 0000000..19117da Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/93.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/94.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/94.png new file mode 100644 index 0000000..7a57a82 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/94.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/95.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/95.png new file mode 100644 index 0000000..dc122ec Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/95.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/96.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/96.png new file mode 100644 index 0000000..5c5359d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/96.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/97.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/97.png new file mode 100644 index 0000000..fbc324b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/97.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/98.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/98.png new file mode 100644 index 0000000..7d1e446 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/98.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/99.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/99.png new file mode 100644 index 0000000..3975f8c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/l/99.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/1.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/1.png new file mode 100644 index 0000000..f403407 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/1.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/10.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/10.png new file mode 100644 index 0000000..ac524a8 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/10.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/100.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/100.png new file mode 100644 index 0000000..8c4f8a9 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/100.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/101.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/101.png new file mode 100644 index 0000000..dfa2ec7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/101.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/102.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/102.png new file mode 100644 index 0000000..4a4ba12 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/102.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/103.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/103.png new file mode 100644 index 0000000..9c0052d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/103.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/104.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/104.png new file mode 100644 index 0000000..d4f7049 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/104.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/105.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/105.png new file mode 100644 index 0000000..c85d832 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/105.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/106.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/106.png new file mode 100644 index 0000000..8217fcb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/106.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/107.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/107.png new file mode 100644 index 0000000..7fad567 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/107.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/108.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/108.png new file mode 100644 index 0000000..f04875d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/108.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/109.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/109.png new file mode 100644 index 0000000..f5bce7c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/109.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/11.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/11.png new file mode 100644 index 0000000..0d6e405 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/11.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/110.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/110.png new file mode 100644 index 0000000..1cae2cb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/110.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/111.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/111.png new file mode 100644 index 0000000..9085cd9 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/111.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/112.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/112.png new file mode 100644 index 0000000..02557b3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/112.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/113.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/113.png new file mode 100644 index 0000000..c7fcc63 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/113.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/114.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/114.png new file mode 100644 index 0000000..3c06061 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/114.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/115.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/115.png new file mode 100644 index 0000000..6c2c3ef Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/115.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/116.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/116.png new file mode 100644 index 0000000..755c414 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/116.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/117.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/117.png new file mode 100644 index 0000000..514fc62 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/117.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/118.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/118.png new file mode 100644 index 0000000..0b8493e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/118.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/119.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/119.png new file mode 100644 index 0000000..afd4aef Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/119.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/12.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/12.png new file mode 100644 index 0000000..6c3922e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/12.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/120.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/120.png new file mode 100644 index 0000000..4c299f7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/120.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/121.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/121.png new file mode 100644 index 0000000..2fba85c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/121.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/122.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/122.png new file mode 100644 index 0000000..11c9cc3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/122.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/123.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/123.png new file mode 100644 index 0000000..18fbe11 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/123.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/124.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/124.png new file mode 100644 index 0000000..f51ceb5 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/124.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/125.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/125.png new file mode 100644 index 0000000..460b50f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/125.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/126.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/126.png new file mode 100644 index 0000000..4ff878d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/126.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/127.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/127.png new file mode 100644 index 0000000..0113f79 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/127.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/128.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/128.png new file mode 100644 index 0000000..b323d1e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/128.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/129.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/129.png new file mode 100644 index 0000000..e30992e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/129.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/13.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/13.png new file mode 100644 index 0000000..e0d8e75 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/13.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/130.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/130.png new file mode 100644 index 0000000..a9146d7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/130.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/131.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/131.png new file mode 100644 index 0000000..0344860 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/131.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/132.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/132.png new file mode 100644 index 0000000..2b44342 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/132.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/133.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/133.png new file mode 100644 index 0000000..d2569e3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/133.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/134.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/134.png new file mode 100644 index 0000000..c0b4e74 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/134.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/135.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/135.png new file mode 100644 index 0000000..82976b8 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/135.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/136.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/136.png new file mode 100644 index 0000000..55f9163 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/136.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/137.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/137.png new file mode 100644 index 0000000..7d11f48 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/137.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/138.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/138.png new file mode 100644 index 0000000..71b5658 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/138.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/139.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/139.png new file mode 100644 index 0000000..382a638 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/139.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/14.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/14.png new file mode 100644 index 0000000..c4e1d0b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/14.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/140.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/140.png new file mode 100644 index 0000000..f564393 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/140.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/141.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/141.png new file mode 100644 index 0000000..e58ef7a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/141.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/142.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/142.png new file mode 100644 index 0000000..7477961 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/142.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/143.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/143.png new file mode 100644 index 0000000..d21c5b8 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/143.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/144.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/144.png new file mode 100644 index 0000000..99392d4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/144.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/145.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/145.png new file mode 100644 index 0000000..50b9cf4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/145.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/146.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/146.png new file mode 100644 index 0000000..2e6e509 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/146.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/147.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/147.png new file mode 100644 index 0000000..afd0adf Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/147.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/148.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/148.png new file mode 100644 index 0000000..b7e9e16 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/148.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/149.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/149.png new file mode 100644 index 0000000..f16484c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/149.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/15.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/15.png new file mode 100644 index 0000000..ebb7318 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/15.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/150.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/150.png new file mode 100644 index 0000000..15fb1ae Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/150.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/151.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/151.png new file mode 100644 index 0000000..cdb90cf Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/151.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/152.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/152.png new file mode 100644 index 0000000..5c653ef Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/152.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/153.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/153.png new file mode 100644 index 0000000..8de3efb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/153.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/154.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/154.png new file mode 100644 index 0000000..2030978 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/154.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/155.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/155.png new file mode 100644 index 0000000..9e553f8 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/155.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/156.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/156.png new file mode 100644 index 0000000..58a996c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/156.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/157.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/157.png new file mode 100644 index 0000000..fe44a21 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/157.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/158.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/158.png new file mode 100644 index 0000000..7812dce Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/158.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/159.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/159.png new file mode 100644 index 0000000..bfc055d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/159.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/16.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/16.png new file mode 100644 index 0000000..d9d3302 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/16.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/160.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/160.png new file mode 100644 index 0000000..d09c837 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/160.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/161.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/161.png new file mode 100644 index 0000000..5dd3d63 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/161.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/162.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/162.png new file mode 100644 index 0000000..01a86c7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/162.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/163.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/163.png new file mode 100644 index 0000000..916b4d4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/163.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/164.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/164.png new file mode 100644 index 0000000..8c492e0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/164.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/165.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/165.png new file mode 100644 index 0000000..dabf597 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/165.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/166.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/166.png new file mode 100644 index 0000000..818217d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/166.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/167.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/167.png new file mode 100644 index 0000000..dbb1404 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/167.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/168.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/168.png new file mode 100644 index 0000000..5e6ad37 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/168.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/169.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/169.png new file mode 100644 index 0000000..f34b806 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/169.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/17.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/17.png new file mode 100644 index 0000000..e265fb3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/17.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/170.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/170.png new file mode 100644 index 0000000..b8437d7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/170.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/171.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/171.png new file mode 100644 index 0000000..81d8263 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/171.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/172.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/172.png new file mode 100644 index 0000000..2f92880 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/172.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/173.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/173.png new file mode 100644 index 0000000..9438795 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/173.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/174.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/174.png new file mode 100644 index 0000000..2ddfede Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/174.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/175.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/175.png new file mode 100644 index 0000000..e59a1bf Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/175.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/176.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/176.png new file mode 100644 index 0000000..d1eeac6 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/176.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/177.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/177.png new file mode 100644 index 0000000..2aaa24e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/177.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/178.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/178.png new file mode 100644 index 0000000..ed27c21 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/178.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/179.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/179.png new file mode 100644 index 0000000..6d60bb0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/179.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/18.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/18.png new file mode 100644 index 0000000..e8b8aa0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/18.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/180.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/180.png new file mode 100644 index 0000000..ce69e83 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/180.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/181.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/181.png new file mode 100644 index 0000000..4383ab5 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/181.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/182.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/182.png new file mode 100644 index 0000000..1aab6b7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/182.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/183.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/183.png new file mode 100644 index 0000000..36af470 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/183.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/184.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/184.png new file mode 100644 index 0000000..1a98d71 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/184.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/185.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/185.png new file mode 100644 index 0000000..23c08eb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/185.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/186.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/186.png new file mode 100644 index 0000000..1bdd3c1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/186.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/187.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/187.png new file mode 100644 index 0000000..c8c9e37 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/187.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/188.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/188.png new file mode 100644 index 0000000..3b1e07c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/188.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/189.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/189.png new file mode 100644 index 0000000..e87a95c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/189.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/19.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/19.png new file mode 100644 index 0000000..fbaf9c1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/19.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/190.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/190.png new file mode 100644 index 0000000..64ffdcc Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/190.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/191.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/191.png new file mode 100644 index 0000000..6535177 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/191.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/192.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/192.png new file mode 100644 index 0000000..410fd9d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/192.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/193.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/193.png new file mode 100644 index 0000000..7af26ad Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/193.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/194.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/194.png new file mode 100644 index 0000000..bba22cb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/194.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/195.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/195.png new file mode 100644 index 0000000..34b099c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/195.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/196.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/196.png new file mode 100644 index 0000000..8d1873d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/196.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/197.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/197.png new file mode 100644 index 0000000..54daa78 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/197.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/198.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/198.png new file mode 100644 index 0000000..2a18555 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/198.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/199.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/199.png new file mode 100644 index 0000000..8c480bb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/199.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/2.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/2.png new file mode 100644 index 0000000..7853c07 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/2.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/20.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/20.png new file mode 100644 index 0000000..d07124b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/20.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/200.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/200.png new file mode 100644 index 0000000..2c666e6 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/200.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/21.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/21.png new file mode 100644 index 0000000..529a75b Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/21.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/22.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/22.png new file mode 100644 index 0000000..5bc4d99 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/22.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/23.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/23.png new file mode 100644 index 0000000..87206fc Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/23.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/24.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/24.png new file mode 100644 index 0000000..5306138 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/24.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/25.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/25.png new file mode 100644 index 0000000..facb540 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/25.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/26.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/26.png new file mode 100644 index 0000000..1c5e2fb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/26.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/27.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/27.png new file mode 100644 index 0000000..fdc40c7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/27.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/28.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/28.png new file mode 100644 index 0000000..4b89a3e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/28.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/29.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/29.png new file mode 100644 index 0000000..63158f9 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/29.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/3.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/3.png new file mode 100644 index 0000000..1092788 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/3.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/30.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/30.png new file mode 100644 index 0000000..fbfbba5 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/30.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/31.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/31.png new file mode 100644 index 0000000..3065285 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/31.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/32.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/32.png new file mode 100644 index 0000000..8b2f6e4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/32.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/33.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/33.png new file mode 100644 index 0000000..76becb3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/33.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/34.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/34.png new file mode 100644 index 0000000..9ac6431 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/34.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/35.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/35.png new file mode 100644 index 0000000..b483fb0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/35.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/36.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/36.png new file mode 100644 index 0000000..dd753fa Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/36.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/37.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/37.png new file mode 100644 index 0000000..f80dd0d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/37.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/38.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/38.png new file mode 100644 index 0000000..58cec03 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/38.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/39.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/39.png new file mode 100644 index 0000000..60d790c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/39.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/4.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/4.png new file mode 100644 index 0000000..9657ff3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/4.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/40.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/40.png new file mode 100644 index 0000000..b1b6364 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/40.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/41.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/41.png new file mode 100644 index 0000000..65baee1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/41.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/42.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/42.png new file mode 100644 index 0000000..571e260 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/42.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/43.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/43.png new file mode 100644 index 0000000..e1359a3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/43.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/44.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/44.png new file mode 100644 index 0000000..020ccb7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/44.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/45.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/45.png new file mode 100644 index 0000000..4cd31db Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/45.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/46.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/46.png new file mode 100644 index 0000000..a81672a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/46.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/47.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/47.png new file mode 100644 index 0000000..af333a8 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/47.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/48.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/48.png new file mode 100644 index 0000000..66f5b41 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/48.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/49.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/49.png new file mode 100644 index 0000000..f3a914a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/49.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/5.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/5.png new file mode 100644 index 0000000..0a89ac0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/5.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/50.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/50.png new file mode 100644 index 0000000..7ba435f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/50.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/51.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/51.png new file mode 100644 index 0000000..3ddcffe Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/51.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/52.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/52.png new file mode 100644 index 0000000..0733de5 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/52.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/53.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/53.png new file mode 100644 index 0000000..c02ae8d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/53.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/54.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/54.png new file mode 100644 index 0000000..5f5add4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/54.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/55.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/55.png new file mode 100644 index 0000000..a68de00 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/55.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/56.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/56.png new file mode 100644 index 0000000..c6b683a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/56.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/57.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/57.png new file mode 100644 index 0000000..a88dc6d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/57.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/58.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/58.png new file mode 100644 index 0000000..0390ba8 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/58.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/59.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/59.png new file mode 100644 index 0000000..25f7f21 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/59.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/6.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/6.png new file mode 100644 index 0000000..1fd0ab1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/6.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/60.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/60.png new file mode 100644 index 0000000..299af2c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/60.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/61.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/61.png new file mode 100644 index 0000000..bf2ff87 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/61.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/62.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/62.png new file mode 100644 index 0000000..e05edeb Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/62.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/63.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/63.png new file mode 100644 index 0000000..be9276a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/63.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/64.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/64.png new file mode 100644 index 0000000..cd94093 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/64.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/65.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/65.png new file mode 100644 index 0000000..8c0f445 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/65.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/66.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/66.png new file mode 100644 index 0000000..37cb7dc Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/66.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/67.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/67.png new file mode 100644 index 0000000..6397c6f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/67.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/68.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/68.png new file mode 100644 index 0000000..e1b46c6 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/68.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/69.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/69.png new file mode 100644 index 0000000..76e2a64 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/69.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/7.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/7.png new file mode 100644 index 0000000..5c497e7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/7.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/70.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/70.png new file mode 100644 index 0000000..f30878a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/70.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/71.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/71.png new file mode 100644 index 0000000..1791d80 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/71.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/72.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/72.png new file mode 100644 index 0000000..c79c663 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/72.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/73.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/73.png new file mode 100644 index 0000000..37225c7 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/73.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/74.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/74.png new file mode 100644 index 0000000..a00d0f1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/74.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/75.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/75.png new file mode 100644 index 0000000..330ca64 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/75.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/76.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/76.png new file mode 100644 index 0000000..bfed9d1 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/76.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/77.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/77.png new file mode 100644 index 0000000..4ead7cd Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/77.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/78.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/78.png new file mode 100644 index 0000000..f6ca150 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/78.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/79.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/79.png new file mode 100644 index 0000000..655249e Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/79.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/8.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/8.png new file mode 100644 index 0000000..27040c4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/8.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/80.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/80.png new file mode 100644 index 0000000..2ab015c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/80.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/81.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/81.png new file mode 100644 index 0000000..20201a0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/81.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/82.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/82.png new file mode 100644 index 0000000..0e164ca Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/82.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/83.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/83.png new file mode 100644 index 0000000..4d50b6d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/83.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/84.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/84.png new file mode 100644 index 0000000..197372c Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/84.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/85.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/85.png new file mode 100644 index 0000000..364f60f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/85.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/86.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/86.png new file mode 100644 index 0000000..5adeb26 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/86.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/87.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/87.png new file mode 100644 index 0000000..48ba91a Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/87.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/88.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/88.png new file mode 100644 index 0000000..2f14f3d Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/88.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/89.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/89.png new file mode 100644 index 0000000..243c3a4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/89.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/9.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/9.png new file mode 100644 index 0000000..ee17497 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/9.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/90.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/90.png new file mode 100644 index 0000000..eef93b2 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/90.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/91.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/91.png new file mode 100644 index 0000000..00900b0 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/91.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/92.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/92.png new file mode 100644 index 0000000..97cff19 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/92.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/93.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/93.png new file mode 100644 index 0000000..b38faff Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/93.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/94.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/94.png new file mode 100644 index 0000000..d5f7c20 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/94.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/95.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/95.png new file mode 100644 index 0000000..1b19de3 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/95.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/96.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/96.png new file mode 100644 index 0000000..64faa14 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/96.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/97.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/97.png new file mode 100644 index 0000000..7f9c221 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/97.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/98.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/98.png new file mode 100644 index 0000000..cd0f201 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/98.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/99.png b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/99.png new file mode 100644 index 0000000..2a984ff Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/img/pp/s/99.png differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/js/jquery-1.4.2.min.js b/legacyworlds-web/legacyworlds-web-main/WebContent/js/jquery-1.4.2.min.js new file mode 100644 index 0000000..7c24308 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/js/jquery-1.4.2.min.js @@ -0,0 +1,154 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, +Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& +(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, +a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== +"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, +function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; +var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, +parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= +false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= +s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, +applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; +else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, +a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== +w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, +cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= +c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); +a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, +function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); +k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), +C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= +e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& +f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; +if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", +e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, +"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, +d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, +e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); +t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| +g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, +CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, +g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, +text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, +setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= +h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== +"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, +h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& +q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; +if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); +(function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: +function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= +{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== +"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", +d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? +a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== +1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, +""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); +return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", +""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= +c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? +c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= +function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= +Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, +"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= +a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= +a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== +"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, +serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), +function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, +global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& +e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? +"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== +false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= +false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", +c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| +d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); +g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== +1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== +"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; +if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== +"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| +c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; +this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= +this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, +e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; +a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); +c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, +d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- +f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": +"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in +e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/js/main.js b/legacyworlds-web/legacyworlds-web-main/WebContent/js/main.js new file mode 100644 index 0000000..545e799 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/js/main.js @@ -0,0 +1,311 @@ +$(function() { + /* + * Main layer location + */ + var _viewportHeight = function() { + return self.innerHeight || jQuery.boxModel + && document.documentElement.clientHeight + || document.body.clientHeight; + }; + var _viewportWidth = function() { + return self.innerWidth || jQuery.boxModel + && document.documentElement.clientWidth + || document.body.clientWidth; + }; + + var _handleSize = function() { + var _h = _viewportHeight(); + if (_h < 560) { + $("#extframe").css('top', '280px'); + } else { + $("#extframe").css('top', '50%'); + } + + var _w = _viewportWidth(); + if (_w < 950) { + $(".internal").css('left', '475px'); + } else { + $(".internal").css('left', '50%'); + } + }; + + $(window).resize(_handleSize); + _handleSize(); + + /* + * Tabs + */ + var _findTabs = function() { + var _found = []; + $(".tabs").each(function(_container) { + var _data = { + container : $(this), + tabs : [] + }; + + $(".tab", $(this)).each(function(_container) { + var _theTab = { + id : $(this).attr('id'), + title : $("> h3", $(this)).text(), + contents : $("div.tab-contents", $(this)) + }; + _data.tabs.push(_theTab); + }); + + _found.push(_data); + }); + return _found; + }; + + var _hideTab = function(_id) { + $('#tabb-' + _id).removeClass('selected-tab'); + $('#tabc-' + _id).css('display', 'none'); + }; + + var _showTab = function(_id) { + $('#tabb-' + _id).addClass('selected-tab'); + $('#tabc-' + _id).css('display', 'block'); + }; + + var _prepareTabContainer = function(_root) { + _root.container.empty(); + + var _titles = $('
').addClass('tab-buttons'); + _titles.appendTo(_root.container); + + for ( var j in _root.tabs) { + var _theTab = _root.tabs[j]; + if (j == 0 || location.hash == '#' + _theTab.id) { + _root.selected = _theTab.id; + } + + $('').addClass('tab-button').attr('id', 'tabb-' + _theTab.id) + .attr('href', '#' + _theTab.id).text(_theTab.title) + .appendTo(_titles).click( + function() { + _hideTab(_root.selected); + _root.selected = $(this).attr('id').replace( + /^tabb-/, ''); + _showTab(_root.selected); + }); + _theTab.contents.css('display', 'none').attr('id', + 'tabc-' + _theTab.id).appendTo(_root.container); + } + _showTab(_root.selected); + }; + + var _prepareTabs = function(_tabs) { + for ( var i in _tabs) { + _prepareTabContainer(_tabs[i]); + } + }; + + var _tabs = _findTabs(); + _prepareTabs(_tabs); + + /* + * Hidden descriptions + */ + $("div.auto-hide").each(function() { + var _div = $(this); + _div.css('display', 'none'); + var _visible = false; + $('').attr('href', '#').text('...').click(function() { + if (_visible) { + _div.css('display', 'none'); + } else { + _div.css('display', 'block'); + } + _visible = !_visible; + return false; + }).insertBefore(_div); + }); + + /* + * "Jump to planet" + */ + $("p#jump-to-planet").each( + function() { + var _form = $('
').attr('action', '/').submit(function() { + return false; + }); + var _fdiv = $('
').appendTo(_form); + var _select = $('').addClass('input').attr('type', 'button') + .attr('title', _title).val('X').css('cursor', + 'pointer').click(function() { + $("input.message-selection").click(); + })); + }); +}); diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/IRCApplet.class b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/IRCApplet.class new file mode 100644 index 0000000..6ce2e98 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/IRCApplet.class differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/background.gif b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/background.gif new file mode 100644 index 0000000..569d4bd Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/background.gif differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/english.lng b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/english.lng new file mode 100644 index 0000000..0403fe2 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/english.lng @@ -0,0 +1,92 @@ +# +# This java file is a part of the +# +# - Plouf's Java IRC Client - +# +# Copyright (C) 2004 Philippe Detournay +# +# This file is licensed under the GPL license +# +# All contacts : theplouf@yahoo.com +# +# +# Syntax : +# Comments begin with the # character. This character must be the first character of the line. +# A data line has three parts : the data id, the data id description, the data string. +# - Data id : An hexadecimal figure identifying the string. +# - Data description : Begins by [ and ends by ]. The description is not parsed and +# can be any string. +# - Data string : The string itself. Parameters are specified using the %i syntax. +# +# Trailing spaces can be added using the \s escape character. + +0001 [INTERPRETOR_NOT_ON_CHANNEL] Not on a channel +0002 [INTERPRETOR_UNKNOWN_DCC] %1 : unknown dcc subcommand +0003 [INTERPRETOR_INSUFFICIENT_PARAMETERS] %1 : insufficient parameters +0004 [INTERPRETOR_BAD_CONTEXT] %1 : unable to perform in current context +0005 [INTERPRETOR_CANNOT_CTCP_IN_DCCCHAT] Cannot send CTCP codes via DCC Chat +0006 [INTERPRETOR_UNKNOWN_CONFIG] %1 : unknown config subcommand +0007 [INTERPRETOR_TIMESTAMP_ON] Timestamp enabled +0008 [INTERPRETOR_TIMESTAMP_OFF] Timestamp disabled +0009 [INTERPRETOR_SMILEYS_ON] Graphical smileys enabled +000a [INTERPRETOR_SMILEYS_OFF] Graphical smileys disabled +000b [INTERPRETOR_IGNORE_ON] Now ignoring %1 +000c [INTERPRETOR_IGNORE_OFF] Not ignoring %1 anymore +000d [INTERPRETOR_MULTISERVER_DISABLED] Multiserver support is disabled + +0101 [DCC_WAITING_INCOMING] Waiting for incoming connection... +0102 [DCC_UNABLE_TO_OPEN_CONNECTION] Unable to open connection : %1 +0103 [DCC_CONNECTION_ESTABLISHED] DCC Connection established +0104 [DCC_CONNECTION_CLOSED] Connection closed +0105 [DCC_ERROR] Error : %1 +0106 [DCC_UNABLE_TO_SEND_TO] %1 : unable to send to %2 +0107 [DCC_BAD_CONTEXT] Unable to execute command from current context +0108 [DCC_NOT_CONNECTED] Not connected +0109 [DCC_UNABLE_PASSIVE_MODE] Unable to initialize passive mode +010a [CTCP_PING_REPLY] [%1 PING reply] : %2 seconds +010b [DCC_STREAM_CLOSED] Stream closed + +0201 [IDENT_FAILED_LAUNCH] Failed to launch Ident server : %1 +0202 [IDENT_REQUEST] Ident request from %1 +0203 [IDENT_ERROR] Error occurred +0204 [IDENT_REPLIED] Replied %1 +0205 [IDENT_DEFAULT_USER] default user +0206 [IDENT_NO_USER] No user for request +0207 [IDENT_RUNNING_ON_PORT] Ident server running on port %1 +0208 [IDENT_LEAVING] Ident server leaving : %1 +0209 [IDENT_NONE] none +020a [IDENT_UNKNOWN] unknown +020b [IDENT_UNDEFINED] Undefined result + +0301 [FILE_SAVEAS] Save file as + +0401 [ABOUT_ABOUT] About +0402 [ABOUT_PROGRAMMING] Programming +0403 [ABOUT_DESIGN] Design +0404 [ABOUT_THANKS] Thanks to +0405 [ABOUT_SUPPORT] for support, ideas and testing +0406 [ABOUT_GPL] This software is licensed under the GPL license + +0501 [SERVER_UNABLE_TO_CONNECT] Unable to connect : %1 +0502 [SERVER_UNABLE_TO_CONNECT_STILL] Unable to connect to %1 : currently trying to connect to %2 +0503 [SERVER_DISCONNECTING] Disconnecting from %1 +0504 [SERVER_CONNECTING] Connecting... +0505 [SERVER_NOT_CONNECTED] Not connected +0506 [SERVER_LOGIN] Logging in... +0507 [SERVER_DISCONNECTED] Disconnected from %1 +0508 [SERVER_ERROR] Error : %1 + + +071a [GUI_CHANGE_NICK] Change nick to +071b [GUI_COPY_WINDOW] Copy text +071c [GUI_DCC_CHAT_WARNING_TITLE] Warning +071d [GUI_DCC_CHAT_WARNING_TEXT] Do you want to accept DCC chat from %1? + +0801 [ASL_MALE] Boy, %1 years old, %2 +0802 [ASL_FEMALE] Girl, %1 years old, %2 +0803 [ASL_UNKNOWN] %1 years old from %2 + +0901 [REPLY_IDLE] %1 has been idle for %2 +0902 [REPLY_SIGNON] %1 connected on %2 + +ffff [ERROR_NOT_DEFINED] Undefined string diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/french.lng b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/french.lng new file mode 100644 index 0000000..5fda7a2 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/french.lng @@ -0,0 +1,91 @@ +# +# This java file is a part of the +# +# - Plouf's Java IRC Client - +# +# Copyright (C) 2004 Philippe Detournay +# +# This file is licensed under the GPL license +# +# All contacts : theplouf@yahoo.com +# +# +# Syntax : +# Comments begin with the # character. This character must be the first character of the line. +# A data line has three parts : the data id, the data id description, the data string. +# - Data id : An hexadecimal figure identifying the string. +# - Data description : Begins by [ and ends by ]. The description is not parsed and +# can contains any string. +# - Data string : The string itself. Parameters are specified using the %i syntax. +# +# Trailing spaces can be added using the \s escape character. + +0001 [INTERPRETOR_NOT_ON_CHANNEL] Pas sur un canal +0002 [INTERPRETOR_UNKNOWN_DCC] %1 : sous-commande dcc inconnue +0003 [INTERPRETOR_INSUFFICIENT_PARAMETERS] %1 : paramčtres insuffisants +0004 [INTERPRETOR_BAD_CONTEXT] Impossible d'effectuer %1 ici +0005 [INTERPRETOR_CANNOT_CTCP_IN_DCCCHAT] Impossible d'envoyer des codes CTCP dans un DCC Chat +0006 [INTERPRETOR_UNKNOWN_CONFIG] %1 : sous-commande de configuration inconnue +0007 [INTERPRETOR_TIMESTAMP_ON] Horodateur activé +0008 [INTERPRETOR_TIMESTAMP_OFF] Horodateur désactivé +0009 [INTERPRETOR_SMILEYS_ON] Emoticons activés +000a [INTERPRETOR_SMILEYS_OFF] Emoticons désactivés +000b [INTERPRETOR_IGNORE_ON] Ignore ą présent %1 +000c [INTERPRETOR_IGNORE_OFF] N'ignore plus %1 +000d [INTERPRETOR_MULTISERVER_DISABLED] Le support multiserveur est désactivé + +0101 [DCC_WAITING_INCOMING] Attente de connexion... +0102 [DCC_UNABLE_TO_OPEN_CONNECTION] Impssible d'ouvrir la connexion : %1 +0103 [DCC_CONNECTION_ESTABLISHED] "Connexion DCC établie +0104 [DCC_CONNECTION_CLOSED] Connexion fermée +0105 [DCC_ERROR] Erreur : %1 +0106 [DCC_UNABLE_TO_SEND_TO] %1 : impossible d'envoyer ą %2 +0107 [DCC_BAD_CONTEXT] Impossible d'exécuter la commande dans le contexte actuel +0108 [DCC_NOT_CONNECTED] Non connecté +0109 [DCC_UNABLE_PASSIVE_MODE] Impossible d'initialiser le mode passif +010a [CTCP_PING_REPLY] [%1 PING reply] : %2 secondes +010b [DCC_STREAM_CLOSED] Stream fermé + +0201 [IDENT_FAILED_LAUNCH] Impossible de lancer le serveur IDENT : %1 +0202 [IDENT_REQUEST] Requźte ident de %1 +0203 [IDENT_ERROR] Erreur survenue +0204 [IDENT_REPLIED] Répondu %1 +0205 [IDENT_DEFAULT_USER] utilisateur par défaut +0206 [IDENT_NO_USER] Aucun utilisateur pour la reqūete +0207 [IDENT_RUNNING_ON_PORT] Le serveur Ident s'exécute sur le port %1 +0208 [IDENT_LEAVING] Le serveur Ident se termine : %1 +0209 [IDENT_NONE] aucun +020a [IDENT_UNKNOWN] inconnu +020b [IDENT_UNDEFINED] Résultat indéterminé + +0301 [FILE_SAVEAS] Sauver le fichier sous + +0401 [ABOUT_ABOUT] A propos +0402 [ABOUT_PROGRAMMING] Programmation +0403 [ABOUT_DESIGN] Design +0404 [ABOUT_THANKS] Remerciements +0405 [ABOUT_SUPPORT] pour leur support, leurs idées et les tests +0406 [ABOUT_GPL] Ce programme est sous license GPL + +0501 [SERVER_UNABLE_TO_CONNECT] Impossible de se connecter : %1 +0502 [SERVER_UNABLE_TO_CONNECT_STILL] Impssible de se connecter ą %1, déją en train d'essayer de se connecter ą %2 +0503 [SERVER_DISCONNECTING] Déconnexion de %1 +0504 [SERVER_CONNECTING] Connexion... +0505 [SERVER_NOT_CONNECTED] Non connecté +0506 [SERVER_LOGIN] Enregistrement... +0507 [SERVER_DISCONNECTED] Déconnecté de %1 +0508 [SERVER_ERROR] Erreur : %1 + +071a [GUI_CHANGE_NICK] Modifier le nick +071b [GUI_COPY_WINDOW] Copier le texte +071c [GUI_DCC_CHAT_WARNING_TITLE] Attention +071d [GUI_DCC_CHAT_WARNING_TEXT] Voulez-vous accepter une connection DCC-chat en provenance de %1? + +0801 [ASL_MALE] Garēon, %1 ans, %2 +0802 [ASL_FEMALE] Fille, %1 ans, %2 +0803 [ASL_UNKNOWN] %1 ans de %2 + +0901 [REPLY_IDLE] %1 est inactif depuis %2 +0902 [REPLY_SIGNON] %1 s'est connecté(e) le %2 + +ffff [ERROR_NOT_DEFINED] Texte non défini diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/irc.cab b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/irc.cab new file mode 100644 index 0000000..fbc50f4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/irc.cab differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/irc.jar b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/irc.jar new file mode 100644 index 0000000..4acfda4 Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/irc.jar differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx-english.lng b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx-english.lng new file mode 100644 index 0000000..ae38037 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx-english.lng @@ -0,0 +1,75 @@ +# +# This java file is a part of the +# +# - Plouf's Java IRC Client - +# +# Copyright (C) 2004 Philippe Detournay +# +# This file is licensed under the GPL license +# +# All contacts : theplouf@yahoo.com +# +# +# Syntax : +# Comments begin with the # character. This character must be the first character of the line. +# A data line has three parts : the data id, the data id description, the data string. +# - Data id : An hexadecimal figure identifying the string. +# - Data description : Begins by [ and ends by ]. The description is not parsed and +# can be any string. +# - Data string : The string itself. Parameters are specified using the %i syntax. +# +# Trailing spaces can be added using the \s escape character. + +8601 [SOURCE_YOU_KICKED] You've been kicked out of %1 by %2 +8602 [SOURCE_STATUS] Status +8603 [SOURCE_CHANLIST] Channels for %1 +8604 [SOURCE_CHANLIST_RETREIVING] Retrieving channels... +8605 [SOURCE_HAS_JOINED] %1 has joined %2 +8606 [SOURCE_HAS_LEFT] %1 has left %2 +8607 [SOURCE_HAS_BEEN_KICKED_BY] %1 has been kicked by %2 +8608 [SOURCE_HAS_QUIT] %1 has quit +8609 [SOURCE_TOPIC_IS] Topic is %1 +860a [SOURCE_CHANGED_TOPIC] %1 changed topic to %2 +860b [SOURCE_CHANNEL_MODE] %1 sets channel mode to %2 +860c [SOURCE_CHANNEL_MODE_IS] Channel mode is %1 +860d [SOURCE_USER_MODE] %1 sets mode %2 on %3 +860e [SOURCE_KNOWN_AS] %1 is now known as %2 +860f [SOURCE_YOUR_MODE] Mode changed to %1 +8610 [SOURCE_YOUR_NICK] Your nick is now %1 +8611 [SOURCE_INFO] Infos +8612 [SOURCE_AWAY] %1 is away +8613 [SOURCE_YOU_INVITED] %1 invites you to join %2 +8614 [SOURCE_YOU_JOINED_AS] You're talking in %1 as %2 + +8701 [GUI_WHOIS] Whois +8702 [GUI_QUERY] Query +8703 [GUI_KICK] Kick +8704 [GUI_BAN] Ban +8705 [GUI_KICKBAN] Kick + Ban +8706 [GUI_OP] Op +8707 [GUI_DEOP] DeOp +8708 [GUI_VOICE] Voice +8709 [GUI_DEVOICE] DeVoice +870a [GUI_PING] Ping +870b [GUI_VERSION] Version +870c [GUI_TIME] Time +870d [GUI_FINGER] Finger +870e [GUI_RETREIVING_FILE] Receiving file (%1 bytes) +870f [GUI_SENDING_FILE] Sending file (%1 bytes) +8710 [GUI_TERMINATED] %1 terminated +8711 [GUI_FAILED] %1 failed +8712 [GUI_CLOSE] Close +8713 [GUI_DISCONNECT] Disconnect +8714 [GUI_CHANNELS] Channels +8715 [GUI_HELP] Help +8716 [GUI_PRIVATE] private +8717 [GUI_PUBLIC] public +8718 [GUI_CONNECT] Connect +8719 [GUI_ABOUT] About +871a [GUI_CHANGE_NICK] Change nick to +871c [GUI_FONT] Font +871d [GUI_FONT_WINDOW] Select font +871e [GUI_FONT_WINDOW_OK] Ok +871f [GUI_ENTER_TEXT_HERE] Enter text here... + +ffff [ERROR_NOT_DEFINED] Undefined string diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx-french.lng b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx-french.lng new file mode 100644 index 0000000..22fd14c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx-french.lng @@ -0,0 +1,75 @@ +# +# This java file is a part of the +# +# - Plouf's Java IRC Client - +# +# Copyright (C) 2004 Philippe Detournay +# +# This file is licensed under the GPL license +# +# All contacts : theplouf@yahoo.com +# +# +# Syntax : +# Comments begin with the # character. This character must be the first character of the line. +# A data line has three parts : the data id, the data id description, the data string. +# - Data id : An hexadecimal figure identifying the string. +# - Data description : Begins by [ and ends by ]. The description is not parsed and +# can be any string. +# - Data string : The string itself. Parameters are specified using the %i syntax. +# +# Trailing spaces can be added using the \s escape character. + +8601 [SOURCE_YOU_KICKED] Vous avez été mis ą la porte de %1 par %2 +8602 [SOURCE_STATUS] Statut +8603 [SOURCE_CHANLIST] Canaux sur %1 +8604 [SOURCE_CHANLIST_RETREIVING] Recherche des canaux... +8605 [SOURCE_HAS_JOINED] %1 est entré sur %2 +8606 [SOURCE_HAS_LEFT] %1 est sorti de %2 +8607 [SOURCE_HAS_BEEN_KICKED_BY] %1 a été mis ą la porte par %2 +8608 [SOURCE_HAS_QUIT] %1 a quitté +8609 [SOURCE_TOPIC_IS] Le sujet est %1 +860a [SOURCE_CHANGED_TOPIC] %1 a changé le sujet vers %2 +860b [SOURCE_CHANNEL_MODE] %1 met les options de canal %2 +860c [SOURCE_CHANNEL_MODE_IS] Les options du canal sont %1 +860d [SOURCE_USER_MODE] %1 met l'option %2 sur %3 +860e [SOURCE_KNOWN_AS] %1 s'appelle dorénavant %2 +860f [SOURCE_YOUR_MODE] Vos options sont mises ą %1 +8610 [SOURCE_YOUR_NICK] Vous vous appelez ą présent %1 +8611 [SOURCE_INFO] Infos +8612 [SOURCE_AWAY] %1 n'est pas lą : +8613 [SOURCE_YOU_INVITED] %1 vous invite sur %2 +8614 [SOURCE_YOU_JOINED_AS] Vous parlez sur %1 avec le pseudo %2 + +8701 [GUI_WHOIS] Qui est-ce +8702 [GUI_QUERY] Aller en privé +8703 [GUI_KICK] Mettre ą la porte +8704 [GUI_BAN] Bannir +8705 [GUI_KICKBAN] Ejecter et bannir +8706 [GUI_OP] Mettre opérateur +8707 [GUI_DEOP] Retirer l'opérateur +8708 [GUI_VOICE] Donner la parole +8709 [GUI_DEVOICE] Retirer la parole +870a [GUI_PING] Ping +870b [GUI_VERSION] Version +870c [GUI_TIME] Heure +870d [GUI_FINGER] Infos +870e [GUI_RETREIVING_FILE] Reēoit le fichier (%1 octets) +870f [GUI_SENDING_FILE] Envoit le fichier (%1 octets) +8710 [GUI_TERMINATED] %1 terminé +8711 [GUI_FAILED] %1 échec +8712 [GUI_CLOSE] Fermer +8713 [GUI_DISCONNECT] Déconnecter +8714 [GUI_CHANNELS] Canaux +8715 [GUI_HELP] Aide +8716 [GUI_PRIVATE] privé +8717 [GUI_PUBLIC] public\s +8718 [GUI_CONNECT] Connecter +8719 [GUI_ABOUT] A propos +871a [GUI_CHANGE_NICK] Modifier le nick +871c [GUI_FONT] Police +871d [GUI_FONT_WINDOW] Choisir une nouvelle police +871e [GUI_FONT_WINDOW_OK] Ok +871f [GUI_ENTER_TEXT_HERE] Entrez le texte ici... + +ffff [ERROR_NOT_DEFINED] Undefined string diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx.cab b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx.cab new file mode 100644 index 0000000..944e1ef Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx.cab differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx.jar b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx.jar new file mode 100644 index 0000000..144dd8f Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/pixx.jar differ diff --git a/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/securedirc.cab b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/securedirc.cab new file mode 100644 index 0000000..f2109ed Binary files /dev/null and b/legacyworlds-web/legacyworlds-web-main/WebContent/pjirc/securedirc.cab differ diff --git a/legacyworlds-web/legacyworlds-web-main/pom.xml b/legacyworlds-web/legacyworlds-web-main/pom.xml new file mode 100644 index 0000000..099a1af --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/pom.xml @@ -0,0 +1,89 @@ + + 4.0.0 + + legacyworlds-web + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-web-main + 5.99.1 + war + Legacy Worlds main site + + + + com.deepclone.lw + legacyworlds-web-beans + ${project.version} + + + + javax.servlet + servlet-api + 2.5 + provided + + + + org.freemarker + freemarker + ${org.freemarker.version} + runtime + + + + + + + + + org.apache.maven.plugins + maven-war-plugin + 2.0 + + true + true + + + legacyworlds-web/legacyworlds-web-main/WebContent + + + + + + build-main-war + package + + war + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/BannedPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/BannedPage.java new file mode 100644 index 0000000..2e899ac --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/BannedPage.java @@ -0,0 +1,35 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "banned" ) +@SessionAttributes( "language" ) +public class BannedPage + extends PageControllerBase +{ + + @RequestMapping( "/banned" ) + public String banned( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession session = this.getSession( PlayerSession.class , request ); + return this.render( model , "restricted" , language , "banned" , session.getBanDetails( ) ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/CommonPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/CommonPages.java new file mode 100644 index 0000000..d77a90e --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/CommonPages.java @@ -0,0 +1,54 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionAttributes( "language" ) +public class CommonPages + extends PageControllerBase +{ + + @RequestMapping( "/scope" ) + public String scopePage( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession session = this.getSession( PlayerSession.class , request ); + if ( session == null || !"game".equals( session.getSessionSubType( ) ) ) { + return this.renderStatic( model , "external" , language , "scope" ); + } + + GameResponseBase response = session.getEnemyList( ); + return this.renderStatic( model , "game" , language , response , "scope" ); + } + + + @RequestMapping( "/rules" ) + public String rulesPage( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession session = this.getSession( PlayerSession.class , request ); + if ( session == null || !"game".equals( session.getSessionSubType( ) ) ) { + return this.renderStatic( model , "external" , language , "rules" ); + } + + GameResponseBase response = session.getEnemyList( ); + return this.renderStatic( model , "game" , language , response , "rules" ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ErrorHandlerBean.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ErrorHandlerBean.java new file mode 100644 index 0000000..d9697fe --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ErrorHandlerBean.java @@ -0,0 +1,86 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import com.deepclone.lw.cmd.MaintenanceResponse; +import com.deepclone.lw.session.SessionCommandException; +import com.deepclone.lw.session.SessionIdentifierException; +import com.deepclone.lw.web.beans.session.MaintenanceStatus; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; + + + +public class ErrorHandlerBean + implements HandlerExceptionResolver +{ + + private MaintenanceStatus maintenanceStatus; + + + @Autowired( required = true ) + public void setMaintenanceStatus( MaintenanceStatus maintenanceStatus ) + { + this.maintenanceStatus = maintenanceStatus; + } + + + private String getLanguage( HttpServletRequest request ) + { + HttpSession session = request.getSession( ); + String l = (String) session.getAttribute( "language" ); + return ( l == null ) ? "en" : l; + } + + + @Override + public ModelAndView resolveException( HttpServletRequest request , HttpServletResponse response , Object handler , + Exception ex ) + { + if ( ex instanceof SessionServerException ) { + MaintenanceResponse maintenance = this.maintenanceStatus.getStatus( ); + if ( maintenance != null ) { + return this.maintenance( request , maintenance ); + } + return this.offline( request ); + } else if ( ex instanceof SessionMaintenanceException ) { + MaintenanceResponse maintenance = ( (SessionMaintenanceException) ex ).getMaintenance( ); + this.maintenanceStatus.storeStatus( maintenance ); + return this.maintenance( request , maintenance ); + } else if ( ex instanceof SessionIdentifierException || ex instanceof SessionCommandException ) { + return new ModelAndView( "redirect:player-session" ); + } + + // Other exceptions are not handled + return null; + } + + + private ModelAndView maintenance( HttpServletRequest request , MaintenanceResponse maintenance ) + { + ModelAndView mav = new ModelAndView( "ROOT" ); + mav.addObject( "container" , "offline" ); + mav.addObject( "language" , this.getLanguage( request ) ); + mav.addObject( "type" , "maintenance" ); + mav.addObject( "data" , maintenance ); + return mav; + } + + + private ModelAndView offline( HttpServletRequest request ) + { + ModelAndView mav = new ModelAndView( "ROOT" ); + mav.addObject( "container" , "offline" ); + mav.addObject( "language" , this.getLanguage( request ) ); + mav.addObject( "type" , "offline" ); + return mav; + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ExternalPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ExternalPages.java new file mode 100644 index 0000000..0bf7109 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ExternalPages.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.web.main; + + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.view.PageControllerBase; + + + +@Controller +@SessionRequirement( value = false , redirectTo = "player-session" ) +@SessionAttributes( "language" ) +public class ExternalPages + extends PageControllerBase +{ + + @RequestMapping( "/" ) + public String root( ) + { + return "redirect:home"; + } + + + @RequestMapping( "/home" ) + public String mainPage( @ModelAttribute( "language" ) String language , Model model ) + { + return this.renderStatic( model , "external" , language , "home" ); + } + + + @RequestMapping( "/no-session" ) + public String noSession( @ModelAttribute( "language" ) String language , Model model ) + { + return this.renderStatic( model , "external" , language , "noSession" ); + } + + + @RequestMapping( "/logged-out" ) + public String loggedOut( @ModelAttribute( "language" ) String language , Model model ) + { + return this.renderStatic( model , "external" , language , "loggedOut" ); + } + + + @RequestMapping( "/password-recovery-ok" ) + public String passwordRecoveryOk( @ModelAttribute( "language" ) String language , Model model ) + { + return this.renderStatic( model , "external" , language , "passwordRecoveryOk" ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/LoginPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/LoginPages.java new file mode 100644 index 0000000..7437ad4 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/LoginPages.java @@ -0,0 +1,46 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = false , redirectTo = "player-session" ) +@SessionAttributes( "language" ) +public class LoginPages + extends PageControllerBase +{ + + @RequestMapping( value = "/login.action" , method = RequestMethod.POST ) + public String login( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "mail" ) String mail , @RequestParam( "password" ) String password ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.initSession( PlayerSession.class , request ); + boolean authenticated = pSession.authenticate( mail , password ); + if ( !authenticated ) { + this.clearSession( request ); + return this.renderStatic( model , "external" , language , "loginFailed" ); + } + + model.addAttribute( "language" , pSession.getLanguage( ) ); + return this.redirect( "player-session" ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/LogoutPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/LogoutPages.java new file mode 100644 index 0000000..fb237d9 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/LogoutPages.java @@ -0,0 +1,34 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "no-session" ) +@SessionAttributes( "language" ) +public class LogoutPages + extends PageControllerBase +{ + + @RequestMapping( value = "/logout.action" ) + public String validation( HttpServletRequest request , Model model ) + throws SessionServerException , SessionException + { + PlayerSession session = this.getSession( PlayerSession.class , request ); + session.terminate( ); + return this.redirect( "logged-out" ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/PasswordRecoveryPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/PasswordRecoveryPages.java new file mode 100644 index 0000000..036dd79 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/PasswordRecoveryPages.java @@ -0,0 +1,73 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.ext.ConfirmPasswordRecoveryResponse; +import com.deepclone.lw.cmd.ext.RequestPasswordRecoveryResponse; +import com.deepclone.lw.cmd.ext.ConfirmPasswordRecoveryResponse.PasswordRecoveryStatus; +import com.deepclone.lw.cmd.ext.RequestPasswordRecoveryResponse.PasswordRecoveryRequestStatus; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.ExternalSession; + + + +@Controller +@SessionRequirement( value = false , redirectTo = "player-session" ) +@SessionAttributes( "language" ) +public class PasswordRecoveryPages + extends PageControllerBase +{ + + @RequestMapping( "/password-recovery" ) + public String passwordRecoveryPage( @ModelAttribute( "language" ) String language , Model model ) + { + return this.renderMap( model , "external" , language , "passwordRecovery" ); + } + + + @RequestMapping( value = "/request-password-recovery.action" , method = RequestMethod.POST ) + public String requestPasswordRecovery( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( "mail" ) String mail ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ExternalSession eSession = this.createTemporarySession( ExternalSession.class , request ); + RequestPasswordRecoveryResponse response = eSession.requestPasswordRecovery( mail ); + PasswordRecoveryRequestStatus status = response.getStatus( ); + if ( status == PasswordRecoveryRequestStatus.OK ) { + return this.renderMap( model , "external" , language , "passwordRecovery" , "sent" , true , "mail" , mail ); + } + return this.renderMap( model , "external" , language , "passwordRecovery" , "mail" , mail , "status" , status ); + } + + + @RequestMapping( value = "/confirm-password-recovery.action" , method = RequestMethod.POST ) + public String confirmPasswordRecovery( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( "mail" ) String mail , @RequestParam( "code" ) String token , + @RequestParam( "password" ) String password , @RequestParam( "passwordConfirm" ) String passwordConfirm ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ExternalSession eSession = this.createTemporarySession( ExternalSession.class , request ); + ConfirmPasswordRecoveryResponse response; + response = eSession.confirmPasswordRecovery( mail , token , password , passwordConfirm ); + PasswordRecoveryStatus status = response.getStatus( ); + if ( status == PasswordRecoveryStatus.OK ) { + return this.redirect( "password-recovery-ok" ); + } + + return this.renderMap( model , "external" , language , "passwordRecovery" , "cStatus" , status , "cMail" , + mail , "cCode" , token ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/PlayerSessionRedirector.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/PlayerSessionRedirector.java new file mode 100644 index 0000000..fe457ba --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/PlayerSessionRedirector.java @@ -0,0 +1,45 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.ClientSessionReference; +import com.deepclone.lw.web.beans.view.PageControllerBase; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "no-session" ) +public class PlayerSessionRedirector + extends PageControllerBase +{ + + @RequestMapping( "/player-session" ) + public String sessionRedirection( HttpServletRequest request ) + { + ClientSessionReference cReference = (ClientSessionReference) request.getSession( ).getAttribute( "sReference" ); + String type = cReference.getReference( ).extra; + + if ( "validation".equals( type ) ) { + return this.redirect( "validate-account" ); + } + + if ( "disabled".equals( type ) ) { + return this.redirect( "reactivate" ); + } + + if ( "game".equals( type ) ) { + return this.redirect( "overview" ); + } + + if ( "banned".equals( type ) ) { + return this.redirect( "banned" ); + } + + throw new RuntimeException( "unknown session sub-type: " + type ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ReactivationPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ReactivationPages.java new file mode 100644 index 0000000..79e577c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ReactivationPages.java @@ -0,0 +1,42 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "disabled" ) +@SessionAttributes( "language" ) +public class ReactivationPages + extends PageControllerBase +{ + + @RequestMapping( "/reactivate" ) + public String reactivationPage( @ModelAttribute( "language" ) String language , Model model ) + { + return this.renderStatic( model , "restricted" , language , "reactivate" ); + } + + + @RequestMapping( "/reactivate.action" ) + public String reactivation( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "restricted" , language , "reactivation" , pSession.reactivate( ) ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/RegistrationPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/RegistrationPages.java new file mode 100644 index 0000000..47763c2 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/RegistrationPages.java @@ -0,0 +1,62 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.ext.CreateAccountResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.ExternalSession; + + + +@Controller +@SessionRequirement( value = false , redirectTo = "player-session" ) +@SessionAttributes( "language" ) +public class RegistrationPages + extends PageControllerBase + +{ + + @RequestMapping( "/register" ) + public String registrationPage( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ExternalSession eSession = this.createTemporarySession( ExternalSession.class , request ); + return this.render( model , "external" , language , "register" , eSession.listLanguages( ) ); + } + + + @RequestMapping( value = "/register.action" , method = RequestMethod.POST ) + public String registration( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( "mail" ) String mail , @RequestParam( "mailConfirm" ) String mailConfirm , + @RequestParam( "password" ) String password , @RequestParam( "passwordConfirm" ) String passwordConfirm , + @RequestParam( "language" ) String selLanguage ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ExternalSession eSession = this.createTemporarySession( ExternalSession.class , request ); + CreateAccountResponse response; + response = eSession.createAccount( mail , mailConfirm , password , passwordConfirm , selLanguage ); + + if ( response.getLanguage( ) != null ) { + language = response.getLanguage( ); + } + + if ( response.getCreated( ) ) { + return this.renderMap( model , "external" , language , "registered" , "mail" , response.getMail( ) ); + } + return this.render( model , "external" , language , "register" , response ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ValidationPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ValidationPages.java new file mode 100644 index 0000000..5c01f52 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/ValidationPages.java @@ -0,0 +1,56 @@ +package com.deepclone.lw.web.main; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.account.AccountValidationResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "validation" ) +@SessionAttributes( "language" ) +public class ValidationPages + extends PageControllerBase +{ + + @RequestMapping( "/validate-account" ) + public String validationPage( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession session = this.getSession( PlayerSession.class , request ); + return this.render( model , "restricted" , language , "validation" , session.startValidation( ) ); + } + + + @RequestMapping( value = "/validation.action" , method = RequestMethod.POST ) + public String validation( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "token" ) String token , @RequestParam( "empire" ) String empire , + @RequestParam( "old" ) String old , @RequestParam( "planet" ) String planet ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession session = this.getSession( PlayerSession.class , request ); + String uEmpire = ( "".equals( empire ) ? old : empire ); + + AccountValidationResponse response = session.validate( token , uEmpire , planet ); + if ( response.isValidated( ) ) { + return this.redirect( "player-session" ); + } + return this.render( model , "restricted" , language , "validation" , response ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/AccountPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/AccountPage.java new file mode 100644 index 0000000..ed4e213 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/AccountPage.java @@ -0,0 +1,158 @@ +package com.deepclone.lw.web.main.game; + + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.account.GetAccountResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class AccountPage + extends PageControllerBase +{ + @RequestMapping( "/account" ) + public String view( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + GetAccountResponse data = pSession.getAccount( ); + return this.render( model , "game" , data.getAccount( ).getLanguage( ) , "account" , data ); + } + + + @RequestMapping( "/set-language.action" ) + public String setLanguage( HttpServletRequest request , Model model , @RequestParam( "language" ) String newLanguage ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.getSession( PlayerSession.class , request ).setLanguage( newLanguage ); + return this.redirect( "account" ); + } + + + @RequestMapping( "/set-password.action" ) + public String setPassword( HttpServletRequest request , Model model , + @RequestParam( "current" ) String currentPassword , @RequestParam( "password" ) String newPass1 , + @RequestParam( "passwordConfirm" ) String newPass2 ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + String challenge = pSession.createAuthenticationChallenge( ); + + GetAccountResponse data = pSession.setPassword( currentPassword , challenge , newPass1 , newPass2 ); + if ( data.getAccount( ) == null ) { + return this.redirect( "account" ); + } + return this.render( model , "game" , data.getAccount( ).getLanguage( ) , "account" , data ); + } + + + @RequestMapping( "/set-address.action" ) + public String setAddress( HttpServletRequest request , Model model , @RequestParam( "password" ) String password , + @RequestParam( "mail" ) String newAddr1 , @RequestParam( "mailConfirm" ) String newAddr2 ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + String challenge = pSession.createAuthenticationChallenge( ); + + GetAccountResponse data = pSession.setAddress( password , challenge , newAddr1 , newAddr2 ); + if ( data.getAccount( ) == null ) { + return this.redirect( "account" ); + } + return this.render( model , "game" , data.getAccount( ).getLanguage( ) , "account" , data ); + } + + + @RequestMapping( "/confirm-set-address.action" ) + public String confirmSetAddress( HttpServletRequest request , Model model , + @RequestParam( value = "cancel-set-address" , required = false ) String cancel , + @RequestParam( "code" ) String code ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + if ( cancel != null ) { + pSession.cancelAddressChange( ); + return this.redirect( "account" ); + } + + GetAccountResponse data = pSession.confirmAddressChange( code ); + if ( data.getAccount( ) == null ) { + return this.redirect( "account" ); + } + return this.render( model , "game" , data.getAccount( ).getLanguage( ) , "account" , data ); + } + + + @RequestMapping( "/set-preferences.action" ) + public String confirmSetAddress( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + Map< String , Object > input = this.getInput( request ); + + if ( input.containsKey( "load-default-preferences" ) ) { + pSession.loadDefaultPreferences( ); + } else { + Map< String , String > prefs = new HashMap< String , String >( ); + for ( Map.Entry< String , Object > entry : input.entrySet( ) ) { + if ( ! ( entry.getValue( ) instanceof String[] ) ) { + continue; + } + + String[] values = (String[]) entry.getValue( ); + if ( values.length < 1 ) { + continue; + } + prefs.put( entry.getKey( ) , values[ 0 ] ); + } + pSession.setPreferences( prefs ); + } + + return this.redirect( "account" ); + } + + + @RequestMapping( "/quit.action" ) + public String quit( HttpServletRequest request , Model model , @RequestParam( "reason" ) String reason ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.getSession( PlayerSession.class , request ).setQuit( reason ); + return this.redirect( "account" ); + } + + + @RequestMapping( "/cancel-quit.action" ) + public String cancelQuit( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.getSession( PlayerSession.class , request ).cancelQuit( ); + return this.redirect( "account" ); + } + + + @RequestMapping( "/toggle-vacation.action" ) + public String toggleVacation( HttpServletRequest request , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + this.getSession( PlayerSession.class , request ).toggleVacation( ); + return this.redirect( "account" ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/AlliancePage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/AlliancePage.java new file mode 100644 index 0000000..89e0321 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/AlliancePage.java @@ -0,0 +1,172 @@ +package com.deepclone.lw.web.main.game; + + +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.alliances.AllianceStatusResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class AlliancePage + extends PageControllerBase +{ + + @RequestMapping( "/alliance" ) + public String view( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "alliance" , pSession.getAllianceStatus( ) ); + } + + + @RequestMapping( value = "/alliance-info.action" , method = RequestMethod.POST ) + public String info( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "tag" ) String tag ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "alliance" , pSession.viewAlliance( tag ) ); + } + + + @RequestMapping( value = "/join-alliance.action" , method = RequestMethod.POST ) + public String join( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "tag" ) String tag ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "alliance" , pSession.joinAlliance( tag ) ); + } + + + @RequestMapping( value = "/cancel-join.action" , method = RequestMethod.POST ) + public String cancelJoin( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "alliance" , pSession.cancelJoinAlliance( ) ); + } + + + @RequestMapping( value = "/create-alliance.action" , method = RequestMethod.POST ) + public String create( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "tag" ) String tag , @RequestParam( "name" ) String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "alliance" , pSession.createAlliance( tag , name ) ); + } + + + @RequestMapping( value = "/manage-requests.action" , method = RequestMethod.POST ) + public String manageRequests( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( value = "members" , required = false ) String[] members , + @RequestParam( "action" ) String action ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + boolean accept = "1".equals( action ); + List< Integer > identifiers = new LinkedList< Integer >( ); + if ( members != null ) { + for ( String member : members ) { + try { + identifiers.add( Integer.parseInt( member ) ); + } catch ( NumberFormatException e ) { + // EMPTY + } + } + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + AllianceStatusResponse response; + if ( identifiers.isEmpty( ) ) { + response = pSession.getAllianceStatus( ); + } else { + int[] ids = new int[ identifiers.size( ) ]; + int i = 0; + for ( Integer l : identifiers ) { + ids[ i++ ] = l.intValue( ); + } + response = pSession.manageRequests( accept , ids ); + } + return this.render( model , "game" , language , "alliance" , response ); + } + + + @RequestMapping( value = "/kick-members.action" , method = RequestMethod.POST ) + public String kickMembers( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( value = "members" , required = false ) String[] members ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + List< Integer > identifiers = new LinkedList< Integer >( ); + if ( members != null ) { + for ( String member : members ) { + try { + identifiers.add( Integer.parseInt( member ) ); + } catch ( NumberFormatException e ) { + // EMPTY + } + } + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + AllianceStatusResponse response; + if ( identifiers.isEmpty( ) ) { + response = pSession.getAllianceStatus( ); + } else { + int[] ids = new int[ identifiers.size( ) ]; + int i = 0; + for ( Integer l : identifiers ) { + ids[ i++ ] = l.intValue( ); + } + response = pSession.kickMembers( ids ); + } + return this.render( model , "game" , language , "alliance" , response ); + } + + + @RequestMapping( value = "/transfer-leadership.action" , method = RequestMethod.POST ) + public String transferLeadership( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( "leadership" ) String leadership ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + AllianceStatusResponse response; + try { + response = pSession.transferLeadership( Integer.parseInt( leadership ) ); + } catch ( NumberFormatException e ) { + response = pSession.getAllianceStatus( ); + } + return this.render( model , "game" , language , "alliance" , response ); + } + + + @RequestMapping( value = "/leave-alliance.action" , method = RequestMethod.POST ) + public String leaveAlliance( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "alliance" , pSession.leaveAlliance( ) ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/BattlePages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/BattlePages.java new file mode 100644 index 0000000..b46ba40 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/BattlePages.java @@ -0,0 +1,132 @@ +package com.deepclone.lw.web.main.game; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.battles.GetBattleResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class BattlePages + extends PageControllerBase +{ + + @RequestMapping( "/battle-{battleId}-latest" ) + public String getBattle( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable( "battleId" ) String sBattleId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long battle; + try { + battle = Long.parseLong( sBattleId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + GetBattleResponse data = this.getSession( PlayerSession.class , request ).getBattle( battle ); + if ( data.getBattle( ) == null ) { + return this.redirect( "overview" ); + } + return this.render( model , "game" , language , "battle" , data ); + } + + + @RequestMapping( "/battle-{battleId}-at-{tickId}" ) + public String getBattle( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable( "battleId" ) String sBattleId , @PathVariable( "tickId" ) String sTickId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long battle; + try { + battle = Long.parseLong( sBattleId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + long tick; + try { + tick = Long.parseLong( sTickId ); + } catch ( NumberFormatException e ) { + return this.redirect( "battle-" + battle + "-latest" ); + } + + GetBattleResponse data = this.getSession( PlayerSession.class , request ).getBattle( battle , tick ); + if ( data.getBattle( ) == null ) { + return this.redirect( "overview" ); + } + return this.render( model , "game" , language , "battle" , data ); + } + + + @RequestMapping( value = "/battle-{battleId}-at.action" , method = RequestMethod.POST ) + public String getBattlePost( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable( "battleId" ) String sBattleId , @RequestParam( "tick" ) String sTickId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long battle; + try { + battle = Long.parseLong( sBattleId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + long tick; + try { + tick = Long.parseLong( sTickId ); + } catch ( NumberFormatException e ) { + return this.redirect( "battle-" + battle + "-latest" ); + } + + return this.redirect( "battle-" + battle + "-at-" + tick ); + } + + + @RequestMapping( value = "/battles" ) + public String getBattles( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.getBattles( request , language , model , 0 ); + } + + + @RequestMapping( value = "/battles-{page}" ) + public String getBattles( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable( "page" ) String sPage ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int page; + try { + page = Integer.parseInt( sPage ); + } catch ( NumberFormatException e ) { + page = 0; + } + + return this.getBattles( request , language , model , page ); + } + + + private String getBattles( HttpServletRequest request , String language , Model model , int page ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "battles" , pSession.getBattles( page ) ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/BugTrackerPages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/BugTrackerPages.java new file mode 100644 index 0000000..03a53d8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/BugTrackerPages.java @@ -0,0 +1,170 @@ +package com.deepclone.lw.web.main.game; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.bt.data.BugEvent; +import com.deepclone.lw.cmd.player.bt.*; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.msgs.MessageFormatter; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.BugTrackerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class BugTrackerPages + extends BugTrackerBase +{ + + private static final int perPage = 10; + + private MessageFormatter formatter; + + + @Autowired( required = true ) + public void setFormatter( MessageFormatter formatter ) + { + this.formatter = formatter; + } + + + @RequestMapping( "/bugtrack" ) + public String listBugs( HttpServletRequest request , Model model , @ModelAttribute( "language" ) String language , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + ListBugsResponse response = pSession.listBugs( query.status , query.ownOnly , query.first , perPage ); + return this.render( model , "game" , language , "bugsList" , response ); + } + + + @RequestMapping( "/report-bug" ) + public String showReportForm( HttpServletRequest request , Model model , + @ModelAttribute( "language" ) String language , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + GamePageData page = pSession.listPlanets( ).getPage( ); + return this.renderMap( model , "game" , language , "bugsReport" , "page" , page , "query" , query ); + } + + + @RequestMapping( value = "/report-bug.action" , method = RequestMethod.POST ) + public String postReport( HttpServletRequest request , Model model , @ModelAttribute( "language" ) String language , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @RequestParam( "title" ) String title , + @RequestParam( "description" ) String description ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + ReportBugResponse response = pSession.reportBug( title , description ); + + if ( response.getTitle( ) == null ) { + // Successful post + String rTo = "bug-" + response.getBugId( ) + this.makeGetParams( query ); + return this.redirect( rTo ); + } + + response = new ReportBugResponse( response , query ); + return this.render( model , "game" , language , "bugsReport" , response ); + } + + + @RequestMapping( value = "/bug-{id}" ) + public String viewBug( HttpServletRequest request , Model model , @ModelAttribute( "language" ) String language , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + ViewBugResponse response = this.getSession( PlayerSession.class , request ).getBugReport( bugId ); + if ( response.getReport( ) == null ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + response = new ViewBugResponse( response , query ); + return this.displayReport( model , language , response ); + } + + + @RequestMapping( value = "/bug-{id}-comment.action" , method = RequestMethod.POST ) + public String commentBug( HttpServletRequest request , Model model , @ModelAttribute( "language" ) String language , + @RequestParam( value = "status" , required = false ) String sStatus , + @RequestParam( value = "own" , required = false ) String sOwn , + @RequestParam( value = "first" , required = false ) String sFirst , @PathVariable( "id" ) String sId , + @RequestParam( "comment" ) String comment ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + BugQuery query = this.getBugQuery( sStatus , sOwn , sFirst ); + + long bugId; + try { + bugId = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + PostCommentResponse response = this.getSession( PlayerSession.class , request ) + .postBugComment( bugId , comment ); + if ( response.isPosted( ) ) { + String rTo = "bug-" + bugId + this.makeGetParams( query ); + return this.redirect( rTo ); + } else if ( response.getReport( ) == null ) { + return this.redirect( "bugtrack" + this.makeGetParams( query ) ); + } + + response = new PostCommentResponse( response , query ); + return this.displayReport( model , language , response ); + } + + + private String displayReport( Model model , String language , ViewBugResponse response ) + { + for ( BugEvent event : response.getEvents( ) ) { + if ( event.getTitle( ) != null ) { + event.setTitle( this.formatter.cleanMessage( event.getTitle( ) ) ); + } + if ( event.getContents( ) != null ) { + event.setContents( this.formatter.formatMessage( event.getContents( ) , false ) ); + } + } + return this.render( model , "game" , language , "bugsView" , response ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/ChatPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/ChatPage.java new file mode 100644 index 0000000..55b36b8 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/ChatPage.java @@ -0,0 +1,37 @@ +package com.deepclone.lw.web.main.game; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.ListPlanetsResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class ChatPage + extends PageControllerBase +{ + + @RequestMapping( "/chat" ) + public String chat( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + ListPlanetsResponse response = this.getSession( PlayerSession.class , request ).listPlanets( ); + return this.render( model , "chat" , language , "chat" , response ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/EnemiesPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/EnemiesPage.java new file mode 100644 index 0000000..a7ab5ab --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/EnemiesPage.java @@ -0,0 +1,111 @@ +package com.deepclone.lw.web.main.game; + + +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.elist.EnemyListResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class EnemiesPage + extends PageControllerBase +{ + + @RequestMapping( "/enemies" ) + public String overview( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "enemies" , pSession.getEnemyList( ) ); + } + + + @RequestMapping( value = "/add-enemy-empire.action" , method = RequestMethod.POST ) + public String addEmpire( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "name" ) String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "enemies" , pSession.addEnemy( false , name ) ); + } + + + @RequestMapping( value = "/add-enemy-alliance.action" , method = RequestMethod.POST ) + public String addAlliance( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( "name" ) String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "enemies" , pSession.addEnemy( true , name ) ); + } + + + @RequestMapping( value = "/remove-enemy-empires.action" , method = RequestMethod.POST ) + public String removeEmpires( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( value = "id" , required = false ) String[] sIds ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.remove( request , language , model , sIds , false ); + } + + + @RequestMapping( value = "/remove-enemy-alliances.action" , method = RequestMethod.POST ) + public String removeAlliances( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( value = "id" , required = false ) String[] sIds ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.remove( request , language , model , sIds , true ); + } + + + private String remove( HttpServletRequest request , String language , Model model , String[] sIds , boolean alliance ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + List< Integer > identifiers = new LinkedList< Integer >( ); + if ( sIds != null ) { + for ( String member : sIds ) { + try { + identifiers.add( Integer.parseInt( member ) ); + } catch ( NumberFormatException e ) { + // EMPTY + } + } + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + EnemyListResponse response; + if ( identifiers.isEmpty( ) ) { + response = pSession.getEnemyList( ); + } else { + int[] ids = new int[ identifiers.size( ) ]; + int i = 0; + for ( Integer l : identifiers ) { + ids[ i++ ] = l.intValue( ); + } + response = pSession.removeEnemies( alliance , ids ); + } + + return this.render( model , "game" , language , "enemies" , response ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/FleetsPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/FleetsPage.java new file mode 100644 index 0000000..54e8480 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/FleetsPage.java @@ -0,0 +1,251 @@ +package com.deepclone.lw.web.main.game; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.fleets.MoveFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.MultiFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.RenameFleetsResponse; +import com.deepclone.lw.cmd.player.fleets.SplitFleetResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class FleetsPage + extends PageControllerBase +{ + + @RequestMapping( "/fleets" ) + public String fleetsList( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "fleets" , pSession.getFleets( ) ); + } + + + @RequestMapping( "/fleets.action" ) + public String fleetsAction( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( value = "selection" , required = false ) String[] selection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Map< String , Object > input = this.getInput( request ); + long fleetIds[] = this.getSelected( selection ); + if ( fleetIds.length == 0 ) { + return this.redirect( "fleets" ); + } + + // "Split" is special - it needs a single fleet, no less, no more + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + if ( input.containsKey( "split" ) ) { + if ( fleetIds.length != 1 ) { + return this.redirect( "fleets" ); + } + SplitFleetResponse response = pSession.splitFleet( fleetIds[ 0 ] ); + if ( response.getInitialFleet( ) == null ) { + return this.redirect( "fleets" ); + } + return this.render( model , "game" , language , "splitFleet" , response ); + } + + // Handle "multiple" commands and responses + MultiFleetsResponse response = null; + if ( input.containsKey( "rename" ) ) { + response = pSession.renameFleets( fleetIds ); + } else if ( input.containsKey( "move" ) ) { + response = pSession.moveFleets( fleetIds ); + } else if ( input.containsKey( "setAttack" ) ) { + response = pSession.setFleetsMode( fleetIds , true , false ); + } else if ( input.containsKey( "setDefend" ) ) { + response = pSession.setFleetsMode( fleetIds , false , false ); + } else if ( input.containsKey( "merge" ) ) { + response = pSession.mergeFleets( fleetIds ); + } else if ( input.containsKey( "disband" ) ) { + response = pSession.disbandFleets( fleetIds , false ); + } else { + return this.redirect( "fleets" ); + } + + // Empty response - we're done, redirect to the fleets page + if ( response == null || response.getFleets( ).isEmpty( ) ) { + return this.redirect( "fleets" ); + } + + return this.render( model , "game" , language , "fleetsCommand" , response ); + } + + + @RequestMapping( "/move-fleets.action" ) + public String moveFleets( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( value = "selection" , required = false ) String[] selection , + @RequestParam( "destination" ) String destination , @RequestParam( "mode" ) String mode ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Map< String , Object > input = this.getInput( request ); + long fleetIds[] = this.getSelected( selection ); + if ( fleetIds.length == 0 || input.containsKey( "cancel" ) ) { + return this.redirect( "fleets" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + MoveFleetsResponse response = pSession.moveFleets( fleetIds , destination , "1".equals( mode ) ); + + if ( response.getFleets( ).isEmpty( ) ) { + return this.redirect( "fleets" ); + } + return this.render( model , "game" , language , "fleetsCommand" , response ); + } + + + @RequestMapping( "/rename-fleets.action" ) + public String renameFleets( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( value = "selection" , required = false ) String[] selection , + @RequestParam( "name" ) String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Map< String , Object > input = this.getInput( request ); + long fleetIds[] = this.getSelected( selection ); + if ( fleetIds.length == 0 || input.containsKey( "cancel" ) ) { + return this.redirect( "fleets" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + RenameFleetsResponse response = pSession.renameFleets( fleetIds , name ); + + if ( response.getFleets( ).isEmpty( ) ) { + return this.redirect( "fleets" ); + } + return this.render( model , "game" , language , "fleetsCommand" , response ); + } + + + @RequestMapping( "/set-fleets-mode.action" ) + public String setFleetsMode( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( value = "selection" , required = false ) String[] selection , + @RequestParam( "attack" ) String sAttack ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Map< String , Object > input = this.getInput( request ); + long fleetIds[] = this.getSelected( selection ); + if ( fleetIds.length == 0 || input.containsKey( "cancel" ) ) { + return this.redirect( "fleets" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + pSession.setFleetsMode( fleetIds , "1".equals( sAttack ) , true ); + return this.redirect( "fleets" ); + } + + + @RequestMapping( "/disband-fleets.action" ) + public String disbandFleets( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( value = "selection" , required = false ) String[] selection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Map< String , Object > input = this.getInput( request ); + long fleetIds[] = this.getSelected( selection ); + if ( fleetIds.length == 0 || input.containsKey( "cancel" ) ) { + return this.redirect( "fleets" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + pSession.disbandFleets( fleetIds , true ); + return this.redirect( "fleets" ); + } + + + @RequestMapping( "/split-fleet.action" ) + public String splitFleet( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "fleet" ) String idStr , @RequestParam( "nFleets" ) String nbStr , + @RequestParam( "name" ) String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long id; + try { + id = Long.parseLong( idStr ); + } catch ( NumberFormatException e ) { + return this.redirect( "fleets" ); + } + + int nb; + try { + nb = Integer.parseInt( nbStr ); + } catch ( NumberFormatException e ) { + nb = 0; + } + + Map< String , Object > input = this.getInput( request ); + Map< Integer , Integer > ships = new HashMap< Integer , Integer >( ); + + // Get ship counts + for ( Map.Entry< String , Object > contents : input.entrySet( ) ) { + String k = contents.getKey( ); + if ( "cancel".equals( k ) ) { + return this.redirect( "fleets" ); + } + + if ( !k.startsWith( "ships_" ) ) { + continue; + } + + try { + int shipType = Integer.parseInt( k.substring( 6 ) ); + String[] value = (String[]) contents.getValue( ); + ships.put( shipType , Integer.parseInt( value[ 0 ] ) ); + } catch ( Throwable t ) { + continue; + } + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + SplitFleetResponse response = pSession.splitFleet( id , ships , nb , name ); + if ( response.getInitialFleet( ) == null ) { + return this.redirect( "fleets" ); + } + + return this.render( model , "game" , language , "splitFleet" , response ); + } + + + private long[] getSelected( String[] selection ) + { + if ( selection == null ) { + return new long[] { }; + } + + ArrayList< Long > selected = new ArrayList< Long >( ); + for ( String sel : selection ) { + try { + selected.add( Long.parseLong( sel ) ); + } catch ( NumberFormatException e ) { + // EMPTY - ignore errors + } + } + + long[] values = new long[ selected.size( ) ]; + for ( int i = 0 ; i < values.length ; i++ ) { + values[ i ] = selected.get( i ).longValue( ); + } + + return values; + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/GetPlanetPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/GetPlanetPage.java new file mode 100644 index 0000000..87d492f --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/GetPlanetPage.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.web.main.game; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.GetNewPlanetResponse; +import com.deepclone.lw.cmd.player.ListPlanetsResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class GetPlanetPage + extends PageControllerBase +{ + @RequestMapping( "/get-planet" ) + public String getPlanet( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + ListPlanetsResponse data = pSession.listPlanets( ); + if ( data.getPlanets( ).size( ) > 0 ) { + return this.redirect( "overview" ); + } + return this.render( model , "game" , language , "getNewPlanet" , new GetNewPlanetResponse( data.getPage( ) , "" , + null ) ); + } + + + @RequestMapping( "/get-planet.action" ) + public String getPlanet( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "name" ) String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + GetNewPlanetResponse data = this.getSession( PlayerSession.class , request ).getNewPlanet( name ); + + if ( data.getPlanet( ) != null ) { + return this.redirect( "planet-" + data.getPlanet( ) ); + } + if ( data.getName( ) == null ) { + return this.redirect( "overview" ); + } + + return this.render( model , "game" , language , "getNewPlanet" , data ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MapPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MapPage.java new file mode 100644 index 0000000..c7ec1d0 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MapPage.java @@ -0,0 +1,98 @@ +package com.deepclone.lw.web.main.game; + + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.player.ViewMapResponse; +import com.deepclone.lw.cmd.player.gdata.MapSize; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class MapPage + extends PageControllerBase +{ + + @RequestMapping( "/map" ) + public String viewMap( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + ViewMapResponse map = this.getMap( pSession , request.getSession( ) ); + return this.render( model , "game" , language , "map" , map ); + } + + + @RequestMapping( value = "/move-map.action" , method = RequestMethod.POST ) + public String viewMap( HttpServletRequest request , @RequestParam( "x" ) String xStr , + @RequestParam( "y" ) String yStr , @RequestParam( "sz" ) String szStr ) + { + int x , y , szOrd; + x = this.getInt( xStr ); + y = this.getInt( yStr ); + szOrd = this.getInt( szStr ); + + MapSize sz; + try { + sz = MapSize.values( )[ szOrd ]; + } catch ( ArrayIndexOutOfBoundsException e ) { + sz = MapSize.SMALL; + } + + HttpSession session = request.getSession( ); + session.setAttribute( "mapX" , x ); + session.setAttribute( "mapY" , y ); + session.setAttribute( "mapSize" , sz ); + + return this.redirect( "map" ); + } + + + private int getInt( String str ) + { + try { + return Integer.parseInt( str ); + } catch ( NumberFormatException e ) { + return 0; + } + } + + + private ViewMapResponse getMap( PlayerSession pSession , HttpSession session ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + Integer mx = (Integer) session.getAttribute( "mapX" ); + Integer my = (Integer) session.getAttribute( "mapY" ); + MapSize size = (MapSize) session.getAttribute( "mapSize" ); + + ViewMapResponse vmr; + if ( mx == null || my == null || size == null ) { + vmr = pSession.viewMap( ); + } else { + vmr = pSession.viewMap( mx , my , size ); + } + + session.setAttribute( "mapX" , vmr.getX( ) ); + session.setAttribute( "mapY" , vmr.getY( ) ); + session.setAttribute( "mapSize" , vmr.getSize( ) ); + + return vmr; + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MessageBoxView.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MessageBoxView.java new file mode 100644 index 0000000..de8ce04 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MessageBoxView.java @@ -0,0 +1,73 @@ +package com.deepclone.lw.web.main.game; + + +import java.util.LinkedList; +import java.util.List; + +import com.deepclone.lw.cmd.msgdata.MessageListEntry; +import com.deepclone.lw.cmd.player.gdata.GamePageData; +import com.deepclone.lw.cmd.player.gdata.GameResponseBase; + + + +public class MessageBoxView + extends GameResponseBase +{ + + private static final long serialVersionUID = 1L; + + private final boolean inbox; + private int pages; + private int cPage; + private final List< MessageListEntry > messages = new LinkedList< MessageListEntry >( ); + + + public MessageBoxView( GamePageData page , boolean inbox ) + { + super( page ); + this.inbox = inbox; + } + + + public int getPages( ) + { + return pages; + } + + + public void setPages( int pages ) + { + this.pages = pages; + } + + + public int getcPage( ) + { + return cPage; + } + + + public void setcPage( int cPage ) + { + this.cPage = cPage; + } + + + public boolean isInbox( ) + { + return inbox; + } + + + public List< MessageListEntry > getMessages( ) + { + return messages; + } + + + public void addMessage( MessageListEntry entry ) + { + this.messages.add( entry ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MessagePages.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MessagePages.java new file mode 100644 index 0000000..17b8188 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/MessagePages.java @@ -0,0 +1,487 @@ +package com.deepclone.lw.web.main.game; + + +import java.util.LinkedList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.cmd.msgdata.Message; +import com.deepclone.lw.cmd.msgdata.MessageListEntry; +import com.deepclone.lw.cmd.msgdata.MessageType; +import com.deepclone.lw.cmd.player.msgs.ComposeMessageResponse; +import com.deepclone.lw.cmd.player.msgs.GetMessagesResponse; +import com.deepclone.lw.cmd.player.msgs.ReadMessageResponse; +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.msgs.MessageFormatter; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class MessagePages + extends PageControllerBase +{ + + private final static int perPage = 12; + + private MessageFormatter formatter; + + + @Autowired( required = true ) + public void setFormatter( MessageFormatter formatter ) + { + this.formatter = formatter; + } + + + @RequestMapping( "/messages" ) + public String viewInbox( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + MessageBoxView view = this.viewMessageBox( true , this.getSession( PlayerSession.class , request ) , 0 ); + return this.render( model , "game" , language , "messageBox" , view ); + } + + + @RequestMapping( "/inbox-{page}" ) + public String viewInbox( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable( "page" ) String sPage ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int page; + try { + page = Integer.parseInt( sPage ); + } catch ( NumberFormatException e ) { + page = 0; + } + + MessageBoxView view = this.viewMessageBox( true , this.getSession( PlayerSession.class , request ) , page ); + return this.render( model , "game" , language , "messageBox" , view ); + } + + + @RequestMapping( "/inbox-from-{id}" ) + public String viewInboxFrom( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + id = 0; + } + + MessageBoxView view = this.viewMessageBoxFrom( true , this.getSession( PlayerSession.class , request ) , id ); + return this.render( model , "game" , language , "messageBox" , view ); + } + + + @RequestMapping( "/outbox" ) + public String viewOutbox( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + MessageBoxView view = this.viewMessageBox( false , this.getSession( PlayerSession.class , request ) , 0 ); + return this.render( model , "game" , language , "messageBox" , view ); + } + + + @RequestMapping( "/outbox-{page}" ) + public String viewOutbox( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable( "page" ) String sPage ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int page; + try { + page = Integer.parseInt( sPage ); + } catch ( NumberFormatException e ) { + page = 0; + } + + MessageBoxView view = this.viewMessageBox( false , this.getSession( PlayerSession.class , request ) , page ); + return this.render( model , "game" , language , "messageBox" , view ); + } + + + @RequestMapping( "/outbox-from-{id}" ) + public String viewOutboxFrom( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + id = 0; + } + + MessageBoxView view = this.viewMessageBoxFrom( false , this.getSession( PlayerSession.class , request ) , id ); + return this.render( model , "game" , language , "messageBox" , view ); + } + + + private MessageBoxView viewMessageBox( boolean inbox , PlayerSession pSession , int page ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + GetMessagesResponse mResponse = pSession.getMessages( inbox ); + MessageBoxView view = new MessageBoxView( mResponse.getPage( ) , inbox ); + List< MessageListEntry > messages = mResponse.getMessages( ); + + // Handle paging + messages = this.setPage( view , messages , page ); + this.prepareMessages( view , messages ); + + return view; + } + + + private MessageBoxView viewMessageBoxFrom( boolean inbox , PlayerSession pSession , long fromId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + GetMessagesResponse mResponse = pSession.getMessages( inbox ); + MessageBoxView view = new MessageBoxView( mResponse.getPage( ) , inbox ); + List< MessageListEntry > messages = mResponse.getMessages( ); + int page = 0; + int nSeen = -1; + for ( MessageListEntry e : messages ) { + nSeen++; + if ( e.getId( ) != fromId ) { + continue; + } + page = ( nSeen - nSeen % MessagePages.perPage ) / MessagePages.perPage; + break; + } + + // Handle paging + messages = this.setPage( view , messages , page ); + this.prepareMessages( view , messages ); + + return view; + } + + + private void prepareMessages( MessageBoxView view , List< MessageListEntry > messages ) + { + for ( MessageListEntry message : messages ) { + message.setTitle( this.formatter.cleanMessage( message.getTitle( ) ) ); + view.addMessage( message ); + } + } + + + private List< MessageListEntry > setPage( MessageBoxView view , List< MessageListEntry > messages , int page ) + { + int nMessages = messages.size( ); + int mod = nMessages % MessagePages.perPage; + int nPages = ( nMessages - mod ) / MessagePages.perPage + ( mod > 0 ? 1 : 0 ); + if ( page < 0 ) { + page = 0; + } else if ( page >= nPages ) { + page = nPages - 1; + } + if ( !messages.isEmpty( ) ) { + messages = messages.subList( page * MessagePages.perPage , Math.min( ( page + 1 ) * MessagePages.perPage , + nMessages ) ); + } + + view.setPages( nPages ); + view.setcPage( page ); + return messages; + } + + + @RequestMapping( "/inbox-message-{id}" ) + public String viewInboxMessage( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.viewMessage( request , language , model , sId , true ); + } + + + @RequestMapping( "/outbox-message-{id}" ) + public String viewOutboxMessage( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.viewMessage( request , language , model , sId , false ); + } + + + private String viewMessage( HttpServletRequest request , String language , Model model , String sId , boolean inbox ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + long id; + try { + id = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + ReadMessageResponse response = pSession.readMessage( inbox , id ); + Message message = response.getMessage( ); + if ( message == null ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + boolean internal = ( message.getType( ) == MessageType.INTERNAL ); + message.setTitle( this.formatter.cleanMessage( message.getTitle( ) ) ); + message.setContents( this.formatter.formatMessage( message.getContents( ) , internal ) ); + + return this.render( model , "game" , language , "message" , response ); + } + + + @RequestMapping( value = "/messages.action" , method = RequestMethod.POST ) + public String mbAction( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "inbox" ) String sInbox , @RequestParam( "page" ) String sPage , + @RequestParam( "target" ) String sTarget , @RequestParam( "action" ) String action , + @RequestParam( value = "selection" , required = false ) String[] sSelection ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + boolean inbox = "1".equals( sInbox ); + if ( !inbox ) { + action = "d"; + } + + boolean useSelected = "0".equals( sTarget ); + long selection[]; + if ( useSelected ) { + List< Long > rSel = new LinkedList< Long >( ); + if ( sSelection != null ) { + for ( String sItem : sSelection ) { + Long value; + try { + value = Long.parseLong( sItem ); + } catch ( NumberFormatException e ) { + continue; + } + rSel.add( value ); + } + + selection = new long[ rSel.size( ) ]; + int i = 0; + for ( Long value : rSel ) { + selection[ i++ ] = value; + } + } else { + selection = new long[ 0 ]; + } + } else { + selection = null; + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + if ( selection == null || selection.length > 0 ) { + if ( "d".equals( action ) ) { + pSession.deleteMessages( inbox , selection ); + } else if ( "r".equals( action ) ) { + pSession.markRead( selection ); + } else if ( "u".equals( action ) ) { + pSession.markUnread( selection ); + } + } + + int page; + try { + page = Integer.parseInt( sPage ); + } catch ( NumberFormatException e ) { + page = 0; + } + return this.redirect( ( inbox ? "inbox" : "outbox" ) + "-" + page ); + } + + + @RequestMapping( value = "/message.action" , method = RequestMethod.POST ) + public String msgAction( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @RequestParam( "inbox" ) String sInbox , @RequestParam( "id" ) String sId , + @RequestParam( "next" ) String sNext , @RequestParam( value = "delete" , required = false ) String delete , + @RequestParam( value = "reply" , required = false ) String reply ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + boolean inbox = "1".equals( sInbox ); + + long id; + try { + id = Long.parseLong( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + if ( delete != null ) { + pSession.deleteMessages( inbox , new long[] { + id + } ); + + try { + id = Long.parseLong( sNext ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + return this.redirect( ( inbox ? "inbox" : "outbox" ) + "-message-" + id ); + } else if ( reply != null ) { + ComposeMessageResponse response; + response = pSession.replyTo( inbox , id ); + return this.showWriter( language , model , response ); + } + return this.redirect( inbox ? "messages" : "outbox" ); + } + + + @RequestMapping( "/compose-message" ) + public String composeNew( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "messageWriter" , pSession.initNewMessage( ) ); + } + + + @RequestMapping( "/msg-empire-{id}" ) + public String messageEmpire( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.newMessageTo( request , language , model , MessageType.EMPIRE , sId ); + } + + + @RequestMapping( "/msg-alliance-{id}" ) + public String messageAlliance( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.newMessageTo( request , language , model , MessageType.ALLIANCE , sId ); + } + + + @RequestMapping( "/msg-admin-{id}" ) + public String messageAdmin( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable( "id" ) String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + return this.newMessageTo( request , language , model , MessageType.ADMINISTRATOR , sId ); + } + + + private String newMessageTo( HttpServletRequest request , String language , Model model , MessageType type , + String sId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( sId ); + } catch ( NumberFormatException e ) { + return this.redirect( "compose-message" ); + } + + ComposeMessageResponse response; + response = this.getSession( PlayerSession.class , request ).messageTo( type , id ); + return this.showWriter( language , model , response ); + } + + + @RequestMapping( value = "/send-message.action" , method = RequestMethod.POST ) + public String sendMessage( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @RequestParam( "toType" ) String sToType , @RequestParam( "toName" ) String toName , + @RequestParam( "title" ) String title , @RequestParam( "contents" ) String contents , + @RequestParam( value = "rtInbox" , required = false ) String sRtInbox , + @RequestParam( value = "rtId" , required = false ) String sRtId , + @RequestParam( value = "cancel" , required = false ) String sCancel ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + // Handle cancellation + if ( sCancel != null ) { + return this.cancelSendRedirect( sRtInbox , sRtId ); + } + + // Get message type + MessageType type; + try { + type = MessageType.valueOf( sToType ); + } catch ( IllegalArgumentException e ) { + type = MessageType.INTERNAL; + } + if ( type == MessageType.INTERNAL ) { + type = MessageType.EMPIRE; + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + ComposeMessageResponse response; + if ( sRtInbox == null || sRtId == null ) { + response = pSession.sendMessage( type , toName , title , contents ); + } else { + boolean inbox = "1".equals( sRtInbox ); + long rtId; + try { + rtId = Long.parseLong( sRtId ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + response = pSession.sendReply( inbox , rtId , type , toName , title , contents ); + } + + if ( !response.isError( ) ) { + return this.cancelSendRedirect( sRtInbox , sRtId ); + } + return this.showWriter( language , model , response ); + } + + + private String showWriter( String language , Model model , ComposeMessageResponse response ) + { + if ( response.getReplyTo( ) != null ) { + Message message = response.getReplyTo( ); + message.setTitle( this.formatter.cleanMessage( message.getTitle( ) ) ); + message.setContents( this.formatter.formatMessage( message.getContents( ) , false ) ); + } + return this.render( model , "game" , language , "messageWriter" , response ); + } + + + private String cancelSendRedirect( String sRtInbox , String sRtId ) + { + if ( sRtInbox == null || sRtId == null ) { + return this.redirect( "messages" ); + } + + boolean inbox = "1".equals( sRtInbox ); + long rtId; + try { + rtId = Long.parseLong( sRtId ); + } catch ( NumberFormatException e ) { + return this.redirect( inbox ? "messages" : "outbox" ); + } + + return this.redirect( ( inbox ? "inbox" : "outbox" ) + "-message-" + rtId ); + } + + + @RequestMapping( "/message-targets" ) + public String listTargets( HttpServletRequest request , Model model , @ModelAttribute( "language" ) String language ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "messageTargets" , pSession.listMessageTargets( ) ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/OverviewPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/OverviewPage.java new file mode 100644 index 0000000..ffbbf46 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/OverviewPage.java @@ -0,0 +1,55 @@ +package com.deepclone.lw.web.main.game; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class OverviewPage + extends PageControllerBase +{ + + @RequestMapping( "/overview" ) + public String overview( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "overview" , pSession.getOverview( ) ); + } + + + @RequestMapping( value = "/implement-{tech}.action" , method = RequestMethod.POST ) + public String implement( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable String tech ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int techId; + try { + techId = Integer.parseInt( tech ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "overview" , pSession.implementTechnology( techId ) ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/PlanetListPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/PlanetListPage.java new file mode 100644 index 0000000..1fc9540 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/PlanetListPage.java @@ -0,0 +1,36 @@ +package com.deepclone.lw.web.main.game; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class PlanetListPage + extends PageControllerBase +{ + + @RequestMapping( "/planets" ) + public String planetList( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planets" , pSession.listPlanets( ) ); + } + +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/PlanetPage.java b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/PlanetPage.java new file mode 100644 index 0000000..e0afc3c --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/java/com/deepclone/lw/web/main/game/PlanetPage.java @@ -0,0 +1,236 @@ +package com.deepclone.lw.web.main.game; + + +import javax.servlet.http.HttpServletRequest; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.SessionAttributes; + +import com.deepclone.lw.session.SessionException; +import com.deepclone.lw.web.beans.intercept.SessionRequirement; +import com.deepclone.lw.web.beans.session.SessionMaintenanceException; +import com.deepclone.lw.web.beans.session.SessionServerException; +import com.deepclone.lw.web.beans.view.PageControllerBase; +import com.deepclone.lw.web.csess.PlayerSession; + + + +@Controller +@SessionRequirement( value = true , redirectTo = "player-session" , subType = "game" ) +@SessionAttributes( "language" ) +public class PlanetPage + extends PageControllerBase +{ + + @RequestMapping( "/planet-{planetId}" ) + public String view( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable String planetId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int id; + try { + id = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.getPlanetView( id ) ); + } + + + @RequestMapping( value = "/planet-{planetId}-rename.action" , method = RequestMethod.POST ) + public String rename( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable String planetId , @RequestParam( "name" ) String name ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int pId; + try { + pId = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.rename( pId , name ) ); + } + + + @RequestMapping( value = "/planet-{planetId}-abandon.action" , method = RequestMethod.POST ) + public String abandon( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable String planetId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int pId; + try { + pId = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.abandon( pId ) ); + } + + + @RequestMapping( value = "/planet-{planetId}-cancel-abandon.action" , method = RequestMethod.POST ) + public String cancelAbandon( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable String planetId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int pId; + try { + pId = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.cancelAbandon( pId ) ); + } + + + @RequestMapping( value = "/planet-{planetId}-build-civ.action" , method = RequestMethod.POST ) + public String construct( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable String planetId , @RequestParam( "type" ) String type , + @RequestParam( "amount" ) String amount ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int pId; + try { + pId = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + int tId; + try { + tId = Integer.parseInt( type ); + } catch ( NumberFormatException e ) { + return this.redirect( "planet-" + pId + "#buildings" ); + } + + int x; + try { + x = Integer.parseInt( amount ); + } catch ( NumberFormatException e ) { + x = 0; + } + if ( x <= 0 ) { + return this.redirect( "planet-" + pId + "#buildings" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.constructBuildings( pId , tId , x ) ); + } + + + @RequestMapping( value = "/planet-{planetId}-destroy.action" , method = RequestMethod.POST ) + public String destroy( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable String planetId , @RequestParam( "type" ) String type , + @RequestParam( "amount" ) String amount ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int pId; + try { + pId = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + int tId; + try { + tId = Integer.parseInt( type ); + } catch ( NumberFormatException e ) { + return this.redirect( "planet-" + pId + "#buildings" ); + } + + int x; + try { + x = Integer.parseInt( amount ); + } catch ( NumberFormatException e ) { + x = 0; + } + if ( x <= 0 ) { + return this.redirect( "planet-" + pId + "#buildings" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.destroyBuildings( pId , tId , x ) ); + } + + + @RequestMapping( value = "/planet-{planetId}-build-mil.action" , method = RequestMethod.POST ) + public String buildShips( HttpServletRequest request , @ModelAttribute( "language" ) String language , Model model , + @PathVariable String planetId , @RequestParam( "type" ) String type , + @RequestParam( "amount" ) String amount ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int pId; + try { + pId = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + int tId; + try { + tId = Integer.parseInt( type ); + } catch ( NumberFormatException e ) { + return this.redirect( "planet-" + pId + "#ships" ); + } + + int x; + try { + x = Integer.parseInt( amount ); + } catch ( NumberFormatException e ) { + x = 0; + } + if ( x <= 0 ) { + return this.redirect( "planet-" + pId + "#ships" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.buildShips( pId , tId , x ) ); + } + + + @RequestMapping( value = "/planet-{planetId}-flush-civ.action" , method = RequestMethod.POST ) + public String flushCivQueue( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable String planetId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int pId; + try { + pId = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.flushQueue( pId , false ) ); + } + + + @RequestMapping( value = "/planet-{planetId}-flush-mil.action" , method = RequestMethod.POST ) + public String flushMilQueue( HttpServletRequest request , @ModelAttribute( "language" ) String language , + Model model , @PathVariable String planetId ) + throws SessionException , SessionServerException , SessionMaintenanceException + { + int pId; + try { + pId = Integer.parseInt( planetId ); + } catch ( NumberFormatException e ) { + return this.redirect( "overview" ); + } + + PlayerSession pSession = this.getSession( PlayerSession.class , request ); + return this.render( model , "game" , language , "planet" , pSession.flushQueue( pId , true ) ); + } +} diff --git a/legacyworlds-web/legacyworlds-web-main/src/main/resources/log4j.properties b/legacyworlds-web/legacyworlds-web-main/src/main/resources/log4j.properties new file mode 100644 index 0000000..774c437 --- /dev/null +++ b/legacyworlds-web/legacyworlds-web-main/src/main/resources/log4j.properties @@ -0,0 +1,5 @@ +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n +log4j.rootLogger=warn, stdout \ No newline at end of file diff --git a/legacyworlds-web/pom.xml b/legacyworlds-web/pom.xml new file mode 100644 index 0000000..67a4c72 --- /dev/null +++ b/legacyworlds-web/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + + legacyworlds + com.deepclone.lw + 5.99.1 + + + com.deepclone.lw + legacyworlds-web + 5.99.1 + pom + Legacy Worlds web sites + Root module for Legacy Worlds web sites + + + legacyworlds-web-main + legacyworlds-web-admin + legacyworlds-web-beans + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8f8a680 --- /dev/null +++ b/pom.xml @@ -0,0 +1,72 @@ + + 4.0.0 + com.deepclone.lw + legacyworlds + 5.99.1 + pom + Legacy Worlds + Main Maven project for LW + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.2 + + 1.6 + 1.6 + + + + + + + + + com.springsource.repository.bundles.release + Spring framework + http://repository.springsource.com/maven/bundles/release + + + com.springsource.repository.bundles.external + Spring framework - external + http://repository.springsource.com/maven/bundles/external + + + + jboss + http://repository.jboss.com/maven2 + + true + + + false + + + + + + + UTF-8 + 3.0.3.RELEASE + 1.2.16 + 1.5.11 + 1.2.2 + 1.4 + 2.2 + 1.4.1 + 1.3.1 + 4.7 + 2.3.16 + + + + legacyworlds-server + legacyworlds-session + legacyworlds-web + legacyworlds-utils + + + \ No newline at end of file diff --git a/runsrv.sh b/runsrv.sh new file mode 100755 index 0000000..d761187 --- /dev/null +++ b/runsrv.sh @@ -0,0 +1,4 @@ +#!/bin/sh +BASE="`dirname $0`" +cd "$BASE/legacyworlds-server/legacyworlds-server-main" +java -jar target/legacyworlds-server-main-5.99.1.jar diff --git a/runtool.sh b/runtool.sh new file mode 100755 index 0000000..30ba8b1 --- /dev/null +++ b/runtool.sh @@ -0,0 +1,4 @@ +#!/bin/sh +BASE="`dirname $0`" +cd "$BASE/legacyworlds-server/legacyworlds-server-main" +java -jar target/legacyworlds-server-main-5.99.1.jar --run-tool $1 "$2"