From 597429fadf83bd66bc2983d232eabcb46fc4048b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 4 Feb 2012 10:43:12 +0100 Subject: [PATCH] In-game resources views * Added session records to carry resource information over to the clients * Added SQL support code for the various views * Added interface and implementation of the resource information access component * Hooked resources information queries into both the empire and planet management component * Added resources display to planet and overview pages --- .../resources/AbstractResourceMapper.java | 61 ++++++ .../game/resources/EmpireResourceMapper.java | 72 +++++++ .../game/resources/PlanetResourceMapper.java | 105 ++++++++++ .../ResourcesInformationDAOBean.java | 99 ++++++++++ .../configuration/game/resources-beans.xml | 8 + .../lw/beans/empire/EmpireManagementBean.java | 16 +- .../lw/beans/map/PlanetsManagementBean.java | 15 +- .../src/main/resources/configuration/game.xml | 8 + .../parts/040-functions/025-resources.sql | 56 ++++++ .../parts/040-functions/040-empire.sql | 110 ++++++++++- .../040-functions/145-resource-providers.sql | 136 +++++++++++++ .../050-resource-category-weight-view.sql | 47 +++++ .../060-ordered-resources-view.sql | 57 ++++++ .../040-empire/020-planet-resources-view.sql | 56 ++++++ .../040-empire/030-resources-view.sql | 169 ++++++++++++++++ .../040-get-planet-resources.sql | 187 ++++++++++++++++++ .../050-resource-category-weight-view.sql | 11 ++ .../060-ordered-resources-view.sql | 11 ++ .../040-empire/020-planet-resources-view.sql | 11 ++ .../040-empire/030-resources-view.sql | 11 ++ .../040-get-planet-resources.sql | 13 ++ .../db-structure/tests/utils/strings.sql | 39 ++-- .../resources/ResourcesInformationDAO.java | 43 ++++ .../src/main/resources/lw-server.xml | 4 +- .../resources/TestAbstractResourceMapper.java | 126 ++++++++++++ .../resources/TestEmpireResourceMapper.java | 104 ++++++++++ .../resources/TestPlanetResourceMapper.java | 131 ++++++++++++ .../deepclone/lw/testing/MockResultSet.java | 22 +++ .../player/gdata/AbstractResourceRecord.java | 109 ++++++++++ .../gdata/empire/EmpireResourceRecord.java | 152 ++++++++++++++ .../cmd/player/gdata/empire/OverviewData.java | 131 +++++++++++- .../player/gdata/planets/PlanetOwnView.java | 175 +++++++++++++++- .../gdata/planets/PlanetResourceRecord.java | 125 ++++++++++++ .../gdata/planets/ResourceProviderRecord.java | 117 +++++++++++ .../gdata/TestAbstractResourceRecord.java | 88 +++++++++ .../empire/TestEmpireResourceRecord.java | 125 ++++++++++++ .../planets/TestPlanetResourceRecord.java | 82 ++++++++ .../planets/TestResourceProviderRecord.java | 83 ++++++++ .../Content/Raw/WEB-INF/fm/en/game.ftl | 9 +- .../Raw/WEB-INF/fm/en/types/overview.ftl | 57 ++++++ .../Raw/WEB-INF/fm/en/types/planet.ftl | 107 +++++++++- .../Content/Raw/WEB-INF/fm/fr/game.ftl | 9 +- .../Raw/WEB-INF/fm/fr/types/overview.ftl | 57 ++++++ .../Raw/WEB-INF/fm/fr/types/planet.ftl | 101 ++++++++++ .../Content/Raw/WEB-INF/fm/layout/lists.ftl | 8 +- 45 files changed, 3211 insertions(+), 52 deletions(-) create mode 100644 legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/AbstractResourceMapper.java create mode 100644 legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/EmpireResourceMapper.java create mode 100644 legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/PlanetResourceMapper.java create mode 100644 legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/ResourcesInformationDAOBean.java create mode 100644 legacyworlds-server-beans-resources/src/main/resources/configuration/game/resources-beans.xml create mode 100644 legacyworlds-server-beans-simple/src/main/resources/configuration/game.xml create mode 100644 legacyworlds-server-data/db-structure/tests/admin/040-functions/025-resources/050-resource-category-weight-view.sql create mode 100644 legacyworlds-server-data/db-structure/tests/admin/040-functions/025-resources/060-ordered-resources-view.sql create mode 100644 legacyworlds-server-data/db-structure/tests/admin/040-functions/040-empire/020-planet-resources-view.sql create mode 100644 legacyworlds-server-data/db-structure/tests/admin/040-functions/040-empire/030-resources-view.sql create mode 100644 legacyworlds-server-data/db-structure/tests/admin/040-functions/145-resource-providers/040-get-planet-resources.sql create mode 100644 legacyworlds-server-data/db-structure/tests/user/040-functions/025-resources/050-resource-category-weight-view.sql create mode 100644 legacyworlds-server-data/db-structure/tests/user/040-functions/025-resources/060-ordered-resources-view.sql create mode 100644 legacyworlds-server-data/db-structure/tests/user/040-functions/040-empire/020-planet-resources-view.sql create mode 100644 legacyworlds-server-data/db-structure/tests/user/040-functions/040-empire/030-resources-view.sql create mode 100644 legacyworlds-server-data/db-structure/tests/user/040-functions/145-resource-providers/040-get-planet-resources.sql create mode 100644 legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/resources/ResourcesInformationDAO.java create mode 100644 legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestAbstractResourceMapper.java create mode 100644 legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestEmpireResourceMapper.java create mode 100644 legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestPlanetResourceMapper.java create mode 100644 legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/AbstractResourceRecord.java create mode 100644 legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/EmpireResourceRecord.java create mode 100644 legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetResourceRecord.java create mode 100644 legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/ResourceProviderRecord.java create mode 100644 legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/TestAbstractResourceRecord.java create mode 100644 legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/empire/TestEmpireResourceRecord.java create mode 100644 legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/planets/TestPlanetResourceRecord.java create mode 100644 legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/planets/TestResourceProviderRecord.java diff --git a/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/AbstractResourceMapper.java b/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/AbstractResourceMapper.java new file mode 100644 index 0000000..39e7847 --- /dev/null +++ b/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/AbstractResourceMapper.java @@ -0,0 +1,61 @@ +package com.deepclone.lw.beans.game.resources; + + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.springframework.jdbc.core.RowMapper; + +import com.deepclone.lw.cmd.player.gdata.AbstractResourceRecord; + + + +/** + * Base class for resource information row mappers + * + *

+ * This class can be used to map resource information rows (for either planets or empires). It + * provides a method which maps the resource information's descriptive fields, and implements + * Spring's {@link RowMapper} for the correct type. + * + * @author E. Benoît + * + * @param + * a resource information record based on {@link AbstractResourceRecord}. + */ +abstract class AbstractResourceMapper< RTYPE extends AbstractResourceRecord > + implements RowMapper< RTYPE > +{ + + /** + * Extract a resource information row's descriptive fields + * + *

+ * This method will extract the descriptive fields from a resource information row and store + * them in a resource information instance. It extracts: + *

+ * + * @param resource + * the resource information record + * @param rs + * the result set with the correct row selected + * + * @throws SQLException + * if a SQLException is encountered getting column values + */ + protected final void getResourceDescription( RTYPE resource , ResultSet rs ) + throws SQLException + { + resource.setIdentifier( rs.getString( "resource_identifier" ) ); + resource.setTitle( rs.getString( "resource_name" ) ); + resource.setDescription( rs.getString( "resource_description" ) ); + resource.setCategory( rs.getString( "resource_category" ) ); + + } + +} diff --git a/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/EmpireResourceMapper.java b/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/EmpireResourceMapper.java new file mode 100644 index 0000000..71e6b7c --- /dev/null +++ b/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/EmpireResourceMapper.java @@ -0,0 +1,72 @@ +package com.deepclone.lw.beans.game.resources; + + +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.deepclone.lw.cmd.player.gdata.empire.EmpireResourceRecord; + + + +/** + * Row mapper for empire resources + * + *

+ * This class is responsible for converting empire resource information rows into instances of the + * corresponding class, {@link EmpireResourceRecord}. + * + * @author E. Benoît + */ +class EmpireResourceMapper + extends AbstractResourceMapper< EmpireResourceRecord > +{ + + /** + * Map a row from emp.resources_view + * + *

+ * This method extracts the resource's description and the fields specific to empire resource + * information from the row, returning the information as an {@link EmpireResourceRecord} + * instance. + */ + @Override + public EmpireResourceRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EmpireResourceRecord resource = new EmpireResourceRecord( ); + this.getResourceDescription( resource , rs ); + this.getEmpireFields( resource , rs ); + return resource; + } + + + /** + * Read empire-specific resource information from a row + * + *

+ * This method extracts the stockpiled quantity as well as income and upkeep from the row. If a + * mining setting is set, it extracts it as well. + * + * @param resource + * the empire resource record + * @param rs + * the result set with the correct row selected + * + * @throws SQLException + * if a SQLException is encountered getting column values + */ + private void getEmpireFields( EmpireResourceRecord resource , ResultSet rs ) + throws SQLException + { + resource.setStockpiled( rs.getLong( "empres_possessed" ) ); + resource.setPlanetUpkeep( rs.getLong( "planets_upkeep" ) ); + resource.setIncome( rs.getLong( "planets_income" ) ); + resource.setFleetUpkeep( rs.getLong( "fleets_upkeep" ) ); + + int miningPriority = rs.getInt( "empmset_weight" ); + if ( !rs.wasNull( ) ) { + resource.setMiningPriority( miningPriority ); + } + } + +} diff --git a/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/PlanetResourceMapper.java b/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/PlanetResourceMapper.java new file mode 100644 index 0000000..f35426d --- /dev/null +++ b/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/PlanetResourceMapper.java @@ -0,0 +1,105 @@ +package com.deepclone.lw.beans.game.resources; + + +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.deepclone.lw.cmd.player.gdata.planets.PlanetResourceRecord; +import com.deepclone.lw.cmd.player.gdata.planets.ResourceProviderRecord; + + + +/** + * Row mapper for planet resources + * + *

+ * This class maps rows obtained from the planet resources information stored procedure into + * instances of {@link PlanetResourceRecord} which can be sent to a client. + * + * @author E. Benoît + */ +class PlanetResourceMapper + extends AbstractResourceMapper< PlanetResourceRecord > +{ + + /** + * Map a row from emp.get_planet_resources( ) + * + *

+ * This method extracts fields that are always present, generating the + * {@link PlanetResourceRecord} instance and setting it accordingly, then reads resource + * provider columns and adds a {@link ResourceProviderRecord} instance to the record if + * necessary. + */ + @Override + public PlanetResourceRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + PlanetResourceRecord resource = getResourceFields( rs ); + getResourceProvider( rs , resource ); + return resource; + } + + + /** + * Map common fields into a {@link PlanetResourceRecord} instance + * + *

+ * This method creates the instance then reads descriptive fields, then extracts the income, + * upkeep and investment fields. + * + * @param rs + * the JDBC result set that contains the row being extracted + * + * @return the new {@link PlanetResourceRecord} instance with its common fields set + * + * @throws SQLException + * if a SQLException is encountered getting column values + */ + private PlanetResourceRecord getResourceFields( ResultSet rs ) + throws SQLException + { + PlanetResourceRecord resource = new PlanetResourceRecord( ); + this.getResourceDescription( resource , rs ); + resource.setIncome( rs.getLong( "pres_income" ) ); + resource.setUpkeep( rs.getLong( "pres_upkeep" ) ); + resource.setInvested( rs.getLong( "pres_invested" ) ); + return resource; + } + + + /** + * Map resource provider fields if they are present. + * + *

+ * Check if the record includes resource provider information. If it does, extract the fields' + * values into a {@link ResourceProviderRecord} instance and add it to the + * {@link PlanetResourceRecord}. + * + * @param rs + * the JDBC result set that contains the row being extracted + * @param resource + * the {@link PlanetResourceRecord} instance to add information to + * + * @throws SQLException + * if a SQLException is encountered getting column values + */ + private void getResourceProvider( ResultSet rs , PlanetResourceRecord resource ) + throws SQLException + { + long capacity = rs.getLong( "resprov_capacity" ); + if ( rs.wasNull( ) ) { + return; + } + + ResourceProviderRecord provider = new ResourceProviderRecord( ); + + provider.setCapacity( capacity ); + provider.setQuantity( rs.getLong( "resprov_quantity" ) ); + provider.setDifficulty( rs.getInt( "resprov_difficulty" ) ); + provider.setPriority( rs.getInt( "mset_weight" ) ); + + resource.setResourceProvider( provider ); + } + +} diff --git a/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/ResourcesInformationDAOBean.java b/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/ResourcesInformationDAOBean.java new file mode 100644 index 0000000..651d4e5 --- /dev/null +++ b/legacyworlds-server-beans-resources/src/main/java/com/deepclone/lw/beans/game/resources/ResourcesInformationDAOBean.java @@ -0,0 +1,99 @@ +package com.deepclone.lw.beans.game.resources; + + +import java.util.List; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; + +import com.deepclone.lw.cmd.player.gdata.empire.EmpireResourceRecord; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetResourceRecord; +import com.deepclone.lw.interfaces.game.resources.ResourcesInformationDAO; + + + +/** + * Resource information access component + * + *

+ * This component's goal is to read information about resources from the database and return the + * records in some usable format. + * + *

+ * It does not contain any method that actually change the database. + * + * @author E. Benoît + * + */ +class ResourcesInformationDAOBean + implements ResourcesInformationDAO +{ + + /** SQL query that fetches a planet's resources information */ + private static final String Q_PLANET_RESOURCES = "SELECT * FROM emp.get_planet_resources( ? )"; + + /** SQL query that fetches an empire's resources information */ + private static final String Q_EMPIRE_RESOURCES = "SELECT * FROM emp.resources_view WHERE empire_id = ?"; + + /** Row mapper for planet resources */ + private final PlanetResourceMapper mPlanetResource; + + /** Row mapper for empire resources */ + private final EmpireResourceMapper mEmpireResource; + + /** Spring JDBC interface */ + private JdbcTemplate dTemplate; + + + /** Initialise the necessary row mappers */ + public ResourcesInformationDAOBean( ) + { + this.mPlanetResource = new PlanetResourceMapper( ); + this.mEmpireResource = new EmpireResourceMapper( ); + } + + + /** + * Dependency injector that sets the data source + * + * @param dataSource + * the data source + */ + @Autowired( required = true ) + public void setDataSource( DataSource dataSource ) + { + this.dTemplate = new JdbcTemplate( dataSource ); + } + + + /** + * Run the planet resources information query and extract the data + * + *

+ * This implementation simply executes a query using the emp.get_planet_resources() + * stored procedure and maps the resulting rows into a list of {@link PlanetResourceRecord} + * instances. + */ + @Override + public List< PlanetResourceRecord > getPlanetInformation( int planet ) + { + return this.dTemplate.query( Q_PLANET_RESOURCES , this.mPlanetResource , planet ); + } + + + /** + * Run the empire resources information query and extract the data + * + *

+ * This implementation executes a query on emp.resources_view for a specific + * empire, and maps the resulting rows into a list of {@link EmpireResourceRecord} instances. + */ + @Override + public List< EmpireResourceRecord > getEmpireInformation( int empire ) + { + return this.dTemplate.query( Q_EMPIRE_RESOURCES , this.mEmpireResource , empire ); + } + +} diff --git a/legacyworlds-server-beans-resources/src/main/resources/configuration/game/resources-beans.xml b/legacyworlds-server-beans-resources/src/main/resources/configuration/game/resources-beans.xml new file mode 100644 index 0000000..2c36ed9 --- /dev/null +++ b/legacyworlds-server-beans-resources/src/main/resources/configuration/game/resources-beans.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java index 18a9571..2d769f3 100644 --- a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java +++ b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/empire/EmpireManagementBean.java @@ -25,6 +25,7 @@ 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.game.resources.ResourcesInformationDAO; import com.deepclone.lw.interfaces.naming.NamingDAO; import com.deepclone.lw.interfaces.prefs.AccountPreferences; import com.deepclone.lw.interfaces.prefs.PreferencesDAO; @@ -46,6 +47,7 @@ public class EmpireManagementBean private EmpireDAO empireDao; private PreferencesDAO prefsDao; private BattlesDAO battlesDao; + private ResourcesInformationDAO resourcesInformationDao; @Autowired( required = true ) @@ -83,6 +85,13 @@ public class EmpireManagementBean } + @Autowired( required = true ) + public void setResourcesInformationDao( ResourcesInformationDAO resourcesInformationDao ) + { + this.resourcesInformationDao = resourcesInformationDao; + } + + @Override public Integer getEmpireId( EmailAddress address ) { @@ -103,8 +112,9 @@ public class EmpireManagementBean 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 ); + return new GamePageData( generalInformation.getName( ) , generalInformation.getStatus( ) , + generalInformation.getTag( ) , generalInformation.getCash( ) , generalInformation.getNextTick( ) , + planets , rlTime ); } @@ -150,6 +160,8 @@ public class EmpireManagementBean battles.add( entry ); } + overview.setEconomy( this.resourcesInformationDao.getEmpireInformation( empireId ) ); + return new EmpireResponse( this.getGeneralInformation( empireId ) , overview , research , battles ); } diff --git a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetsManagementBean.java b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetsManagementBean.java index 709fe4b..0e364ca 100644 --- a/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetsManagementBean.java +++ b/legacyworlds-server-beans-simple/src/main/java/com/deepclone/lw/beans/map/PlanetsManagementBean.java @@ -19,6 +19,7 @@ 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.game.resources.ResourcesInformationDAO; import com.deepclone.lw.interfaces.naming.NamingDAO; import com.deepclone.lw.sqld.game.PlanetData; import com.deepclone.lw.sqld.game.PlanetData.AccessType; @@ -36,6 +37,7 @@ public class PlanetsManagementBean private EmpireManagement empireManagement; private PlanetDAO planetDao; private NamingDAO namingDao; + private ResourcesInformationDAO resourcesInformationDao; @Autowired( required = true ) @@ -59,6 +61,13 @@ public class PlanetsManagementBean } + @Autowired( required = true ) + public void setResourcesInformationDao( ResourcesInformationDAO resourcesInformationDao ) + { + this.resourcesInformationDao = resourcesInformationDao; + } + + private PlanetOrbitalView getOrbitalView( int empireId , int planetId , AccessType access ) { if ( access == AccessType.BASIC ) { @@ -107,6 +116,8 @@ public class PlanetsManagementBean view.setbBuildings( this.planetDao.getAvailableBuildings( planetId ) ); view.setbShips( this.planetDao.getAvailableShips( planetId ) ); + view.setResources( this.resourcesInformationDao.getPlanetInformation( planetId ) ); + return view; } @@ -199,8 +210,8 @@ public class PlanetsManagementBean 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( ) ); + return new RenamePlanetResponse( planetId , page , this.getBasicView( basic ) , orbital , owner , name , + one.toString( ) ); } diff --git a/legacyworlds-server-beans-simple/src/main/resources/configuration/game.xml b/legacyworlds-server-beans-simple/src/main/resources/configuration/game.xml new file mode 100644 index 0000000..952f3f6 --- /dev/null +++ b/legacyworlds-server-beans-simple/src/main/resources/configuration/game.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/parts/040-functions/025-resources.sql b/legacyworlds-server-data/db-structure/parts/040-functions/025-resources.sql index 3a47212..4a7fa06 100644 --- a/legacyworlds-server-data/db-structure/parts/040-functions/025-resources.sql +++ b/legacyworlds-server-data/db-structure/parts/040-functions/025-resources.sql @@ -505,3 +505,59 @@ GRANT EXECUTE DOUBLE PRECISION , DOUBLE PRECISION , DOUBLE PRECISION , DOUBLE PRECISION ) TO :dbuser; + + + +/* + * View of resource category weights + * + * This view computes the average resource weight per category for all + * resource definitions. + * + * Fields: + * resource_category_id The category's identifier + * resource_category_weight The average weight of resource defintions + * in the category. + */ +DROP VIEW IF EXISTS defs.resource_category_weight_view CASCADE; +CREATE VIEW defs.resource_category_weight_view + AS SELECT resource_category_id , + AVG( resource_weight ) AS resource_category_weight + FROM defs.resources + WHERE resource_category_id IS NOT NULL + GROUP BY resource_category_id; + + + +/* + * Ordered resource definitions + * + * This view contains the name, category and description identifier for all + * resource definitions, ordered based on the category's average weight and + * the resource's own weight. + * + * Fields: + * resource_name_id The identifier of the resource's name + * resource_category_id The identifier of the category's name, or NULL + * if the resource is not in a category + * resource_description_id The identifier of the resource's description + * resource_ordering The index of the resource in a sorted view + */ +DROP VIEW IF EXISTS defs.ordered_resources_view CASCADE; +CREATE VIEW defs.ordered_resources_view + AS SELECT resource_name_id , resource_category_id , resource_description_id , + row_number( ) OVER( + ORDER BY ( + CASE + WHEN resource_category_id IS NULL THEN + resource_weight + ELSE + resource_category_weight + END ) , resource_weight + ) AS resource_ordering + + FROM defs.resources + LEFT OUTER JOIN defs.resource_category_weight_view + USING ( resource_category_id ) + + ; diff --git a/legacyworlds-server-data/db-structure/parts/040-functions/040-empire.sql b/legacyworlds-server-data/db-structure/parts/040-functions/040-empire.sql index 63ac90e..cb30603 100644 --- a/legacyworlds-server-data/db-structure/parts/040-functions/040-empire.sql +++ b/legacyworlds-server-data/db-structure/parts/040-functions/040-empire.sql @@ -668,4 +668,112 @@ CREATE VIEW emp.enemy_lists 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 +GRANT SELECT ON emp.enemy_lists TO :dbuser; + + +/* + * Planets income and upkeep totals + * + * This view computes the totals of planets' incomes and upkeeps for each + * empire and resource type. + * + * FIXME: time-related factor is hardcoded + * + * Fields: + * empire_id The empire's identifier + * resource_name_id The identifier of the resource type + * planets_income The planets' income over 12h RT / 1 month GT, + * rounded down + * planets_upkeep The planets' upkeep over 12h RT / 1 month GT, + * rounded up + */ +DROP VIEW IF EXISTS emp.planet_resources_view CASCADE; +CREATE VIEW emp.planet_resources_view + AS SELECT + empire_id , resource_name_id , + FLOOR( SUM( pres_income ) * 720.0 )::BIGINT AS planets_income , + CEIL( SUM( pres_upkeep ) * 720.0 )::BIGINT AS planets_upkeep + FROM emp.planets + LEFT OUTER JOIN verse.planet_resources + USING ( planet_id ) + GROUP BY empire_id , resource_name_id; + + +/* + * Empire resources view + * + * This view contains all resource-related information for each empire and + * resource type. + * + * FIXME: fleets upkeep is set to 0 at the moment. + * + * Fields: + * empire_id The empire's identifier + * resource_identifier The text identifier of the resource + * resource_name The internationalised name of the resource + * resource_description The internationalised description of the + * resource + * resource_category The internationalised category of the resource, + * or NULL if the resource is not in a + * category. + * empres_possessed The empire's stockpile of this type of + * resource, rounded down + * empmset_weight The empire-wide mining setting for the + * resource type, or NULL if this is a basic + * resource + * planets_income The planets' total income + * planets_upkeep The planets' total upkeep + * fleets_upkeep The fleets' total upkeep + */ +DROP VIEW IF EXISTS emp.resources_view CASCADE; +CREATE VIEW emp.resources_view + AS SELECT + empire_id , + _r_name_str.name AS resource_identifier , + _r_name.translated_string AS resource_name , + _r_desc.translated_string AS resource_description , + _r_cat.translated_string AS resource_category , + FLOOR( empres_possessed )::BIGINT AS empres_possessed , + empmset_weight , + ( CASE + WHEN planets_income IS NULL THEN + 0::BIGINT + ELSE + planets_income + END ) AS planets_income , + ( CASE + WHEN planets_upkeep IS NULL THEN + 0::BIGINT + ELSE + planets_upkeep + END ) AS planets_upkeep , + 0::BIGINT AS fleets_upkeep + + FROM defs.ordered_resources_view + INNER JOIN emp.resources + USING ( resource_name_id ) + INNER JOIN naming.empire_names _name + ON _name.id = empire_id + INNER JOIN users.credentials _creds + ON _creds.address_id = _name.owner_id + INNER JOIN defs.strings _r_name_str + ON _r_name_str.id = resource_name_id + INNER JOIN defs.translations _r_name + ON _r_name.string_id = resource_name_id + AND _r_name.lang_id = _creds.language_id + INNER JOIN defs.translations _r_desc + ON _r_desc.string_id = resource_description_id + AND _r_desc.lang_id = _creds.language_id + LEFT OUTER JOIN defs.translations _r_cat + ON _r_cat.string_id = resource_category_id + AND _r_cat.lang_id = _creds.language_id + LEFT OUTER JOIN emp.mining_settings + USING ( empire_id , resource_name_id ) + LEFT OUTER JOIN emp.planet_resources_view + USING ( empire_id , resource_name_id ) + + ORDER BY resource_ordering; + +GRANT SELECT + ON emp.resources_view + TO :dbuser; diff --git a/legacyworlds-server-data/db-structure/parts/040-functions/145-resource-providers.sql b/legacyworlds-server-data/db-structure/parts/040-functions/145-resource-providers.sql index 0dfccb2..74b758b 100644 --- a/legacyworlds-server-data/db-structure/parts/040-functions/145-resource-providers.sql +++ b/legacyworlds-server-data/db-structure/parts/040-functions/145-resource-providers.sql @@ -139,3 +139,139 @@ REVOKE EXECUTE DOUBLE PRECISION , DOUBLE PRECISION ) FROM PUBLIC; + +/* + * Planet resources type + * + * This type is used to transmit a planet's resources information to the game + * server. It contains the resource's description, the planet's economic data + * and, if there is a resource provider on the planet, the provider's + * information and mining priority. + */ +DROP TYPE IF EXISTS emp.planet_resources_type CASCADE; +CREATE TYPE emp.planet_resources_type AS ( + /* Text identifier of the resource */ + resource_identifier TEXT , + + /* Internationalised name of the resource */ + resource_name TEXT , + + /* Internationalised description of the resource */ + resource_description TEXT , + + /* Internationalised name of the category the resource is a part of, or + * NULL if the resource is not in any category. + */ + resource_category TEXT , + + /* The planet's income for this resource, over a period of 12h RT/ 1 month + * GT. + */ + pres_income BIGINT , + + /* The planet's upkeep for this resource, over a period of 12h RT/ 1 month + * GT. + */ + pres_upkeep BIGINT , + + /* The current quantity of this resource invested in the planet's build + * queues. + */ + pres_invested BIGINT , + + /** The capacity of the resource provider, if there is one, or NULL if + * there is no provider. + */ + resprov_capacity BIGINT , + + /** The quantity of resources in the resource provider, if there is one, + * or NULL if there is no provider. + */ + resprov_quantity BIGINT , + + /** The extraction difficulty of the resource provider as a percentage, or + * NULL if there is no provider. + */ + resprov_difficulty INT , + + /* The mining priority for the resource in question, or NULL if there is no + * resource provider. + */ + mset_weight INT +); + + + +/* + * Access all available information about a planet's resources + * + * This function retrieves resource information about an empire-owned planet, + * and converts it to the format used in the game server (rounded quantities, + * difficulty as percentage, internationalised strings). + * + * FIXME: + * 1) pres_invested is always set to 0 in the output + * 2) time-related computations use hardcoded values + * + * Parameters: + * _planet The planet's identifier + * + * Returns: + * N/A Resource information records, ordered using resource + * weights. + */ +DROP FUNCTION IF EXISTS emp.get_planet_resources( INT ); +CREATE FUNCTION emp.get_planet_resources( _planet INT ) + RETURNS SETOF emp.planet_resources_type + STRICT STABLE + SECURITY DEFINER +AS $get_planet_resources$ + + SELECT _name_str.name AS resource_identifier , + _name_trans.translated_string AS resource_name , + _desc_trans.translated_string AS resource_description , + _cat_trans.translated_string AS resource_category , + FLOOR( pres_income * 720.0 )::BIGINT AS pres_income , + CEIL( pres_upkeep * 720.0 )::BIGINT AS pres_upkeep , + 0::BIGINT AS pres_invested , + ROUND( resprov_quantity_max )::BIGINT AS resprov_capacity , + ROUND( resprov_quantity )::BIGINT AS resprov_quantity , + ROUND( 100.0 * resprov_difficulty )::INT AS resprov_difficulty , + mset_weight + + FROM defs.ordered_resources_view + INNER JOIN verse.planet_resources USING ( resource_name_id ) + INNER JOIN emp.planets USING ( planet_id ) + INNER JOIN naming.empire_names _emp_name + ON _emp_name.id = empire_id + INNER JOIN users.credentials _user + ON _emp_name.owner_id = _user.address_id + INNER JOIN defs.strings _name_str + ON _name_str.id = resource_name_id + INNER JOIN defs.translations _name_trans + ON _name_trans.string_id = resource_name_id + AND _name_trans.lang_id = _user.language_id + INNER JOIN defs.translations _desc_trans + ON _desc_trans.string_id = resource_description_id + AND _desc_trans.lang_id = _user.language_id + LEFT OUTER JOIN defs.translations _cat_trans + ON _cat_trans.string_id = resource_category_id + AND _cat_trans.lang_id = _user.language_id + LEFT OUTER JOIN verse.resource_providers + USING ( planet_id , resource_name_id ) + LEFT OUTER JOIN emp.mining_settings_view + USING ( planet_id , resource_name_id ) + + WHERE planet_id = $1 + + ORDER BY resource_ordering; + +$get_planet_resources$ LANGUAGE SQL; + +REVOKE EXECUTE + ON FUNCTION emp.get_planet_resources( INT ) + FROM PUBLIC; +GRANT EXECUTE + ON FUNCTION emp.get_planet_resources( INT ) + TO :dbuser; + diff --git a/legacyworlds-server-data/db-structure/tests/admin/040-functions/025-resources/050-resource-category-weight-view.sql b/legacyworlds-server-data/db-structure/tests/admin/040-functions/025-resources/050-resource-category-weight-view.sql new file mode 100644 index 0000000..f5a59ba --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/admin/040-functions/025-resources/050-resource-category-weight-view.sql @@ -0,0 +1,47 @@ +/* + * Tests for defs.resource_category_weight_view + */ +BEGIN; + /* + * We need a few resources, with a known average per category. Some of the + * resources must not belong to any category. + */ + \i utils/strings.sql + SELECT _create_test_strings( 5 , 'resource' ); + SELECT _create_test_strings( 5 , 'resDesc' ); + SELECT _create_test_strings( 2 , 'resCat' ); + + INSERT INTO defs.resources( + resource_name_id , resource_description_id , + resource_category_id , resource_weight + ) VALUES ( + _get_string( 'resource1' ) , _get_string( 'resDesc1' ) , + _get_string( 'resCat1' ) , 2 + ) , ( + _get_string( 'resource2' ) , _get_string( 'resDesc2' ) , + _get_string( 'resCat1' ) , 4 + ) , ( + _get_string( 'resource3' ) , _get_string( 'resDesc3' ) , + _get_string( 'resCat2' ) , 3 + ) , ( + _get_string( 'resource4' ) , _get_string( 'resDesc4' ) , + _get_string( 'resCat2' ) , 5 + ) , ( + _get_string( 'resource5' ) , _get_string( 'resDesc5' ) , + NULL , 150 + ); + + SELECT plan( 1 ); + + SELECT diag_test_name( 'defs.resource_category_weight_view - Resulting set contains correct values' ); + SELECT set_eq( + $$ SELECT * FROM defs.resource_category_weight_view $$ , + $$ VALUES ( + _get_string( 'resCat1' ) , 3 + ) , ( + _get_string( 'resCat2' ) , 4 + ) $$ + ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/admin/040-functions/025-resources/060-ordered-resources-view.sql b/legacyworlds-server-data/db-structure/tests/admin/040-functions/025-resources/060-ordered-resources-view.sql new file mode 100644 index 0000000..aecee23 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/admin/040-functions/025-resources/060-ordered-resources-view.sql @@ -0,0 +1,57 @@ +/* + * Tests for defs.ordered_resources_view + */ +BEGIN; + + /* + * We need: + * - one resource without category with weight 1, + * - one resource with category 1 and weight 2, + * - one resource with weight 4 and no category, + * - two resourcew with weights 3 and 7 and category 2. + */ + \i utils/strings.sql + SELECT _create_test_strings( 5 , 'resource' ); + SELECT _create_test_strings( 5 , 'resDesc' ); + SELECT _create_test_strings( 2 , 'resCat' ); + + INSERT INTO defs.resources( + resource_name_id , resource_description_id , + resource_category_id , resource_weight + ) VALUES ( + _get_string( 'resource1' ) , _get_string( 'resDesc1' ) , + NULL , 1 + ) , ( + _get_string( 'resource2' ) , _get_string( 'resDesc2' ) , + _get_string( 'resCat1' ) , 2 + ) , ( + _get_string( 'resource3' ) , _get_string( 'resDesc3' ) , + NULL , 4 + ) , ( + _get_string( 'resource4' ) , _get_string( 'resDesc4' ) , + _get_string( 'resCat2' ) , 3 + ) , ( + _get_string( 'resource5' ) , _get_string( 'resDesc5' ) , + _get_string( 'resCat2' ) , 7 + ); + + SELECT plan( 1 ); + SELECT diag_test_name( 'defs.ordered_resources_view - Resources are in the correct order' ); + SELECT set_eq( + $$ SELECT resource_name_id , resource_ordering + FROM defs.ordered_resources_view $$ , + $$ VALUES ( + _get_string( 'resource1' ) , 1 + ) , ( + _get_string( 'resource2' ) , 2 + ) , ( + _get_string( 'resource3' ) , 3 + ) , ( + _get_string( 'resource4' ) , 4 + ) , ( + _get_string( 'resource5' ) , 5 + ) $$ + ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/admin/040-functions/040-empire/020-planet-resources-view.sql b/legacyworlds-server-data/db-structure/tests/admin/040-functions/040-empire/020-planet-resources-view.sql new file mode 100644 index 0000000..3130b92 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/admin/040-functions/040-empire/020-planet-resources-view.sql @@ -0,0 +1,56 @@ +/* + * Tests for emp.planet_resources_view + */ +BEGIN; + /* + * Create two empires, one with 2 planets, the other without. Add 2 planet + * resources records. + * + * Disable all foreign keys to avoid a lot of work. + */ + + ALTER TABLE emp.planets + DROP CONSTRAINT fk_eplanets_empire , + DROP CONSTRAINT fk_eplanets_planet; + ALTER TABLE verse.planet_resources + DROP CONSTRAINT fk_pres_planet , + DROP CONSTRAINT fk_pres_resource; + + INSERT INTO verse.planet_resources ( + planet_id , resource_name_id , pres_income , pres_upkeep + ) VALUES + ( 1 , 1 , 1 , 2 ) , ( 1 , 2 , 3 , 4 ) , + ( 2 , 1 , 3 , 4 ) , ( 2 , 2 , 5 , 6 ) , + ( 3 , 1 , 0.1 / 720 , 0.4 / 720 ) , + ( 3 , 2 , 0.9 / 720, 0.9 / 720 ); + INSERT INTO emp.planets( empire_id , planet_id ) + VALUES ( 1 , 1 ) , ( 1 , 2 ) , ( 2 , 3 ); + + + /***** TESTS BEGIN HERE *****/ + SELECT plan( 3 ); + + SELECT diag_test_name( 'emp.planet_resources_view - Sums' ); + SELECT set_eq( + $$ SELECT * FROM emp.planet_resources_view WHERE empire_id = 1 $$ , + $$ VALUES ( 1 , 1 , 4 * 720 , 6 * 720 ) , ( 1 , 2 , 8 * 720 , 10 * 720 ) $$ + ); + + SELECT diag_test_name( 'emp.planet_resources_view - Incomes are rounded down' ); + SELECT set_eq( + $$ SELECT resource_name_id , planets_income + FROM emp.planet_resources_view + WHERE empire_id = 2 $$ , + $$ VALUES ( 1 , 0 ) , ( 2 , 0 ) $$ + ); + + SELECT diag_test_name( 'emp.planet_resources_view - Upkeeps are rounded up' ); + SELECT set_eq( + $$ SELECT resource_name_id , planets_upkeep + FROM emp.planet_resources_view + WHERE empire_id = 2 $$ , + $$ VALUES ( 1 , 1 ) , ( 2 , 1 ) $$ + ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/admin/040-functions/040-empire/030-resources-view.sql b/legacyworlds-server-data/db-structure/tests/admin/040-functions/040-empire/030-resources-view.sql new file mode 100644 index 0000000..8a38970 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/admin/040-functions/040-empire/030-resources-view.sql @@ -0,0 +1,169 @@ +/* + * Tests for emp.resources_view + */ +BEGIN; + + /* + * We will use a fake emp.planet_resources_view to avoid having to set + * planet resources. + * + * In terms of data, we need two resources (one with a category, the other + * without, and two empires (one with "planet resources", the other + * without). Both empires will have mining settings for one of the resource + * types. + */ + + \i utils/strings.sql + SELECT _create_test_strings( 2 , 'resource' , 'Resource name ' ); + SELECT _create_test_strings( 2 , 'rDesc' , 'Resource description ' ); + SELECT _create_test_strings( 1 , 'rCat' , 'Resource category ' ); + + INSERT INTO defs.resources ( + resource_name_id , resource_description_id , + resource_category_id , resource_weight + ) VALUES ( + _get_string( 'resource1' ) , _get_string( 'rDesc1' ) , + _get_string( 'rCat1' ) , 2 + ) , ( + _get_string( 'resource2' ) , _get_string( 'rDesc2' ) , + NULL , 1 + ); + + \i utils/accounts.sql + \i utils/naming.sql + SELECT _create_emp_names( 2 , 'emp' ); + INSERT INTO emp.empires( name_id , cash ) + SELECT id , 0 FROM naming.empire_names; + + ALTER TABLE emp.mining_settings DROP CONSTRAINT fk_empmset_resource; + INSERT INTO emp.mining_settings ( empire_id , resource_name_id , empmset_weight ) + SELECT id , _get_string( 'resource1' ) , row_number( ) OVER () + FROM naming.empire_names + ORDER BY id; + + INSERT INTO emp.resources ( empire_id , resource_name_id , empres_possessed ) + SELECT name_id , resource_name_id , 0.4 * row_number( ) OVER () + FROM emp.empires + CROSS JOIN defs.resources + ORDER BY name_id , resource_name_id; + + + CREATE TABLE fake_planet_resources_view ( + empire_id INT , + resource_name_id INT , + planets_income BIGINT , + planets_upkeep BIGINT + ); + + CREATE OR REPLACE VIEW emp.planet_resources_view + AS SELECT * FROM fake_planet_resources_view; + + INSERT INTO fake_planet_resources_view + VALUES ( + _get_emp_name( 'emp1' ) , _get_string( 'resource1' ) , 1 , 2 + ) , ( + _get_emp_name( 'emp1' ) , _get_string( 'resource2' ) , 3 , 4 + ); + + + /***** TESTS BEGIN HERE *****/ + SELECT plan( 13 ); + + SELECT diag_test_name( 'emp.resources_view - One row per empire/resource combination' ); + SELECT is( COUNT(*)::INT , 4 ) FROM emp.resources_view; + + SELECT diag_test_name( 'emp.resources_view - Resource ordering' ); + SELECT set_eq( + $$ SELECT resource_identifier , row_number( ) OVER ( ) + FROM emp.resources_view + WHERE empire_id = _get_emp_name( 'emp1' ) $$ , + $$ VALUES ( 'resource2' , 1 ) , ( 'resource1' , 2 ) $$ + ); + + SELECT diag_test_name( 'emp.resources_view - Name translation' ); + SELECT is_empty( $$ + SELECT * + FROM emp.resources_view + WHERE resource_name NOT LIKE 'Resource name %' + $$ ); + + SELECT diag_test_name( 'emp.resources_view - Description translation' ); + SELECT is_empty( $$ + SELECT * + FROM emp.resources_view + WHERE resource_description NOT LIKE 'Resource description %' + $$ ); + + SELECT diag_test_name( 'emp.resources_view - Category translation' ); + SELECT is_empty( $$ + SELECT * + FROM emp.resources_view + WHERE resource_identifier = 'resource1' + AND resource_category NOT LIKE 'Resource category %' + $$ ); + + SELECT diag_test_name( 'emp.resources_view - NULL category -> NULL translation' ); + SELECT is_empty( $$ + SELECT * + FROM emp.resources_view + WHERE resource_identifier <> 'resource1' + AND resource_category IS NOT NULL + $$ ); + + SELECT diag_test_name( 'emp.resources_view - Possessed quantities are rounded down' ); + SELECT set_eq( + $$ SELECT empire_id , resource_identifier , empres_possessed + FROM emp.resources_view $$ , + $$ VALUES ( + _get_emp_name( 'emp1' ) , 'resource1' , 0 + ) , ( + _get_emp_name( 'emp1' ) , 'resource2' , 0 + ) , ( + _get_emp_name( 'emp2' ) , 'resource1' , 1 + ) , ( + _get_emp_name( 'emp2' ) , 'resource2' , 1 + ) $$ + ); + + SELECT diag_test_name( 'emp.resources_view - Basic resources have NULL mining settings' ); + SELECT is( COUNT(*)::INT , 2 ) + FROM emp.resources_view + WHERE resource_identifier = 'resource2' + AND empmset_weight IS NULL; + + SELECT diag_test_name( 'emp.resources_view - Mining settings for natural resources' ); + SELECT set_eq( + $$ SELECT empire_id , empmset_weight + FROM emp.resources_view + WHERE resource_identifier = 'resource1' $$ , + $$ VALUES ( _get_emp_name( 'emp1' ) , 1 ) , + ( _get_emp_name( 'emp2' ) , 2 ) $$ + ); + SELECT is( COUNT(*)::INT , 2 ) + FROM emp.resources_view + WHERE resource_identifier = 'resource1' + AND empmset_weight IS NOT NULL; + + SELECT diag_test_name( 'emp.resources_view - Planet upkeep/income is zero when there are no planets' ); + SELECT is( COUNT(*)::INT , 2 ) + FROM emp.resources_view + WHERE empire_id = _get_emp_name( 'emp2' ) + AND planets_upkeep = 0 + AND planets_income = 0; + + SELECT diag_test_name( 'emp.resources_view - Planet upkeep/income from planet resources view' ); + SELECT set_eq( + $$ SELECT resource_identifier , planets_upkeep , planets_income + FROM emp.resources_view + WHERE empire_id = _get_emp_name( 'emp1' ) $$ , + $$ VALUES ( 'resource1' , 2 , 1 ) , ( 'resource2' , 4 , 3 ) $$ + ); + + SELECT diag_test_name( 'emp.resources_view - FIXME - Fleets upkeep set to zero' ); + SELECT is_empty( + $$ SELECT * FROM emp.resources_view + WHERE fleets_upkeep <> 0 $$ + ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/admin/040-functions/145-resource-providers/040-get-planet-resources.sql b/legacyworlds-server-data/db-structure/tests/admin/040-functions/145-resource-providers/040-get-planet-resources.sql new file mode 100644 index 0000000..39a081b --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/admin/040-functions/145-resource-providers/040-get-planet-resources.sql @@ -0,0 +1,187 @@ +/* + * Tests for the emp.get_planet_resources() function + */ +BEGIN; + /* + * We need two planets, one being owned by some empire, the other being + * neutral. Both planets' resource records must exist. Both planets will + * also include resource providers which will serve as tests for the + * various rounding which takes place. + * + * To avoid having to define actual natural resources, we disable the + * foreign keys on resource providers and mining settings. We can't do + * that for the empire, tho: we need an actual account as the translations + * must be looked up. + */ + + \i utils/strings.sql + SELECT _create_test_strings( 3 , 'resource' , 'Resource name ' ); + SELECT _create_test_strings( 3 , 'rDesc' , 'Resource description ' ); + SELECT _create_test_strings( 1 , 'rCat' , 'Resource category ' ); + + INSERT INTO defs.resources ( + resource_name_id , resource_description_id , + resource_category_id , resource_weight + ) VALUES ( + _get_string( 'resource1' ) , _get_string( 'rDesc1' ) , + _get_string( 'rCat1' ) , 2 + ) , ( + _get_string( 'resource2' ) , _get_string( 'rDesc2' ) , + NULL , 1 + ) , ( + _get_string( 'resource3' ) , _get_string( 'rDesc3' ) , + NULL , 3 + ); + + \i utils/accounts.sql + \i utils/naming.sql + SELECT _create_emp_names( 1 , 'emp' ); + INSERT INTO emp.empires( name_id , cash ) + VALUES( _get_emp_name( 'emp1' ) , 0 ); + + ALTER TABLE emp.mining_settings DROP CONSTRAINT fk_empmset_resource; + INSERT INTO emp.mining_settings ( empire_id , resource_name_id ) + SELECT _get_emp_name( 'emp1' ) , resource_name_id + FROM defs.resources; + + \i utils/universe.sql + SELECT _create_raw_planets( 2 , 'planet' ); + + INSERT INTO verse.planet_resources ( + planet_id , resource_name_id , pres_income , pres_upkeep + ) VALUES ( + _get_map_name( 'planet1' ) , _get_string( 'resource1' ) , + 99.4 / 720.0 , 99.4 / 720.0 + ) , ( + _get_map_name( 'planet1' ) , _get_string( 'resource2' ) , + 99.5 / 720.0 , 99.5 / 720.0 + ) , ( + _get_map_name( 'planet1' ) , _get_string( 'resource3' ) , + 99.6 / 720.0 , 99.6 / 720.0 + ); + INSERT INTO verse.planet_resources ( planet_id , resource_name_id ) + SELECT _get_map_name( 'planet2' ) , resource_name_id + FROM defs.resources; + + ALTER TABLE verse.resource_providers DROP CONSTRAINT fk_resprov_resource; + INSERT INTO verse.resource_providers( + planet_id , resource_name_id , resprov_quantity_max , + resprov_quantity , resprov_difficulty , resprov_recovery + ) VALUES ( + _get_map_name( 'planet1' ) , _get_string( 'resource1' ) , 99.4 , + 99.4 , 0.494 , 0.5 + ) , ( + _get_map_name( 'planet1' ) , _get_string( 'resource2' ) , 99.5 , + 99.5 , 0.495 , 0.5 + ) , ( + _get_map_name( 'planet2' ) , _get_string( 'resource1' ) , 100 , + 100 , 0.5 , 0.5 + ); + + INSERT INTO emp.planets ( empire_id , planet_id ) + VALUES ( _get_emp_name( 'emp1' ) , _get_map_name( 'planet1' ) ); + + + /***** TESTS BEGIN HERE *****/ + SELECT plan( 13 ); + + SELECT diag_test_name( 'emp.get_planet_resources() - No results on missing planets' ); + SELECT is_empty( $$ SELECT * FROM emp.get_planet_resources( _get_bad_map_name( ) ) $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - No results on neutral planets' ); + SELECT is_empty( $$ SELECT * FROM emp.get_planet_resources( _get_map_name( 'planet2' ) ) $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - One row per resource type' ); + SELECT is( COUNT(*)::INT , 3 ) FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Row ordering' ); + SELECT set_eq( + $$ SELECT resource_identifier , row_number() OVER ( ) + FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) $$ , + $$ VALUES ( + 'resource1' , 2 + ) , ( + 'resource2' , 1 + ) , ( + 'resource3' , 3 + ) $$ + ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Name translation' ); + SELECT is_empty( $$ + SELECT * + FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE resource_name NOT LIKE 'Resource name %' + $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Description translation' ); + SELECT is_empty( $$ + SELECT * + FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE resource_description NOT LIKE 'Resource description %' + $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Category translation' ); + SELECT is_empty( $$ + SELECT * + FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE resource_identifier = 'resource1' + AND resource_category NOT LIKE 'Resource category %' + $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - NULL category -> NULL translation' ); + SELECT is_empty( $$ + SELECT * + FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE resource_identifier <> 'resource1' + AND resource_category IS NOT NULL + $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Upkeep is valid and rounded up' ); + SELECT is_empty( $$ + SELECT * + FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE pres_upkeep IS NULL OR pres_upkeep <> 100 + $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Income is valid and rounded down' ); + SELECT is_empty( $$ + SELECT * FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE pres_income IS NULL OR pres_income <> 99 + $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - No mining-related fields when there is no resource provider' ); + SELECT is_empty( $$ + SELECT * FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE resource_identifier = 'resource3' AND NOT ( + resprov_capacity IS NULL + AND resprov_quantity IS NULL + AND resprov_difficulty IS NULL + AND mset_weight IS NULL + ); + $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Resource provider fields are present' ); + SELECT is_empty( $$ + SELECT * FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE resource_identifier <> 'resource3' AND ( + resprov_capacity IS NULL + OR resprov_quantity IS NULL + OR resprov_difficulty IS NULL + OR mset_weight IS NULL + ); + $$ ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Resource provider values' ); + SELECT set_eq( $$ + SELECT resource_identifier , resprov_capacity , resprov_quantity , resprov_difficulty + FROM emp.get_planet_resources( _get_map_name( 'planet1' ) ) + WHERE resource_identifier <> 'resource3' + $$ , $$ VALUES ( + 'resource1' , 99 , 99 , 49 + ) , ( + 'resource2' , 100 , 100 , 50 + ) $$ ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/user/040-functions/025-resources/050-resource-category-weight-view.sql b/legacyworlds-server-data/db-structure/tests/user/040-functions/025-resources/050-resource-category-weight-view.sql new file mode 100644 index 0000000..17df905 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/user/040-functions/025-resources/050-resource-category-weight-view.sql @@ -0,0 +1,11 @@ +/* + * Test privileges on defs.resource_category_weight_view + */ +BEGIN; + SELECT plan( 1 ); + + SELECT diag_test_name( 'defs.resource_category_weight_view - Privileges' ); + SELECT throws_ok( 'SELECT * FROM defs.resource_category_weight_view' , 42501 ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/user/040-functions/025-resources/060-ordered-resources-view.sql b/legacyworlds-server-data/db-structure/tests/user/040-functions/025-resources/060-ordered-resources-view.sql new file mode 100644 index 0000000..a632f1f --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/user/040-functions/025-resources/060-ordered-resources-view.sql @@ -0,0 +1,11 @@ +/* + * Test privileges on defs.ordered_resources_view + */ +BEGIN; + SELECT plan( 1 ); + + SELECT diag_test_name( 'defs.ordered_resources_view - Privileges' ); + SELECT throws_ok( 'SELECT * FROM defs.ordered_resources_view' , 42501 ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/user/040-functions/040-empire/020-planet-resources-view.sql b/legacyworlds-server-data/db-structure/tests/user/040-functions/040-empire/020-planet-resources-view.sql new file mode 100644 index 0000000..619ad96 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/user/040-functions/040-empire/020-planet-resources-view.sql @@ -0,0 +1,11 @@ +/* + * Test privileges on emp.planet_resources_view + */ +BEGIN; + SELECT plan( 1 ); + + SELECT diag_test_name( 'emp.planet_resources_view - Privileges' ); + SELECT throws_ok( 'SELECT * FROM emp.planet_resources_view' , 42501 ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/user/040-functions/040-empire/030-resources-view.sql b/legacyworlds-server-data/db-structure/tests/user/040-functions/040-empire/030-resources-view.sql new file mode 100644 index 0000000..817d0e1 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/user/040-functions/040-empire/030-resources-view.sql @@ -0,0 +1,11 @@ +/* + * Test privileges on emp.resources_view + */ +BEGIN; + SELECT plan( 1 ); + + SELECT diag_test_name( 'emp.resources_view - Privileges' ); + SELECT lives_ok( 'SELECT * FROM emp.resources_view' ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/user/040-functions/145-resource-providers/040-get-planet-resources.sql b/legacyworlds-server-data/db-structure/tests/user/040-functions/145-resource-providers/040-get-planet-resources.sql new file mode 100644 index 0000000..e2ed935 --- /dev/null +++ b/legacyworlds-server-data/db-structure/tests/user/040-functions/145-resource-providers/040-get-planet-resources.sql @@ -0,0 +1,13 @@ +/* + * Test privileges on emp.get_planet_resources() + */ +BEGIN; + SELECT plan( 1 ); + + SELECT diag_test_name( 'emp.get_planet_resources() - Privileges' ); + SELECT lives_ok( $$ + SELECT emp.get_planet_resources( 1 ) + $$ ); + + SELECT * FROM finish( ); +ROLLBACK; \ No newline at end of file diff --git a/legacyworlds-server-data/db-structure/tests/utils/strings.sql b/legacyworlds-server-data/db-structure/tests/utils/strings.sql index 33ead96..3303ae3 100644 --- a/legacyworlds-server-data/db-structure/tests/utils/strings.sql +++ b/legacyworlds-server-data/db-structure/tests/utils/strings.sql @@ -29,24 +29,11 @@ CREATE FUNCTION _get_string( TEXT ) RETURNS INT AS $$ $$ LANGUAGE SQL; -/* - * Function that creates some quantity of test strings - */ -CREATE FUNCTION _create_test_strings( _quantity INT ) - RETURNS VOID - AS $$ -DECLARE - i INT; -BEGIN - PERFORM _create_test_strings( _quantity , 'test' ); -END; -$$ LANGUAGE PLPGSQL; - - /* * Function that creates some quantity of test strings using a specific prefix + * and translation prefix. */ -CREATE FUNCTION _create_test_strings( _quantity INT , _prefix TEXT ) +CREATE FUNCTION _create_test_strings( _quantity INT , _prefix TEXT , _trans TEXT ) RETURNS VOID AS $$ DECLARE @@ -59,7 +46,27 @@ BEGIN LOOP i := i + 1; PERFORM defs.uoc_translation( 't' , _prefix || i::TEXT , - 'Test string #' || i::TEXT ); + _trans || i::TEXT ); END LOOP; END; $$ LANGUAGE PLPGSQL; + +/* + * Function that creates some quantity of test strings using a specific prefix + */ +CREATE FUNCTION _create_test_strings( _quantity INT , _prefix TEXT ) + RETURNS VOID +AS $$ + SELECT _create_test_strings( $1 , $2 , 'Test string #' ); +$$ LANGUAGE SQL; + + +/* + * Function that creates some quantity of test strings + */ +CREATE FUNCTION _create_test_strings( _quantity INT ) + RETURNS VOID +AS $$ + SELECT _create_test_strings( $1 , 'test' ); +$$ LANGUAGE SQL; + diff --git a/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/resources/ResourcesInformationDAO.java b/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/resources/ResourcesInformationDAO.java new file mode 100644 index 0000000..5c88115 --- /dev/null +++ b/legacyworlds-server-interfaces/src/main/java/com/deepclone/lw/interfaces/game/resources/ResourcesInformationDAO.java @@ -0,0 +1,43 @@ +package com.deepclone.lw.interfaces.game.resources; + + +import java.util.List; + +import com.deepclone.lw.cmd.player.gdata.empire.EmpireResourceRecord; +import com.deepclone.lw.cmd.player.gdata.planets.PlanetResourceRecord; + + + +/** + * Resources information access component interface + * + *

+ * This interface defines the methods which execute the queries required to extract information + * about resources from the database. + * + * @author E. Benoît + */ +public interface ResourcesInformationDAO +{ + + /** + * Obtain resources information for a planet + * + * @param planet + * the planet to obtain information about + * + * @return the list of planetary resource records + */ + public List< PlanetResourceRecord > getPlanetInformation( int planet ); + + + /** + * Obtain resources information for an empire + * + * @param empire + * the empire to obtain information about + * + * @return the list of empire economic records + */ + public List< EmpireResourceRecord > getEmpireInformation( int empire ); +} diff --git a/legacyworlds-server-main/src/main/resources/lw-server.xml b/legacyworlds-server-main/src/main/resources/lw-server.xml index cf7c8ea..081b882 100644 --- a/legacyworlds-server-main/src/main/resources/lw-server.xml +++ b/legacyworlds-server-main/src/main/resources/lw-server.xml @@ -13,14 +13,13 @@ - + - @@ -29,5 +28,4 @@ - diff --git a/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestAbstractResourceMapper.java b/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestAbstractResourceMapper.java new file mode 100644 index 0000000..4a0cd03 --- /dev/null +++ b/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestAbstractResourceMapper.java @@ -0,0 +1,126 @@ +package com.deepclone.lw.beans.game.resources; + + +import static org.junit.Assert.*; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; + +import org.junit.Before; +import org.junit.Test; + +import com.deepclone.lw.cmd.player.gdata.AbstractResourceRecord; +import com.deepclone.lw.testing.MockResultSet; + + + +/** + * Tests of the {@link AbstractResourceMapper} class + * + * @author E. Benoît + */ +public class TestAbstractResourceMapper +{ + /** Strings used for the various fields */ + private static final String TEST_STRINGS[] = { + "1" , "2" , "3" , "4" + }; + + /** + * An empty resource record used to test the {@link AbstractResourceMapper} + * + * @author E. Benoît + */ + @SuppressWarnings( "serial" ) + private static class EmptyResourceRecord + extends AbstractResourceRecord + { + // EMPTY + } + + /** + * Resource row mapper that calls + * {@link AbstractResourceMapper#getResourceDescription(AbstractResourceRecord, ResultSet)} + * + * @author E. Benoît + * + */ + private static class EmptyResourceMapper + extends AbstractResourceMapper< EmptyResourceRecord > + { + + @Override + public EmptyResourceRecord mapRow( ResultSet rs , int rowNum ) + throws SQLException + { + EmptyResourceRecord record = new EmptyResourceRecord( ); + this.getResourceDescription( record , rs ); + return record; + } + + } + + /** The result set fed to the resource row mapper */ + private ResultSet resultSet; + + /** The mapper used in the tests */ + private EmptyResourceMapper mapper; + + + /** + * Create the test mapper and a fake result set with two results: one that includes a category, + * and another without category. + */ + @Before + public void setUp( ) + { + this.mapper = new EmptyResourceMapper( ); + + @SuppressWarnings( "unchecked" ) + HashMap< String , Object > rows[] = new HashMap[ 2 ]; + for ( int i = 0 ; i < 2 ; i++ ) { + HashMap< String , Object > row = new HashMap< String , Object >( ); + row.put( "resource_identifier" , TEST_STRINGS[ 0 ] ); + row.put( "resource_name" , TEST_STRINGS[ 1 ] ); + row.put( "resource_description" , TEST_STRINGS[ 2 ] ); + if ( i == 1 ) { + row.put( "resource_category" , TEST_STRINGS[ 3 ] ); + } + rows[ i ] = row; + } + + this.resultSet = MockResultSet.create( rows ); + } + + + /** Test mapping a row with a NULL category */ + @Test + public void testMapRowWithoutCategory( ) + throws SQLException + { + this.resultSet.absolute( 1 ); + EmptyResourceRecord record = this.mapper.mapRow( this.resultSet , 1 ); + + assertEquals( TEST_STRINGS[ 0 ] , record.getIdentifier( ) ); + assertEquals( TEST_STRINGS[ 1 ] , record.getTitle( ) ); + assertEquals( TEST_STRINGS[ 2 ] , record.getDescription( ) ); + assertNull( record.getCategory( ) ); + } + + + /** Test mapping a row with a non-NULL category */ + @Test + public void testMapRowWithCategory( ) + throws SQLException + { + this.resultSet.absolute( 2 ); + EmptyResourceRecord record = this.mapper.mapRow( this.resultSet , 1 ); + + assertEquals( TEST_STRINGS[ 0 ] , record.getIdentifier( ) ); + assertEquals( TEST_STRINGS[ 1 ] , record.getTitle( ) ); + assertEquals( TEST_STRINGS[ 2 ] , record.getDescription( ) ); + assertEquals( TEST_STRINGS[ 3 ] , record.getCategory( ) ); + } + +} diff --git a/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestEmpireResourceMapper.java b/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestEmpireResourceMapper.java new file mode 100644 index 0000000..f9966ab --- /dev/null +++ b/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestEmpireResourceMapper.java @@ -0,0 +1,104 @@ +package com.deepclone.lw.beans.game.resources; + + +import static org.junit.Assert.*; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; + +import org.junit.Before; +import org.junit.Test; + +import com.deepclone.lw.cmd.player.gdata.empire.EmpireResourceRecord; +import com.deepclone.lw.testing.MockResultSet; + + + +/** + * Tests of the {@link EmpireResourceMapper} class. + * + * @author E. Benoît + */ +public class TestEmpireResourceMapper +{ + private static final String TEST_STRING = "Test"; + + private static final long POSSESSED_VALUE = 2L; + + private static final long P_INCOME_VALUE = 3L; + + private static final long P_UPKEEP_VALUE = 4L; + + private static final long F_UPKEEP_VALUE = 5L; + + private static final Integer PRIORITY_VALUE = 6; + + /** The fake result set fed to the mapper */ + private ResultSet resultSet; + + /** The mapper being tested */ + private EmpireResourceMapper mapper; + + + @Before + public void setUp( ) + { + this.mapper = new EmpireResourceMapper( ); + + @SuppressWarnings( "unchecked" ) + HashMap< String , Object > rows[] = new HashMap[ 2 ]; + for ( int i = 0 ; i < 2 ; i++ ) { + HashMap< String , Object > row = new HashMap< String , Object >( ); + + row.put( "resource_identifier" , TEST_STRING ); + + row.put( "empres_possessed" , POSSESSED_VALUE + i ); + row.put( "planets_income" , P_INCOME_VALUE + i ); + row.put( "planets_upkeep" , P_UPKEEP_VALUE + i ); + row.put( "fleets_upkeep" , F_UPKEEP_VALUE + i ); + if ( i == 1 ) { + row.put( "empmset_weight" , PRIORITY_VALUE + i ); + } + + rows[ i ] = row; + } + this.resultSet = MockResultSet.create( rows ); + } + + + /** Test mapping a row that does not include a mining priority */ + @Test + public void testMapWithoutPriority( ) + throws SQLException + { + this.resultSet.absolute( 1 ); + EmpireResourceRecord record = this.mapper.mapRow( this.resultSet , 1 ); + + assertEquals( TEST_STRING , record.getIdentifier( ) ); + assertEquals( POSSESSED_VALUE , record.getStockpiled( ) ); + assertEquals( P_INCOME_VALUE , record.getIncome( ) ); + assertEquals( P_UPKEEP_VALUE , record.getPlanetUpkeep( ) ); + assertEquals( F_UPKEEP_VALUE , record.getFleetUpkeep( ) ); + assertNull( record.getMiningPriority( ) ); + } + + + /** Test mapping a row that includes a mining priority */ + @Test + public void testMapWithPriority( ) + throws SQLException + { + this.resultSet.absolute( 2 ); + EmpireResourceRecord record = this.mapper.mapRow( this.resultSet , 1 ); + + assertEquals( TEST_STRING , record.getIdentifier( ) ); + assertEquals( 1 + POSSESSED_VALUE , record.getStockpiled( ) ); + assertEquals( 1 + P_INCOME_VALUE , record.getIncome( ) ); + assertEquals( 1 + P_UPKEEP_VALUE , record.getPlanetUpkeep( ) ); + assertEquals( 1 + F_UPKEEP_VALUE , record.getFleetUpkeep( ) ); + assertNotNull( record.getMiningPriority( ) ); + assertEquals( 1 + PRIORITY_VALUE , (int) record.getMiningPriority( ) ); + } + +} diff --git a/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestPlanetResourceMapper.java b/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestPlanetResourceMapper.java new file mode 100644 index 0000000..5f2990f --- /dev/null +++ b/legacyworlds-server-tests/src/test/java/com/deepclone/lw/beans/game/resources/TestPlanetResourceMapper.java @@ -0,0 +1,131 @@ +package com.deepclone.lw.beans.game.resources; + + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +import com.deepclone.lw.cmd.player.gdata.planets.PlanetResourceRecord; +import com.deepclone.lw.cmd.player.gdata.planets.ResourceProviderRecord; +import com.deepclone.lw.testing.MockResultSet; + + + +/** + * Tests for {@link PlanetResourceMapper} + * + * @author E. Benoît + */ +public class TestPlanetResourceMapper +{ + + /** Value used as the resource identifier */ + private static final Object RID_VALUE = "resource id"; + + /** Value used as the income */ + private static final long P_INCOME_VALUE = 1; + + /** Value used as the upkeep */ + private static final long P_UPKEEP_VALUE = 2; + + /** Value used as the investment */ + private static final long P_INVEST_VALUE = 3; + + /** Value used as the resource provider's capacity */ + private static final long RP_CAPACITY_VALUE = 5L; + + /** Value used as the resource provider's current quantity */ + private static final long RP_QUANTITY_VALUE = 6L; + + /** Value used as the resource provider's difficulty */ + private static final int RP_DIFF_VALUE = 7; + + /** Value used as the mining setting */ + private static final int MS_WEIGHT_VALUE = 8; + + /** The mapper under test */ + private PlanetResourceMapper mapper; + + /** The fake result set fed to the mapper */ + private ResultSet resultSet; + + + /** + * Create the mapper and a result set to test it with. + */ + @Before + public void setUp( ) + { + this.mapper = new PlanetResourceMapper( ); + + @SuppressWarnings( "unchecked" ) + HashMap< String , Object > rows[] = new HashMap[ 2 ]; + for ( int i = 0 ; i < 2 ; i++ ) { + HashMap< String , Object > row = new HashMap< String , Object >( ); + + row.put( "resource_identifier" , RID_VALUE ); + + row.put( "pres_income" , P_INCOME_VALUE + i ); + row.put( "pres_upkeep" , P_UPKEEP_VALUE + i ); + row.put( "pres_invested" , P_INVEST_VALUE + i ); + if ( i == 1 ) { + row.put( "resprov_capacity" , RP_CAPACITY_VALUE ); + row.put( "resprov_quantity" , RP_QUANTITY_VALUE ); + row.put( "resprov_difficulty" , RP_DIFF_VALUE ); + row.put( "mset_weight" , MS_WEIGHT_VALUE ); + } + + rows[ i ] = row; + } + this.resultSet = MockResultSet.create( rows ); + } + + + /** + * Planet resource row with no resource provider + */ + @Test + public void testRowWithoutResourceProvider( ) + throws SQLException + { + this.resultSet.absolute( 1 ); + PlanetResourceRecord row = this.mapper.mapRow( this.resultSet , 1 ); + + assertEquals( RID_VALUE , row.getIdentifier( ) ); + + assertEquals( P_INCOME_VALUE , row.getIncome( ) ); + assertEquals( P_UPKEEP_VALUE , row.getUpkeep( ) ); + assertEquals( P_INVEST_VALUE , row.getInvested( ) ); + + assertNull( row.getResourceProvider( ) ); + } + + + /** + * Planet resource row with a resource provider + */ + @Test + public void testRowWithResourceProvider( ) + throws SQLException + { + this.resultSet.absolute( 2 ); + PlanetResourceRecord row = this.mapper.mapRow( this.resultSet , 2 ); + + assertEquals( RID_VALUE , row.getIdentifier( ) ); + + assertEquals( P_INCOME_VALUE + 1 , row.getIncome( ) ); + assertEquals( P_UPKEEP_VALUE + 1 , row.getUpkeep( ) ); + assertEquals( P_INVEST_VALUE + 1 , row.getInvested( ) ); + + ResourceProviderRecord rp = row.getResourceProvider( ); + assertNotNull( rp ); + assertEquals( RP_CAPACITY_VALUE , rp.getCapacity( ) ); + assertEquals( RP_QUANTITY_VALUE , rp.getQuantity( ) ); + assertEquals( RP_DIFF_VALUE , rp.getDifficulty( ) ); + assertEquals( MS_WEIGHT_VALUE , rp.getPriority( ) ); + } +} diff --git a/legacyworlds-server-tests/src/test/java/com/deepclone/lw/testing/MockResultSet.java b/legacyworlds-server-tests/src/test/java/com/deepclone/lw/testing/MockResultSet.java index da5bd52..fc92bed 100644 --- a/legacyworlds-server-tests/src/test/java/com/deepclone/lw/testing/MockResultSet.java +++ b/legacyworlds-server-tests/src/test/java/com/deepclone/lw/testing/MockResultSet.java @@ -225,6 +225,28 @@ public class MockResultSet } + /** + * Return the object in some column of the current "row" as a long integer + * + * @param columnName + * the column's name + * + * @return the object from the fake results, as a long integer + * + * @throws SQLException + * if no row is selected + */ + public long getLong( String columnName ) + throws SQLException + { + Object object = this.getObject( columnName ); + if ( object != null ) { + return (Long) object; + } + return 0; + } + + /** * Return the object in some column of the current "row" as a double * diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/AbstractResourceRecord.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/AbstractResourceRecord.java new file mode 100644 index 0000000..605a4ac --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/AbstractResourceRecord.java @@ -0,0 +1,109 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import java.io.Serializable; + + + +public abstract class AbstractResourceRecord + implements Serializable +{ + + /** + * The serialisation version identifier + * + *

+ */ + private static final long serialVersionUID = 1L; + + /** The text identifier of the resource */ + private String identifier; + + /** The internationalised name of the resource's category */ + private String category; + + /** The internationalised name of the resource */ + private String title; + + /** The internationalised description of the resource */ + private String description; + + + /** @return the text identifying the resource */ + public String getIdentifier( ) + { + return this.identifier; + } + + + /** + * Set the text identifying the resource + * + * @param identifier + * the text identifying the resource + */ + public void setIdentifier( String identifier ) + { + this.identifier = identifier; + } + + + /** @return the internationalised title of the resource */ + public String getTitle( ) + { + return this.title; + } + + + /** + * Set the internationalised title of the resource + * + * @param title + * the internationalised title of the resource + */ + public void setTitle( String title ) + { + this.title = title; + } + + + /** @return the internationalised name of the category of the resource */ + public String getCategory( ) + { + return this.category; + } + + + /** + * Set the internationalised name of the category of the resource + * + * @param category + * the internationalised name of the category of the resource + */ + public void setCategory( String category ) + { + this.category = category; + } + + + /** @return the internationalised description of the resource */ + public String getDescription( ) + { + return this.description; + } + + + /** + * Set the internationalised description of the resource + * + * @param description + * the internationalised description of the resource + */ + public void setDescription( String description ) + { + this.description = description; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/EmpireResourceRecord.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/EmpireResourceRecord.java new file mode 100644 index 0000000..9a9bd64 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/empire/EmpireResourceRecord.java @@ -0,0 +1,152 @@ +package com.deepclone.lw.cmd.player.gdata.empire; + + +import com.deepclone.lw.cmd.player.gdata.AbstractResourceRecord; + + + +/** + * Resource economic record + * + *

+ * This record describes a resource. It is used in the empire overview's economic information and + * for mining settings. + * + * @author E. Benoît + * + */ +public class EmpireResourceRecord + extends AbstractResourceRecord +{ + + /** + * The serialisation version identifier + * + *

+ */ + private static final long serialVersionUID = 1L; + + /** The income for this type of resource over 12h RT / 1 month GT */ + private long income; + + /** The planet upkeep for this type of resource over 12h RT / 1 month GT */ + private long planetUpkeep; + + /** The fleet upkeep for this type of resource over 12h RT / 1 month GT */ + private long fleetUpkeep; + + /** The amount of resources of this type possessed by the empire */ + private long stockpiled; + + /** The resource's mining priority, or null for basic resources */ + private Integer miningPriority; + + + /** @return the income for this type of resource over a period of 12h RT / 1 month GT */ + public long getIncome( ) + { + return this.income; + } + + + /** + * Set the income for this type of resource over a period of 12h RT / 1 month GT + * + * @param income + * the income for this type of resource over a period of 12h RT / 1 month GT + */ + public void setIncome( long income ) + { + this.income = income; + } + + + /** @return the upkeep for this type of resource over a period of 12h RT / 1 month GT on planets */ + public long getPlanetUpkeep( ) + { + return this.planetUpkeep; + } + + + /** + * Set the upkeep for this type of resource over a period of 12h RT / 1 month GT on planets + * + * @param planetUpkeep + * the upkeep for this type of resource over a period of 12h RT / 1 month GT on + * planets + */ + public void setPlanetUpkeep( long planetUpkeep ) + { + this.planetUpkeep = planetUpkeep; + } + + + /** @return the upkeep for this type of resource over a period of 12h RT / 1 month GT on planets */ + public long getFleetUpkeep( ) + { + return this.fleetUpkeep; + } + + + /** + * Set the fleet upkeep for this type of resource over a period of 12h RT / 1 month GT + * + * @param fleetUpkeep + * the fleet upkeep for this type of resource over a period of 12h RT / 1 month GT + */ + public void setFleetUpkeep( long fleetUpkeep ) + { + this.fleetUpkeep = fleetUpkeep; + } + + + /** @return the total upkeep (including both fleet and planet upkeep) */ + public long getUpkeep( ) + { + return this.fleetUpkeep + this.planetUpkeep; + } + + + /** @return the amount of resources of this type the empire possesses */ + public long getStockpiled( ) + { + return this.stockpiled; + } + + + /** + * Set the amount of resources of this type the empire possesses + * + * @param stockpiled + * the amount of resources of this type the empire possesses + */ + public void setStockpiled( long stockpiled ) + { + this.stockpiled = stockpiled; + } + + + /** + * @return the mining priority for this type of resource, or null if it is a basic + * resource + */ + public Integer getMiningPriority( ) + { + return this.miningPriority; + } + + + /** + * Set the mining priority for this type of resource + * + * @param miningPriority + * the mining priority for this type of resource + */ + public void setMiningPriority( int miningPriority ) + { + this.miningPriority = miningPriority; + } + +} 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 index d82cc66..9858969 100644 --- 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 @@ -2,6 +2,7 @@ package com.deepclone.lw.cmd.player.gdata.empire; import java.io.Serializable; +import java.util.List; @@ -9,124 +10,234 @@ public class OverviewData implements Serializable { - private static final long serialVersionUID = 1L; + /** + * Serialisation version identifier + * + * + */ + private static final long serialVersionUID = 2L; + /** Quantity of planets owned by the empire */ private long planets; + + /** Amount of unread messages */ private int newMessages; + + /** Total population in the empire */ private long population; + + /** Average happiness of the population on the planets, as a percentage */ private int avgHappiness; + + /** Total fleet power */ private long fleetPower; + + /** Total monetary income from planets */ private long planetIncome; + + /** Total monetary upkeep for planets */ private long planetUpkeep; + + /** Total monetary fleet upkeep */ private long fleetUpkeep; + + /** Total amount of money in the various queues */ private long investment; + /** Economic information */ + private List< EmpireResourceRecord > economy; + + /** @return the quantity of planets owned by the empire */ public long getPlanets( ) { - return planets; + return this.planets; } + /** + * Set the quantity of planets owned by the empire + * + * @param planets + * the quantity of planets owned by the empire + */ public void setPlanets( long planets ) { this.planets = planets; } + /** @return the quantity of unread messages */ public int getNewMessages( ) { - return newMessages; + return this.newMessages; } + /** + * Set the quantity of unread messages + * + * @param newMessages + * the quantity of unread messages + */ public void setNewMessages( int newMessages ) { this.newMessages = newMessages; } + /** @return the empire's total population */ public long getPopulation( ) { - return population; + return this.population; } + /** + * Set the empire's total population + * + * @param population + * the empire's total population + */ public void setPopulation( long population ) { this.population = population; } + /** @return the average happiness on the empire's planets */ public int getAvgHappiness( ) { - return avgHappiness; + return this.avgHappiness; } + /** + * Set the average happiness on the empire's planets + * + * @param avgHappiness + * the average happiness on the empire's planets + */ public void setAvgHappiness( int avgHappiness ) { this.avgHappiness = avgHappiness; } + /** @return the total fleet power */ public long getFleetPower( ) { - return fleetPower; + return this.fleetPower; } + /** + * Set the total fleet power + * + * @param fleetPower + * the total fleet power + */ public void setFleetPower( long fleetPower ) { this.fleetPower = fleetPower; } + /** @return the monetary income from the empire's planets */ public long getPlanetIncome( ) { - return planetIncome; + return this.planetIncome; } + /** + * Set the monetary income from the empire's planets + * + * @param planetIncome + * the monetary income from the empire's planets + */ public void setPlanetIncome( long planetIncome ) { this.planetIncome = planetIncome; } + /** @return the monetary upkeep for the empire's planets */ public long getPlanetUpkeep( ) { - return planetUpkeep; + return this.planetUpkeep; } + /** + * Set the monetary upkeep for the empire's planets + * + * @param planetUpkeep + * the monetary upkeep for the empire's planets + */ public void setPlanetUpkeep( long planetUpkeep ) { this.planetUpkeep = planetUpkeep; } + /** @return the monetary upkeep for the empire's fleets */ public long getFleetUpkeep( ) { - return fleetUpkeep; + return this.fleetUpkeep; } + /** + * Set the monetary upkeep for the empire's fleets + * + * @param fleetUpkeep + * the monetary upkeep for the empire's fleets + */ public void setFleetUpkeep( long fleetUpkeep ) { this.fleetUpkeep = fleetUpkeep; } + /** @return the total amount of money invested in civilian or military queues */ public long getInvestment( ) { - return investment; + return this.investment; } + /** + * Set the total amount of money invested in civilian or military queues + * + * @param investment + * the total amount of money invested in civilian or military queues + */ public void setInvestment( long investment ) { this.investment = investment; } + + /** @return the list of economic information records */ + public List< EmpireResourceRecord > getEconomy( ) + { + return this.economy; + } + + + /** + * Set the list of economic information records + * + * @param economy + * the list of economic information records + */ + public void setEconomy( List< EmpireResourceRecord > economy ) + { + this.economy = economy; + } + } 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 index a567a8e..9dfc71f 100644 --- 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 @@ -6,128 +6,283 @@ import java.util.List; +/** + * Planet view details available to planet owners + * + *

+ * This class carries the part of the planet view which is only available to empires owning the + * planet being viewed. + * + * @author E. Benoît + */ public class PlanetOwnView implements Serializable { - private static final long serialVersionUID = 1L; + /** + * Serialisation version identifier + * + *

+ */ + private static final long serialVersionUID = 2L; + /** Happiness of the planet's population as a percentage */ private int happiness; + + /** + * Happiness change indicator + * + *

+ * This field's value is an integer between -2 and 2 (inclusive). It indicates the direction of + * the happiness' change (positive meaning that the happiness is increasing, negative meaning it + * is decreasing), and the strength of the change (absolute value 1 meaning a relatively small + * change, 2 a bigger one) + */ private int hChange; + + /** Planet monetary income for 24h of RL time */ private long income; + + /** Planet monetary upkeep for 24h of RL time */ private long upkeep; + + /** + * Various planet state indicators + * + *

+ * This field carries a few flags about whether it is possible to rename or abandon the planet, + * and similar information. + */ private OwnPlanetStatusData status; + + /** Civilian construction queue */ private QueueData civQueue; + + /** Military construction queue */ private QueueData milQueue; + + /** Descriptions of ships that can be built */ private List< BuildableShipData > bShips; + + /** Descriptions of buildings that can be constructed */ private List< BuildableBuildingData > bBuildings; + /** List of the planet's resources */ + private List< PlanetResourceRecord > resources; + /** Is the planet using specific mining settings? */ + private boolean ownMiningSettings; + + + /** @return the planet's happiness */ public int getHappiness( ) { - return happiness; + return this.happiness; } + /** + * Set the planet's happiness + * + * @param happiness + * the planet's happiness + */ public void setHappiness( int happiness ) { this.happiness = happiness; } + /** @return the planet's happiness change indicator */ public int gethChange( ) { - return hChange; + return this.hChange; } + /** + * Set the planet's happiness change indicator + * + * @param hChange + * the planet's happiness change indicator + */ public void sethChange( int hChange ) { this.hChange = hChange; } + /** @return the planet's monetary income */ public long getIncome( ) { - return income; + return this.income; } + /** + * Set the planet's monetary income + * + * @param income + * the planet's monetary income + */ public void setIncome( long income ) { this.income = income; } + /** @return the planet's monetary upkeep */ public long getUpkeep( ) { - return upkeep; + return this.upkeep; } + /** + * Set the planet's monetary upkeep + * + * @param upkeep + * the planet's monetary upkeep + */ public void setUpkeep( long upkeep ) { this.upkeep = upkeep; } + /** @return the planet status object */ public OwnPlanetStatusData getStatus( ) { - return status; + return this.status; } + /** + * Set the planet status object + * + * @param status + * the planet status object + */ public void setStatus( OwnPlanetStatusData status ) { this.status = status; } + /** @return the civilian construction queue */ public QueueData getCivQueue( ) { - return civQueue; + return this.civQueue; } + /** + * Set the civilian construction queue + * + * @param civQueue + * the civilian construction queue + */ public void setCivQueue( QueueData civQueue ) { this.civQueue = civQueue; } + /** @return the military construction queue */ public QueueData getMilQueue( ) { - return milQueue; + return this.milQueue; } + /** + * Set the military construction queue + * + * @param milQueue + * the military construction queue + */ public void setMilQueue( QueueData milQueue ) { this.milQueue = milQueue; } + /** @return the descriptions of all ships which can be constructed */ public List< BuildableShipData > getbShips( ) { - return bShips; + return this.bShips; } + /** + * Set the descriptions of ships which can be constructed + * + * @param bShips + * the descriptions of ships which can be constructed + */ public void setbShips( List< BuildableShipData > bShips ) { this.bShips = bShips; } + /** @return the descriptions of all buildings which can be constructed */ public List< BuildableBuildingData > getbBuildings( ) { - return bBuildings; + return this.bBuildings; } + /** + * Set the descriptions of buildings which can be constructed + * + * @param bBuildings + * the descriptions of buildings which can be constructed + */ public void setbBuildings( List< BuildableBuildingData > bBuildings ) { this.bBuildings = bBuildings; } + + /** @return the list of resources */ + public List< PlanetResourceRecord > getResources( ) + { + return this.resources; + } + + + /** + * Set the list of resources + * + * @param resourceProviders + * the list of resources + */ + public void setResources( List< PlanetResourceRecord > resources ) + { + this.resources = resources; + } + + + /** @return whether the planet is using specific mining settings */ + public boolean getOwnMiningSettings( ) + { + return this.ownMiningSettings; + } + + + /** + * Set whether the planet is using specific mining settings + * + * @param ownMiningSettings + * whether the planet is using specific mining settings + */ + public void setOwnMiningSettings( boolean ownMiningSettings ) + { + this.ownMiningSettings = ownMiningSettings; + } + } diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetResourceRecord.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetResourceRecord.java new file mode 100644 index 0000000..704e422 --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/PlanetResourceRecord.java @@ -0,0 +1,125 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import com.deepclone.lw.cmd.player.gdata.AbstractResourceRecord; + + + +/** + * Planet resources information + * + *

+ * This class carries information about a resource type, including all required strings, as well as + * income, upkeep and investment. It also contains information about the planet's resource provider + * if there is one. + * + *

+ * The class is used by {@link PlanetOwnView} to represent all of a planet's resources. + * + * @author E. Benoît + */ +public class PlanetResourceRecord + extends AbstractResourceRecord +{ + + /** + * The serialisation version identifier + * + *

+ */ + private static final long serialVersionUID = 1L; + + /** Income for 12h RT / 1 month GT */ + private long income; + + /** Upkeep for 12h RT / 1 month GT */ + private long upkeep; + + /** Quantity of that resource that will be used by the planet's queues */ + private long invested; + + /** Information about the planet's resource provider of that type, if there is one */ + private ResourceProviderRecord resourceProvider; + + + /** @return the planet's income for that resource, over 12h RT / 1 month GT */ + public long getIncome( ) + { + return this.income; + } + + + /** + * Set the planet's income for that resource + * + * @param income + * the planet's income for that resource, over 12h RT / 1 month GT + */ + public void setIncome( long income ) + { + this.income = income; + } + + + /** @return the planet's upkeep for that resource, over 12h RT / 1 month GT */ + public long getUpkeep( ) + { + return this.upkeep; + } + + + /** + * Set the planet's upkeep for that resource + * + * @param upkeep + * the planet's upkeep for that resource, over 12h RT / 1 month GT + */ + public void setUpkeep( long upkeep ) + { + this.upkeep = upkeep; + } + + + /** @return the amount of that resource invested in the planet's build queues */ + public long getInvested( ) + { + return this.invested; + } + + + /** + * Set the amount of that resource invested in the planet's build queues + * + * @param invested + * the amount of that resource invested in the planet's build queues + */ + public void setInvested( long invested ) + { + this.invested = invested; + } + + + /** + * @return the resource provider data on that planet for the current resource type or + * null if there is no resource provider of that type. + */ + public ResourceProviderRecord getResourceProvider( ) + { + return this.resourceProvider; + } + + + /** + * Set the resource provider data on that planet for the current resource type + * + * @param resourceProvider + * the resource provider data on that planet for the current resource type + */ + public void setResourceProvider( ResourceProviderRecord resourceProvider ) + { + this.resourceProvider = resourceProvider; + } + +} diff --git a/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/ResourceProviderRecord.java b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/ResourceProviderRecord.java new file mode 100644 index 0000000..dee594d --- /dev/null +++ b/legacyworlds-session/src/main/java/com/deepclone/lw/cmd/player/gdata/planets/ResourceProviderRecord.java @@ -0,0 +1,117 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import java.io.Serializable; + + + +/** + * Information displayed about a resource provider + * + *

+ * This class carries the information about a resource provider and associated mining priorities. + * + * @author E. Benoît + */ +public class ResourceProviderRecord + implements Serializable +{ + + /** + * The serialisation version identifier + * + *

+ */ + private static final long serialVersionUID = 1L; + + /** The resource provider's capacity (maximal quantity of resources) */ + private long capacity; + + /** The current quantity of resources in the provider */ + private long quantity; + + /** The extraction difficulty as a percentage */ + private int difficulty; + + /** The extraction priority */ + private int priority; + + + /** @return the resource provider's capacity */ + public long getCapacity( ) + { + return this.capacity; + } + + + /** + * Set the resource provider's capacity + * + * @param capacity + * the resource provider's capacity + */ + public void setCapacity( long capacity ) + { + this.capacity = capacity; + } + + + /** @return the resource provider's current quantity */ + public long getQuantity( ) + { + return this.quantity; + } + + + /** + * Set the resource provider's current quantity + * + * @param quantity + * the resource provider's current quantity + */ + public void setQuantity( long quantity ) + { + this.quantity = quantity; + } + + + /** @return the extraction difficulty */ + public int getDifficulty( ) + { + return this.difficulty; + } + + + /** + * Set the extraction difficulty + * + * @param difficulty + * the extraction difficulty + */ + public void setDifficulty( int difficulty ) + { + this.difficulty = difficulty; + } + + + /** @return the extraction priority */ + public int getPriority( ) + { + return this.priority; + } + + + /** + * Set the extraction priority + * + * @param priority + * the extraction priority + */ + public void setPriority( int priority ) + { + this.priority = priority; + } + +} diff --git a/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/TestAbstractResourceRecord.java b/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/TestAbstractResourceRecord.java new file mode 100644 index 0000000..e4a0e5c --- /dev/null +++ b/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/TestAbstractResourceRecord.java @@ -0,0 +1,88 @@ +package com.deepclone.lw.cmd.player.gdata; + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Before; +import org.junit.Test; + + + +/** + * Tests of the {@link AbstractResourceRecord} class + * + * @author E. Benoît + */ +public class TestAbstractResourceRecord +{ + /** String used in tests */ + private static final String TEST_STRING = "Test"; + + /** Class used in the tests */ + @SuppressWarnings( "serial" ) + private static class FakeChild + extends AbstractResourceRecord + { + // EMPTY + } + + /** Guinea pig instance */ + private FakeChild resource; + + + /** Create the "guinea pig" instance */ + @Before + public void setUp( ) + { + this.resource = new FakeChild( ); + } + + + /** Test default values */ + @Test + public void testDefaults( ) + { + assertNull( this.resource.getIdentifier( ) ); + assertNull( this.resource.getCategory( ) ); + assertNull( this.resource.getTitle( ) ); + assertNull( this.resource.getDescription( ) ); + } + + + /** Test setting and reading the identifier */ + @Test + public void testIdentifier( ) + { + this.resource.setIdentifier( TEST_STRING ); + assertEquals( TEST_STRING , this.resource.getIdentifier( ) ); + } + + + /** Test setting and reading the category */ + @Test + public void testCategory( ) + { + this.resource.setCategory( TEST_STRING ); + assertEquals( TEST_STRING , this.resource.getCategory( ) ); + } + + + /** Test setting and reading the title */ + @Test + public void testTitle( ) + { + this.resource.setTitle( TEST_STRING ); + assertEquals( TEST_STRING , this.resource.getTitle( ) ); + } + + + /** Test setting and reading the description */ + @Test + public void testDescription( ) + { + this.resource.setDescription( TEST_STRING ); + assertEquals( TEST_STRING , this.resource.getDescription( ) ); + } + +} diff --git a/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/empire/TestEmpireResourceRecord.java b/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/empire/TestEmpireResourceRecord.java new file mode 100644 index 0000000..02f3ea7 --- /dev/null +++ b/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/empire/TestEmpireResourceRecord.java @@ -0,0 +1,125 @@ +package com.deepclone.lw.cmd.player.gdata.empire; + + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + + + +/** + * Tests for the {@link EmpireResourceRecord} class + * + * @author E. Benoît + */ +public class TestEmpireResourceRecord +{ + /** String used in tests */ + private static final String TEST_STRING = "Test"; + + /** Long integer used in tests */ + private static final long TEST_LONG = 42L; + + private static final int TEST_INTEGER = 42; + + /** The "guinea pig" instance */ + private EmpireResourceRecord instance; + + + /** Create the "guinea pig" instance */ + @Before + public void setUp( ) + { + this.instance = new EmpireResourceRecord( ); + } + + + /** Check default values */ + @Test + public void testDefaults( ) + { + assertNull( this.instance.getIdentifier( ) ); + assertNull( this.instance.getDescription( ) ); + assertEquals( 0L , this.instance.getIncome( ) ); + assertEquals( 0L , this.instance.getPlanetUpkeep( ) ); + assertEquals( 0L , this.instance.getFleetUpkeep( ) ); + assertEquals( 0L , this.instance.getUpkeep( ) ); + assertEquals( 0L , this.instance.getStockpiled( ) ); + assertNull( this.instance.getMiningPriority( ) ); + } + + + /** Setting and reading the identifier */ + @Test + public void testIdentifier( ) + { + this.instance.setIdentifier( TEST_STRING ); + assertEquals( TEST_STRING , this.instance.getIdentifier( ) ); + } + + + /** Setting and reading the description */ + @Test + public void testDescription( ) + { + this.instance.setDescription( TEST_STRING ); + assertEquals( TEST_STRING , this.instance.getDescription( ) ); + } + + + /** Setting and reading the income */ + @Test + public void testIncome( ) + { + this.instance.setIncome( TEST_LONG ); + assertEquals( TEST_LONG , this.instance.getIncome( ) ); + } + + + /** Setting and reading the planet upkeep */ + @Test + public void testPlanetUpkeep( ) + { + this.instance.setPlanetUpkeep( TEST_LONG ); + assertEquals( TEST_LONG , this.instance.getPlanetUpkeep( ) ); + } + + + /** Setting and reading the fleet upkeep */ + @Test + public void testFleetUpkeep( ) + { + this.instance.setFleetUpkeep( TEST_LONG ); + assertEquals( TEST_LONG , this.instance.getFleetUpkeep( ) ); + } + + + /** Setting and reading the stockpiled quantity */ + @Test + public void testStockpiled( ) + { + this.instance.setStockpiled( TEST_LONG ); + assertEquals( TEST_LONG , this.instance.getStockpiled( ) ); + } + + + /** Setting and reading the mining priority */ + @Test + public void testMiningPriority( ) + { + this.instance.setMiningPriority( TEST_INTEGER ); + assertEquals( (Integer) TEST_INTEGER , this.instance.getMiningPriority( ) ); + } + + + /** Total upkeep = fleet upkeep + planet upkeep */ + @Test + public void testTotalUpkeep( ) + { + this.instance.setPlanetUpkeep( TEST_LONG ); + assertEquals( TEST_LONG , this.instance.getUpkeep( ) ); + this.instance.setFleetUpkeep( TEST_LONG + 1 ); + assertEquals( TEST_LONG * 2 + 1 , this.instance.getUpkeep( ) ); + } +} diff --git a/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/planets/TestPlanetResourceRecord.java b/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/planets/TestPlanetResourceRecord.java new file mode 100644 index 0000000..30818de --- /dev/null +++ b/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/planets/TestPlanetResourceRecord.java @@ -0,0 +1,82 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + + + +/** + * Tests for the {@link PlanetResourceRecord} class. + * + * @author E. Benoît + */ +public class TestPlanetResourceRecord +{ + /** Long integer used in tests */ + private static final long TEST_LONG = 42L; + + /** Resource data instance to test on */ + private PlanetResourceRecord resourceData; + + + /** Create the "guinea pig" instance */ + @Before + public void setUp( ) + { + this.resourceData = new PlanetResourceRecord( ); + } + + + /** Test default values */ + @Test + public void testDefaults( ) + { + assertEquals( 0L , this.resourceData.getIncome( ) ); + assertEquals( 0L , this.resourceData.getUpkeep( ) ); + assertEquals( 0L , this.resourceData.getInvested( ) ); + assertNull( this.resourceData.getResourceProvider( ) ); + } + + + /** Test setting and reading the income */ + @Test + public void testIncome( ) + { + this.resourceData.setIncome( TEST_LONG ); + assertEquals( TEST_LONG , this.resourceData.getIncome( ) ); + } + + + /** Test setting and reading the upkeep */ + @Test + public void testUpkeep( ) + { + this.resourceData.setUpkeep( TEST_LONG ); + assertEquals( TEST_LONG , this.resourceData.getUpkeep( ) ); + } + + + /** Test setting and reading the invested amount */ + @Test + public void testInvested( ) + { + this.resourceData.setInvested( TEST_LONG ); + assertEquals( TEST_LONG , this.resourceData.getInvested( ) ); + } + + + /** Test setting and reading the resource provider */ + @Test + public void testResourceProvider( ) + { + ResourceProviderRecord rpd = new ResourceProviderRecord( ); + rpd.setCapacity( TEST_LONG ); + this.resourceData.setResourceProvider( rpd ); + rpd = this.resourceData.getResourceProvider( ); + assertNotNull( rpd ); + assertEquals( TEST_LONG , rpd.getCapacity( ) ); + } +} diff --git a/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/planets/TestResourceProviderRecord.java b/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/planets/TestResourceProviderRecord.java new file mode 100644 index 0000000..cac3037 --- /dev/null +++ b/legacyworlds-tests/src/test/java/com/deepclone/lw/cmd/player/gdata/planets/TestResourceProviderRecord.java @@ -0,0 +1,83 @@ +package com.deepclone.lw.cmd.player.gdata.planets; + + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + + + +/** + * Tests for the {@link ResourceProviderRecord} class. + * + * @author E. Benoît + * + */ +public class TestResourceProviderRecord +{ + + /** Long integer used in tests */ + private static final long TEST_LONG = 42L; + + /** Integer used in tests */ + private static final int TEST_INT = 42; + + /** Resource provider data instance to test on */ + private ResourceProviderRecord resProvData; + + + /** Create the "guinea pig" instance */ + @Before + public void setUp( ) + { + this.resProvData = new ResourceProviderRecord( ); + } + + /** Check default values */ + @Test + public void testDefaults( ) + { + assertEquals( 0L , this.resProvData.getCapacity( ) ); + assertEquals( 0L , this.resProvData.getQuantity( ) ); + assertEquals( 0 , this.resProvData.getDifficulty( ) ); + assertEquals( 0 , this.resProvData.getPriority( ) ); + } + + + /** Setting and reading the capacity */ + @Test + public void testSetCapacity( ) + { + this.resProvData.setCapacity( TEST_LONG ); + assertEquals( TEST_LONG , this.resProvData.getCapacity( ) ); + } + + + /** Setting and reading the quantity */ + @Test + public void testSetQuantity( ) + { + this.resProvData.setQuantity( TEST_LONG ); + assertEquals( TEST_LONG , this.resProvData.getQuantity( ) ); + } + + + /** Setting and reading the difficulty */ + @Test + public void testSetDifficulty( ) + { + this.resProvData.setDifficulty( TEST_INT ); + assertEquals( TEST_INT , this.resProvData.getDifficulty( ) ); + } + + + /** Setting and reading the priority */ + @Test + public void testSetPriority( ) + { + this.resProvData.setPriority( TEST_INT ); + assertEquals( TEST_INT , this.resProvData.getPriority( ) ); + } + +} diff --git a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/game.ftl b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/game.ftl index f9518eb..122c93a 100644 --- a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/game.ftl +++ b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/game.ftl @@ -63,4 +63,11 @@ <#macro abbr_bgc>bgc <#macro abbr_st>ST -<#macro abbr_gt>GT \ No newline at end of file +<#macro abbr_gt>GT +<#macro over_time title> + <#if data.page.useRLTime> + ${title?xhtml} (for 12h) + <#else> + Monthly ${title?xhtml} + + \ No newline at end of file diff --git a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/types/overview.ftl b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/types/overview.ftl index af04b79..639de56 100644 --- a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/types/overview.ftl +++ b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/types/overview.ftl @@ -61,7 +61,64 @@ + + <@tab id="economy" title="Economy"> + <@listview> + <@lv_line headers=true> + <@lv_column width=30>  + <@lv_column width="x">Resource + <@lv_column width=100 centered=true><@over_time "Income" /> + <@lv_column width=100 centered=true><@over_time "Upkeep" /> + <@lv_column width=100 centered=true>Reserves + <@lv_column width=100 centered=true>Mining priority + + + <#list ov.economy as resource> + + <#if previousCategory?has_content && !resource.category?has_content + || resource.category?has_content && !previousCategory?has_content + || resource.category?has_content && previousCategory?has_content + && resource.category != previousCategory> + <@lv_line> + <#if resource.category?has_content> + ${resource.category?xhtml} + <#else> +
+ + + <#local previousCategory=resource.category> + + + <@lv_line> + <@lv_column>  + <@lv_column>${resource.title?xhtml} +
${resource.description?xhtml}
+ + <@lv_column centered=true>${resource.income?string(",##0")} + <@lv_column centered=true>${resource.upkeep?string(",##0")} + <@lv_column centered=true>${resource.stockpiled?string(",##0")} + <@lv_column centered=true> + <#if resource.miningPriority?has_content> + <#switch resource.miningPriority> + <#case 0>lowest<#break> + <#case 1>low<#break> + <#case 2>normal<#break> + <#case 3>high<#break> + <#case 4>highest<#break> + + <#else> + N/A + + + + + + + + + + <@tab id="research" title="Research"> <#if rs?size == 0>

Our scientists are still settling in.

diff --git a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/types/planet.ftl b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/types/planet.ftl index f32d709..7f3649c 100644 --- a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/types/planet.ftl +++ b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/en/types/planet.ftl @@ -108,6 +108,55 @@ + + <#if data.own?has_content && data.own.resources?size gt 0> + + <@tab id="resources" title="Economy"> + + <@listview> + <#local previousCategory=""> + + <@lv_line headers=true> + <@lv_column width=30>  + <@lv_column width="x">Resource + <@lv_column width=100 centered=true><@over_time "Income" /> + <@lv_column width=100 centered=true><@over_time "Upkeep" /> + <@lv_column width=100 centered=true>Invested + + + <#list data.own.resources as resource> + + <#if previousCategory?has_content && !resource.category?has_content + || resource.category?has_content && !previousCategory?has_content + || resource.category?has_content && previousCategory?has_content + && resource.category != previousCategory> + <@lv_line> + <#if resource.category?has_content> + ${resource.category?xhtml} + <#else> +
+ + + <#local previousCategory=resource.category> + + + <@lv_line> + <@lv_column>  + <@lv_column>${resource.title?xhtml} +
${resource.description?xhtml}
+ + <@lv_column centered=true>${resource.income?string(",##0")} + <@lv_column centered=true>${resource.upkeep?string(",##0")} + <@lv_column centered=true>${resource.invested?string(",##0")} + + + + + + + + + <#if data.orbit?has_content> @@ -143,6 +192,7 @@ <#case "DEF">defence<#break> <#case "WORK">mil. output<#break> <#case "POP">growth<#break> + <#case "MINE">res. extraction<#break> <@lv_column centered=true>${building.jobs?string(",##0")} @@ -189,6 +239,7 @@ <#case "DEF">defence<#break> <#case "WORK">mil. output<#break> <#case "POP">growth<#break> + <#case "MINE">res. extraction<#break> @@ -251,6 +302,7 @@ <#if data.own?has_content> + <@tab id="ships" title="Shipyards"> <#if data.page.special! != 'v'> <#if data.own.milQueue.appendPossible> @@ -321,9 +373,60 @@ - - + + + <#list data.own.resources as resource> + <#if resource.resourceProvider?has_content> + <#local showResources=true> + <#break> + + + + <#if showResources?has_content> + <@tab id="natres" title="Natural resources"> + + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Resource + <@lv_column width=100 right=true>Quantity  + <@lv_column width=100>  Capacity + <@lv_column width=100 centered=true>Extraction
difficulty + <@lv_column width=100 centered=true>Priority + + + <#list data.own.resources as resource> + <#if resource.resourceProvider?has_content> + <#local resProv=resource.resourceProvider> + + <@lv_line> + <@lv_column> + ${resource.title?xhtml} +
${resource.description?xhtml}
+ + <@lv_column right=true>${resProv.quantity?string(",##0")}  + <@lv_column>/ ${resProv.capacity?string(",##0")} + <@lv_column centered=true>${resProv.difficulty} % + <@lv_column centered=true> + <#switch resProv.priority> + <#case 0>lowest<#break> + <#case 1>low<#break> + <#case 2>normal<#break> + <#case 3>high<#break> + <#case 4>highest<#break> + + + + + + + + + + + + + \ No newline at end of file diff --git a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/game.ftl b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/game.ftl index 81e8aa9..b0c8a1a 100644 --- a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/game.ftl +++ b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/game.ftl @@ -63,4 +63,11 @@ <#macro abbr_bgc>mcg <#macro abbr_st>TS -<#macro abbr_gt>TJ \ No newline at end of file +<#macro abbr_gt>TJ +<#macro over_time title feminin=false pluriel=false> + <#if data.page.useRLTime> + ${title?xhtml} (pour 12h) + <#else> + ${title?xhtml} mensuel<#if feminin>le<#if pluriel>s + + \ No newline at end of file diff --git a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/types/overview.ftl b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/types/overview.ftl index 919f8e9..5bf71e8 100644 --- a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/types/overview.ftl +++ b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/types/overview.ftl @@ -62,6 +62,63 @@ + <@tab id="economy" title="Économie"> + + <@listview> + <@lv_line headers=true> + <@lv_column width=30>  + <@lv_column width="x">Ressource + <@lv_column width=100 centered=true><@over_time "Bénéfice" /> + <@lv_column width=100 centered=true><@over_time title="Charges" feminin=true pluriel=true /> + <@lv_column width=100 centered=true>Réserves + <@lv_column width=100 centered=true>Priorité d'extraction + + + <#list ov.economy as resource> + + <#if previousCategory?has_content && !resource.category?has_content + || resource.category?has_content && !previousCategory?has_content + || resource.category?has_content && previousCategory?has_content + && resource.category != previousCategory> + <@lv_line> + <#if resource.category?has_content> + ${resource.category?xhtml} + <#else> +
+ + + <#local previousCategory=resource.category> + + + <@lv_line> + <@lv_column>  + <@lv_column>${resource.title?xhtml} +
${resource.description?xhtml}
+ + <@lv_column centered=true>${resource.income?string(",##0")} + <@lv_column centered=true>${resource.upkeep?string(",##0")} + <@lv_column centered=true>${resource.stockpiled?string(",##0")} + <@lv_column centered=true> + <#if resource.miningPriority?has_content> + <#switch resource.miningPriority> + <#case 0>très basse<#break> + <#case 1>basse<#break> + <#case 2>normale<#break> + <#case 3>haute<#break> + <#case 4>très haute<#break> + + <#else> + N/A + + + + + + + + + + <@tab id="research" title="Recherche"> <#if rs?size == 0>

Nos scientifiques sont encore en train de s'installer.

diff --git a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/types/planet.ftl b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/types/planet.ftl index 1aed9bf..5f6fadd 100644 --- a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/types/planet.ftl +++ b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/fr/types/planet.ftl @@ -108,6 +108,55 @@ + + <#if data.own?has_content && data.own.resources?size gt 0> + + <@tab id="resources" title="Économie"> + + <@listview> + <#local previousCategory=""> + + <@lv_line headers=true> + <@lv_column width=30>  + <@lv_column width="x">Ressource + <@lv_column width=100 centered=true><@over_time "Bénéfice" /> + <@lv_column width=100 centered=true><@over_time title="Charges" feminin=true pluriel=true /> + <@lv_column width=100 centered=true>Investissement + + + <#list data.own.resources as resource> + + <#if previousCategory?has_content && !resource.category?has_content + || resource.category?has_content && !previousCategory?has_content + || resource.category?has_content && previousCategory?has_content + && resource.category != previousCategory> + <@lv_line> + <#if resource.category?has_content> + ${resource.category?xhtml} + <#else> +
+ + + <#local previousCategory=resource.category> + + + <@lv_line> + <@lv_column>  + <@lv_column>${resource.title?xhtml} +
${resource.description?xhtml}
+ + <@lv_column centered=true>${resource.income?string(",##0")} + <@lv_column centered=true>${resource.upkeep?string(",##0")} + <@lv_column centered=true>${resource.invested?string(",##0")} + + + + + + + + + <#if data.orbit?has_content> @@ -143,6 +192,7 @@ <#case "DEF">défense<#break> <#case "WORK">production mil.<#break> <#case "POP">croissance<#break> + <#case "MINE">extraction<#break> <@lv_column centered=true>${building.jobs?string(",##0")} @@ -189,6 +239,7 @@ <#case "DEF">défense<#break> <#case "WORK">production mil.<#break> <#case "POP">croissance<#break> + <#case "MINE">extraction<#break> @@ -322,6 +373,56 @@ + + <#list data.own.resources as resource> + <#if resource.resourceProvider?has_content> + <#local showResources=true> + <#break> + + + + <#if showResources?has_content> + <@tab id="natres" title="Ressources naturelles"> + + <@listview> + <@lv_line headers=true> + <@lv_column width="x">Ressource + <@lv_column width=100 right=true>Quantité  + <@lv_column width=100>  Capacité + <@lv_column width=100 centered=true>Difficulté
d'extraction + <@lv_column width=100 centered=true>Priorité + + + <#list data.own.resources as resource> + <#if resource.resourceProvider?has_content> + <#local resProv=resource.resourceProvider> + + <@lv_line> + <@lv_column> + ${resource.title?xhtml} +
${resource.description?xhtml}
+ + <@lv_column right=true>${resProv.quantity?string(",##0")}  + <@lv_column>/ ${resProv.capacity?string(",##0")} + <@lv_column centered=true>${resProv.difficulty} % + <@lv_column centered=true> + <#switch resProv.priority> + <#case 0>très basse<#break> + <#case 1>basse<#break> + <#case 2>normale<#break> + <#case 3>haute<#break> + <#case 4>très haute<#break> + + + + + + + + + + + diff --git a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/layout/lists.ftl b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/layout/lists.ftl index 798342a..3e196b7 100644 --- a/legacyworlds-web-main/Content/Raw/WEB-INF/fm/layout/lists.ftl +++ b/legacyworlds-web-main/Content/Raw/WEB-INF/fm/layout/lists.ftl @@ -8,17 +8,17 @@ <#nested> -<#macro lv_column width=0 centered=false right=false> +<#macro lv_column width=0 centered=false right=false colspan=0> <#if width?is_string> - + colspan="${colspan}"> <#nested> <#elseif width gt 0> - + colspan="${colspan}"> <#nested> <#else> - + colspan="${colspan}"> <#nested>