Importing SVN archives - Trunk

This commit is contained in:
Emmanuel BENOîT 2018-10-23 09:43:42 +02:00
parent fc4c6bd340
commit ff53af6668
507 changed files with 8866 additions and 2450 deletions

View file

@ -4,12 +4,12 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-accounts</artifactId> <artifactId>legacyworlds-server-beans-accounts</artifactId>
<name>Legacy Worlds account management</name> <name>Legacy Worlds account management</name>
<version>5.99.1</version> <version>5.99.2</version>
<description>This package contains the beans responsible for managing accounts, including registration, inactivity checks, bans and authentication.</description> <description>This package contains the beans responsible for managing accounts, including registration, inactivity checks, bans and authentication.</description>
</project> </project>

View file

@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<dependencies> <dependencies>
@ -20,6 +20,6 @@
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-bt</artifactId> <artifactId>legacyworlds-server-beans-bt</artifactId>
<version>5.99.1</version> <version>5.99.2</version>
<name>Legacy Worlds bug tracking system</name> <name>Legacy Worlds bug tracking system</name>
</project> </project>

View file

@ -28,6 +28,7 @@ public class EmpireSummaryBean
private final RowMapper< DebugInformation > mMainInfo; private final RowMapper< DebugInformation > mMainInfo;
private final RowMapper< ResearchInformation > mResearch; private final RowMapper< ResearchInformation > mResearch;
private final RowMapper< TechnologyInformation > mTechnology;
private final RowMapper< PlanetInformation > mPlanet; private final RowMapper< PlanetInformation > mPlanet;
private final RowMapper< QueueItemInformation > mQueueItem; private final RowMapper< QueueItemInformation > mQueueItem;
private final RowMapper< BuildingsInformation > mBuildings; private final RowMapper< BuildingsInformation > mBuildings;
@ -42,7 +43,8 @@ public class EmpireSummaryBean
AccountInformation.class , AllianceInformation.class , BuildingsInformation.class , AccountInformation.class , AllianceInformation.class , BuildingsInformation.class ,
DebugInformation.class , EmpireInformation.class , FleetInformation.class , MovementInformation.class , DebugInformation.class , EmpireInformation.class , FleetInformation.class , MovementInformation.class ,
PlanetInformation.class , QueueInformation.class , QueueItemInformation.class , PlanetInformation.class , QueueInformation.class , QueueItemInformation.class ,
ResearchInformation.class , ShipsInformation.class , SystemInformation.class ResearchInformation.class , TechnologyInformation.class , ShipsInformation.class ,
SystemInformation.class
} ); } );
this.mMainInfo = new RowMapper< DebugInformation >( ) { this.mMainInfo = new RowMapper< DebugInformation >( ) {
@ -83,13 +85,23 @@ public class EmpireSummaryBean
throws SQLException throws SQLException
{ {
ResearchInformation ri = new ResearchInformation( ); ResearchInformation ri = new ResearchInformation( );
ri.setId( rs.getInt( "line_id" ) ); ri.setName( rs.getString( "name" ) );
ri.setCurrentLevel( rs.getInt( "level" ) );
ri.setLevelName( rs.getString( "name" ) );
ri.setAccumulated( rs.getDouble( "accumulated" ) ); ri.setAccumulated( rs.getDouble( "accumulated" ) );
ri.setPriority( rs.getInt( "priority" ) );
return ri; return ri;
} }
}; };
this.mTechnology = new RowMapper< TechnologyInformation >( ) {
@Override
public TechnologyInformation mapRow( ResultSet rs , int rowNum )
throws SQLException
{
TechnologyInformation ti = new TechnologyInformation( );
ti.setName( rs.getString( "name" ) );
ti.setImplemented( rs.getBoolean( "implemented" ) );
return ti;
}
};
this.mPlanet = new RowMapper< PlanetInformation >( ) { this.mPlanet = new RowMapper< PlanetInformation >( ) {
@Override @Override
public PlanetInformation mapRow( ResultSet rs , int rowNum ) public PlanetInformation mapRow( ResultSet rs , int rowNum )
@ -199,9 +211,10 @@ public class EmpireSummaryBean
DebugInformation di = this.dTemplate.queryForObject( sql , this.mMainInfo , empireId ); DebugInformation di = this.dTemplate.queryForObject( sql , this.mMainInfo , empireId );
sql = "SELECT * FROM bugs.dump_research_view WHERE empire_id = ?"; sql = "SELECT * FROM bugs.dump_research_view WHERE empire_id = ?";
for ( ResearchInformation ri : this.dTemplate.query( sql , this.mResearch , empireId ) ) { di.getResearch( ).addAll( this.dTemplate.query( sql , this.mResearch , empireId ) );
di.getResearch( ).add( ri );
} sql = "SELECT * FROM bugs.dump_technologies_view WHERE empire_id = ?";
di.getTechnologies( ).addAll( this.dTemplate.query( sql , this.mTechnology , empireId ) );
sql = "SELECT * FROM bugs.dump_planets_view WHERE empire_id = ?"; sql = "SELECT * FROM bugs.dump_planets_view WHERE empire_id = ?";
Map< Integer , PlanetInformation > planets = new HashMap< Integer , PlanetInformation >( ); Map< Integer , PlanetInformation > planets = new HashMap< Integer , PlanetInformation >( );

View file

@ -15,26 +15,29 @@ public class DebugInformation
implements Serializable implements Serializable
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 2L;
@XStreamAsAttribute @XStreamAsAttribute
@XStreamAlias( "dump-version" ) @XStreamAlias( "dump-version" )
private int version = 1; private final int version = 2;
private SystemInformation system = new SystemInformation( ); private final SystemInformation system = new SystemInformation( );
private AccountInformation account = new AccountInformation( ); private final AccountInformation account = new AccountInformation( );
private EmpireInformation empire = new EmpireInformation( ); private final EmpireInformation empire = new EmpireInformation( );
@XStreamAlias( "research" ) @XStreamAlias( "research" )
private List< ResearchInformation > research = new LinkedList< ResearchInformation >( ); private final List< ResearchInformation > research = new LinkedList< ResearchInformation >( );
@XStreamAlias( "technologies" )
private final List< TechnologyInformation > technologies = new LinkedList< TechnologyInformation >( );
@XStreamAlias( "planets" ) @XStreamAlias( "planets" )
private List< PlanetInformation > planets = new LinkedList< PlanetInformation >( ); private final List< PlanetInformation > planets = new LinkedList< PlanetInformation >( );
@XStreamAlias( "fleets" ) @XStreamAlias( "fleets" )
private List< FleetInformation > fleets = new LinkedList< FleetInformation >( ); private final List< FleetInformation > fleets = new LinkedList< FleetInformation >( );
public int getVersion( ) public int getVersion( )
@ -67,6 +70,12 @@ public class DebugInformation
} }
public List< TechnologyInformation > getTechnologies( )
{
return technologies;
}
public List< PlanetInformation > getPlanets( ) public List< PlanetInformation > getPlanets( )
{ {
return planets; return planets;

View file

@ -8,64 +8,34 @@ import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
@XStreamAlias( "research-line" ) @XStreamAlias( "research-topic" )
public class ResearchInformation public class ResearchInformation
implements Serializable implements Serializable
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 2L;
@XStreamAsAttribute @XStreamAsAttribute
@XStreamAlias( "line") private String name;
private int id;
@XStreamAsAttribute @XStreamAsAttribute
@XStreamAlias( "level") @XStreamAlias( "accumulated-points" )
private int currentLevel;
@XStreamAsAttribute
@XStreamAlias( "name")
private String levelName;
@XStreamAsAttribute
@XStreamAlias( "accumulated-points")
private double accumulated; private double accumulated;
@XStreamAsAttribute
private int priority;
public int getId( )
public String getName( )
{ {
return id; return name;
} }
public void setId( int id ) public void setName( String name )
{ {
this.id = id; this.name = name;
}
public int getCurrentLevel( )
{
return currentLevel;
}
public void setCurrentLevel( int currentLevel )
{
this.currentLevel = currentLevel;
}
public String getLevelName( )
{
return levelName;
}
public void setLevelName( String levelName )
{
this.levelName = levelName;
} }
@ -80,4 +50,16 @@ public class ResearchInformation
this.accumulated = accumulated; this.accumulated = accumulated;
} }
public int getPriority( )
{
return priority;
}
public void setPriority( int priority )
{
this.priority = priority;
}
} }

View file

@ -0,0 +1,48 @@
package com.deepclone.lw.beans.bt.esdata;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
@XStreamAlias( "technology" )
public class TechnologyInformation
implements Serializable
{
private static final long serialVersionUID = 1L;
@XStreamAsAttribute
private String name;
@XStreamAsAttribute
private boolean implemented;
public String getName( )
{
return name;
}
public void setName( String name )
{
this.name = name;
}
public boolean isImplemented( )
{
return implemented;
}
public void setImplemented( boolean implemented )
{
this.implemented = implemented;
}
}

View file

@ -4,12 +4,12 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-eventlog</artifactId> <artifactId>legacyworlds-server-beans-eventlog</artifactId>
<version>5.99.1</version> <version>5.99.2</version>
<name>Legacy Worlds event log</name> <name>Legacy Worlds event log</name>
<description>This package is responsible for all logging in Legacy Worlds through three different beans (system event logger, admin event logger and user event logger).</description> <description>This package is responsible for all logging in Legacy Worlds through three different beans (system event logger, admin event logger and user event logger).</description>
</project> </project>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>legacyworlds-server-beans-events</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,6 @@
#Sun Apr 03 09:36:59 CEST 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6

View file

@ -0,0 +1,9 @@
#Sun Apr 03 09:36:59 CEST 2011
activeProfiles=
eclipse.preferences.version=1
fullBuildGoals=process-test-resources
includeModules=false
resolveWorkspaceProjects=true
resourceFilterGoals=process-resources resources\:testResources
skipCompilerPlugin=true
version=1

View file

@ -0,0 +1,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId>
<version>5.99.2</version>
</parent>
<groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-events</artifactId>
<version>5.99.2</version>
<name>Game events</name>
<description>This module contains components which manage game events.</description>
</project>

View file

@ -4,13 +4,13 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-i18n</artifactId> <artifactId>legacyworlds-server-beans-i18n</artifactId>
<name>Legacy Worlds internationalisation</name> <name>Legacy Worlds internationalisation</name>
<version>5.99.1</version> <version>5.99.2</version>
<description>This package defines the two beans which control server-side internationalised text management.</description> <description>This package defines the two beans which control server-side internationalised text management.</description>
</project> </project>

View file

@ -6,6 +6,7 @@ import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import com.deepclone.lw.interfaces.i18n.LanguageTranslator;
import com.deepclone.lw.interfaces.i18n.Translator; import com.deepclone.lw.interfaces.i18n.Translator;
import com.deepclone.lw.interfaces.i18n.UnknownLanguageException; import com.deepclone.lw.interfaces.i18n.UnknownLanguageException;
import com.deepclone.lw.interfaces.i18n.UnknownStringException; import com.deepclone.lw.interfaces.i18n.UnknownStringException;
@ -21,6 +22,67 @@ import com.deepclone.lw.interfaces.i18n.UnknownStringException;
public class TranslatorBean public class TranslatorBean
implements Translator implements Translator
{ {
/**
* Implementation of a language-specific translator.
*/
private static class LanguageTranslatorImpl
implements LanguageTranslator
{
/** Language used by the translator */
private final String language;
/** Translations store */
private final I18NData data;
LanguageTranslatorImpl( String language , TranslatorBean translator )
{
this.language = language;
this.data = translator.data;
}
/* Documentation in LanguageTranslator interface */
@Override
public String getLanguage( )
{
return this.language;
}
/* Documentation in LanguageTranslator interface */
@Override
public String getLanguageName( )
{
this.data.readLock( ).lock( );
try {
return this.data.getLanguageName( language );
} finally {
this.data.readLock( ).unlock( );
}
}
/* Documentation in LanguageTranslator interface */
@Override
public String translate( String string )
throws UnknownStringException
{
this.data.readLock( ).lock( );
try {
if ( !this.data.hasString( string ) ) {
throw new UnknownStringException( string );
}
return this.data.getTranslation( language , string );
} finally {
this.data.readLock( ).unlock( );
}
}
}
/** Translations store */
private I18NData data; private I18NData data;
@ -119,4 +181,21 @@ public class TranslatorBean
} }
} }
/* Documentation in Translator interface */
@Override
public LanguageTranslator getLanguageTranslator( String language )
throws UnknownLanguageException
{
this.data.readLock( ).lock( );
try {
if ( !this.data.isLanguageComplete( language ) ) {
throw new UnknownLanguageException( language );
}
return new LanguageTranslatorImpl( language , this );
} finally {
this.data.readLock( ).unlock( );
}
}
} }

View file

@ -4,12 +4,12 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-mailer</artifactId> <artifactId>legacyworlds-server-beans-mailer</artifactId>
<version>5.99.1</version> <version>5.99.2</version>
<name>Legacy Worlds mailer</name> <name>Legacy Worlds mailer</name>
<description> <description>
This package contains the mailer component, which uses LW's i18n system and Spring's mail sending interfaces. This package contains the mailer component, which uses LW's i18n system and Spring's mail sending interfaces.

View file

@ -4,12 +4,12 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-naming</artifactId> <artifactId>legacyworlds-server-beans-naming</artifactId>
<version>5.99.1</version> <version>5.99.2</version>
<name>Legacy Worlds object naming system</name> <name>Legacy Worlds object naming system</name>
<description>This module contains the beans responsible for managing the names of the various objects (players and planets).</description> <description>This module contains the beans responsible for managing the names of the various objects (players and planets).</description>
</project> </project>

View file

@ -3,11 +3,11 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-simple</artifactId> <artifactId>legacyworlds-server-beans-simple</artifactId>
<version>5.99.1</version> <version>5.99.2</version>
<name>Legacy Worlds simple game</name> <name>Legacy Worlds simple game</name>
<description>This module contains code that corresponds to a simple "placeholder" game. This code should become obsolete over time, as it is being replaced with actual LWB6 code, until the module can finally be removed.</description> <description>This module contains code that corresponds to a simple "placeholder" game. This code should become obsolete over time, as it is being replaced with actual LWB6 code, until the module can finally be removed.</description>
</project> </project>

View file

@ -4,9 +4,7 @@ package com.deepclone.lw.beans.empire;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -20,8 +18,6 @@ import com.deepclone.lw.cmd.player.gdata.NameIdPair;
import com.deepclone.lw.cmd.player.gdata.PlanetListData; import com.deepclone.lw.cmd.player.gdata.PlanetListData;
import com.deepclone.lw.cmd.player.gdata.empire.OverviewData; import com.deepclone.lw.cmd.player.gdata.empire.OverviewData;
import com.deepclone.lw.interfaces.game.EmpireDAO; import com.deepclone.lw.interfaces.game.EmpireDAO;
import com.deepclone.lw.sqld.game.EmpireTechLine;
import com.deepclone.lw.sqld.game.EmpireTechnology;
import com.deepclone.lw.sqld.game.GeneralInformation; import com.deepclone.lw.sqld.game.GeneralInformation;
import com.deepclone.lw.utils.StoredProc; import com.deepclone.lw.utils.StoredProc;
@ -31,7 +27,6 @@ public class EmpireDAOBean
implements EmpireDAO implements EmpireDAO
{ {
private SimpleJdbcTemplate dTemplate; private SimpleJdbcTemplate dTemplate;
private StoredProc fImplementTech;
private StoredProc fAddEmpEnemy; private StoredProc fAddEmpEnemy;
private StoredProc fAddAllEnemy; private StoredProc fAddAllEnemy;
private StoredProc fRemoveEmpEnemy; private StoredProc fRemoveEmpEnemy;
@ -40,16 +35,36 @@ public class EmpireDAOBean
private final PlanetListMapper mPlanetList = new PlanetListMapper( ); private final PlanetListMapper mPlanetList = new PlanetListMapper( );
private final RowMapper< GeneralInformation > mEmpireInfo;
public EmpireDAOBean( )
{
this.mEmpireInfo = new RowMapper< GeneralInformation >( ) {
@Override
public GeneralInformation mapRow( ResultSet rs , int rowNum )
throws SQLException
{
String st = rs.getString( "status" );
Character status = ( st == null ) ? null : st.charAt( 0 );
String name = rs.getString( "name" );
String tag = rs.getString( "alliance" );
String language = rs.getString( "language" );
long cash = rs.getLong( "cash" );
long nextTick = rs.getLong( "game_time" );
int accountId = rs.getInt( "account_id" );
return new GeneralInformation( status , name , tag , language , cash , nextTick , accountId );
}
};
}
@Autowired( required = true ) @Autowired( required = true )
public void setDataSource( DataSource dataSource ) public void setDataSource( DataSource dataSource )
{ {
this.dTemplate = new SimpleJdbcTemplate( dataSource ); this.dTemplate = new SimpleJdbcTemplate( dataSource );
this.fImplementTech = new StoredProc( dataSource , "emp" , "implement_tech" );
this.fImplementTech.addParameter( "empire_id" , Types.INTEGER );
this.fImplementTech.addParameter( "line_id" , Types.INTEGER );
this.fAddEmpEnemy = new StoredProc( dataSource , "emp" , "add_enemy_empire" ); this.fAddEmpEnemy = new StoredProc( dataSource , "emp" , "add_enemy_empire" );
this.fAddEmpEnemy.addParameter( "empire_id" , Types.INTEGER ); this.fAddEmpEnemy.addParameter( "empire_id" , Types.INTEGER );
this.fAddEmpEnemy.addParameter( "enemy_name" , Types.VARCHAR ); this.fAddEmpEnemy.addParameter( "enemy_name" , Types.VARCHAR );
@ -79,19 +94,8 @@ public class EmpireDAOBean
public GeneralInformation getInformation( int empireId ) public GeneralInformation getInformation( int empireId )
{ {
String sql = "SELECT * FROM emp.general_information WHERE id = ?"; String sql = "SELECT * FROM emp.general_information WHERE id = ?";
RowMapper< GeneralInformation > mapper = new RowMapper< GeneralInformation >( ) {
@Override
public GeneralInformation mapRow( ResultSet rs , int rowNum )
throws SQLException
{
String st = rs.getString( "status" );
Character status = ( st == null ) ? null : st.charAt( 0 );
return new GeneralInformation( status , rs.getString( "name" ) , rs.getString( "alliance" ) , rs
.getLong( "cash" ) , rs.getLong( "game_time" ) , rs.getInt( "account_id" ) );
}
};
try { try {
return this.dTemplate.queryForObject( sql , mapper , empireId ); return this.dTemplate.queryForObject( sql , this.mEmpireInfo , empireId );
} catch ( EmptyResultDataAccessException e ) { } catch ( EmptyResultDataAccessException e ) {
return null; return null;
} }
@ -156,65 +160,6 @@ public class EmpireDAOBean
} }
@Override
public List< EmpireTechLine > getTechnology( int empireId )
{
String sql = "SELECT * FROM emp.tech_lines_view WHERE empire = ?";
RowMapper< EmpireTechLine > lineMapper = new RowMapper< EmpireTechLine >( ) {
@Override
public EmpireTechLine mapRow( ResultSet rs , int rowNum )
throws SQLException
{
EmpireTechLine etl = new EmpireTechLine( );
etl.setId( rs.getInt( "tech_line" ) );
etl.setName( rs.getString( "name" ) );
etl.setDescription( rs.getString( "description" ) );
return etl;
}
};
List< EmpireTechLine > lines = this.dTemplate.query( sql , lineMapper , empireId );
if ( lines.isEmpty( ) ) {
return lines;
}
Map< Integer , EmpireTechLine > linesById = new HashMap< Integer , EmpireTechLine >( );
for ( EmpireTechLine etl : lines ) {
linesById.put( etl.getId( ) , etl );
}
sql = "SELECT * FROM emp.technologies_view WHERE empire = ?";
RowMapper< EmpireTechnology > techMapper = new RowMapper< EmpireTechnology >( ) {
@Override
public EmpireTechnology mapRow( ResultSet rs , int rowNum )
throws SQLException
{
EmpireTechnology et = new EmpireTechnology( );
et.setLine( rs.getInt( "tech_line" ) );
et.setName( rs.getString( "name" ) );
et.setDescription( rs.getString( "description" ) );
et.setImplemented( rs.getBoolean( "implemented" ) );
et.setProgress( (int) rs.getDouble( "progress" ) );
et.setCost( rs.getInt( "cost" ) );
return et;
}
};
for ( EmpireTechnology et : this.dTemplate.query( sql , techMapper , empireId ) ) {
linesById.get( et.getLine( ) ).addTechnology( et );
}
return lines;
}
@Override
public void implementTechnology( int empireId , int lineId )
{
this.fImplementTech.execute( empireId , lineId );
}
@Override @Override
public List< PlanetListData > getPlanetList( int empireId ) public List< PlanetListData > getPlanetList( int empireId )
{ {

View file

@ -18,19 +18,18 @@ import com.deepclone.lw.cmd.player.gdata.NameIdPair;
import com.deepclone.lw.cmd.player.gdata.PlanetListData; import com.deepclone.lw.cmd.player.gdata.PlanetListData;
import com.deepclone.lw.cmd.player.gdata.battles.BattleListEntry; import com.deepclone.lw.cmd.player.gdata.battles.BattleListEntry;
import com.deepclone.lw.cmd.player.gdata.empire.OverviewData; import com.deepclone.lw.cmd.player.gdata.empire.OverviewData;
import com.deepclone.lw.cmd.player.gdata.empire.ResearchLineData;
import com.deepclone.lw.cmd.player.gdata.empire.TechnologyData;
import com.deepclone.lw.interfaces.acm.UsersDAO; import com.deepclone.lw.interfaces.acm.UsersDAO;
import com.deepclone.lw.interfaces.game.BattlesCache; import com.deepclone.lw.interfaces.game.BattlesCache;
import com.deepclone.lw.interfaces.game.BattlesDAO; import com.deepclone.lw.interfaces.game.BattlesDAO;
import com.deepclone.lw.interfaces.game.EmpireDAO; import com.deepclone.lw.interfaces.game.EmpireDAO;
import com.deepclone.lw.interfaces.game.EmpireManagement; import com.deepclone.lw.interfaces.game.EmpireManagement;
import com.deepclone.lw.interfaces.i18n.LanguageTranslator;
import com.deepclone.lw.interfaces.i18n.Translator;
import com.deepclone.lw.interfaces.i18n.UnknownLanguageException;
import com.deepclone.lw.interfaces.naming.NamingDAO; import com.deepclone.lw.interfaces.naming.NamingDAO;
import com.deepclone.lw.interfaces.prefs.AccountPreferences; import com.deepclone.lw.interfaces.prefs.AccountPreferences;
import com.deepclone.lw.interfaces.prefs.PreferencesDAO; import com.deepclone.lw.interfaces.prefs.PreferencesDAO;
import com.deepclone.lw.sqld.accounts.Account; import com.deepclone.lw.sqld.accounts.Account;
import com.deepclone.lw.sqld.game.EmpireTechLine;
import com.deepclone.lw.sqld.game.EmpireTechnology;
import com.deepclone.lw.sqld.game.GeneralInformation; import com.deepclone.lw.sqld.game.GeneralInformation;
import com.deepclone.lw.sqld.game.battle.BattleListRecord; import com.deepclone.lw.sqld.game.battle.BattleListRecord;
import com.deepclone.lw.utils.EmailAddress; import com.deepclone.lw.utils.EmailAddress;
@ -46,6 +45,7 @@ public class EmpireManagementBean
private EmpireDAO empireDao; private EmpireDAO empireDao;
private PreferencesDAO prefsDao; private PreferencesDAO prefsDao;
private BattlesDAO battlesDao; private BattlesDAO battlesDao;
private Translator translator;
@Autowired( required = true ) @Autowired( required = true )
@ -83,6 +83,13 @@ public class EmpireManagementBean
} }
@Autowired( required = true )
public void setI18NManager( Translator translator )
{
this.translator = translator;
}
@Override @Override
public Integer getEmpireId( EmailAddress address ) public Integer getEmpireId( EmailAddress address )
{ {
@ -108,29 +115,22 @@ public class EmpireManagementBean
} }
@Override
public LanguageTranslator getTranslator( int empireId )
{
GeneralInformation generalInformation = this.empireDao.getInformation( empireId );
try {
return this.translator.getLanguageTranslator( generalInformation.getLanguage( ) );
} catch ( UnknownLanguageException e ) {
throw new RuntimeException( "account for empire " + empireId + " is using an unsupported language" , e );
}
}
@Override @Override
public EmpireResponse getOverview( int empireId ) public EmpireResponse getOverview( int empireId )
{ {
OverviewData overview = this.empireDao.getOverview( empireId ); OverviewData overview = this.empireDao.getOverview( empireId );
List< ResearchLineData > research = new LinkedList< ResearchLineData >( );
for ( EmpireTechLine etl : this.empireDao.getTechnology( empireId ) ) {
List< TechnologyData > implemented = new LinkedList< TechnologyData >( );
TechnologyData current = null;
for ( EmpireTechnology et : etl.getTechnologies( ) ) {
if ( et.isImplemented( ) ) {
implemented.add( new TechnologyData( et.getName( ) , et.getDescription( ) ) );
} else if ( et.getProgress( ) == 100 ) {
current = new TechnologyData( et.getName( ) , et.getDescription( ) , 100 , et.getCost( ) );
} else {
current = new TechnologyData( et.getName( ) , et.getDescription( ) , et.getProgress( ) );
}
}
research.add( new ResearchLineData( etl.getId( ) , etl.getName( ) , etl.getDescription( ) , implemented ,
current ) );
}
List< BattleListEntry > battles = new LinkedList< BattleListEntry >( ); List< BattleListEntry > battles = new LinkedList< BattleListEntry >( );
for ( BattleListRecord record : this.battlesDao.getBattles( empireId ) ) { for ( BattleListRecord record : this.battlesDao.getBattles( empireId ) ) {
@ -150,15 +150,7 @@ public class EmpireManagementBean
battles.add( entry ); battles.add( entry );
} }
return new EmpireResponse( this.getGeneralInformation( empireId ) , overview , research , battles ); return new EmpireResponse( this.getGeneralInformation( empireId ) , overview , battles );
}
@Override
public EmpireResponse implementTechnology( int empireId , int techId )
{
this.empireDao.implementTechnology( empireId , techId );
return this.getOverview( empireId );
} }

View file

@ -1,138 +0,0 @@
package com.deepclone.lw.beans.updates;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.deepclone.lw.cmd.admin.logs.LogLevel;
import com.deepclone.lw.interfaces.eventlog.Logger;
import com.deepclone.lw.interfaces.eventlog.SystemLogger;
import com.deepclone.lw.interfaces.game.UpdatesDAO;
import com.deepclone.lw.interfaces.sys.MaintenanceStatusException;
import com.deepclone.lw.interfaces.sys.SystemStatus;
import com.deepclone.lw.interfaces.sys.TickStatusException;
import com.deepclone.lw.interfaces.sys.Ticker;
import com.deepclone.lw.interfaces.sys.Ticker.Frequency;
public class GameUpdateBean
implements InitializingBean , Runnable
{
private Ticker ticker;
private SystemStatus systemStatus;
private SystemLogger logger;
private TransactionTemplate tTemplate;
private UpdatesDAO updatesDao;
@Autowired( required = true )
public void setTicker( Ticker ticker )
{
this.ticker = ticker;
}
@Autowired( required = true )
public void setSystemStatus( SystemStatus systemStatus )
{
this.systemStatus = systemStatus;
}
@Autowired( required = true )
public void setLogger( Logger logger )
{
this.logger = logger.getSystemLogger( "GameUpdate" );
}
@Autowired( required = true )
public void setTransactionManager( PlatformTransactionManager transactionManager )
{
this.tTemplate = new TransactionTemplate( transactionManager );
}
@Autowired( required = true )
public void setUpdatesDAO( UpdatesDAO updatesDao )
{
this.updatesDao = updatesDao;
}
@Override
public void afterPropertiesSet( )
{
try {
this.endPreviousTick( );
} catch ( MaintenanceStatusException e ) {
// Do nothing
}
this.ticker.registerTask( Frequency.MINUTE , "Game update" , this );
}
@Override
public void run( )
{
// Attempt to end the previous tick, if e.g. maintenance mode was initiated while it was
// being processed
try {
this.endPreviousTick( );
} catch ( MaintenanceStatusException e1 ) {
return;
}
// Initiate next tick
long tickId;
try {
tickId = this.systemStatus.startTick( );
} catch ( TickStatusException e ) {
throw new RuntimeException( "tick initiated while previous tick still being processed" , e );
} catch ( MaintenanceStatusException e ) {
return;
}
// Execute tick
this.logger.log( LogLevel.DEBUG , "Tick " + tickId + " started" ).flush( );
this.executeTick( tickId );
}
private void endPreviousTick( )
throws MaintenanceStatusException
{
Long currentTick = this.systemStatus.checkStuckTick( );
if ( currentTick == null ) {
return;
}
this.logger.log( LogLevel.WARNING , "Tick " + currentTick + " restarted" ).flush( );
this.executeTick( currentTick.longValue( ) );
}
private void executeTick( final long tickId )
{
boolean hasMore;
do {
hasMore = this.tTemplate.execute( new TransactionCallback< Boolean >( ) {
@Override
public Boolean doInTransaction( TransactionStatus status )
{
return updatesDao.processUpdates( tickId );
}
} );
} while ( hasMore );
this.logger.log( LogLevel.TRACE , "Tick " + tickId + " completed" ).flush( );
}
}

View file

@ -1,43 +0,0 @@
package com.deepclone.lw.beans.updates;
import java.sql.Types;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import com.deepclone.lw.interfaces.game.UpdatesDAO;
public class UpdatesDAOBean
implements UpdatesDAO
{
private SimpleJdbcCall process;
@Autowired( required = true )
public void setDataSource( DataSource dataSource )
{
this.process = new SimpleJdbcCall( dataSource );
this.process.withCatalogName( "sys" ).withFunctionName( "process_updates" );
this.process.withoutProcedureColumnMetaDataAccess( );
this.process.addDeclaredParameter( new SqlParameter( "tick_id" , Types.BIGINT ) );
this.process.addDeclaredParameter( new SqlOutParameter( "has_more" , Types.BOOLEAN ) );
}
@Override
public boolean processUpdates( long tickId )
{
Map< String , Object > m = this.process.execute( tickId );
return (Boolean) m.get( "has_more" );
}
}

View file

@ -10,13 +10,11 @@
<import resource="simple/empire-management-bean.xml" /> <import resource="simple/empire-management-bean.xml" />
<import resource="simple/fleet-management-bean.xml" /> <import resource="simple/fleet-management-bean.xml" />
<import resource="simple/fleets-dao-bean.xml" /> <import resource="simple/fleets-dao-bean.xml" />
<import resource="simple/game-update-bean.xml" />
<import resource="simple/map-viewer-bean.xml" /> <import resource="simple/map-viewer-bean.xml" />
<import resource="simple/message-beans.xml" /> <import resource="simple/message-beans.xml" />
<import resource="simple/planet-dao-bean.xml" /> <import resource="simple/planet-dao-bean.xml" />
<import resource="simple/planets-management-bean.xml" /> <import resource="simple/planets-management-bean.xml" />
<import resource="simple/universe-dao-bean.xml" /> <import resource="simple/universe-dao-bean.xml" />
<import resource="simple/universe-generator-bean.xml" /> <import resource="simple/universe-generator-bean.xml" />
<import resource="simple/updates-dao-bean.xml" />
</beans> </beans>

View file

@ -4,12 +4,12 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-system</artifactId> <artifactId>legacyworlds-server-beans-system</artifactId>
<version>5.99.1</version> <version>5.99.2</version>
<name>Legacy Worlds system management</name> <name>Legacy Worlds system management</name>
<description>This module regroups system management beans such as the constants manager.</description> <description>This module regroups system management beans such as the constants manager.</description>
</project> </project>

View file

@ -93,7 +93,7 @@ class ConstantsData
this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) ); this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) );
this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) ); this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) );
this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) ); this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) );
this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "value" , Types.REAL ) ); this.uocConstantNoBounds.addDeclaredParameter( new SqlParameter( "value" , Types.DOUBLE ) );
this.uocConstantSingleBound = new SimpleJdbcCall( dataSource ); this.uocConstantSingleBound = new SimpleJdbcCall( dataSource );
this.uocConstantSingleBound.withCatalogName( "sys" ).withFunctionName( "uoc_constant" ); this.uocConstantSingleBound.withCatalogName( "sys" ).withFunctionName( "uoc_constant" );
@ -101,8 +101,8 @@ class ConstantsData
this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) ); this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) );
this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) ); this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) );
this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) ); this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) );
this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "value" , Types.REAL ) ); this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "value" , Types.DOUBLE ) );
this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "boundary" , Types.REAL ) ); this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "boundary" , Types.DOUBLE ) );
this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "is_min" , Types.BOOLEAN ) ); this.uocConstantSingleBound.addDeclaredParameter( new SqlParameter( "is_min" , Types.BOOLEAN ) );
this.uocConstantTwoBounds = new SimpleJdbcCall( dataSource ); this.uocConstantTwoBounds = new SimpleJdbcCall( dataSource );
@ -111,13 +111,13 @@ class ConstantsData
this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) ); this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "cname" , Types.VARCHAR ) );
this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) ); this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "cdesc" , Types.VARCHAR ) );
this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) ); this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "catname" , Types.VARCHAR ) );
this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "value" , Types.REAL ) ); this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "value" , Types.DOUBLE ) );
this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "min" , Types.REAL ) ); this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "min" , Types.DOUBLE ) );
this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "max" , Types.REAL ) ); this.uocConstantTwoBounds.addDeclaredParameter( new SqlParameter( "max" , Types.DOUBLE ) );
this.fSetConstant = new StoredProc( dataSource , "sys" , "set_constant" ); this.fSetConstant = new StoredProc( dataSource , "sys" , "set_constant" );
this.fSetConstant.addParameter( "cname" , Types.VARCHAR ); this.fSetConstant.addParameter( "cname" , Types.VARCHAR );
this.fSetConstant.addParameter( "value" , Types.REAL ); this.fSetConstant.addParameter( "value" , Types.DOUBLE );
this.fSetConstant.addParameter( "admin" , Types.INTEGER ); this.fSetConstant.addParameter( "admin" , Types.INTEGER );
this.tTemplate = tTemplate; this.tTemplate = tTemplate;
@ -149,8 +149,8 @@ class ConstantsData
c.setName( rs.getString( "name" ) ); c.setName( rs.getString( "name" ) );
c.setDescription( rs.getString( "description" ) ); c.setDescription( rs.getString( "description" ) );
c.setValue( rs.getDouble( "value" ) ); c.setValue( rs.getDouble( "value" ) );
c.setMinValue( (Float) rs.getObject( "min" ) ); c.setMinValue( (Double) rs.getObject( "min" ) );
c.setMaxValue( (Float) rs.getObject( "max" ) ); c.setMaxValue( (Double) rs.getObject( "max" ) );
return c; return c;
} }
@ -609,7 +609,7 @@ class ConstantsData
@Override @Override
protected void doInTransactionWithoutResult( TransactionStatus status ) protected void doInTransactionWithoutResult( TransactionStatus status )
{ {
fSetConstant.execute( name , value.floatValue( ) , admin ); fSetConstant.execute( name , value , admin );
} }
} ); } );

View file

@ -1,8 +1,9 @@
package com.deepclone.lw.beans.sys; package com.deepclone.lw.beans.sys;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Set; import java.util.HashSet;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -92,9 +93,10 @@ public class ConstantsManagerBean
/* Documented in ConstantsManager interface */ /* Documented in ConstantsManager interface */
@Override @Override
public void registerUser( ConstantsUser user , Set< String > constants ) public void registerUser( ConstantsUser user , String... constants )
{ {
this.data.registerUser( user , constants ); HashSet< String > cSet = new HashSet< String >( Arrays.asList( constants ) );
this.data.registerUser( user , cSet );
} }
@ -112,4 +114,5 @@ public class ConstantsManagerBean
{ {
return new ConstantsAdministrationImpl( this.data , admin ); return new ConstantsAdministrationImpl( this.data , admin );
} }
} }

View file

@ -89,7 +89,7 @@ public class ConstantsRegistrarBean
// Work and income // Work and income
String[] wcNames = { String[] wcNames = {
"population" , "factory" , "strikeEffect" , "wuPerPopUnit" , "destructionRecovery" , "destructionWork" , "population" , "factory" , "strikeEffect" , "wuPerPopUnit" , "destructionRecovery" , "destructionWork" ,
"rpPerPopUnit" , "cancelRecovery" "cancelRecovery"
}; };
for ( int i = 0 ; i < wcNames.length ; i++ ) { for ( int i = 0 ; i < wcNames.length ; i++ ) {
wcNames[ i ] = "game.work." + wcNames[ i ]; wcNames[ i ] = "game.work." + wcNames[ i ];
@ -107,10 +107,8 @@ public class ConstantsRegistrarBean
defs.add( new ConstantDefinition( wcNames[ 4 ] , cat , cDesc , 0.1 , 0.01 , 0.99 ) ); defs.add( new ConstantDefinition( wcNames[ 4 ] , cat , cDesc , 0.1 , 0.01 , 0.99 ) );
cDesc = "Proportion of a building's construction work units required to destroy it"; cDesc = "Proportion of a building's construction work units required to destroy it";
defs.add( new ConstantDefinition( wcNames[ 5 ] , cat , cDesc , 0.25 , 0.01 , 1.0 ) ); defs.add( new ConstantDefinition( wcNames[ 5 ] , cat , cDesc , 0.25 , 0.01 , 1.0 ) );
cDesc = "Research points per population unit.";
defs.add( new ConstantDefinition( wcNames[ 6 ] , cat , cDesc , 0.50 , 0.01 , true ) );
cDesc = "Proportion of queue investments that is recovered when flushing the queue."; cDesc = "Proportion of queue investments that is recovered when flushing the queue.";
defs.add( new ConstantDefinition( wcNames[ 7 ] , cat , cDesc , 0.1 , 0.01 , 1.0 ) ); defs.add( new ConstantDefinition( wcNames[ 6 ] , cat , cDesc , 0.1 , 0.01 , 1.0 ) );
// Vacation mode // Vacation mode
cDesc = "Initial vacation credits."; cDesc = "Initial vacation credits.";
@ -172,29 +170,40 @@ public class ConstantsRegistrarBean
// Accounts - warnings // Accounts - warnings
cDesc = "Amount of warnings that triggers an automatic ban request."; cDesc = "Amount of warnings that triggers an automatic ban request.";
defs.add( new ConstantDefinition( "accounts.warnings.autoBan" , "Accounts - Warnings" , cDesc , 3.0 , 1.0 , true ) ); defs.add( new ConstantDefinition( "accounts.warnings.autoBan" , "Accounts - Warnings" , cDesc , 3.0 , 1.0 ,
true ) );
cDesc = "Period after a warning is received during which additional warnings will be ignored (seconds)."; cDesc = "Period after a warning is received during which additional warnings will be ignored (seconds).";
defs.add( new ConstantDefinition( "accounts.warnings.grace" , "Accounts - Warnings" , cDesc , 7200.0 , 60.0 , true ) ); defs.add( new ConstantDefinition( "accounts.warnings.grace" , "Accounts - Warnings" , cDesc , 7200.0 , 60.0 ,
true ) );
cDesc = "Time after which warnings are decreased (expressed in units as defined by a.w.expiration.units)."; cDesc = "Time after which warnings are decreased (expressed in units as defined by a.w.expiration.units).";
defs.add( new ConstantDefinition( "accounts.warnings.expiration" , "Accounts - Warnings" , cDesc , 60.0 , 1.0 , true ) ); defs.add( new ConstantDefinition( "accounts.warnings.expiration" , "Accounts - Warnings" , cDesc , 60.0 , 1.0 ,
true ) );
cDesc = "Units used to express warning expiration time (seconds)."; cDesc = "Units used to express warning expiration time (seconds).";
defs.add( new ConstantDefinition( "accounts.warnings.expiration.units" , "Accounts - Warnings" , cDesc , 86400.0 , 1.0 , true ) ); defs.add( new ConstantDefinition( "accounts.warnings.expiration.units" , "Accounts - Warnings" , cDesc ,
86400.0 , 1.0 , true ) );
// Account inactivity // Account inactivity
cDesc = "Time units (seconds)"; cDesc = "Time units (seconds)";
defs.add( new ConstantDefinition( "accounts.inactivity.units" , "Accounts - Inactivity" , cDesc , oneWeek , 3600.0 , true ) ); defs.add( new ConstantDefinition( "accounts.inactivity.units" , "Accounts - Inactivity" , cDesc , oneWeek ,
3600.0 , true ) );
cDesc = "Time after which the inactivity warning e-mail is to be sent, expressed using units defined by a.i.units."; cDesc = "Time after which the inactivity warning e-mail is to be sent, expressed using units defined by a.i.units.";
defs.add( new ConstantDefinition( "accounts.inactivity.warningMail" , "Accounts - Inactivity" , cDesc , 3.0 , 1.0 , true ) ); defs.add( new ConstantDefinition( "accounts.inactivity.warningMail" , "Accounts - Inactivity" , cDesc , 3.0 ,
1.0 , true ) );
cDesc = "Time between the inactivity warning e-mail and actual account deletion, expressed using units defined by a.i.units."; cDesc = "Time between the inactivity warning e-mail and actual account deletion, expressed using units defined by a.i.units.";
defs.add( new ConstantDefinition( "accounts.inactivity.deletion" , "Accounts - Inactivity" , cDesc , 1.0 , 1.0 , true ) ); defs.add( new ConstantDefinition( "accounts.inactivity.deletion" , "Accounts - Inactivity" , cDesc , 1.0 , 1.0 ,
true ) );
// Bug reports // Bug reports
cDesc = "Amount of credits granted for low priority bug reports."; cDesc = "Amount of credits granted for low priority bug reports.";
defs.add( new ConstantDefinition( "bugtracker.lowCredits" , "Bug tracking system" , cDesc , 1.0 , 1.0 , true ) ); defs.add( new ConstantDefinition( "bugtracker.lowCredits" , "Bug tracking system" , cDesc , 1.0 , 1.0 , true ) );
cDesc = "Amount of credits granted for normal bug reports."; cDesc = "Amount of credits granted for normal bug reports.";
defs.add( new ConstantDefinition( "bugtracker.mediumCredits" , "Bug tracking system" , cDesc , 2.0 , 1.0 , true ) ); defs
.add( new ConstantDefinition( "bugtracker.mediumCredits" , "Bug tracking system" , cDesc , 2.0 , 1.0 ,
true ) );
cDesc = "Amount of credits granted for critical bug reports."; cDesc = "Amount of credits granted for critical bug reports.";
defs.add( new ConstantDefinition( "bugtracker.highCredits" , "Bug tracking system" , cDesc , 3.0 , 1.0 , true ) ); defs
.add( new ConstantDefinition( "bugtracker.highCredits" , "Bug tracking system" , cDesc , 3.0 , 1.0 ,
true ) );
cm.registerConstants( defs ); cm.registerConstants( defs );
} }

View file

@ -10,8 +10,6 @@ import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
@ -44,13 +42,14 @@ public class SystemStatusBean
/** Current maintenance mode record */ /** Current maintenance mode record */
private MaintenanceData maintenance = null; private MaintenanceData maintenance = null;
private SimpleJdbcCall doStartTick;
private SimpleJdbcCall doCheckTick;
private StoredProc fEnterMaintenanceMode; private StoredProc fEnterMaintenanceMode;
private StoredProc fExtendMaintenanceMode; private StoredProc fExtendMaintenanceMode;
private StoredProc fExitMaintenanceMode; private StoredProc fExitMaintenanceMode;
private StoredProc fCheckTick;
private StoredProc fStartTick;
private StoredProc fEndTick;
@Autowired( required = true ) @Autowired( required = true )
public void setDataSource( DataSource dataSource ) public void setDataSource( DataSource dataSource )
@ -72,16 +71,14 @@ public class SystemStatusBean
this.fExitMaintenanceMode.addParameter( "admin_id" , Types.INTEGER ); this.fExitMaintenanceMode.addParameter( "admin_id" , Types.INTEGER );
this.fExitMaintenanceMode.addOutput( "success" , Types.BOOLEAN ); this.fExitMaintenanceMode.addOutput( "success" , Types.BOOLEAN );
this.doStartTick = new SimpleJdbcCall( dataSource ); this.fCheckTick = new StoredProc( dataSource , "sys" , "check_stuck_tick" );
this.doStartTick.withCatalogName( "sys" ).withFunctionName( "start_tick" ); this.fCheckTick.addOutput( "tick_id" , Types.BIGINT );
this.doStartTick.withoutProcedureColumnMetaDataAccess( );
this.doStartTick.addDeclaredParameter( new SqlOutParameter( "tick_id" , Types.BIGINT ) );
this.doCheckTick = new SimpleJdbcCall( dataSource ); this.fStartTick = new StoredProc( dataSource , "sys" , "start_tick" );
this.doCheckTick.withCatalogName( "sys" ).withFunctionName( "check_stuck_tick" ); this.fStartTick.addOutput( "tick_id" , Types.BIGINT );
this.doCheckTick.withoutProcedureColumnMetaDataAccess( );
this.doCheckTick.addDeclaredParameter( new SqlOutParameter( "tick_id" , Types.BIGINT ) );
this.fEndTick = new StoredProc( dataSource , "sys" , "end_tick" );
this.fEndTick.addParameter( "tick_id" , Types.BIGINT );
} }
@ -246,6 +243,31 @@ public class SystemStatusBean
} }
/* Documented in interface */
@Override
public Long checkStuckTick( )
throws MaintenanceStatusException
{
Long tid = this.tTemplate.execute( new TransactionCallback< Long >( ) {
@Override
public Long doInTransaction( TransactionStatus status )
{
Map< String , Object > m = fCheckTick.execute( );
loadStatus( );
return (Long) m.get( "tick_id" );
}
} );
if ( tid == null && this.maintenance != null ) {
throw new MaintenanceStatusException( this.maintenance );
}
return tid;
}
/* Documented in interface */ /* Documented in interface */
@Override @Override
synchronized public long startTick( ) synchronized public long startTick( )
@ -256,7 +278,7 @@ public class SystemStatusBean
@Override @Override
public Long doInTransaction( TransactionStatus status ) public Long doInTransaction( TransactionStatus status )
{ {
Map< String , Object > m = doStartTick.execute( ); Map< String , Object > m = fStartTick.execute( );
loadStatus( ); loadStatus( );
return (Long) m.get( "tick_id" ); return (Long) m.get( "tick_id" );
} }
@ -277,26 +299,28 @@ public class SystemStatusBean
/* Documented in interface */ /* Documented in interface */
@Override @Override
public Long checkStuckTick( ) public void endTick( )
throws MaintenanceStatusException throws TickStatusException , MaintenanceStatusException
{ {
Long tid = this.tTemplate.execute( new TransactionCallback< Long >( ) { if ( this.maintenance != null ) {
@Override
public Long doInTransaction( TransactionStatus status )
{
Map< String , Object > m = doCheckTick.execute( );
loadStatus( );
return (Long) m.get( "tick_id" );
}
} );
if ( tid == null && this.maintenance != null ) {
throw new MaintenanceStatusException( this.maintenance ); throw new MaintenanceStatusException( this.maintenance );
} }
return tid; final Long tid = this.status.getCurrentTick( );
if ( tid == null ) {
throw new TickStatusException( );
}
this.tTemplate.execute( new TransactionCallbackWithoutResult( ) {
@Override
protected void doInTransactionWithoutResult( TransactionStatus status )
{
fEndTick.execute( tid );
loadStatus( );
}
} );
} }
} }

View file

@ -1,9 +1,6 @@
package com.deepclone.lw.beans.sys; package com.deepclone.lw.beans.sys;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -101,9 +98,7 @@ public class TickerBean
this.mainThread = new TickerThread( this.logger , this.tickerManager ); this.mainThread = new TickerThread( this.logger , this.tickerManager );
// Register thread as a constants user // Register thread as a constants user
Set< String > use = new HashSet< String >( ); this.constantsManager.registerUser( this.mainThread , "ticker.interval" );
use.add( "ticker.interval" );
this.constantsManager.registerUser( this.mainThread , use );
} }

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>legacyworlds-server-beans-techs</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,6 @@
#Mon Mar 28 09:14:01 CEST 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6

View file

@ -0,0 +1,9 @@
#Mon Mar 28 09:13:56 CEST 2011
activeProfiles=
eclipse.preferences.version=1
fullBuildGoals=process-test-resources
includeModules=false
resolveWorkspaceProjects=true
resourceFilterGoals=process-resources resources\:testResources
skipCompilerPlugin=true
version=1

View file

@ -0,0 +1,15 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId>
<version>5.99.2</version>
</parent>
<groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-techs</artifactId>
<version>5.99.2</version>
<name>Legacy Worlds technology management</name>
<description>This package contains components which are used to manage technologies in LW games.</description>
</project>

View file

@ -0,0 +1,160 @@
package com.deepclone.lw.beans.techs;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import com.deepclone.lw.interfaces.game.techs.EmpireTechnologyDAO;
import com.deepclone.lw.sqld.game.techs.EmpireTechnology;
import com.deepclone.lw.utils.StoredProc;
/**
* Implementation the empire technology and research data access component.
*
* @author tseeker
*/
public class EmpireTechnologyDAOBean
implements EmpireTechnologyDAO
{
/** SQL query that reads the list of an empire's technologies */
private static final String qGetTechnologies = "SELECT * FROM emp.technologies_view WHERE empire = ?";
/** SQL query that executes the priorities update preparation function */
private static final String qStartPrioritiesUpdate = "SELECT emp.prepare_research_priorities_update( )";
/** SQL query that inserts research priority changes into the temporary table */
private static final String qUploadPriorities = "INSERT INTO research_priorities_updates ( technology , priority ) "
+ "VALUES ( ? , ? )";
/** Data source access component */
private SimpleJdbcTemplate dTemplate;
/** Row mapper for empire technologies */
private RowMapper< EmpireTechnology > mEmpireTechnology;
/** Wrapper for the stored procedure that implements technologies */
private StoredProc fImplementTech;
/** Wrapper for the stored procedure to apply research priority updates */
private StoredProc fApplyResearchPriorities;
/** Initialise the row mapper */
public EmpireTechnologyDAOBean( )
{
this.mEmpireTechnology = new RowMapper< EmpireTechnology >( ) {
@Override
public EmpireTechnology mapRow( ResultSet rs , int rowNum )
throws SQLException
{
int techId = rs.getInt( "technology_id" );
String techName = rs.getString( "technology" );
boolean detailed = rs.getBoolean( "detailed" );
Integer completion = (Integer) rs.getObject( "completion" );
Integer cost = (Integer) rs.getObject( "cost" );
Integer priority = (Integer) rs.getObject( "priority" );
EmpireTechnology result;
if ( !detailed ) {
result = new EmpireTechnology( techId * rs.getInt( "empire" ) , techName , completion , priority );
} else if ( completion != null ) {
result = new EmpireTechnology( techName , completion , priority );
} else if ( cost != null ) {
result = new EmpireTechnology( techName , cost );
} else {
result = new EmpireTechnology( techName );
}
return result;
}
};
}
/**
* Dependency injector that initialises the database access component and stored procedure
* wrappers.
*
* @param dataSource
* the data source
*/
@Autowired( required = true )
public void setDataSource( DataSource dataSource )
{
this.dTemplate = new SimpleJdbcTemplate( dataSource );
// Stored procedure for technology implementation
this.fImplementTech = new StoredProc( dataSource , "emp" , "implement_tech" );
this.fImplementTech.addParameter( "empire_id" , Types.INTEGER );
this.fImplementTech.addParameter( "technology" , Types.VARCHAR );
this.fImplementTech.addOutput( "error_code" , Types.INTEGER );
// Stored procedure to apply research priority updates
this.fApplyResearchPriorities = new StoredProc( dataSource , "emp" , "apply_research_priorities" );
this.fApplyResearchPriorities.addParameter( "empire_id" , Types.INTEGER );
this.fApplyResearchPriorities.addOutput( "error_code" , Types.INTEGER );
}
/* Documentation in EmpireTechnologyDAO interface */
@Override
public List< EmpireTechnology > getTechnologies( int empireId )
{
return this.dTemplate.query( qGetTechnologies , this.mEmpireTechnology , empireId );
}
/* Documentation in EmpireTechnologyDAO interface */
@Override
public int implementTechnology( int empireId , String technology )
{
return (Integer) this.fImplementTech.execute( empireId , technology ).get( "error_code" );
}
/* Documentation in EmpireTechnologyDAO interface */
@Override
public void startPrioritiesUpdate( )
{
this.dTemplate.queryForList( qStartPrioritiesUpdate );
}
/* Documentation in EmpireTechnologyDAO interface */
@Override
public void uploadPriorities( Map< String , Integer > priorities )
{
List< Object[] > batch = new ArrayList< Object[] >( priorities.size( ) );
int counter = 0;
for ( Entry< String , Integer > entry : priorities.entrySet( ) ) {
Object[] values = new Object[] {
entry.getKey( ) , entry.getValue( )
};
batch.add( counter++ , values );
}
this.dTemplate.batchUpdate( qUploadPriorities , batch );
}
/* Documentation in EmpireTechnologyDAO interface */
@Override
public int finishPrioritiesUpdate( int empireId )
{
return (Integer) this.fApplyResearchPriorities.execute( empireId ).get( "error_code" );
}
}

View file

@ -0,0 +1,181 @@
package com.deepclone.lw.beans.techs;
import java.util.Arrays;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import com.deepclone.lw.cmd.player.research.ResearchOperationResponse;
import com.deepclone.lw.cmd.player.research.ViewResearchResponse;
import com.deepclone.lw.interfaces.game.EmpireManagement;
import com.deepclone.lw.interfaces.game.techs.EmpireTechnologyDAO;
import com.deepclone.lw.interfaces.game.techs.EmpireTechnologyManager;
import com.deepclone.lw.interfaces.game.techs.TechnologyGraphManager;
import com.deepclone.lw.interfaces.sys.ConstantDefinition;
import com.deepclone.lw.interfaces.sys.ConstantsManager;
/**
* Implementation of the empire technology and research management component.
*
* @author tseeker
*/
@Transactional
public class EmpireTechnologyManagerBean
implements EmpireTechnologyManager
{
/** Empire management component */
private EmpireManagement empireManager;
/** Data access component for empire technologies and research */
private EmpireTechnologyDAO empireTechnologyDAO;
/** Technology graph management component */
private TechnologyGraphManager techGraphManager;
/**
* Dependency injector for the empire management component.
*
* @param empireManager
* the empire management component
*/
@Autowired( required = true )
public void setEmpireManager( EmpireManagement empireManager )
{
this.empireManager = empireManager;
}
/**
* Dependency injector for the data access component for empire technologies and research
*
* @param empireTechnologyDAO
* data access component for empire technologies and research
*/
@Autowired( required = true )
public void setEmpireTechnologyDAO( EmpireTechnologyDAO empireTechnologyDAO )
{
this.empireTechnologyDAO = empireTechnologyDAO;
}
/**
* Dependency injector for the technology graph management component.
*
* @param techGraphManager
* the technology graph management component
*/
@Autowired( required = true )
public void setTechnologyGraphManager( TechnologyGraphManager techGraphManager )
{
this.techGraphManager = techGraphManager;
}
/**
* Dependency injector which registers research-related constants into the constants manager.
*
* @param constantsManager
* the constants manager component
*/
@Autowired( required = true )
public void setConstantsManager( ConstantsManager constantsManager )
{
ConstantDefinition[] definitions = new ConstantDefinition[] {
new ConstantDefinition( "game.research.minPoints" , "Research" ,
"Minimal research points before a technology being researched is identified" , 50000.0 , 1.0 ,
true ) ,
new ConstantDefinition( "game.research.minRatio" , "Research" ,
"Minimal ratio before a technology being researched is identified" , 0.75 , 0.01 , 0.99 ) ,
new ConstantDefinition( "game.research.perPopUnit" , "Research" ,
"Research points per population unit." , 0.50 , 0.01 , true )
};
constantsManager.registerConstants( Arrays.asList( definitions ) );
}
/* Documentation in EmpireTechnologyManager interface */
@Override
public ViewResearchResponse getResearchData( int empireId )
{
return new ResearchResponseBuilder( empireId , this.empireManager , this.empireTechnologyDAO ,
this.techGraphManager ).getResponse( );
}
/* Documentation in EmpireTechnologyManager interface */
@Override
public ResearchOperationResponse implementTechnology( int empireId , String technology )
{
int result = this.empireTechnologyDAO.implementTechnology( empireId , technology );
ResearchOperationResponse response;
if ( result == 0 ) {
response = new ResearchOperationResponse( );
} else {
ResearchResponseBuilder builder = new ResearchResponseBuilder( empireId , this.empireManager ,
this.empireTechnologyDAO , this.techGraphManager );
switch ( result ) {
case 1:
response = builder.getResponse( ResearchOperationResponse.Result.ERR_RESOURCES );
break;
case 2:
response = builder.getResponse( ResearchOperationResponse.Result.ERR_STATE_CHANGED );
break;
default:
throw new RuntimeException( "unsupported return value " + result );
}
}
return response;
}
/* Documentation in EmpireTechnologyManager interface */
@Override
public ResearchOperationResponse setResearchPriorities( int empireId , Map< String , Integer > priorities )
{
int result;
if ( priorities.size( ) < 2 ) {
result = 2;
} else {
this.empireTechnologyDAO.startPrioritiesUpdate( );
this.empireTechnologyDAO.uploadPriorities( priorities );
result = this.empireTechnologyDAO.finishPrioritiesUpdate( empireId );
}
ResearchOperationResponse response;
if ( result == 0 ) {
response = new ResearchOperationResponse( );
} else {
ResearchResponseBuilder builder = new ResearchResponseBuilder( empireId , this.empireManager ,
this.empireTechnologyDAO , this.techGraphManager );
switch ( result ) {
case 1:
response = builder.getResponse( ResearchOperationResponse.Result.ERR_STATE_CHANGED );
break;
case 2:
response = builder.getResponse( ResearchOperationResponse.Result.ERR_INVALID );
break;
default:
throw new RuntimeException( "unsupported return value " + result );
}
}
return response;
}
}

View file

@ -0,0 +1,293 @@
package com.deepclone.lw.beans.techs;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.deepclone.lw.cmd.admin.logs.LogLevel;
import com.deepclone.lw.interfaces.eventlog.SystemLogger;
import com.deepclone.lw.sqld.game.techs.ResearchStatus;
import com.deepclone.lw.sqld.game.techs.ResearchUpdateInput;
import com.deepclone.lw.sqld.game.techs.ResearchUpdateOutput;
import com.deepclone.lw.sqld.game.techs.TechGraph;
import com.deepclone.lw.sqld.game.techs.TechGraphException;
import com.deepclone.lw.sqld.game.techs.Technology;
/**
* Research update implementation for a single empire.
*
* @author tseeker
*/
class EmpireUpdate
{
/** Empire identifier */
private final int id;
/** Research points produced */
private double production;
/** All technologies (known or being researched) */
private final Map< String , ResearchUpdateInput > byName;
/** Technology names by status */
private final Map< ResearchStatus , Set< String >> byStatus;
/** Output records by name */
private final Map< String , ResearchUpdateOutput > output;
/** Sum of the current research priorities */
private double totalPriority;
/** Amount of active research topics */
private int activeTopics;
/** Parent component's logging interface */
private SystemLogger logger;
/**
* Initialise the empire updater using the global lists of production points and research
* statuses.
*
* @param logger
* the component's logging system
* @param empireId
* the empire for whom the research update is to be computed
* @param production
* the map of production points for all empires in the batch
* @param status
* the list of statuses for all empires in the batch
*/
EmpireUpdate( SystemLogger logger , int empireId , Map< Integer , Double > production ,
HashMap< Integer , List< ResearchUpdateInput >> status )
{
this.id = empireId;
this.production = production.get( this.id );
this.logger = logger;
this.byName = new HashMap< String , ResearchUpdateInput >( );
this.output = new HashMap< String , ResearchUpdateOutput >( );
this.byStatus = new EnumMap< ResearchStatus , Set< String > >( ResearchStatus.class );
this.byStatus.put( ResearchStatus.IN_PROGRESS , new HashSet< String >( ) );
this.byStatus.put( ResearchStatus.RESEARCHED , new HashSet< String >( ) );
this.byStatus.put( ResearchStatus.IMPLEMENTED , new HashSet< String >( ) );
// Initialise sets and maps
List< ResearchUpdateInput > empStatus = status.get( this.id );
if ( empStatus != null ) {
for ( ResearchUpdateInput entry : status.get( this.id ) ) {
this.byName.put( entry.getTechnology( ) , entry );
this.byStatus.get( entry.getStatus( ) ).add( entry.getTechnology( ) );
}
this.logger.flush( );
}
}
/**
* Perform the research update, filling the {@link #output} map.
*
* @param techGraph
* the technology graph
* @throws TechGraphException
* indicates an internal error
*/
void compute( TechGraph techGraph )
throws TechGraphException
{
if ( this.production == 0 ) {
return;
}
this.prepareOutput( );
List< Technology > newResearch = this.findNewTechnologies( techGraph );
if ( !newResearch.isEmpty( ) ) {
this.addResearch( newResearch );
}
if ( this.output.isEmpty( ) ) {
return;
}
List< String > inProgress = new LinkedList< String >( this.output.keySet( ) );
for ( String resName : inProgress ) {
this.researchProgress( techGraph.getTechnology( resName ) , resName );
}
this.updatePriorities( );
}
/**
* Copy information from the list of research to the output map.
*/
private void prepareOutput( )
{
this.totalPriority = 0;
for ( ResearchUpdateInput entry : this.byName.values( ) ) {
if ( entry.getStatus( ) != ResearchStatus.IN_PROGRESS ) {
continue;
}
this.output.put( entry.getTechnology( ) , new ResearchUpdateOutput( this.id , entry.getTechnology( ) ,
false , entry.getPoints( ) , entry.getPriority( ) ) );
this.totalPriority += entry.getPriority( );
}
this.activeTopics = this.byStatus.get( ResearchStatus.IN_PROGRESS ).size( );
}
/**
* Find new technologies to research
*
* XXX: we shouldn't be doing that at every update; it's only required if the techs were added
* or deleted, if dependencies were changed or if the empire implemented a technology.
*
* @param techGraph
* the technology graph
* @return the list of technologies on which research can start
* @throws TechGraphException
* indicates an internal error
*/
private List< Technology > findNewTechnologies( TechGraph techGraph )
throws TechGraphException
{
LinkedList< Technology > newResearch = new LinkedList< Technology >( );
Set< String > implemented = this.byStatus.get( ResearchStatus.IMPLEMENTED );
if ( implemented == null ) {
throw new RuntimeException( "wtf?!" );
}
for ( String catName : techGraph.getCategories( ) ) {
for ( String techName : techGraph.getCategory( catName ).getTechnologies( ) ) {
// Check if the empire "knows" of the tech
if ( this.byName.containsKey( techName ) ) {
continue;
}
// Check dependencies
Technology tech = techGraph.getTechnology( techName );
boolean mayStart = true;
for ( String depName : tech.getDependencies( ) ) {
if ( !implemented.contains( depName ) ) {
mayStart = false;
break;
}
}
if ( mayStart ) {
newResearch.add( tech );
}
}
}
return newResearch;
}
/**
* Add new entries to the list of current research topics and updates the total priority
* accordingly.
*
* @param newResearch
* the list of research topics to add
*/
private void addResearch( List< Technology > newResearch )
{
int increment;
if ( this.totalPriority == 0 ) {
increment = 1;
} else {
increment = (int) Math.ceil( this.totalPriority / this.activeTopics );
}
for ( Technology tech : newResearch ) {
this.output.put( tech.getName( ) , new ResearchUpdateOutput( this.id , tech.getName( ) , true , 0 ,
increment ) );
this.totalPriority += increment;
}
this.activeTopics += newResearch.size( );
}
/**
* Update the progress on a research topic.
*
* @param technology
* the technology's definition
* @param name
* the name of the research topic
*/
private void researchProgress( Technology technology , String name )
{
ResearchUpdateOutput entry = this.output.get( name );
if ( entry.getPriority( ) == 0 ) {
return;
}
double points = this.production * entry.getPriority( ) / this.totalPriority;
double total = points + entry.getPoints( );
if ( total >= technology.getPoints( ) ) {
this.totalPriority -= entry.getPriority( );
this.production = this.production + total - entry.getPoints( );
this.output.put( name , new ResearchUpdateOutput( this.id , name ) );
this.activeTopics--;
} else {
entry.addPoints( points );
}
}
/**
* Update priorities of active research topics in the output map.
*/
private void updatePriorities( )
{
if ( this.activeTopics == 0 || this.totalPriority == 100 ) {
return;
}
List< ResearchUpdateOutput > progress = new LinkedList< ResearchUpdateOutput >( );
int newTotal = 0;
for ( ResearchUpdateOutput update : this.output.values( ) ) {
Integer prio = update.getPriority( );
if ( prio == null ) {
continue;
}
int newValue = (int) Math.floor( 100.0 * prio / this.totalPriority );
progress.add( update );
update.setPriority( newValue );
newTotal += newValue;
}
// Distribute the rest of the points
while ( newTotal < 100 ) {
for ( ResearchUpdateOutput update : progress ) {
update.setPriority( update.getPriority( ) + 1 );
newTotal++;
if ( newTotal == 100 ) {
break;
}
}
}
this.logger.flush( );
}
/** @return the update output records */
Collection< ResearchUpdateOutput > getOutput( )
{
if ( !this.output.isEmpty( ) ) {
this.logger.log( LogLevel.TRACE , "Empire " + this.id + " - " + this.output.size( ) + " update(s)" )
.flush( );
}
return this.output.values( );
}
}

View file

@ -0,0 +1,280 @@
package com.deepclone.lw.beans.techs;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.deepclone.lw.cmd.player.gdata.GamePageData;
import com.deepclone.lw.cmd.player.gdata.empire.ResearchData;
import com.deepclone.lw.cmd.player.gdata.empire.TechnologyCategoryData;
import com.deepclone.lw.cmd.player.gdata.empire.TechnologyData;
import com.deepclone.lw.cmd.player.research.ResearchOperationResponse;
import com.deepclone.lw.cmd.player.research.ViewResearchResponse;
import com.deepclone.lw.cmd.player.research.ResearchOperationResponse.Result;
import com.deepclone.lw.interfaces.game.EmpireManagement;
import com.deepclone.lw.interfaces.game.techs.EmpireTechnologyDAO;
import com.deepclone.lw.interfaces.game.techs.TechnologyGraphManager;
import com.deepclone.lw.interfaces.i18n.LanguageTranslator;
import com.deepclone.lw.interfaces.i18n.UnknownStringException;
import com.deepclone.lw.sqld.game.techs.Category;
import com.deepclone.lw.sqld.game.techs.EmpireTechnology;
import com.deepclone.lw.sqld.game.techs.ResearchStatus;
import com.deepclone.lw.sqld.game.techs.TechGraph;
import com.deepclone.lw.sqld.game.techs.TechGraphException;
import com.deepclone.lw.sqld.game.techs.Technology;
/**
* Class that builds {@link ViewResearchResponse} or {@link ResearchOperationResponse} instances.
*
* @author tseeker
*/
class ResearchResponseBuilder
{
/** Empire identifier */
private final int empireId;
/** Empire management component */
private final EmpireManagement empireManager;
/** Technology and research data access component */
private final EmpireTechnologyDAO empireTechnologyDAO;
/** Technology graph management component */
private final TechnologyGraphManager techGraphManager;
/** Game page data */
private GamePageData pageData;
/** List of current research topics */
private List< ResearchData > research;
/** Lists of implemented technologies by category */
private Map< String , List< TechnologyData > > implementedMap;
/** Final list of implemented technologies */
private List< TechnologyCategoryData > implementedLists;
/** All implemented technologies by identifier */
private Map< String , TechnologyData > implementedById;
/**
* Initialise the response builder by setting the empire identifier and the various components
* that may be required to generate the response.
*
* @param empireId
* the empire identifier
* @param empireManager
* the empire management component
* @param empireTechnologyDAO
* the technology and research data access component
* @param techGraphManager
* the technology graph management component
*/
ResearchResponseBuilder( int empireId , EmpireManagement empireManager , EmpireTechnologyDAO empireTechnologyDAO ,
TechnologyGraphManager techGraphManager )
{
this.empireId = empireId;
this.empireManager = empireManager;
this.empireTechnologyDAO = empireTechnologyDAO;
this.techGraphManager = techGraphManager;
}
/**
* Build a basic research view response.
*
* @return the research view response.
*/
ViewResearchResponse getResponse( )
{
try {
this.buildResponseContents( );
} catch ( Exception e ) {
throw new RuntimeException( "internal error while processing research data" , e );
}
return new ViewResearchResponse( this.pageData , this.research , this.implementedLists );
}
/**
* Build a research operation response.
*
* @param errorCode
* the operation's error code (should not be
* {@link ResearchOperationResponse.Result#OK}).
* @return the research operation response.
*/
ResearchOperationResponse getResponse( Result errorCode )
{
try {
this.buildResponseContents( );
} catch ( Exception e ) {
throw new RuntimeException( "internal error while processing research data" , e );
}
return new ResearchOperationResponse( this.pageData , this.research , this.implementedLists , errorCode );
}
/**
* Build the lists and records required by research view or operation responses. This includes
* the list of current research topics as well as the list of implemented technologies.
*
* @throws UnknownStringException
* if there is an incoherence between the tech graph and the translations database.
* @throws TechGraphException
* if there is an incoherence between the empire research records and the tech
* graph.
*/
private void buildResponseContents( )
throws UnknownStringException , TechGraphException
{
LanguageTranslator translator = this.empireManager.getTranslator( this.empireId );
TechGraph techGraph = this.techGraphManager.getGraph( );
this.research = new LinkedList< ResearchData >( );
this.implementedMap = new HashMap< String , List< TechnologyData > >( );
this.implementedById = new HashMap< String , TechnologyData >( );
for ( EmpireTechnology record : this.empireTechnologyDAO.getTechnologies( this.empireId ) ) {
if ( record.getStatus( ) == ResearchStatus.IMPLEMENTED ) {
this.addImplemented( record , translator , techGraph );
} else {
this.addResearchData( record , translator , techGraph );
}
}
this.pageData = this.empireManager.getGeneralInformation( this.empireId );
Collections.sort( this.research );
this.postProcessImplemented( translator , techGraph );
}
/**
* Add an implemented technology record.
*
* @param record
* the original record as returned by the {@link EmpireTechnologyDAO}.
* @param translator
* the translator for the empire's language
* @param techGraph
* the technology graph
*
* @throws TechGraphException
* if there is an incoherence between the empire research records and the tech
* graph.
* @throws UnknownStringException
* if there is an incoherence between the tech graph and the translations database.
*/
private void addImplemented( EmpireTechnology record , LanguageTranslator translator , TechGraph techGraph )
throws TechGraphException , UnknownStringException
{
String techId = record.getIdentifier( );
Technology tech = techGraph.getTechnology( techId );
Category category = tech.getCategory( );
List< TechnologyData > catTechs = this.implementedMap.get( category.getName( ) );
if ( catTechs == null ) {
catTechs = new LinkedList< TechnologyData >( );
this.implementedMap.put( category.getName( ) , catTechs );
}
TechnologyData tData;
String name = translator.translate( techId );
String description = translator.translate( tech.getDescription( ) );
tData = new TechnologyData( techId , name , description , tech.getDependencies( ) , new LinkedList< String >( ) );
catTechs.add( tData );
this.implementedById.put( techId , tData );
}
/**
* Add a research topic record.
*
* @param record
* the original record as returned by the {@link EmpireTechnologyDAO}.
* @param translator
* the translator for the empire's language
* @param techGraph
* the technology graph
*
* @throws TechGraphException
* if there is an incoherence between the empire research records and the tech
* graph.
* @throws UnknownStringException
* if there is an incoherence between the tech graph and the translations database.
*/
private void addResearchData( EmpireTechnology record , LanguageTranslator translator , TechGraph techGraph )
throws TechGraphException , UnknownStringException
{
String techId = record.getIdentifier( );
Technology tech = techGraph.getTechnology( techId );
String category = translator.translate( tech.getCategory( ).getName( ) );
ResearchData rData;
if ( !record.isDetailed( ) ) {
rData = new ResearchData( record.getNumericId( ) , category , record.getPercentage( ) , record
.getPriority( ) );
} else {
String name = translator.translate( techId );
String description = translator.translate( tech.getDescription( ) );
String[] dependencies = tech.getDependencies( ).toArray( new String[] { } );
if ( record.getStatus( ) == ResearchStatus.RESEARCHED ) {
rData = new ResearchData( techId , category , name , description , dependencies , (int) tech.getCost( ) );
} else {
rData = new ResearchData( techId , category , name , description , dependencies , record
.getPercentage( ) , record.getPriority( ) );
}
}
this.research.add( rData );
}
/**
* Post-process implemented technologies by adding reverse dependencies, sorting each list, and
* generating the sorted list of technology categories.
*
* @param translator
* the translator for the empire's language
* @param techGraph
* the technology graph
*
* @throws TechGraphException
* if there is an incoherence between the empire research records and the tech
* graph.
* @throws UnknownStringException
* if there is an incoherence between the tech graph and the translations database.
*/
private void postProcessImplemented( LanguageTranslator translator , TechGraph techGraph )
throws UnknownStringException , TechGraphException
{
this.implementedLists = new LinkedList< TechnologyCategoryData >( );
for ( String catId : this.implementedMap.keySet( ) ) {
List< TechnologyData > techs = this.implementedMap.get( catId );
for ( TechnologyData tData : techs ) {
for ( String dependency : tData.getDependsOn( ) ) {
TechnologyData depData = this.implementedById.get( dependency );
if ( depData != null ) {
depData.getDependencyOf( ).add( tData.getIdentifier( ) );
}
}
}
Collections.sort( techs );
String catName = translator.translate( catId );
String catDesc = translator.translate( techGraph.getCategory( catId ).getDescription( ) );
this.implementedLists.add( new TechnologyCategoryData( catName , catDesc , techs ) );
}
Collections.sort( this.implementedLists );
}
}

View file

@ -0,0 +1,180 @@
package com.deepclone.lw.beans.techs;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import com.deepclone.lw.interfaces.eventlog.Logger;
import com.deepclone.lw.interfaces.eventlog.SystemLogger;
import com.deepclone.lw.interfaces.game.techs.ResearchUpdateDAO;
import com.deepclone.lw.interfaces.game.techs.TechnologyGraphManager;
import com.deepclone.lw.interfaces.game.updates.GameUpdate;
import com.deepclone.lw.interfaces.game.updates.GameUpdatePhase;
import com.deepclone.lw.interfaces.game.updates.GameUpdatePhaseHandler;
import com.deepclone.lw.interfaces.game.updates.UpdatesDAO;
import com.deepclone.lw.sqld.game.techs.ResearchUpdateInput;
import com.deepclone.lw.sqld.game.techs.ResearchUpdateOutput;
import com.deepclone.lw.sqld.game.techs.TechGraph;
import com.deepclone.lw.sqld.game.techs.TechGraphException;
/**
* Component responsible for updating empires' research status.
*
* @author tseeker
*/
public class ResearchUpdateBean
implements GameUpdatePhaseHandler
{
/** The component's logging interface */
private SystemLogger logger;
/** The technology graph management component */
private TechnologyGraphManager techGraphManager;
/** The current technology graph */
private TechGraph techGraph;
/** The main game update data access component */
private UpdatesDAO updatesDAO;
/** The research updates data access component */
private ResearchUpdateDAO researchUpdateDAO;
/**
* Dependency injector that initialises the component's logging interface.
*
* @param logger
* the system logger
*/
@Autowired( required = true )
public void setLogger( Logger logger )
{
this.logger = logger.getSystemLogger( "ResearchUpdate" );
}
/**
* Dependency injector for the technology graph management component.
*
* @param techGraphManager
* the technology graph management component
*/
@Autowired( required = true )
public void setTechGraphManager( TechnologyGraphManager techGraphManager )
{
this.techGraphManager = techGraphManager;
}
/**
* Dependency injector that sets the main game update data access component.
*
* @param updatesDAO
* the main game update data access component
*/
@Autowired( required = true )
public void setUpdatesDAO( UpdatesDAO updatesDAO )
{
this.updatesDAO = updatesDAO;
}
/**
* Dependency injector that sets the research updates data access component
*
* @param researchUpdateDAO
* the research updates data access component
*/
@Autowired( required = true )
public void setResearchUpdateDAO( ResearchUpdateDAO researchUpdateDAO )
{
this.researchUpdateDAO = researchUpdateDAO;
}
/**
* Dependency injector that registers the handler with the main game update manager
*
* @param updateManager
* the game update manager
*/
@Autowired( required = true )
public void setUpdateManager( GameUpdate updateManager )
{
updateManager.registerHandler( this );
}
/* Documentation in GameUpdatePhaseHandler interface */
@Override
public GameUpdatePhase getPhase( )
{
return GameUpdatePhase.EMPIRE_RESEARCH;
}
/**
* Get a copy of the technology graph when the update phase starts.
*/
@Override
public void onPhaseStart( long updateId )
{
this.techGraph = this.techGraphManager.getGraph( );
}
/**
* If there are research updates left to process, lock the records, then obtain all relevant
* data, process each empire using {@link EmpireUpdate}, and send the updates to the database.
*/
@Override
public boolean updateGame( long updateId )
{
// Look for records to update
if ( !this.updatesDAO.prepareUpdates( updateId , this.getPhase( ) ) ) {
return false;
}
Map< Integer , Double > production;
HashMap< Integer , List< ResearchUpdateInput >> status;
status = new HashMap< Integer , List< ResearchUpdateInput > >( );
// Prepare update and load input
this.researchUpdateDAO.prepareUpdate( updateId );
production = this.researchUpdateDAO.getResearchPoints( updateId );
for ( ResearchUpdateInput input : this.researchUpdateDAO.getUpdateData( updateId ) ) {
List< ResearchUpdateInput > eStatus = status.get( input.getEmpireId( ) );
if ( eStatus == null ) {
eStatus = new LinkedList< ResearchUpdateInput >( );
status.put( input.getEmpireId( ) , eStatus );
}
eStatus.add( input );
}
// Handle the update for each empire
List< ResearchUpdateOutput > output = new LinkedList< ResearchUpdateOutput >( );
for ( int empireId : production.keySet( ) ) {
EmpireUpdate update = new EmpireUpdate( this.logger , empireId , production , status );
try {
update.compute( this.techGraph );
} catch ( TechGraphException e ) {
throw new RuntimeException( "incoherent technology graph" , e );
}
output.addAll( update.getOutput( ) );
}
// Send and validate updates
this.researchUpdateDAO.submitUpdateData( output );
this.updatesDAO.validateUpdatedRecords( updateId , GameUpdatePhase.EMPIRE_RESEARCH );
return true;
}
}

View file

@ -0,0 +1,138 @@
package com.deepclone.lw.beans.techs;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import com.deepclone.lw.interfaces.game.techs.ResearchUpdateDAO;
import com.deepclone.lw.sqld.game.techs.ResearchUpdateInput;
import com.deepclone.lw.sqld.game.techs.ResearchUpdateOutput;
import com.deepclone.lw.utils.StoredProc;
public class ResearchUpdateDAOBean
implements ResearchUpdateDAO
{
/** Query that reads research update input */
private static final String qGetInput = "SELECT * FROM emp.research_update_input_view WHERE update_id = ?";
/** Query that reads empire research points production */
private static final String qGetPoints = "SELECT * FROM emp.research_points_production WHERE update_id = ?";
/** Query that adds a record to the output */
private static final String qAddOutput = "INSERT INTO research_update_output "
+ "(empire_id , technology , creation , points , priority) "
+ "VALUES ( :empireId , :technology , :creation , :points , :priority )";
/** Query that submits the update */
private static final String qSubmitUpdate = "SELECT emp.submit_research_update( )";
/** Data source access */
private SimpleJdbcTemplate dTemplate;
/** Wrapper for the stored procedure that prepares the database for update */
private StoredProc fPrepareUpdate;
/** Row mapper for research update input */
RowMapper< ResearchUpdateInput > ruiMapper;
/**
* Initialise the component's row mapper.
*/
public ResearchUpdateDAOBean( )
{
this.ruiMapper = new RowMapper< ResearchUpdateInput >( ) {
@Override
public ResearchUpdateInput mapRow( ResultSet rs , int rowNum )
throws SQLException
{
int empireId = rs.getInt( "empire_id" );
String technology = rs.getString( "technology" );
Boolean implemented = (Boolean) rs.getObject( "implemented" );
if ( implemented == null ) {
double points = rs.getDouble( "points" );
int priority = rs.getInt( "priority" );
return new ResearchUpdateInput( empireId , technology , points , priority );
}
return new ResearchUpdateInput( empireId , technology , implemented );
}
};
}
/**
* Dependency injector that initialises the component's database access and stored procedure
* wrappers.
*
* @param dataSource
* the data source
*/
@Autowired( required = true )
public void setDataSource( DataSource dataSource )
{
this.dTemplate = new SimpleJdbcTemplate( dataSource );
// Stored procedure that prepares the database for update
this.fPrepareUpdate = new StoredProc( dataSource , "emp" , "prepare_research_update" );
this.fPrepareUpdate.addParameter( "update_id" , Types.BIGINT );
}
/* Documented in ResearchUpdateDAO interface */
@Override
public void prepareUpdate( long updateId )
{
this.fPrepareUpdate.execute( updateId );
}
/* Documented in ResearchUpdateDAO interface */
@Override
public List< ResearchUpdateInput > getUpdateData( long updateId )
{
return this.dTemplate.query( qGetInput , this.ruiMapper , updateId );
}
/* Documented in ResearchUpdateDAO interface */
@Override
public Map< Integer , Double > getResearchPoints( long updateId )
{
Map< Integer , Double > result = new HashMap< Integer , Double >( );
for ( Map< String , Object > row : this.dTemplate.queryForList( qGetPoints , updateId ) ) {
result.put( (Integer) row.get( "empire_id" ) , (Double) row.get( "points" ) );
}
return result;
}
/* Documented in ResearchUpdateDAO interface */
@Override
public void submitUpdateData( List< ResearchUpdateOutput > output )
{
if ( !output.isEmpty( ) ) {
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch( output.toArray( ) );
this.dTemplate.batchUpdate( qAddOutput , batch );
}
this.dTemplate.queryForList( qSubmitUpdate );
}
}

View file

@ -0,0 +1,134 @@
package com.deepclone.lw.beans.techs;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import com.deepclone.lw.interfaces.game.techs.TechnologyGraphDAO;
import com.deepclone.lw.sqld.game.techs.TechGraph;
import com.deepclone.lw.sqld.game.techs.TechGraphException;
public class TechnologyGraphDAOBean
implements TechnologyGraphDAO
{
private static final String qGetCategories = "SELECT name , description FROM tech.categories_view";
private static final String qGetTechnologies = "SELECT category , name , description , points , cost FROM tech.technologies_view";
private static final String qGetDependencies = "SELECT technology , dependency FROM tech.dependencies_view";
private static abstract class TechGraphDBHandler
implements RowCallbackHandler
{
TechGraph graph;
TechGraphException error;
public TechGraphDBHandler( )
{
// EMPTY
}
public final void setGraph( TechGraph graph )
{
this.graph = graph;
}
@Override
public final void processRow( ResultSet rs )
throws SQLException
{
if ( this.error != null ) {
return;
}
try {
this.extractData( rs );
} catch ( TechGraphException e ) {
this.error = e;
}
}
protected abstract void extractData( ResultSet rs )
throws TechGraphException , SQLException;
}
private static class CategoryExtractor
extends TechGraphDBHandler
{
@Override
protected void extractData( ResultSet rs )
throws TechGraphException , SQLException
{
this.graph.addCategory( rs.getString( "name" ) , rs.getString( "description" ) );
}
}
private static class TechnologyExtractor
extends TechGraphDBHandler
{
@Override
protected void extractData( ResultSet rs )
throws TechGraphException , SQLException
{
this.graph.addTechnology( rs.getString( "category" ) , rs.getString( "name" ) , rs
.getString( "description" ) , rs.getInt( "points" ) , rs.getInt( "cost" ) );
}
}
private static class DependencyExtractor
extends TechGraphDBHandler
{
@Override
protected void extractData( ResultSet rs )
throws TechGraphException , SQLException
{
this.graph.addDependency( rs.getString( "technology" ) , rs.getString( "dependency" ) );
}
}
private JdbcTemplate dTemplate;
@Autowired( required = true )
public void setDataSource( DataSource dataSource )
{
this.dTemplate = new JdbcTemplate( dataSource );
}
@Override
public TechGraph loadGraph( )
throws TechGraphException
{
TechGraph result = new TechGraph( );
this.extractGraphData( result , new CategoryExtractor( ) , qGetCategories );
this.extractGraphData( result , new TechnologyExtractor( ) , qGetTechnologies );
this.extractGraphData( result , new DependencyExtractor( ) , qGetDependencies );
return result;
}
private void extractGraphData( TechGraph graph , TechGraphDBHandler extractor , String query )
throws TechGraphException
{
extractor.setGraph( graph );
this.dTemplate.query( query , extractor );
if ( extractor.error != null ) {
throw extractor.error;
}
}
}

View file

@ -0,0 +1,74 @@
package com.deepclone.lw.beans.techs;
import java.util.LinkedList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import com.deepclone.lw.cmd.admin.techs.TechCategory;
import com.deepclone.lw.interfaces.game.techs.TechnologyGraphDAO;
import com.deepclone.lw.interfaces.game.techs.TechnologyGraphManager;
import com.deepclone.lw.sqld.game.techs.Category;
import com.deepclone.lw.sqld.game.techs.TechGraph;
import com.deepclone.lw.sqld.game.techs.TechGraphException;
@Transactional
public class TechnologyGraphManagerBean
implements TechnologyGraphManager
{
private TechGraph graph;
private TechnologyGraphDAO technologyGraphDAO;
@Autowired( required = true )
public void setTechGraphDAO( TechnologyGraphDAO technologyGraphDAO )
{
this.technologyGraphDAO = technologyGraphDAO;
}
private void loadGraph( )
throws TechGraphException
{
if ( this.graph == null ) {
this.graph = this.technologyGraphDAO.loadGraph( );
}
}
/* Documented in TechnologyGraphManager interface */
@Override
public TechGraph getGraph( )
{
try {
this.loadGraph( );
} catch ( TechGraphException e ) {
throw new RuntimeException( e );
}
return new TechGraph( this.graph );
}
/* Documented in TechnologyGraphManager interface */
@Override
public List< TechCategory > listCategories( )
{
try {
this.loadGraph( );
List< TechCategory > result = new LinkedList< TechCategory >( );
for ( String catName : this.graph.getCategories( ) ) {
Category cat = this.graph.getCategory( catName );
result.add( new TechCategory( catName , cat.getDescription( ) , cat.getTechnologies( ) ) );
}
return result;
} catch ( TechGraphException e ) {
throw new RuntimeException( e );
}
}
}

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="techs/empire-technology-dao-bean.xml" />
<import resource="techs/empire-technology-manager-bean.xml" />
<import resource="techs/research-update-bean.xml" />
<import resource="techs/research-update-dao-bean.xml" />
<import resource="techs/technology-graph-dao-bean.xml" />
<import resource="techs/technology-graph-manager-bean.xml" />
</beans>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="empireTechnologyDAO" class="com.deepclone.lw.beans.techs.EmpireTechnologyDAOBean" />
</beans>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="empireTechnologyManager" class="com.deepclone.lw.beans.techs.EmpireTechnologyManagerBean" />
</beans>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="researchUpdate" class="com.deepclone.lw.beans.techs.ResearchUpdateBean" />
</beans>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="researchUpdateDAO" class="com.deepclone.lw.beans.techs.ResearchUpdateDAOBean" />
</beans>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="technologyGraphDAO" class="com.deepclone.lw.beans.techs.TechnologyGraphDAOBean" />
</beans>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="technologyGraphManager" class="com.deepclone.lw.beans.techs.TechnologyGraphManagerBean" />
</beans>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>legacyworlds-server-beans-updates</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>

View file

@ -0,0 +1,6 @@
#Tue Mar 29 13:49:47 CEST 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6

View file

@ -0,0 +1,9 @@
#Tue Mar 29 13:49:47 CEST 2011
activeProfiles=
eclipse.preferences.version=1
fullBuildGoals=process-test-resources
includeModules=false
resolveWorkspaceProjects=true
resourceFilterGoals=process-resources resources\:testResources
skipCompilerPlugin=true
version=1

View file

@ -0,0 +1,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId>
<version>5.99.2</version>
</parent>
<groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-updates</artifactId>
<version>5.99.2</version>
<name>Legacy Worlds updates and pre-computation management</name>
<description>This Maven module contains the components which implement both the game's "standard", per-minute update system as well as the pre-computation manager.</description>
</project>

View file

@ -0,0 +1,367 @@
package com.deepclone.lw.beans.updates;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.deepclone.lw.cmd.admin.logs.LogLevel;
import com.deepclone.lw.interfaces.eventlog.Logger;
import com.deepclone.lw.interfaces.eventlog.SystemLogger;
import com.deepclone.lw.interfaces.game.updates.DuplicateUpdateHandler;
import com.deepclone.lw.interfaces.game.updates.GameUpdate;
import com.deepclone.lw.interfaces.game.updates.GameUpdatePhase;
import com.deepclone.lw.interfaces.game.updates.GameUpdatePhaseHandler;
import com.deepclone.lw.interfaces.game.updates.UpdatesDAO;
import com.deepclone.lw.interfaces.sys.ConstantDefinition;
import com.deepclone.lw.interfaces.sys.ConstantsManager;
import com.deepclone.lw.interfaces.sys.MaintenanceStatusException;
import com.deepclone.lw.interfaces.sys.SystemStatus;
import com.deepclone.lw.interfaces.sys.TickStatusException;
import com.deepclone.lw.interfaces.sys.Ticker;
import com.deepclone.lw.interfaces.sys.Ticker.Frequency;
/**
* Implementation of the game update management component.
*
* @author tseeker
*/
public class GameUpdateBean
implements GameUpdate , InitializingBean , Runnable , ApplicationContextAware
{
/** The event scheduling component */
private Ticker ticker;
/** The system status access and update component */
private SystemStatus systemStatus;
/** The game update component's logger */
private SystemLogger logger;
/** Transaction template */
private TransactionTemplate tTemplate;
/** Game updates data access component */
private UpdatesDAO updatesDao;
/** Amount of registered, non-default handlers */
private int nRegisteredHandlers = 0;
/** Amount of handler components */
private int nHandlerComponents = -1;
/** Registered game update phase handlers */
private final EnumMap< GameUpdatePhase , GameUpdatePhaseHandler > handlers;
public GameUpdateBean( )
{
this.handlers = new EnumMap< GameUpdatePhase , GameUpdatePhaseHandler >( GameUpdatePhase.class );
}
/**
* Dependency injector for the event scheduling component
*
* @param ticker
* the event scheduling component
*/
@Autowired( required = true )
public void setTicker( Ticker ticker )
{
this.ticker = ticker;
}
/**
* Dependency injector for the system status access component
*
* @param systemStatus
* the system status access component
*/
@Autowired( required = true )
public void setSystemStatus( SystemStatus systemStatus )
{
this.systemStatus = systemStatus;
}
/**
* Dependency injector that initialises the game update component's logger.
*
* @param logger
* the system logging component
*/
@Autowired( required = true )
public void setLogger( Logger logger )
{
this.logger = logger.getSystemLogger( "GameUpdate" );
}
/**
* Dependency injector that initialises the transaction template.
*
* @param transactionManager
* the application's transaction manager
*/
@Autowired( required = true )
public void setTransactionManager( PlatformTransactionManager transactionManager )
{
this.tTemplate = new TransactionTemplate( transactionManager );
}
/**
* Dependency injector for the game updates data access component
*
* @param updatesDao
* the game updates data access component
*/
@Autowired( required = true )
public void setUpdatesDAO( UpdatesDAO updatesDao )
{
this.updatesDao = updatesDao;
}
/**
* Dependency injector which registers the game.updatesPerDay constant.
*
* @param constantsManager
* the constants manager
*/
@Autowired( required = true )
public void setConstantsManager( ConstantsManager constantsManager )
{
List< ConstantDefinition > definitions;
ConstantDefinition constant;
definitions = new ArrayList< ConstantDefinition >( 1 );
constant = new ConstantDefinition(
"game.updatesPerDay" ,
"Game (misc)" ,
"Game updates per day from the computations's point of view. "
+ "This does not affect the actual amount of updates, but changes the computations. "
+ "Can be used to speed things up or slow them down without actually changing ticker.interval." ,
1440.0 , 0.05 , 5760.0 );
definitions.add( 0 , constant );
constantsManager.registerConstants( definitions );
}
/**
* Read the amount of update phase handlers from the application context.
*
* @param context
* the application context
*/
@Override
public void setApplicationContext( ApplicationContext context )
throws BeansException
{
this.nHandlerComponents = context.getBeansOfType( GameUpdatePhaseHandler.class ).size( );
if ( this.nRegisteredHandlers == this.nHandlerComponents ) {
this.initialise( );
}
}
/* Documentation in GameUpdate interface */
@Override
public void registerHandler( GameUpdatePhaseHandler handler )
throws DuplicateUpdateHandler
{
GameUpdatePhase phase = handler.getPhase( );
synchronized ( this.handlers ) {
if ( this.handlers.containsKey( phase ) ) {
throw new DuplicateUpdateHandler( phase );
}
this.handlers.put( phase , handler );
}
this.logger.log( LogLevel.DEBUG , "Registered game update handler for phase " + phase.toString( ) ).flush( );
this.nRegisteredHandlers++;
if ( this.nRegisteredHandlers == this.nHandlerComponents ) {
this.initialise( );
}
}
/**
* Initialise the component if it is ready.
*/
@Override
public void afterPropertiesSet( )
{
if ( this.nRegisteredHandlers == this.nHandlerComponents ) {
this.initialise( );
}
}
/**
* Finish any pending computations (unless maintenance mode is active), then register the game
* update task into the {@link #ticker}.
*/
private void initialise( )
{
// Finish previous tick if possible
try {
this.endPreviousTick( );
} catch ( MaintenanceStatusException e ) {
// EMPTY
}
// Register ticker task
this.ticker.registerTask( Frequency.MINUTE , "Game update" , this );
// Make sure initialisation only occurs once
this.nHandlerComponents = -1;
}
/**
* When the game update event is triggered by the system's scheduling component, attempt to run
* a game update.
*
* First, check if there is already a game update in progress, and attempt to finish running it
* if necessary. Otherwise start a new update though the system status manager, and execute it.
*/
@Override
public void run( )
{
// Attempt to end the previous tick, if e.g. maintenance mode was initiated while it was
// being processed
try {
if ( this.endPreviousTick( ) ) {
return;
}
} catch ( MaintenanceStatusException e ) {
return;
}
// Initiate next tick
long tickId;
try {
tickId = this.systemStatus.startTick( );
} catch ( TickStatusException e ) {
throw new RuntimeException( "tick initiated while previous tick still being processed" , e );
} catch ( MaintenanceStatusException e ) {
return;
}
// Execute tick
this.logger.log( LogLevel.DEBUG , "Tick " + tickId + " started" ).flush( );
this.executeUpdate( tickId );
}
/**
* Check if a game update was in progress and finish running it if necessary.
*
* @return <code>true</code> if a game update was already being executed, <code>false</code>
* otherwise.
*
* @throws MaintenanceStatusException
* if the game is under maintenance.
*/
private boolean endPreviousTick( )
throws MaintenanceStatusException
{
Long currentTick = this.systemStatus.checkStuckTick( );
if ( currentTick == null ) {
return false;
}
this.logger.log( LogLevel.WARNING , "Tick " + currentTick + " restarted" ).flush( );
this.executeUpdate( currentTick.longValue( ) );
return true;
}
/**
* Execute all phase handlers for a game update, then mark the update as completed.
*
* @param updateId
* the identifier of the current update
*/
private void executeUpdate( long updateId )
{
for ( GameUpdatePhase phase : GameUpdatePhase.values( ) ) {
this.executeUpdatePhase( updateId , phase );
}
try {
this.systemStatus.endTick( );
} catch ( TickStatusException e ) {
throw new RuntimeException( "Game update completed but status error reported" , e );
} catch ( MaintenanceStatusException e ) {
return;
}
this.logger.log( LogLevel.TRACE , "Tick " + updateId + " completed" ).flush( );
}
/**
* Execute a phase of the game update.
*
* @param updateId
* the identifier of the current update
* @param phase
* the phase of the update to execute
*/
private void executeUpdatePhase( final long updateId , GameUpdatePhase phase )
{
final GameUpdatePhaseHandler handler = this.getHandlerForPhase( phase );
handler.onPhaseStart( updateId );
boolean hasMore;
do {
hasMore = this.tTemplate.execute( new TransactionCallback< Boolean >( ) {
@Override
public Boolean doInTransaction( TransactionStatus status )
{
return handler.updateGame( updateId );
}
} );
} while ( hasMore );
}
/**
* Access the handler for an update phase. If no handler has been registered, create a default
* {@link ProceduralGameUpdate} handler.
*
* @param phase
* the update phase whose handler is to be retrieved
* @return the game update handler
*/
private GameUpdatePhaseHandler getHandlerForPhase( GameUpdatePhase phase )
{
GameUpdatePhaseHandler handler;
synchronized ( this.handlers ) {
handler = this.handlers.get( phase );
if ( handler == null ) {
this.logger.log( LogLevel.DEBUG , "Creating default handler for phase " + phase.toString( ) ).flush( );
handler = new ProceduralGameUpdate( this.updatesDao , phase );
this.handlers.put( phase , handler );
}
}
return handler;
}
}

View file

@ -0,0 +1,52 @@
package com.deepclone.lw.beans.updates;
import com.deepclone.lw.interfaces.game.updates.GameUpdatePhase;
import com.deepclone.lw.interfaces.game.updates.GameUpdatePhaseHandler;
import com.deepclone.lw.interfaces.game.updates.UpdatesDAO;
class ProceduralGameUpdate
implements GameUpdatePhaseHandler
{
private final GameUpdatePhase phase;
private final UpdatesDAO updatesDao;
ProceduralGameUpdate( UpdatesDAO updatesDao , GameUpdatePhase phase )
{
this.updatesDao = updatesDao;
this.phase = phase;
}
@Override
public GameUpdatePhase getPhase( )
{
return this.phase;
}
@Override
public boolean updateGame( long updateId )
{
if ( !this.updatesDao.prepareUpdates( updateId , this.phase ) ) {
return false;
}
this.updatesDao.executeProceduralUpdate( updateId , this.phase );
this.updatesDao.validateUpdatedRecords( updateId , this.phase );
return true;
}
@Override
public void onPhaseStart( long updateId )
{
// EMPTY
}
}

View file

@ -0,0 +1,85 @@
package com.deepclone.lw.beans.updates;
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import com.deepclone.lw.interfaces.game.updates.GameUpdatePhase;
import com.deepclone.lw.interfaces.game.updates.UpdatesDAO;
import com.deepclone.lw.utils.StoredProc;
/**
* Implementation of the game update data access component.
*
* @author tseeker
*/
public class UpdatesDAOBean
implements UpdatesDAO
{
/** Wrapper for the stored procedure that prepares updates */
private StoredProc fPrepareUpdates;
/** Wrapper for the stored procedure that executes a procedural game update */
private StoredProc fExecuteProcedural;
/** Wrapper for the stored procedure that marks update records as processed */
private StoredProc fUpdatesProcessed;
/**
* Dependency injector that initialises stored procedure call handlers.
*
* @param dataSource
* the data source
*/
@Autowired( required = true )
public void setDataSource( DataSource dataSource )
{
// Stored procedure that prepares updates
this.fPrepareUpdates = new StoredProc( dataSource , "sys" , "prepare_updates" );
this.fPrepareUpdates.addParameter( "u_id" , Types.BIGINT );
this.fPrepareUpdates.addParameter( "u_type" , "update_type" );
this.fPrepareUpdates.addOutput( "has_more" , Types.BOOLEAN );
// Stored procedure that executes a procedural game update
this.fExecuteProcedural = new StoredProc( dataSource , "sys" , "exec_update_proc" );
this.fExecuteProcedural.addParameter( "u_id" , Types.BIGINT );
this.fExecuteProcedural.addParameter( "u_type" , "update_type" );
// Stored procedure that marks update records as processed
this.fUpdatesProcessed = new StoredProc( dataSource , "sys" , "updates_processed" );
this.fUpdatesProcessed.addParameter( "u_id" , Types.BIGINT );
this.fUpdatesProcessed.addParameter( "u_type" , "update_type" );
}
/* Documentation in UpdatesDAO interface */
@Override
public boolean prepareUpdates( long updateId , GameUpdatePhase phase )
{
return (Boolean) this.fPrepareUpdates.execute( updateId , phase.toString( ) ).get( "has_more" );
}
/* Documentation in UpdatesDAO interface */
@Override
public void executeProceduralUpdate( long updateId , GameUpdatePhase phase )
{
this.fExecuteProcedural.execute( updateId , phase.toString( ) );
}
/* Documentation in UpdatesDAO interface */
@Override
public void validateUpdatedRecords( long updateId , GameUpdatePhase phase )
{
this.fUpdatesProcessed.execute( updateId , phase );
}
}

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="updates/game-update-bean.xml" />
<import resource="updates/updates-dao-bean.xml" />
</beans>

View file

@ -4,12 +4,12 @@
<parent> <parent>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans-user</artifactId> <artifactId>legacyworlds-server-beans-user</artifactId>
<version>5.99.1</version> <version>5.99.2</version>
<name>Legacy Worlds server - user actions</name> <name>Legacy Worlds server - user actions</name>
<description>This module defines beans and classes that handle user actions.</description> <description>This module defines beans and classes that handle user actions.</description>
</project> </project>

View file

@ -0,0 +1,59 @@
package com.deepclone.lw.beans.user.admin.main.techs;
import org.springframework.beans.factory.annotation.Autowired;
import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate;
import com.deepclone.lw.beans.user.abst.SessionCommandHandler;
import com.deepclone.lw.beans.user.admin.common.AdminOperation;
import com.deepclone.lw.beans.user.admin.main.AdminCommandsBean;
import com.deepclone.lw.cmd.admin.adata.Administrator;
import com.deepclone.lw.cmd.admin.adata.Privileges;
import com.deepclone.lw.cmd.admin.techs.ListCategoriesCommand;
import com.deepclone.lw.cmd.admin.techs.ListCategoriesResponse;
import com.deepclone.lw.interfaces.game.techs.TechnologyGraphManager;
import com.deepclone.lw.interfaces.session.ServerSession;
import com.deepclone.lw.session.Command;
import com.deepclone.lw.session.CommandResponse;
public class ListCategoriesCommandDelegateBean
extends AdminOperation
implements AutowiredCommandDelegate
{
private TechnologyGraphManager manager;
@Autowired( required = true )
public void setManager( TechnologyGraphManager manager )
{
this.manager = manager;
}
@Override
public Class< ? extends SessionCommandHandler > getCommandHandler( )
{
return AdminCommandsBean.class;
}
@Override
public Class< ? extends Command > getType( )
{
return ListCategoriesCommand.class;
}
@Override
public CommandResponse execute( ServerSession session , Command command )
{
Administrator admin = this.getAdministrator( session );
if ( !admin.hasPrivilege( Privileges.GDAT ) ) {
return new ListCategoriesResponse( admin );
}
return new ListCategoriesResponse( admin , this.manager.listCategories( ) );
}
}

View file

@ -1,4 +1,4 @@
package com.deepclone.lw.beans.user.player.game; package com.deepclone.lw.beans.user.player.game.techs;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -6,8 +6,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate; import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate;
import com.deepclone.lw.beans.user.abst.SessionCommandHandler; import com.deepclone.lw.beans.user.abst.SessionCommandHandler;
import com.deepclone.lw.beans.user.player.GameSubTypeBean; import com.deepclone.lw.beans.user.player.GameSubTypeBean;
import com.deepclone.lw.cmd.player.ImplementTechCommand; import com.deepclone.lw.cmd.player.research.ImplementTechCommand;
import com.deepclone.lw.interfaces.game.EmpireManagement; import com.deepclone.lw.cmd.player.research.ResearchOperationResponse;
import com.deepclone.lw.interfaces.game.techs.EmpireTechnologyManager;
import com.deepclone.lw.interfaces.session.ServerSession; import com.deepclone.lw.interfaces.session.ServerSession;
import com.deepclone.lw.session.Command; import com.deepclone.lw.session.Command;
import com.deepclone.lw.session.CommandResponse; import com.deepclone.lw.session.CommandResponse;
@ -19,13 +20,13 @@ public class ImplementTechCommandDelegateBean
{ {
private EmpireManagement empireManagement; private EmpireTechnologyManager techManagement;
@Autowired( required = true ) @Autowired( required = true )
public void setEmpireManager( EmpireManagement manager ) public void setEmpireManager( EmpireTechnologyManager manager )
{ {
this.empireManagement = manager; this.techManagement = manager;
} }
@ -49,8 +50,8 @@ public class ImplementTechCommandDelegateBean
ImplementTechCommand command = (ImplementTechCommand) cParam; ImplementTechCommand command = (ImplementTechCommand) cParam;
int empireId = session.get( "empireId" , Integer.class ); int empireId = session.get( "empireId" , Integer.class );
if ( session.get( "vacation" , Boolean.class ) ) { if ( session.get( "vacation" , Boolean.class ) ) {
return this.empireManagement.getOverview( empireId ); return new ResearchOperationResponse( );
} }
return this.empireManagement.implementTechnology( empireId , command.getTech( ) ); return this.techManagement.implementTechnology( empireId , command.getTech( ) );
} }
} }

View file

@ -0,0 +1,56 @@
package com.deepclone.lw.beans.user.player.game.techs;
import org.springframework.beans.factory.annotation.Autowired;
import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate;
import com.deepclone.lw.beans.user.abst.SessionCommandHandler;
import com.deepclone.lw.beans.user.player.GameSubTypeBean;
import com.deepclone.lw.cmd.player.research.ResearchOperationResponse;
import com.deepclone.lw.cmd.player.research.SetResearchPrioritiesCommand;
import com.deepclone.lw.interfaces.game.techs.EmpireTechnologyManager;
import com.deepclone.lw.interfaces.session.ServerSession;
import com.deepclone.lw.session.Command;
import com.deepclone.lw.session.CommandResponse;
public class SetResearchPrioritiesCommandDelegateBean
implements AutowiredCommandDelegate
{
private EmpireTechnologyManager techManagement;
@Autowired( required = true )
public void setEmpireManager( EmpireTechnologyManager manager )
{
this.techManagement = manager;
}
@Override
public Class< ? extends Command > getType( )
{
return SetResearchPrioritiesCommand.class;
}
@Override
public Class< ? extends SessionCommandHandler > getCommandHandler( )
{
return GameSubTypeBean.class;
}
@Override
public CommandResponse execute( ServerSession session , Command cParam )
{
SetResearchPrioritiesCommand command = (SetResearchPrioritiesCommand) cParam;
int empireId = session.get( "empireId" , Integer.class );
if ( session.get( "vacation" , Boolean.class ) ) {
return new ResearchOperationResponse( );
}
return this.techManagement.setResearchPriorities( empireId , command.getPriorities( ) );
}
}

View file

@ -0,0 +1,52 @@
package com.deepclone.lw.beans.user.player.game.techs;
import org.springframework.beans.factory.annotation.Autowired;
import com.deepclone.lw.beans.user.abst.AutowiredCommandDelegate;
import com.deepclone.lw.beans.user.abst.SessionCommandHandler;
import com.deepclone.lw.beans.user.player.GameSubTypeBean;
import com.deepclone.lw.cmd.player.research.ViewResearchCommand;
import com.deepclone.lw.interfaces.game.techs.EmpireTechnologyManager;
import com.deepclone.lw.interfaces.session.ServerSession;
import com.deepclone.lw.session.Command;
import com.deepclone.lw.session.CommandResponse;
public class ViewResearchCommandDelegateBean
implements AutowiredCommandDelegate
{
private EmpireTechnologyManager techManagement;
@Autowired( required = true )
public void setEmpireManager( EmpireTechnologyManager manager )
{
this.techManagement = manager;
}
@Override
public Class< ? extends Command > getType( )
{
return ViewResearchCommand.class;
}
@Override
public Class< ? extends SessionCommandHandler > getCommandHandler( )
{
return GameSubTypeBean.class;
}
@Override
public CommandResponse execute( ServerSession session , Command cParam )
{
int empireId = session.get( "empireId" , Integer.class );
return this.techManagement.getResearchData( empireId );
}
}

View file

@ -94,4 +94,7 @@
<bean class="com.deepclone.lw.beans.user.admin.main.mntm.EndMaintenanceCommandDelegateBean" /> <bean class="com.deepclone.lw.beans.user.admin.main.mntm.EndMaintenanceCommandDelegateBean" />
<bean class="com.deepclone.lw.beans.user.admin.main.mntm.ExtendMaintenanceCommandDelegateBean" /> <bean class="com.deepclone.lw.beans.user.admin.main.mntm.ExtendMaintenanceCommandDelegateBean" />
<!-- Technology graph -->
<bean class="com.deepclone.lw.beans.user.admin.main.techs.ListCategoriesCommandDelegateBean" />
</beans> </beans>

View file

@ -44,9 +44,13 @@
<!-- Game: empire --> <!-- Game: empire -->
<bean class="com.deepclone.lw.beans.user.player.game.OverviewCommandDelegateBean" /> <bean class="com.deepclone.lw.beans.user.player.game.OverviewCommandDelegateBean" />
<bean class="com.deepclone.lw.beans.user.player.game.ImplementTechCommandDelegateBean" />
<bean class="com.deepclone.lw.beans.user.player.game.GetNewPlanetCommandDelegateBean" /> <bean class="com.deepclone.lw.beans.user.player.game.GetNewPlanetCommandDelegateBean" />
<!-- Game: technologies -->
<bean class="com.deepclone.lw.beans.user.player.game.techs.ViewResearchCommandDelegateBean" />
<bean class="com.deepclone.lw.beans.user.player.game.techs.ImplementTechCommandDelegateBean" />
<bean class="com.deepclone.lw.beans.user.player.game.techs.SetResearchPrioritiesCommandDelegateBean" />
<!-- Game: planet list --> <!-- Game: planet list -->
<bean class="com.deepclone.lw.beans.user.player.game.ListPlanetsCommandDelegateBean" /> <bean class="com.deepclone.lw.beans.user.player.game.ListPlanetsCommandDelegateBean" />

View file

@ -4,13 +4,13 @@
<parent> <parent>
<artifactId>legacyworlds-server</artifactId> <artifactId>legacyworlds-server</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-beans</artifactId> <artifactId>legacyworlds-server-beans</artifactId>
<name>Legacy Worlds server beans</name> <name>Legacy Worlds server beans</name>
<version>5.99.1</version> <version>5.99.2</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<description>This metapackage regroups all packages which define beans for the Legacy Worlds server.</description> <description>This metapackage regroups all packages which define beans for the Legacy Worlds server.</description>
@ -32,5 +32,8 @@
<module>legacyworlds-server-beans-bt</module> <module>legacyworlds-server-beans-bt</module>
<module>legacyworlds-server-beans-user</module> <module>legacyworlds-server-beans-user</module>
<module>legacyworlds-server-beans-simple</module> <module>legacyworlds-server-beans-simple</module>
<module>legacyworlds-server-beans-techs</module>
<module>legacyworlds-server-beans-updates</module>
<module>legacyworlds-server-beans-events</module>
</modules> </modules>
</project> </project>

View file

@ -14,6 +14,7 @@
\i parts/functions/030-tech-functions.sql \i parts/functions/030-tech-functions.sql
\i parts/functions/035-users-view.sql \i parts/functions/035-users-view.sql
\i parts/functions/040-empire-functions.sql \i parts/functions/040-empire-functions.sql
\i parts/functions/045-research-functions.sql
\i parts/functions/050-computation-functions.sql \i parts/functions/050-computation-functions.sql
\i parts/functions/060-universe-functions.sql \i parts/functions/060-universe-functions.sql
\i parts/functions/070-users-functions.sql \i parts/functions/070-users-functions.sql

View file

@ -25,9 +25,9 @@ CREATE TABLE sys.constant_definitions(
name VARCHAR(64) NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL PRIMARY KEY,
category_id INT NOT NULL , category_id INT NOT NULL ,
description TEXT NOT NULL , description TEXT NOT NULL ,
min_value REAL , min_value DOUBLE PRECISION ,
max_value REAL , max_value DOUBLE PRECISION ,
c_value REAL NOT NULL , c_value DOUBLE PRECISION NOT NULL ,
CHECK( CHECK(
( min_value IS NULL OR ( ( min_value IS NULL OR (
min_value IS NOT NULL AND c_value >= min_value ) ) min_value IS NOT NULL AND c_value >= min_value ) )

View file

@ -8,49 +8,65 @@
-- --
-- Technology lines -- Categories
-- --
CREATE TABLE tech.categories(
CREATE TABLE tech.lines(
name_id INT NOT NULL PRIMARY KEY , name_id INT NOT NULL PRIMARY KEY ,
description_id INT NOT NULL description_id INT NOT NULL
); );
CREATE INDEX idx_lines_description CREATE INDEX idx_categories_description
ON tech.lines (description_id); ON tech.categories (description_id);
ALTER TABLE tech.lines ALTER TABLE tech.categories
ADD CONSTRAINT fk_lines_name ADD CONSTRAINT fk_categories_name
FOREIGN KEY (name_id) REFERENCES defs.strings , FOREIGN KEY (name_id) REFERENCES defs.strings ,
ADD CONSTRAINT fk_lines_description ADD CONSTRAINT fk_categories_description
FOREIGN KEY (description_id) REFERENCES defs.strings; FOREIGN KEY (description_id) REFERENCES defs.strings;
-- --
-- Technology levels -- Technologies
-- --
CREATE TABLE tech.levels( CREATE TABLE tech.technologies(
id SERIAL NOT NULL PRIMARY KEY , name_id INT NOT NULL PRIMARY KEY ,
line_id INT NOT NULL ,
level INT NOT NULL CHECK( level > 0 ) ,
name_id INT NOT NULL ,
description_id INT NOT NULL , description_id INT NOT NULL ,
category_id INT NOT NULL ,
points INT NOT NULL CHECK( points > 0 ) , points INT NOT NULL CHECK( points > 0 ) ,
cost INT NOT NULL CHECK( cost > 0 ) cost INT NOT NULL CHECK( cost > 0 )
); );
CREATE UNIQUE INDEX idx_levels_linelevel CREATE INDEX idx_technologies_description
ON tech.levels (line_id, level); ON tech.technologies (description_id);
CREATE INDEX idx_levels_name CREATE INDEX idx_technologies_category
ON tech.levels (name_id); ON tech.technologies (category_id);
CREATE INDEX idx_levels_description
ON tech.levels (description_id);
ALTER TABLE tech.levels ALTER TABLE tech.technologies
ADD CONSTRAINT fk_levels_line ADD CONSTRAINT fk_technologies_category
FOREIGN KEY (line_id) REFERENCES tech.lines , FOREIGN KEY (category_id) REFERENCES tech.categories ,
ADD CONSTRAINT fk_levels_name ADD CONSTRAINT fk_technologies_name
FOREIGN KEY (name_id) REFERENCES defs.strings , FOREIGN KEY (name_id) REFERENCES defs.strings ,
ADD CONSTRAINT fk_levels_description ADD CONSTRAINT fk_technologies_description
FOREIGN KEY (description_id) REFERENCES defs.strings; FOREIGN KEY (description_id) REFERENCES defs.strings;
--
-- Dependencies
--
CREATE TABLE tech.dependencies(
technology_id INT NOT NULL ,
depends_on INT NOT NULL ,
PRIMARY KEY( technology_id , depends_on )
);
CREATE INDEX idx_dependencies_dependson
ON tech.dependencies (depends_on);
ALTER TABLE tech.dependencies
ADD CONSTRAINT fk_dependencies_technology
FOREIGN KEY (technology_id) REFERENCES tech.technologies ,
ADD CONSTRAINT fk_dependencies_dependson
FOREIGN KEY (depends_on) REFERENCES tech.technologies;

View file

@ -32,18 +32,18 @@ ALTER TABLE tech.buildables
-- --
CREATE TABLE tech.buildable_requirements( CREATE TABLE tech.buildable_requirements(
buildable_id INT NOT NULL , buildable_id INT NOT NULL ,
level_id INT NOT NULL , technology_id INT NOT NULL ,
PRIMARY KEY( buildable_id , level_id ) PRIMARY KEY( buildable_id , technology_id )
); );
CREATE INDEX idx_buildablereqs_level CREATE INDEX idx_buildablereqs_technology
ON tech.buildable_requirements( level_id ); ON tech.buildable_requirements( technology_id );
ALTER TABLE tech.buildable_requirements ALTER TABLE tech.buildable_requirements
ADD CONSTRAINT fk_buildablereqs_buildable ADD CONSTRAINT fk_buildablereqs_buildable
FOREIGN KEY (buildable_id) REFERENCES tech.buildables , FOREIGN KEY (buildable_id) REFERENCES tech.buildables ,
ADD CONSTRAINT fk_buildablereqs_level ADD CONSTRAINT fk_buildablereqs_technology
FOREIGN KEY (level_id) REFERENCES tech.levels; FOREIGN KEY (technology_id) REFERENCES tech.technologies;
-- --

View file

@ -28,7 +28,7 @@ CREATE TABLE verse.planets(
orbit INT NOT NULL orbit INT NOT NULL
CHECK( orbit BETWEEN 1 AND 5 ) , CHECK( orbit BETWEEN 1 AND 5 ) ,
picture INT NOT NULL , picture INT NOT NULL ,
population REAL NOT NULL population DOUBLE PRECISION NOT NULL
CHECK( population >= 0 ) CHECK( population >= 0 )
); );
@ -47,9 +47,9 @@ ALTER TABLE verse.planets
-- --
CREATE TABLE verse.planet_happiness( CREATE TABLE verse.planet_happiness(
planet_id INT NOT NULL PRIMARY KEY , planet_id INT NOT NULL PRIMARY KEY ,
target REAL NOT NULL target DOUBLE PRECISION NOT NULL
CHECK( target BETWEEN 0.0 AND 1.0 ) , CHECK( target BETWEEN 0.0 AND 1.0 ) ,
current REAL NOT NULL current DOUBLE PRECISION NOT NULL
CHECK( current > 0 ) CHECK( current > 0 )
); );
@ -63,9 +63,9 @@ ALTER TABLE verse.planet_happiness
-- --
CREATE TABLE verse.planet_money( CREATE TABLE verse.planet_money(
planet_id INT NOT NULL PRIMARY KEY , planet_id INT NOT NULL PRIMARY KEY ,
income REAL NOT NULL income DOUBLE PRECISION NOT NULL
CHECK( income >= 0 ) , CHECK( income >= 0 ) ,
upkeep REAL NOT NULL upkeep DOUBLE PRECISION NOT NULL
CHECK( upkeep >= 0 ) CHECK( upkeep >= 0 )
); );
@ -81,7 +81,7 @@ CREATE TABLE verse.planet_buildings(
planet_id INT NOT NULL , planet_id INT NOT NULL ,
building_id INT NOT NULL , building_id INT NOT NULL ,
amount INT NOT NULL CHECK( amount >= 0 ) , amount INT NOT NULL CHECK( amount >= 0 ) ,
damage REAL NOT NULL CHECK( damage >= 0 ) , damage DOUBLE PRECISION NOT NULL CHECK( damage >= 0 ) ,
PRIMARY KEY( planet_id , building_id ) PRIMARY KEY( planet_id , building_id )
); );

View file

@ -13,9 +13,9 @@
CREATE TABLE emp.empires( CREATE TABLE emp.empires(
name_id INT NOT NULL PRIMARY KEY , name_id INT NOT NULL PRIMARY KEY ,
cash REAL NOT NULL cash DOUBLE PRECISION NOT NULL
CHECK( cash >= 0 ), CHECK( cash >= 0 ),
debt REAL NOT NULL DEFAULT 0 debt DOUBLE PRECISION NOT NULL DEFAULT 0
CHECK( debt >= 0) CHECK( debt >= 0)
); );
@ -25,28 +25,55 @@ ALTER TABLE emp.empires
-- --
-- Empire technologies -- Research in progress
-- --
CREATE TABLE emp.technologies( CREATE TABLE emp.research(
empire_id INT NOT NULL , empire_id INT NOT NULL ,
line_id INT NOT NULL , technology_id INT NOT NULL ,
level INT NOT NULL DEFAULT 1 accumulated DOUBLE PRECISION NOT NULL DEFAULT 0
CHECK( level > 0 ) , CHECK( accumulated >= 0 ) ,
accumulated REAL NOT NULL DEFAULT 0 priority INT NOT NULL
CHECK( accumulated >= 0 ), CHECK( priority BETWEEN 0 AND 100 ) ,
PRIMARY KEY( empire_id , line_id ) PRIMARY KEY( empire_id , technology_id )
); );
CREATE INDEX idx_technologies_line CREATE INDEX idx_research_technology
ON emp.technologies (line_id); ON emp.research (technology_id);
ALTER TABLE emp.technologies ALTER TABLE emp.research
ADD CONSTRAINT fk_technologies_empire ADD CONSTRAINT fk_research_empire
FOREIGN KEY (empire_id) REFERENCES emp.empires FOREIGN KEY (empire_id) REFERENCES emp.empires
ON DELETE CASCADE , ON DELETE CASCADE ,
ADD CONSTRAINT fk_technologies_line ADD CONSTRAINT fk_research_technology
FOREIGN KEY (line_id) REFERENCES tech.lines; FOREIGN KEY (technology_id) REFERENCES tech.technologies
ON DELETE CASCADE;
--
-- Researched technologies (both implemented and pending implementation)
--
CREATE TABLE emp.researched_technologies(
empire_id INT NOT NULL ,
technology_id INT NOT NULL ,
implemented BOOLEAN NOT NULL ,
PRIMARY KEY ( empire_id , technology_id )
);
CREATE INDEX idx_researched_technology
ON emp.researched_technologies ( technology_id );
CREATE INDEX idx_researched_implemented
ON emp.researched_technologies ( empire_id , implemented );
ALTER TABLE emp.researched_technologies
ADD CONSTRAINT fk_researched_empire
FOREIGN KEY ( empire_id ) REFERENCES emp.empires
ON DELETE CASCADE ,
ADD CONSTRAINT fk_researched_technology
FOREIGN KEY ( technology_id ) REFERENCES tech.technologies
ON DELETE CASCADE;
-- --

View file

@ -13,8 +13,8 @@
CREATE TABLE verse.bld_queues( CREATE TABLE verse.bld_queues(
planet_id INT NOT NULL PRIMARY KEY , planet_id INT NOT NULL PRIMARY KEY ,
money REAL NOT NULL CHECK( money >= 0 ), money DOUBLE PRECISION NOT NULL CHECK( money >= 0 ),
work REAL NOT NULL CHECK( work >= 0 ) work DOUBLE PRECISION NOT NULL CHECK( work >= 0 )
); );
ALTER TABLE verse.bld_queues ALTER TABLE verse.bld_queues
@ -51,8 +51,8 @@ ALTER TABLE verse.bld_items
CREATE TABLE verse.mil_queues( CREATE TABLE verse.mil_queues(
planet_id INT NOT NULL PRIMARY KEY , planet_id INT NOT NULL PRIMARY KEY ,
money REAL NOT NULL CHECK( money >= 0 ), money DOUBLE PRECISION NOT NULL CHECK( money >= 0 ),
work REAL NOT NULL CHECK( work >= 0 ) work DOUBLE PRECISION NOT NULL CHECK( work >= 0 )
); );
ALTER TABLE verse.mil_queues ALTER TABLE verse.mil_queues

View file

@ -46,7 +46,7 @@ CREATE TABLE fleets.ships(
fleet_id BIGINT NOT NULL , fleet_id BIGINT NOT NULL ,
ship_id INT NOT NULL , ship_id INT NOT NULL ,
amount INT NOT NULL CHECK( amount >= 0 ) , amount INT NOT NULL CHECK( amount >= 0 ) ,
damage REAL NOT NULL , damage DOUBLE PRECISION NOT NULL ,
PRIMARY KEY( fleet_id , ship_id ) PRIMARY KEY( fleet_id , ship_id )
); );
@ -89,8 +89,8 @@ ALTER TABLE fleets.movements
CREATE TABLE fleets.ms_space( CREATE TABLE fleets.ms_space(
movement_id BIGINT NOT NULL PRIMARY KEY , movement_id BIGINT NOT NULL PRIMARY KEY ,
start_x REAL NOT NULL , start_x DOUBLE PRECISION NOT NULL ,
start_y REAL NOT NULL start_y DOUBLE PRECISION NOT NULL
); );
ALTER TABLE fleets.ms_space ALTER TABLE fleets.ms_space

View file

@ -3,10 +3,163 @@
-- --
-- Storage of events (internal messages) -- Storage of events (internal messages)
-- --
-- Copyright(C) 2004-2010, DeepClone Development -- Copyright(C) 2004-2011, DeepClone Development
-- -------------------------------------------------------- -- --------------------------------------------------------
--
-- Event type definitionss
--
CREATE TABLE events.event_type_definitions(
etd_type VARCHAR( 48 ) NOT NULL
PRIMARY KEY ,
etd_priority INT NOT NULL
CHECK( etd_priority BETWEEN 1 AND 5 ) ,
etd_user_priority BOOLEAN NOT NULL
);
--
-- Types of field contents
--
-- INMB integer
-- RNMB real number
-- TEXT text
-- BOOL boolean
-- I18N internationalised string
-- EREF game entity reference
--
CREATE TYPE events.field_content_type
AS ENUM ( 'INMB' , 'RNMB' , 'TEXT' , 'BOOL' , 'I18N' , 'EREF' );
--
-- Subtypes of reference field contents
--
-- EMP empire
-- MAP map object
-- FLT fleet
-- BAT battle
-- ADM administrator
-- MSG message
-- BUG bug report
--
CREATE TYPE events.field_reference_type
AS ENUM ( 'EMP' , 'MAP' , 'FLT' , 'BAT' , 'ADM' , 'MSG' , 'BUG' );
--
-- Event field definitions
--
CREATE TABLE events.event_field_definitions(
etd_type VARCHAR( 48 ) NOT NULL ,
efd_field VARCHAR( 48 ) NOT NULL ,
efd_required BOOLEAN NOT NULL ,
efd_type events.field_content_type NOT NULL ,
efd_reference_type events.field_reference_type ,
efd_low_boundary DOUBLE PRECISION ,
efd_high_boundary DOUBLE PRECISION ,
PRIMARY KEY ( etd_type , efd_field ) ,
CHECK( efd_type = 'EREF' AND efd_reference_type IS NOT NULL
OR efd_type <> 'EREF' AND efd_reference_type IS NULL ) ,
CHECK ( efd_type IN ( 'INMB' , 'RNMB' , 'TEXT' )
OR efd_type NOT IN ( 'INMB' , 'RNMB' , 'TEXT' )
AND efd_low_boundary IS NULL
AND efd_high_boundary IS NULL ) ,
CHECK ( efd_low_boundary IS NULL OR efd_high_boundary IS NULL
OR efd_low_boundary < efd_high_boundary )
);
ALTER TABLE events.event_field_definitions
ADD CONSTRAINT fk_efd_type
FOREIGN KEY ( etd_type ) REFERENCES events.event_type_definitions;
--
-- Event format definitions
--
CREATE TABLE events.event_format_definitions(
etd_type VARCHAR( 48 ) NOT NULL ,
efmd_order INT NOT NULL ,
efmd_template INT NOT NULL ,
PRIMARY KEY ( etd_type , efmd_order )
);
CREATE INDEX idx_efmd_template
ON events.event_format_definitions ( efmd_template );
ALTER TABLE events.event_format_definitions
ADD CONSTRAINT fk_efmd_type
FOREIGN KEY ( etd_type ) REFERENCES events.event_type_definitions ,
ADD CONSTRAINT fk_efmd_template
FOREIGN KEY ( efmd_template ) REFERENCES defs.strings;
--
-- Types of format conditions
--
-- EX has value all
-- EQ is equal to ... all except EREF
-- NE is not equal to ... all except EREF
-- GT > ... INMB , RNMB
-- length > ... TEXT
-- LT < ... INMB , RNMB
-- shorter than ... TEXT
-- GE >= ... INMB , RNMB
-- length >= ... TEXT
-- LE <= ... INMB , RNMB
-- length <= ... TEXT
-- AV available EREF
--
CREATE TYPE events.format_condition_type
AS ENUM ( 'EX' , 'EQ' , 'NE' , 'GT' , 'LT' , 'GE' , 'LE' , 'AV' );
--
-- Conditions on format definitions
--
CREATE TABLE events.efmt_conditions(
etd_type VARCHAR( 48 ) NOT NULL ,
efmd_order INT NOT NULL ,
efd_field VARCHAR( 48 ) NOT NULL ,
efc_type events.format_condition_type NOT NULL ,
efc_boolean BOOLEAN ,
efc_numeric DOUBLE PRECISION ,
efc_string TEXT ,
PRIMARY KEY( etd_type , efmd_order , efd_field , efc_type )
);
CREATE INDEX idx_efmtc_field
ON events.efmt_conditions ( etd_type , efd_field );
ALTER TABLE events.efmt_conditions
ADD CONSTRAINT fk_efmtc_format
FOREIGN KEY ( etd_type , efmd_order ) REFERENCES events.event_format_definitions ,
ADD CONSTRAINT fk_efmtc_field
FOREIGN KEY ( etd_type , efd_field ) REFERENCES events.event_field_definitions;
-- --------------------------------------------------------
-- OLD CODE BELOW
--
CREATE TYPE event_type CREATE TYPE event_type
AS ENUM ( 'QUEUE' , 'EMPIRE' , 'FLEETS' , 'PLANET', 'ALLIANCE', 'ADMIN' , 'BUGS' ); AS ENUM ( 'QUEUE' , 'EMPIRE' , 'FLEETS' , 'PLANET', 'ALLIANCE', 'ADMIN' , 'BUGS' );
@ -101,7 +254,7 @@ ALTER TABLE events.empire_events
FOREIGN KEY (event_id) REFERENCES events.events FOREIGN KEY (event_id) REFERENCES events.events
ON DELETE CASCADE, ON DELETE CASCADE,
ADD CONSTRAINT fk_empevents_tech ADD CONSTRAINT fk_empevents_tech
FOREIGN KEY (technology_id) REFERENCES tech.levels; FOREIGN KEY (technology_id) REFERENCES tech.technologies;

View file

@ -57,8 +57,8 @@ $$ LANGUAGE plpgsql;
-- the constant's actual value -- the constant's actual value
-- --
CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL ) CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT STRICT
VOLATILE VOLATILE
SECURITY DEFINER SECURITY DEFINER
@ -66,7 +66,7 @@ CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT ,
DECLARE DECLARE
ccid INT; ccid INT;
occid INT; occid INT;
cval REAL; cval DOUBLE PRECISION;
BEGIN BEGIN
ccid := sys.cog_constant_category( ccnm ); ccid := sys.cog_constant_category( ccnm );
@ -97,7 +97,7 @@ BEGIN
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL ) TO :dbuser; GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , DOUBLE PRECISION ) TO :dbuser;
@ -116,8 +116,8 @@ GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL ) TO :dbus
-- the constant's actual value -- the constant's actual value
-- --
CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL , bval REAL , ismin BOOLEAN ) CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval DOUBLE PRECISION , bval DOUBLE PRECISION , ismin BOOLEAN )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT STRICT
VOLATILE VOLATILE
SECURITY DEFINER SECURITY DEFINER
@ -125,9 +125,9 @@ CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT ,
DECLARE DECLARE
ccid INT; ccid INT;
occid INT; occid INT;
cval REAL; cval DOUBLE PRECISION;
mival REAL; mival DOUBLE PRECISION;
maval REAL; maval DOUBLE PRECISION;
BEGIN BEGIN
IF ismin THEN IF ismin THEN
mival := bval; mival := bval;
@ -175,7 +175,7 @@ BEGIN
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL , REAL , BOOLEAN ) TO :dbuser; GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , DOUBLE PRECISION , DOUBLE PRECISION , BOOLEAN ) TO :dbuser;
@ -194,8 +194,8 @@ GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL , REAL , B
-- the constant's actual value -- the constant's actual value
-- --
CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL , mival REAL , maval REAL ) CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval DOUBLE PRECISION , mival DOUBLE PRECISION , maval DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT STRICT
VOLATILE VOLATILE
SECURITY DEFINER SECURITY DEFINER
@ -203,7 +203,7 @@ CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT ,
DECLARE DECLARE
ccid INT; ccid INT;
occid INT; occid INT;
cval REAL; cval DOUBLE PRECISION;
BEGIN BEGIN
ccid := sys.cog_constant_category( ccnm ); ccid := sys.cog_constant_category( ccnm );
@ -243,7 +243,7 @@ BEGIN
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL , REAL , REAL ) TO :dbuser; GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , DOUBLE PRECISION , DOUBLE PRECISION , DOUBLE PRECISION ) TO :dbuser;
@ -259,7 +259,7 @@ GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL , REAL , R
-- TRUE on success, FALSE on failure -- TRUE on success, FALSE on failure
-- --
CREATE OR REPLACE FUNCTION sys.set_constant( cnm TEXT , nval REAL , aid INT ) CREATE OR REPLACE FUNCTION sys.set_constant( cnm TEXT , nval DOUBLE PRECISION , aid INT )
RETURNS BOOLEAN RETURNS BOOLEAN
STRICT STRICT
VOLATILE VOLATILE
@ -282,7 +282,7 @@ BEGIN
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION sys.set_constant( TEXT , REAL , INT ) TO :dbuser; GRANT EXECUTE ON FUNCTION sys.set_constant( TEXT , DOUBLE PRECISION , INT ) TO :dbuser;
@ -294,7 +294,7 @@ GRANT EXECUTE ON FUNCTION sys.set_constant( TEXT , REAL , INT ) TO :dbuser;
-- --
CREATE OR REPLACE FUNCTION sys.get_constant( cnm TEXT ) CREATE OR REPLACE FUNCTION sys.get_constant( cnm TEXT )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT STABLE STRICT STABLE
SECURITY DEFINER SECURITY DEFINER
AS $$ AS $$

View file

@ -42,92 +42,224 @@ CREATE VIEW tech.ships_view
ON b.name_id = s.buildable_id; ON b.name_id = s.buildable_id;
--
-- Categories view
--
CREATE VIEW tech.categories_view
AS SELECT ns.name AS name , ds.name AS description
FROM tech.categories c
INNER JOIN defs.strings ns
ON ns.id = c.name_id
INNER JOIN defs.strings ds
ON ds.id = c.description_id;
GRANT SELECT ON tech.categories_view TO :dbuser;
-- --
-- Creates or updates a technology line -- Technologies view
--
CREATE VIEW tech.technologies_view
AS SELECT cs.name AS category , ns.name AS name ,
ds.name AS description , t.points , t.cost
FROM tech.technologies t
INNER JOIN defs.strings cs
ON cs.id = t.category_id
INNER JOIN defs.strings ns
ON ns.id = t.name_id
INNER JOIN defs.strings ds
ON ds.id = t.description_id;
GRANT SELECT ON tech.technologies_view TO :dbuser;
--
-- Dependencies view
--
CREATE VIEW tech.dependencies_view
AS SELECT ts.name AS technology , ds.name AS dependency
FROM tech.dependencies d
INNER JOIN defs.strings ts
ON ts.id = d.technology_id
INNER JOIN defs.strings ds
ON ds.id = d.depends_on;
GRANT SELECT ON tech.dependencies_view TO :dbuser;
--
-- Creates or updates a technology category
-- --
-- Parameters: -- Parameters:
-- tln Tech line name -- cat_name String identifier of the category's name
-- tld Tech line description -- cat_desc String identifier of the category's description
--
-- Returns:
-- 0 No error
-- 1 Name string not found
-- 2 Description string not found
-- --
CREATE OR REPLACE FUNCTION tech.uoc_line( tln TEXT , tld TEXT ) CREATE OR REPLACE FUNCTION tech.uoc_category( cat_name TEXT , cat_desc TEXT )
RETURNS VOID RETURNS INT
STRICT STRICT VOLATILE
VOLATILE
SECURITY DEFINER SECURITY DEFINER
AS $$ AS $$
DECLARE DECLARE
nid INT; cn_id INT;
did INT; cd_id INT;
BEGIN BEGIN
-- Get string identifiers -- Get name / description identifiers
SELECT INTO nid id FROM defs.strings WHERE name = tln; SELECT INTO cn_id id FROM defs.strings WHERE name = cat_name;
SELECT INTO did id FROM defs.strings WHERE name = tld; IF NOT FOUND THEN
RETURN 1;
END IF;
SELECT INTO cd_id id FROM defs.strings WHERE name = cat_desc;
IF NOT FOUND THEN
RETURN 2;
END IF;
-- Try creating / updating -- Create or update the category
BEGIN BEGIN
INSERT INTO tech.lines ( name_id , description_id ) INSERT INTO tech.categories ( name_id , description_id )
VALUES ( nid , did ); VALUES ( cn_id , cd_id );
EXCEPTION EXCEPTION
WHEN unique_violation THEN WHEN unique_violation THEN
UPDATE tech.lines SET description_id = did UPDATE tech.categories SET description_id = cd_id
WHERE name_id = nid; WHERE name_id = cn_id;
END; END;
RETURN 0;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION tech.uoc_line( TEXT , TEXT ) TO :dbuser; GRANT EXECUTE ON FUNCTION tech.uoc_category( TEXT , TEXT ) to :dbuser;
-- --
-- Creates or updates a technology level -- Creates or updates a technology. If there are dependencies, clear them.
-- --
-- Parameters: -- Parameters:
-- tln Tech line name -- nt_name Name string identifier
-- lv Level -- nt_category Category string identifier
-- lvn Level name -- nt_desc Description string identifier
-- lvd Level description -- nt_points Research points for the technology
-- lvp Points -- nt_cost Cost of the technology
-- lvc Cost --
-- Returns:
-- 0 No error
-- 1 Name string not found
-- 2 Category not found
-- 3 Description string not found
-- 4 Invalid parameters (points or cost)
-- --
CREATE OR REPLACE FUNCTION tech.uoc_level( tln TEXT , lv INT , lvn TEXT , lvd TEXT , lvp INT , lvc INT ) CREATE OR REPLACE FUNCTION tech.uoc_technology( nt_name TEXT , nt_category TEXT , nt_desc TEXT ,
RETURNS VOID nt_points INT , nt_cost INT )
STRICT RETURNS INT
VOLATILE STRICT VOLATILE
SECURITY DEFINER SECURITY DEFINER
AS $$ AS $$
DECLARE DECLARE
lid INT; n_id INT;
nid INT; c_id INT;
did INT; d_id INT;
BEGIN BEGIN
-- Get tech line -- Get name, category and description identifiers
SELECT INTO lid t.name_id SELECT INTO n_id id FROM defs.strings WHERE name = nt_name;
FROM tech.lines t IF NOT FOUND THEN
RETURN 1;
END IF;
SELECT INTO c_id c.name_id FROM tech.categories c
INNER JOIN defs.strings s INNER JOIN defs.strings s
ON s.id = t.name_id ON s.id = c.name_id AND s.name = nt_category;
WHERE s.name = tln; IF NOT FOUND THEN
RETURN 2;
END IF;
SELECT INTO d_id id FROM defs.strings WHERE name = nt_desc;
IF NOT FOUND THEN
RETURN 3;
END IF;
-- Get name / description IDs -- Create or update the technology
SELECT INTO nid id FROM defs.strings WHERE name = lvn;
SELECT INTO did id FROM defs.strings WHERE name = lvd;
-- Create or update the level
BEGIN BEGIN
INSERT INTO tech.levels ( line_id , level , name_id , description_id , points , cost ) BEGIN
VALUES ( lid , lv , nid , did , lvp , lvc ); INSERT INTO tech.technologies ( name_id , category_id , description_id , points , cost )
VALUES ( n_id , c_id , d_id , nt_points , nt_cost );
EXCEPTION EXCEPTION
WHEN unique_violation THEN WHEN unique_violation THEN
UPDATE tech.levels SET name_id = nid , description_id = did , points = lvp , cost = lvc UPDATE tech.technologies
WHERE line_id = lid AND level = lv; SET category_id = c_id , description_id = cd_id ,
points = nt_points , cost = nt_cost
WHERE name_id = n_id;
DELETE FROM tech.dependencies
WHERE technology_id = n_id;
END; END;
EXCEPTION
WHEN check_violation THEN
RETURN 4;
END;
RETURN 0;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION tech.uoc_level( TEXT , INT , TEXT , TEXT , INT , INT ) to :dbuser; GRANT EXECUTE ON FUNCTION tech.uoc_technology( TEXT , TEXT , TEXT , INT , INT ) to :dbuser;
--
-- Adds a technology dependency
--
-- Parameters:
-- nd_name Name of the dependent technology
-- nd_dep Name of the dependency
--
-- Returns:
-- 0 No error
-- 1 Technology not found
-- 2 Dependency not found
-- 3 Duplicate dependency
--
CREATE OR REPLACE FUNCTION tech.add_dependency( nd_name TEXT , nd_dep TEXT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $$
DECLARE
t_id INT;
d_id INT;
BEGIN
-- Get technology
SELECT INTO t_id t.name_id FROM tech.technologies t
INNER JOIN defs.strings s
ON s.id = t.name_id AND s.name = nd_name;
IF NOT FOUND THEN
RETURN 1;
END IF;
-- Get dependency
SELECT INTO d_id t.name_id FROM tech.technologies t
INNER JOIN defs.strings s
ON s.id = t.name_id AND s.name = nd_dep;
IF NOT FOUND THEN
RETURN 2;
END IF;
-- Add dependency
BEGIN
INSERT INTO tech.dependencies ( technology_id , depends_on )
VALUES ( t_id , d_id );
EXCEPTION
WHEN unique_violation THEN
RETURN 3;
END;
RETURN 0;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION tech.add_dependency( TEXT, TEXT ) TO :dbuser;
@ -140,14 +272,13 @@ GRANT EXECUTE ON FUNCTION tech.uoc_level( TEXT , INT , TEXT , TEXT , INT , INT )
-- bdc Cost -- bdc Cost
-- bdw Work -- bdw Work
-- bdu Upkeep -- bdu Upkeep
-- bdtn Dependency (name) -- bdtn Dependency
-- bdtl Dependency (level)
-- --
-- Returns: -- Returns:
-- the buildable's identifier -- the buildable's identifier
-- --
CREATE OR REPLACE FUNCTION tech.uoc_buildable( bdn TEXT , bdd TEXT , bdc INT , bdw INT , bdu INT , bdtn TEXT , bdtl INT ) CREATE OR REPLACE FUNCTION tech.uoc_buildable( bdn TEXT , bdd TEXT , bdc INT , bdw INT , bdu INT , bdtn TEXT )
RETURNS INT RETURNS INT
STRICT STRICT
VOLATILE VOLATILE
@ -162,10 +293,10 @@ BEGIN
SELECT INTO nid id FROM defs.strings WHERE name = bdn; SELECT INTO nid id FROM defs.strings WHERE name = bdn;
SELECT INTO did id FROM defs.strings WHERE name = bdd; SELECT INTO did id FROM defs.strings WHERE name = bdd;
IF bdtn <> '' THEN IF bdtn <> '' THEN
SELECT INTO tdid tl.id FROM tech.levels tl SELECT INTO tdid tl.name_id FROM tech.technologies tl
INNER JOIN defs.strings s INNER JOIN defs.strings s
ON s.id = tl.line_id ON s.id = tl.name_id
WHERE s.name = bdtn AND tl.level = bdtl; WHERE s.name = bdtn;
END IF; END IF;
-- Create or update the definition -- Create or update the definition
@ -181,7 +312,7 @@ BEGIN
-- Set dependencies -- Set dependencies
DELETE FROM tech.buildable_requirements WHERE buildable_id = nid; DELETE FROM tech.buildable_requirements WHERE buildable_id = nid;
IF bdtn <> '' THEN IF bdtn <> '' THEN
INSERT INTO tech.buildable_requirements ( buildable_id , level_id ) INSERT INTO tech.buildable_requirements ( buildable_id , technology_id )
VALUES ( nid , tdid ); VALUES ( nid , tdid );
END IF; END IF;
@ -215,7 +346,7 @@ CREATE OR REPLACE FUNCTION tech.uoc_building( bdn TEXT , bdd TEXT , bdc INT , bd
DECLARE DECLARE
bdid INT; bdid INT;
BEGIN BEGIN
bdid := tech.uoc_buildable( bdn , bdd , bdc , bdw , bdu , '' , 0 ); bdid := tech.uoc_buildable( bdn , bdd , bdc , bdw , bdu , '' );
PERFORM buildable_id FROM tech.ships WHERE buildable_id = bdid; PERFORM buildable_id FROM tech.ships WHERE buildable_id = bdid;
IF FOUND THEN IF FOUND THEN
@ -249,22 +380,20 @@ GRANT EXECUTE ON FUNCTION tech.uoc_building( TEXT , TEXT , INT , INT , INT , INT
-- bdwk Workers -- bdwk Workers
-- bdot Output type -- bdot Output type
-- bdo Output -- bdo Output
-- bdtn Dependency (name) -- bdtn Dependency
-- bdtl Dependency (level)
-- --
CREATE OR REPLACE FUNCTION tech.uoc_building( bdn TEXT , bdd TEXT , bdc INT , bdw INT , CREATE OR REPLACE FUNCTION tech.uoc_building( bdn TEXT , bdd TEXT , bdc INT , bdw INT ,
bdu INT , bdwk INT , bdot building_output_type , bdo INT , bdu INT , bdwk INT , bdot building_output_type , bdo INT ,
bdtn TEXT , bdtl INT ) bdtn TEXT )
RETURNS VOID RETURNS VOID
STRICT STRICT VOLATILE
VOLATILE
SECURITY DEFINER SECURITY DEFINER
AS $$ AS $$
DECLARE DECLARE
bdid INT; bdid INT;
BEGIN BEGIN
bdid := tech.uoc_buildable( bdn , bdd , bdc , bdw , bdu , bdtn , bdtl ); bdid := tech.uoc_buildable( bdn , bdd , bdc , bdw , bdu , bdtn );
PERFORM buildable_id FROM tech.ships WHERE buildable_id = bdid; PERFORM buildable_id FROM tech.ships WHERE buildable_id = bdid;
IF FOUND THEN IF FOUND THEN
@ -282,7 +411,7 @@ BEGIN
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION tech.uoc_building( TEXT , TEXT , INT , INT , INT , INT , building_output_type , INT , TEXT , INT ) TO :dbuser; GRANT EXECUTE ON FUNCTION tech.uoc_building( TEXT , TEXT , INT , INT , INT , INT , building_output_type , INT , TEXT ) TO :dbuser;
@ -309,7 +438,7 @@ CREATE OR REPLACE FUNCTION tech.uoc_ship( sn TEXT , sd TEXT , sc INT , sw INT ,
DECLARE DECLARE
bdid INT; bdid INT;
BEGIN BEGIN
bdid := tech.uoc_buildable( sn , sd , sc , sw , su , '' , 0 ); bdid := tech.uoc_buildable( sn , sd , sc , sw , su , '' );
PERFORM buildable_id FROM tech.buildings WHERE buildable_id = bdid; PERFORM buildable_id FROM tech.buildings WHERE buildable_id = bdid;
IF FOUND THEN IF FOUND THEN
@ -342,12 +471,11 @@ GRANT EXECUTE ON FUNCTION tech.uoc_ship( TEXT , TEXT , INT , INT , INT , INT , I
-- su Upkeep -- su Upkeep
-- sp Power -- sp Power
-- sft Orbital flight time -- sft Orbital flight time
-- stdn Tech line name -- stdn Tech name
-- stdl Tech level
-- --
CREATE OR REPLACE FUNCTION tech.uoc_ship( sn TEXT , sd TEXT , sc INT , sw INT , CREATE OR REPLACE FUNCTION tech.uoc_ship( sn TEXT , sd TEXT , sc INT , sw INT ,
su INT , sp INT , sft INT , stdn TEXT , stdl INT ) su INT , sp INT , sft INT , stdn TEXT )
RETURNS VOID RETURNS VOID
STRICT STRICT
VOLATILE VOLATILE
@ -356,7 +484,7 @@ CREATE OR REPLACE FUNCTION tech.uoc_ship( sn TEXT , sd TEXT , sc INT , sw INT ,
DECLARE DECLARE
bdid INT; bdid INT;
BEGIN BEGIN
bdid := tech.uoc_buildable( sn , sd , sc , sw , su , stdn , stdl ); bdid := tech.uoc_buildable( sn , sd , sc , sw , su , stdn );
PERFORM buildable_id FROM tech.buildings WHERE buildable_id = bdid; PERFORM buildable_id FROM tech.buildings WHERE buildable_id = bdid;
IF FOUND THEN IF FOUND THEN
@ -374,6 +502,6 @@ BEGIN
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION tech.uoc_ship( TEXT , TEXT , INT , INT , INT , INT , INT , TEXT , INT ) TO :dbuser; GRANT EXECUTE ON FUNCTION tech.uoc_ship( TEXT , TEXT , INT , INT , INT , INT , INT , TEXT ) TO :dbuser;

View file

@ -3,7 +3,7 @@
-- --
-- Empire management functions and views -- Empire management functions and views
-- --
-- Copyright(C) 2004-2010, DeepClone Development -- Copyright(C) 2004-2011, DeepClone Development
-- -------------------------------------------------------- -- --------------------------------------------------------
@ -15,7 +15,7 @@
-- pid Planet identifier -- pid Planet identifier
-- icash Initial cash -- icash Initial cash
-- --
CREATE OR REPLACE FUNCTION emp.create_empire( nid INT , pid INT , icash REAL ) CREATE OR REPLACE FUNCTION emp.create_empire( nid INT , pid INT , icash DOUBLE PRECISION )
RETURNS VOID RETURNS VOID
STRICT STRICT
VOLATILE VOLATILE
@ -81,49 +81,6 @@ $$ LANGUAGE SQL;
GRANT EXECUTE ON FUNCTION emp.get_current( INT ) TO :dbuser; GRANT EXECUTE ON FUNCTION emp.get_current( INT ) TO :dbuser;
--
-- Implements a technology
--
CREATE OR REPLACE FUNCTION emp.implement_tech( e_id INT , l_id INT )
RETURNS VOID
STRICT VOLATILE
SECURITY DEFINER
AS $$
DECLARE
e_cash REAL;
lev INT;
cost REAL;
BEGIN
SELECT INTO e_cash , lev , cost e.cash , et.level , tl.cost
FROM emp.empires e
INNER JOIN emp.technologies et
ON et.line_id = l_id AND et.empire_id = e.name_id
INNER JOIN tech.levels tl
ON tl.line_id = l_id AND tl.level = et.level
AND tl.points = floor( et.accumulated )
AND tl.cost <= e.cash
WHERE e.name_id = e_id
FOR UPDATE OF e , et;
IF NOT FOUND THEN
RETURN;
END IF;
UPDATE emp.empires
SET cash = e_cash - cost
WHERE name_id = e_id;
UPDATE emp.technologies
SET level = lev + 1 , accumulated = 0
WHERE empire_id = e_id AND line_id = l_id;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION emp.implement_tech( INT , INT ) TO :dbuser;
-- --
-- Add an enemy empire -- Add an enemy empire
-- --
@ -413,7 +370,7 @@ CREATE OR REPLACE FUNCTION emp.get_new_planet( e_id INT , p_name TEXT , OUT err_
DECLARE DECLARE
plid INT; plid INT;
accid INT; accid INT;
ccash REAL; ccash DOUBLE PRECISION;
f_id BIGINT; f_id BIGINT;
fleets BIGINT[]; fleets BIGINT[];
BEGIN BEGIN
@ -484,7 +441,7 @@ CREATE VIEW emp.enemies
-- --
CREATE VIEW emp.general_information CREATE VIEW emp.general_information
AS SELECT e.name_id AS id , en.name AS name , AS SELECT e.name_id AS id , en.name AS name , av.language ,
( CASE ( CASE
WHEN av.status = 'QUITTING' THEN 'q' WHEN av.status = 'QUITTING' THEN 'q'
WHEN av.status = 'VACATION' THEN 'v' WHEN av.status = 'VACATION' THEN 'v'
@ -600,50 +557,6 @@ CREATE VIEW emp.overview
GRANT SELECT ON emp.overview TO :dbuser; GRANT SELECT ON emp.overview TO :dbuser;
--
-- Empire tech lines
--
CREATE VIEW emp.tech_lines_view
AS SELECT e.name_id AS empire , tl.name_id AS tech_line ,
t1.translated_string AS name ,
t2.translated_string AS description
FROM emp.empires e
INNER JOIN emp.technologies et ON et.empire_id = e.name_id
INNER JOIN tech.lines tl ON tl.name_id = et.line_id
INNER JOIN naming.empire_names en ON en.id = e.name_id
INNER JOIN users.credentials c ON c.address_id = en.owner_id
INNER JOIN defs.translations t1 ON t1.string_id = tl.name_id AND t1.lang_id = c.language_id
INNER JOIN defs.translations t2 ON t2.string_id = tl.description_id AND t2.lang_id = c.language_id
ORDER BY t1.translated_string;
GRANT SELECT ON emp.tech_lines_view TO :dbuser;
--
-- Empire technologies
--
CREATE VIEW emp.technologies_view
AS SELECT e.name_id AS empire , tl.name_id AS tech_line ,
t1.translated_string AS name ,
t2.translated_string AS description ,
( et.level > tlv.level ) AS implemented ,
floor( 100 * et.accumulated / tlv.points ) AS progress ,
tlv.cost AS cost
FROM emp.empires e
INNER JOIN emp.technologies et ON et.empire_id = e.name_id
INNER JOIN tech.lines tl ON tl.name_id = et.line_id
INNER JOIN tech.levels tlv ON tlv.line_id = tl.name_id AND tlv.level <= et.level
INNER JOIN naming.empire_names en ON en.id = e.name_id
INNER JOIN users.credentials c ON c.address_id = en.owner_id
INNER JOIN defs.translations t1 ON t1.string_id = tlv.name_id AND t1.lang_id = c.language_id
INNER JOIN defs.translations t2 ON t2.string_id = tlv.description_id AND t2.lang_id = c.language_id
ORDER BY tl.name_id , tlv.level;
GRANT SELECT ON emp.technologies_view TO :dbuser;
-- --
-- Enemy lists -- Enemy lists
-- --

View file

@ -0,0 +1,227 @@
-- LegacyWorlds Beta 6
-- PostgreSQL database scripts
--
-- Research mananagement functions and views
--
-- Copyright(C) 2004-2011, DeepClone Development
-- --------------------------------------------------------
--
-- Implement a technology
--
-- Parameters:
-- e_id Empire identifier
-- t_name Technology name
--
-- Returns:
-- 0 on success
-- 1 if the empire does not posses the necessary resources
-- 2 if the technology or empire were not found
--
CREATE OR REPLACE FUNCTION emp.implement_tech( e_id INT , t_name TEXT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $$
DECLARE
e_cash DOUBLE PRECISION;
t_id INT;
t_cost DOUBLE PRECISION;
BEGIN
SELECT INTO e_cash , t_id , t_cost e.cash , ns.id , td.cost
FROM defs.strings ns
INNER JOIN tech.technologies td
ON td.name_id = ns.id
INNER JOIN emp.researched_technologies rt
ON rt.technology_id = td.name_id
INNER JOIN emp.empires e
ON rt.empire_id = e.name_id
WHERE e.name_id = e_id AND ns.name = t_name
FOR UPDATE OF e , rt;
IF NOT FOUND THEN
RETURN 2;
END IF;
IF e_cash < t_cost THEN
RETURN 1;
END IF;
UPDATE emp.empires
SET cash = e_cash - t_cost
WHERE name_id = e_id;
UPDATE emp.researched_technologies
SET implemented = TRUE
WHERE empire_id = e_id AND technology_id = t_id;
RETURN 0;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION emp.implement_tech( INT , TEXT ) TO :dbuser;
--
-- Prepare for research priorities updates
--
CREATE OR REPLACE FUNCTION emp.prepare_research_priorities_update( )
RETURNS VOID
STRICT VOLATILE
SECURITY DEFINER
AS $$
BEGIN
CREATE TEMPORARY TABLE research_priorities_updates(
technology TEXT ,
priority INT
);
CREATE INDEX rpu_technology ON research_priorities_updates ( technology );
IF session_user <> current_user THEN
EXECUTE 'GRANT INSERT ON research_priorities_updates TO ' || session_user;
END IF;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION emp.prepare_research_priorities_update( ) TO :dbuser;
--
-- Applies research priorities updates
--
-- Parameters:
-- e_id identifier of the empire the updates should be applied to
--
-- Returns:
-- an error code:
-- 0 success
-- 1 list of updates does not match current research topics
-- 2 invalid priorities
--
CREATE OR REPLACE FUNCTION emp.apply_research_priorities( IN e_id INT )
RETURNS INT
STRICT VOLATILE
SECURITY DEFINER
AS $$
DECLARE
rec RECORD;
t INT;
rval INT;
BEGIN
-- Lock empire and research info
PERFORM er.technology_id
FROM emp.empires e
INNER JOIN emp.research er ON er.empire_id = e.name_id
WHERE e.name_id = e_id
FOR UPDATE OF e , er;
-- Check values
t := 0;
rval := 0;
FOR rec IN SELECT rpu.priority , r.technology_id FROM research_priorities_updates rpu
LEFT OUTER JOIN emp.research_view r
ON ( r.detailed AND r.technology = rpu.technology )
OR ( NOT r.detailed AND ( 'unknown-' || ( r.technology_id * e_id )::TEXT ) = rpu.technology )
WHERE r.empire = e_id OR r.empire IS NULL
UNION SELECT rpu.priority , r.technology_id FROM research_priorities_updates rpu
RIGHT OUTER JOIN emp.research_view r
ON ( r.detailed AND r.technology = rpu.technology )
OR ( NOT r.detailed AND ( 'unknown-' || ( r.technology_id * e_id )::TEXT ) = rpu.technology )
WHERE r.empire = e_id
LOOP
IF rec.priority IS NULL OR rec.technology_id IS NULL THEN
rval := 1;
EXIT;
ELSIF rec.priority NOT BETWEEN 0 AND 100 THEN
rval := 2;
EXIT;
END IF;
t := t + rec.priority;
END LOOP;
IF rval = 0 AND t <> 100 THEN
rval := 2;
END IF;
-- Update research info
IF rval = 0 THEN
UPDATE emp.research er SET priority = rpu.priority
FROM research_priorities_updates rpu , emp.research_view rv
WHERE ( rpu.technology = CASE
WHEN rv.detailed THEN
rv.technology
ELSE
( 'unknown-' || ( rv.technology_id * e_id )::TEXT )
END )
AND rv.empire = e_id
AND er.empire_id = e_id
AND er.technology_id = rv.technology_id;
END IF;
DROP TABLE research_priorities_updates;
RETURN rval;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION emp.apply_research_priorities( INT ) TO :dbuser;
--
-- Base research view
--
CREATE VIEW emp.base_research_view
AS SELECT er.empire_id AS empire , er.technology_id , ns.name AS technology ,
td.points AS required , ( CASE
WHEN er.accumulated > td.points THEN
td.points - 1
ELSE
er.accumulated
END ) AS accumulated , er.priority
FROM emp.research er
INNER JOIN tech.technologies td ON td.name_id = er.technology_id
INNER JOIN defs.strings ns ON ns.id = er.technology_id;
--
-- Research view
--
CREATE VIEW emp.research_view
AS SELECT empire , technology , technology_id ,
FLOOR( 100 * accumulated / required )::INT AS completion ,
( accumulated >= sys.get_constant( 'game.research.minPoints' )
OR accumulated / required >= sys.get_constant( 'game.research.minRatio' ) ) AS detailed ,
priority
FROM emp.base_research_view;
--
-- Researched and implemented technologies view
CREATE VIEW emp.known_techs_view
AS SELECT et.empire_id AS empire , et.technology_id , ns.name AS technology ,
( CASE WHEN et.implemented THEN NULL::INT ELSE td.cost END ) AS cost
FROM emp.researched_technologies et
INNER JOIN tech.technologies td ON td.name_id = et.technology_id
INNER JOIN defs.strings ns ON ns.id = et.technology_id;
--
-- Combined research and technologies view
--
CREATE VIEW emp.technologies_view
AS SELECT empire , technology_id , technology ,
detailed , completion , priority , NULL::INT AS cost
FROM emp.research_view
UNION ALL SELECT empire , technology_id , technology ,
TRUE AS detailed , NULL::INT AS completion , NULL::INT AS priority , cost
FROM emp.known_techs_view;
GRANT SELECT ON emp.technologies_view TO :dbuser;

View file

@ -11,14 +11,14 @@
-- sigma( x ) = exp( x ) / ( 1 + exp( x ) ) -- sigma( x ) = exp( x ) / ( 1 + exp( x ) )
-- --
CREATE OR REPLACE FUNCTION verse.sigma( x REAL ) CREATE OR REPLACE FUNCTION verse.sigma( x DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
SELECT ( CASE SELECT ( CASE
WHEN $1 < -100 THEN 0 WHEN $1 < -100 THEN 0
WHEN $1 > 100 THEN 1 WHEN $1 > 100 THEN 1
ELSE ( exp( $1 ) / ( 1 + exp( $1 ) ) )::REAL ELSE ( exp( $1 ) / ( 1 + exp( $1 ) ) )
END ); END );
$$ LANGUAGE SQL; $$ LANGUAGE SQL;
@ -28,8 +28,8 @@ $$ LANGUAGE SQL;
-- poly( x , a , b , c ) = ( a * x + b ) * x + c -- poly( x , a , b , c ) = ( a * x + b ) * x + c
-- --
CREATE OR REPLACE FUNCTION verse.poly( x REAL , a REAL , b REAL , c REAL ) CREATE OR REPLACE FUNCTION verse.poly( x DOUBLE PRECISION , a DOUBLE PRECISION , b DOUBLE PRECISION , c DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
SELECT ( $2 * $1 + $3 ) * $1 + $4; SELECT ( $2 * $1 + $3 ) * $1 + $4;
@ -41,11 +41,11 @@ $$ LANGUAGE SQL;
-- Happiness curve, K1 constant -- Happiness curve, K1 constant
-- --
CREATE OR REPLACE FUNCTION verse.hcc_const_k1( xmax REAL , ymax REAL , xlimit REAL , ylimit REAL ) CREATE OR REPLACE FUNCTION verse.hcc_const_k1( xmax DOUBLE PRECISION , ymax DOUBLE PRECISION , xlimit DOUBLE PRECISION , ylimit DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
SELECT ( ( $4 - $2 ) / ( ( $3 - $1 ) ^ 2 ) )::REAL; SELECT ( ( $4 - $2 ) / ( ( $3 - $1 ) ^ 2 ) );
$$ LANGUAGE SQL; $$ LANGUAGE SQL;
@ -54,11 +54,11 @@ $$ LANGUAGE SQL;
-- Happiness curve, K2 constant -- Happiness curve, K2 constant
-- --
CREATE OR REPLACE FUNCTION verse.hcc_const_k2( ylimit REAL , yasymptote REAL ) CREATE OR REPLACE FUNCTION verse.hcc_const_k2( ylimit DOUBLE PRECISION , yasymptote DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
SELECT ( 2 * ( $1 - $2 ) )::REAL; SELECT ( 2 * ( $1 - $2 ) );
$$ LANGUAGE SQL; $$ LANGUAGE SQL;
@ -67,11 +67,11 @@ $$ LANGUAGE SQL;
-- Happiness curve, K3 constant -- Happiness curve, K3 constant
-- --
CREATE OR REPLACE FUNCTION verse.hcc_const_k3( xmax REAL , ymax REAL , xlimit REAL , ylimit REAL , yasymptote REAL ) CREATE OR REPLACE FUNCTION verse.hcc_const_k3( xmax DOUBLE PRECISION , ymax DOUBLE PRECISION , xlimit DOUBLE PRECISION , ylimit DOUBLE PRECISION , yasymptote DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
SELECT ( verse.hcc_const_k1( $1 , $2 , $3 , $4 ) * 4 * ( $3 - $1 ) / ( $5 - $4 ) ) ::REAL; SELECT ( verse.hcc_const_k1( $1 , $2 , $3 , $4 ) * 4 * ( $3 - $1 ) / ( $5 - $4 ) );
$$ LANGUAGE SQL; $$ LANGUAGE SQL;
@ -80,15 +80,15 @@ $$ LANGUAGE SQL;
-- Happiness curve, first part -- Happiness curve, first part
-- --
CREATE OR REPLACE FUNCTION verse.hcc_part_1( x REAL , ymin REAL , ymax REAL , xmax REAL ) CREATE OR REPLACE FUNCTION verse.hcc_part_1( x DOUBLE PRECISION , ymin DOUBLE PRECISION , ymax DOUBLE PRECISION , xmax DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
v REAL; v DOUBLE PRECISION;
BEGIN BEGIN
v := ( ymin - ymax ) / xmax; v := ( ymin - ymax ) / xmax;
RETURN verse.poly( x , ( v / xmax )::REAL , ( -2 * v )::REAL , ymin ); RETURN verse.poly( x , v / xmax , -2 * v , ymin );
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
@ -98,15 +98,15 @@ $$ LANGUAGE plpgsql;
-- Happiness curve, second part -- Happiness curve, second part
-- --
CREATE OR REPLACE FUNCTION verse.hcc_part_2( x REAL , xmax REAL , ymax REAL , xlimit REAL , ylimit REAL ) CREATE OR REPLACE FUNCTION verse.hcc_part_2( x DOUBLE PRECISION , xmax DOUBLE PRECISION , ymax DOUBLE PRECISION , xlimit DOUBLE PRECISION , ylimit DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
k1 REAL; k1 DOUBLE PRECISION;
BEGIN BEGIN
k1 := verse.hcc_const_k1( xmax , ymax , xlimit , ylimit ); k1 := verse.hcc_const_k1( xmax , ymax , xlimit , ylimit );
RETURN verse.poly( x , k1 , ( -2 * xmax * k1 )::REAL , ( ymax + k1 * xmax * xmax )::REAL ); RETURN verse.poly( x , k1 , -2 * xmax * k1 , ymax + k1 * xmax * xmax );
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
@ -116,17 +116,17 @@ $$ LANGUAGE plpgsql;
-- Happiness curve, third part -- Happiness curve, third part
-- --
CREATE OR REPLACE FUNCTION verse.hcc_part_3( x REAL , xmax REAL , ymax REAL , xlimit REAL , ylimit REAL , yasymptote REAL ) CREATE OR REPLACE FUNCTION verse.hcc_part_3( x DOUBLE PRECISION , xmax DOUBLE PRECISION , ymax DOUBLE PRECISION , xlimit DOUBLE PRECISION , ylimit DOUBLE PRECISION , yasymptote DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
k2 REAL; k2 DOUBLE PRECISION;
k3 REAL; k3 DOUBLE PRECISION;
BEGIN BEGIN
k2 := verse.hcc_const_k2( ylimit , yasymptote ); k2 := verse.hcc_const_k2( ylimit , yasymptote );
k3 := verse.hcc_const_k3( xmax , ymax , xlimit , ylimit , yasymptote ); k3 := verse.hcc_const_k3( xmax , ymax , xlimit , ylimit , yasymptote );
RETURN yasymptote + k2 * ( 1 - verse.sigma( ( k3 * ( x - xlimit ) ) )::REAL ); RETURN yasymptote + k2 * ( 1 - verse.sigma( ( k3 * ( x - xlimit ) ) ) );
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
@ -136,8 +136,8 @@ $$ LANGUAGE plpgsql;
-- Happiness curve -- Happiness curve
-- --
CREATE OR REPLACE FUNCTION verse.happiness_curve( x REAL , ymin REAL , xmax REAL , ymax REAL , xlimit REAL , ylimit REAL , yasymptote REAL ) CREATE OR REPLACE FUNCTION verse.happiness_curve( x DOUBLE PRECISION , ymin DOUBLE PRECISION , xmax DOUBLE PRECISION , ymax DOUBLE PRECISION , xlimit DOUBLE PRECISION , ylimit DOUBLE PRECISION , yasymptote DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE SECURITY INVOKER STRICT IMMUTABLE SECURITY INVOKER
AS $$ AS $$
SELECT (CASE SELECT (CASE
@ -156,37 +156,37 @@ $$ LANGUAGE SQL;
-- Happiness computation -- Happiness computation
-- --
CREATE OR REPLACE FUNCTION verse.compute_happiness( population REAL , workers REAL , defence REAL , empsize INT ) CREATE OR REPLACE FUNCTION verse.compute_happiness( population DOUBLE PRECISION , workers DOUBLE PRECISION , defence DOUBLE PRECISION , empsize INT )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT STABLE SECURITY INVOKER STRICT STABLE SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
whappiness REAL; whappiness DOUBLE PRECISION;
dhappiness REAL; dhappiness DOUBLE PRECISION;
shappiness REAL; shappiness DOUBLE PRECISION;
BEGIN BEGIN
-- Work-related happiness -- Work-related happiness
whappiness := verse.happiness_curve( whappiness := verse.happiness_curve(
( workers / population )::REAL , workers / population ,
sys.get_constant( 'game.happiness.noEmployment' ) , 1.0 , 1.0 , sys.get_constant( 'game.happiness.noEmployment' ) , 1.0 , 1.0 ,
sys.get_constant( 'game.happiness.employmentLimit' ) , 0.5 , 0 sys.get_constant( 'game.happiness.employmentLimit' ) , 0.5 , 0
); );
-- Defence-related happiness -- Defence-related happiness
dhappiness := verse.happiness_curve( dhappiness := verse.happiness_curve(
( sys.get_constant( 'game.happiness.popPerDefencePoint' ) * defence / population )::REAL , sys.get_constant( 'game.happiness.popPerDefencePoint' ) * defence / population ,
sys.get_constant( 'game.happiness.noDefence' ) , 1.0 , 1.0 , sys.get_constant( 'game.happiness.noDefence' ) , 1.0 , 1.0 ,
sys.get_constant( 'game.happiness.defenceLimit' ) , 0.5 , 0 sys.get_constant( 'game.happiness.defenceLimit' ) , 0.5 , 0
); );
-- Influence of empire size -- Influence of empire size
shappiness := verse.happiness_curve( shappiness := verse.happiness_curve(
( empsize::REAL / sys.get_constant( 'game.happiness.idealEmpireSize' ) )::REAL , empsize / sys.get_constant( 'game.happiness.idealEmpireSize' ) ,
sys.get_constant( 'game.happiness.smallEmpire' ) , 1.0 , 1.0 , sys.get_constant( 'game.happiness.smallEmpire' ) , 1.0 , 1.0 ,
sys.get_constant( 'game.happiness.eSizeLimit' ) , 0.5 , 0 sys.get_constant( 'game.happiness.eSizeLimit' ) , 0.5 , 0
); );
RETURN ( shappiness * ( whappiness + dhappiness ) / 2.0 )::REAL; RETURN shappiness * ( whappiness + dhappiness ) / 2.0;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
@ -195,14 +195,14 @@ $$ LANGUAGE plpgsql;
-- --
-- Production adjustment -- Production adjustment
-- --
CREATE OR REPLACE FUNCTION verse.adjust_production( prod REAL , happiness REAL ) CREATE OR REPLACE FUNCTION verse.adjust_production( prod DOUBLE PRECISION , happiness DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE STRICT IMMUTABLE
SECURITY INVOKER SECURITY INVOKER
AS $$ AS $$
SELECT ( CASE SELECT ( CASE
WHEN $2 < sys.get_constant( 'game.happiness.strike' ) THEN WHEN $2 < sys.get_constant( 'game.happiness.strike' ) THEN
( $1 * ( 1 - ( $2 / sys.get_constant( 'game.happiness.strike' ) ) ) )::REAL $1 * ( 1 - ( $2 / sys.get_constant( 'game.happiness.strike' ) ) )
ELSE ELSE
$1 $1
END ); END );
@ -213,15 +213,15 @@ $$ LANGUAGE SQL;
-- Income computation -- Income computation
-- --
CREATE OR REPLACE FUNCTION verse.compute_income( population REAL , happiness REAL , cashprod REAL ) CREATE OR REPLACE FUNCTION verse.compute_income( population DOUBLE PRECISION , happiness DOUBLE PRECISION , cashprod DOUBLE PRECISION )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT STABLE STRICT STABLE
SECURITY INVOKER SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
base REAL; base DOUBLE PRECISION;
badj REAL; badj DOUBLE PRECISION;
cprod REAL; cprod DOUBLE PRECISION;
BEGIN BEGIN
badj := ( 1 - verse.adjust_production( 1.0 , happiness ) ) * sys.get_constant( 'game.work.strikeEffect' ); badj := ( 1 - verse.adjust_production( 1.0 , happiness ) ) * sys.get_constant( 'game.work.strikeEffect' );
base := floor( population ) * sys.get_constant( 'game.work.population' ) * ( 1 - badj ); base := floor( population ) * sys.get_constant( 'game.work.population' ) * ( 1 - badj );

View file

@ -19,14 +19,14 @@
-- --
CREATE OR REPLACE FUNCTION verse.get_raw_production( pid INT , pt building_output_type ) CREATE OR REPLACE FUNCTION verse.get_raw_production( pid INT , pt building_output_type )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT STABLE STRICT STABLE
SECURITY DEFINER SECURITY DEFINER
AS $$ AS $$
DECLARE DECLARE
rv REAL; rv DOUBLE PRECISION;
BEGIN BEGIN
SELECT INTO rv SUM( b.amount * d.output )::REAL SELECT INTO rv SUM( b.amount * d.output )
FROM verse.planet_buildings b FROM verse.planet_buildings b
INNER JOIN tech.buildings d INNER JOIN tech.buildings d
ON d.buildable_id = b.building_id AND d.output_type = pt ON d.buildable_id = b.building_id AND d.output_type = pt
@ -114,14 +114,14 @@ $$ LANGUAGE SQL;
-- --
CREATE OR REPLACE FUNCTION verse.get_planet_upkeep( pid INT ) CREATE OR REPLACE FUNCTION verse.get_planet_upkeep( pid INT )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT STABLE STRICT STABLE
SECURITY INVOKER SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
rv REAL; rv DOUBLE PRECISION;
BEGIN BEGIN
SELECT INTO rv SUM( b.amount * d.upkeep )::REAL SELECT INTO rv SUM( b.amount * d.upkeep )
FROM verse.planet_buildings b FROM verse.planet_buildings b
INNER JOIN tech.buildables d INNER JOIN tech.buildables d
ON d.name_id = b.building_id ON d.name_id = b.building_id
@ -145,7 +145,7 @@ $$ LANGUAGE plpgsql;
-- npics Amount of planet pictures -- npics Amount of planet pictures
-- --
CREATE OR REPLACE FUNCTION verse.create_planet( sid INT , o INT , ipop REAL , npics INT ) CREATE OR REPLACE FUNCTION verse.create_planet( sid INT , o INT , ipop DOUBLE PRECISION , npics INT )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY INVOKER
@ -156,7 +156,7 @@ DECLARE
bpp INT; bpp INT;
uid BIGINT; uid BIGINT;
utp update_type; utp update_type;
happiness REAL; happiness DOUBLE PRECISION;
BEGIN BEGIN
-- Planet name and planet -- Planet name and planet
pnid := naming.create_map_name( 'P' ); pnid := naming.create_map_name( 'P' );
@ -217,7 +217,7 @@ $$ LANGUAGE plpgsql;
-- npics Amount of planet pictures -- npics Amount of planet pictures
-- --
CREATE OR REPLACE FUNCTION verse.create_system( sx INT , sy INT , ipop REAL , npics INT ) CREATE OR REPLACE FUNCTION verse.create_system( sx INT , sy INT , ipop DOUBLE PRECISION , npics INT )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY INVOKER
@ -249,7 +249,7 @@ $$ LANGUAGE plpgsql;
-- ipop Initial population -- ipop Initial population
-- --
CREATE OR REPLACE FUNCTION verse.create_systems( x0 INT , y0 INT , x1 INT , y1 INT , ipop REAL ) CREATE OR REPLACE FUNCTION verse.create_systems( x0 INT , y0 INT , x1 INT , y1 INT , ipop DOUBLE PRECISION )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY INVOKER
@ -283,7 +283,7 @@ CREATE OR REPLACE FUNCTION verse.generate_initial_universe( )
AS $$ AS $$
DECLARE DECLARE
sz INT; sz INT;
pop REAL; pop DOUBLE PRECISION;
npics INT; npics INT;
BEGIN BEGIN
sz := floor( sys.get_constant( 'game.universe.initialSize' ) ); sz := floor( sys.get_constant( 'game.universe.initialSize' ) );
@ -316,7 +316,7 @@ DECLARE
y0 INT; y0 INT;
x1 INT; x1 INT;
y1 INT; y1 INT;
pop REAL; pop DOUBLE PRECISION;
BEGIN BEGIN
-- Get current bounds -- Get current bounds
SELECT INTO min_x , max_x , min_y , max_y SELECT INTO min_x , max_x , min_y , max_y
@ -368,7 +368,7 @@ CREATE OR REPLACE FUNCTION verse.generate( )
AS $$ AS $$
DECLARE DECLARE
p_count INT; p_count INT;
f_ratio REAL; f_ratio DOUBLE PRECISION;
BEGIN BEGIN
-- Get total planet count -- Get total planet count
SELECT INTO p_count 5 * count(*) SELECT INTO p_count 5 * count(*)
@ -381,7 +381,7 @@ BEGIN
END IF; END IF;
-- Get available planets ratio -- Get available planets ratio
SELECT INTO f_ratio count(*)::REAL / p_count::REAL SELECT INTO f_ratio count(*)::DOUBLE PRECISION / p_count::DOUBLE PRECISION
FROM verse.available_planets; FROM verse.available_planets;
-- Expand universe if required -- Expand universe if required

View file

@ -175,17 +175,17 @@ CREATE OR REPLACE FUNCTION verse.get_orbital_view( e_id INT , p_id INT )
AS $$ AS $$
DECLARE DECLARE
rv planet_orbital_data; rv planet_orbital_data;
happ REAL; happ DOUBLE PRECISION;
e_att BOOLEAN; e_att BOOLEAN;
rec RECORD; rec RECORD;
BEGIN BEGIN
-- Get the planet's population and defence -- Get the planet's population and defence
SELECT INTO rv.population , happ SELECT INTO rv.population , happ
floor( p.population )::BIGINT , ( ph.current / p.population )::REAL floor( p.population )::BIGINT , ( ph.current / p.population )::DOUBLE PRECISION
FROM verse.planets p FROM verse.planets p
INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id
WHERE p.name_id = p_id; WHERE p.name_id = p_id;
rv.defence := round( verse.adjust_production( verse.get_raw_production( p_id , 'DEF' ) , happ ) ); rv.defence := verse.adjust_production( verse.get_raw_production( p_id , 'DEF' ) , happ );
-- Get the empire's fleet mode -- Get the empire's fleet mode
SELECT INTO e_att f.attacking SELECT INTO e_att f.attacking
@ -332,8 +332,7 @@ AS $$
( bd.workers * b.amount )::INT AS jobs , ( bd.workers * b.amount )::INT AS jobs ,
( bd.upkeep * b.amount )::BIGINT AS upkeep , ( bd.upkeep * b.amount )::BIGINT AS upkeep ,
bd.output_type AS p_type , bd.output_type AS p_type ,
floor( verse.adjust_production( ( bd.output * b.amount )::REAL , floor( verse.adjust_production( bd.output * b.amount , ph.current / p.population )
( ph.current / p.population )::REAL )
)::BIGINT AS p_value )::BIGINT AS p_value
FROM verse.planet_buildings b FROM verse.planet_buildings b
INNER JOIN verse.planets p ON p.name_id = b.planet_id INNER JOIN verse.planets p ON p.name_id = b.planet_id
@ -373,9 +372,9 @@ AS $$
ELSE floor( qi.amount * bd.cost - ( CASE WHEN qi.queue_order = 0 THEN q.money ELSE 0 END ) ) ELSE floor( qi.amount * bd.cost - ( CASE WHEN qi.queue_order = 0 THEN q.money ELSE 0 END ) )
END )::BIGINT AS investment , END )::BIGINT AS investment ,
( CASE ( CASE
WHEN ceil( verse.adjust_production( ( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) )::REAL , ( ph.current / p.population )::REAL ) ) = 0 THEN NULL WHEN ceil( verse.adjust_production( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) , ph.current / p.population ) ) = 0 THEN NULL
ELSE ceil( ( qi.amount * bd.work * ( CASE WHEN qi.destroy THEN sys.get_constant( 'game.work.destructionWork' ) ELSE 1 END ) - ( CASE WHEN qi.queue_order = 0 THEN q.work ELSE 0 END ) ) ELSE ceil( ( qi.amount * bd.work * ( CASE WHEN qi.destroy THEN sys.get_constant( 'game.work.destructionWork' ) ELSE 1 END ) - ( CASE WHEN qi.queue_order = 0 THEN q.work ELSE 0 END ) )
/ verse.adjust_production( ( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) )::REAL , ( ph.current / p.population )::REAL ) ) / verse.adjust_production( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) , ph.current / p.population ) )
END )::BIGINT AS time_left END )::BIGINT AS time_left
FROM verse.planets p FROM verse.planets p
INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id
@ -414,9 +413,9 @@ AS $$
qi.amount AS amount , FALSE AS destroy , qi.amount AS amount , FALSE AS destroy ,
floor( qi.amount * bd.cost - ( CASE WHEN qi.queue_order = 0 THEN q.money ELSE 0 END ) )::BIGINT AS investment , floor( qi.amount * bd.cost - ( CASE WHEN qi.queue_order = 0 THEN q.money ELSE 0 END ) )::BIGINT AS investment ,
( CASE ( CASE
WHEN ceil( verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ( ph.current / p.population )::REAL ) ) = 0 THEN NULL WHEN ceil( verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ph.current / p.population ) ) = 0 THEN NULL
ELSE ceil( ( qi.amount * bd.work - ( CASE WHEN qi.queue_order = 0 THEN q.work ELSE 0 END ) ) ELSE ceil( ( qi.amount * bd.work - ( CASE WHEN qi.queue_order = 0 THEN q.work ELSE 0 END ) )
/ verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ( ph.current / p.population )::REAL ) ) / verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ph.current / p.population ) )
END )::BIGINT AS time_left END )::BIGINT AS time_left
FROM verse.planets p FROM verse.planets p
INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id
@ -465,12 +464,12 @@ AS $$
UNION SELECT bv.* UNION SELECT bv.*
FROM tech.buildings_view bv FROM tech.buildings_view bv
INNER JOIN tech.buildable_requirements r ON r.buildable_id = bv.name_id INNER JOIN tech.buildable_requirements r ON r.buildable_id = bv.name_id
INNER JOIN tech.levels l ON l.id = r.level_id INNER JOIN tech.technologies l ON l.name_id = r.technology_id
INNER JOIN emp.planets ep ON ep.planet_id = $1 INNER JOIN emp.planets ep ON ep.planet_id = $1
INNER JOIN emp.technologies t INNER JOIN emp.researched_technologies t
ON t.empire_id = ep.empire_id AND t.line_id = l.line_id AND t.level > l.level ON t.empire_id = ep.empire_id AND t.technology_id = l.name_id
) AS bv , ( ) AS bv , (
SELECT verse.adjust_production( ( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) )::REAL , ( ph.current / p.population )::REAL ) AS p_work , SELECT verse.adjust_production( p.population * sys.get_constant( 'game.work.wuPerPopUnit' ) , ph.current / p.population ) AS p_work ,
c.language_id AS language c.language_id AS language
FROM verse.planets p FROM verse.planets p
INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id
@ -517,12 +516,12 @@ AS $$
UNION SELECT bv.* UNION SELECT bv.*
FROM tech.ships_view bv FROM tech.ships_view bv
INNER JOIN tech.buildable_requirements r ON r.buildable_id = bv.name_id INNER JOIN tech.buildable_requirements r ON r.buildable_id = bv.name_id
INNER JOIN tech.levels l ON l.id = r.level_id INNER JOIN tech.technologies l ON l.name_id = r.technology_id
INNER JOIN emp.planets ep ON ep.planet_id = $1 INNER JOIN emp.planets ep ON ep.planet_id = $1
INNER JOIN emp.technologies t INNER JOIN emp.researched_technologies t
ON t.empire_id = ep.empire_id AND t.line_id = l.line_id AND t.level > l.level ON t.empire_id = ep.empire_id AND t.technology_id = l.name_id
) AS bv , ( ) AS bv , (
SELECT verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ( ph.current / p.population )::REAL ) AS p_work , SELECT verse.adjust_production( verse.get_raw_production( $1 , 'WORK' ) , ph.current / p.population ) AS p_work ,
c.language_id AS language c.language_id AS language
FROM verse.planets p FROM verse.planets p
INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id
@ -594,7 +593,7 @@ CREATE OR REPLACE FUNCTION verse.flush_build_queue( p_id INT )
AS $$ AS $$
DECLARE DECLARE
e_id INT; e_id INT;
q_cash REAL; q_cash DOUBLE PRECISION;
BEGIN BEGIN
SELECT INTO e_id , q_cash e.name_id , q.money SELECT INTO e_id , q_cash e.name_id , q.money
FROM verse.planets p FROM verse.planets p
@ -633,7 +632,7 @@ CREATE OR REPLACE FUNCTION verse.flush_military_queue( p_id INT )
AS $$ AS $$
DECLARE DECLARE
e_id INT; e_id INT;
q_cash REAL; q_cash DOUBLE PRECISION;
BEGIN BEGIN
SELECT INTO e_id , q_cash e.name_id , q.money SELECT INTO e_id , q_cash e.name_id , q.money
FROM verse.planets p FROM verse.planets p
@ -699,10 +698,10 @@ BEGIN
FROM tech.ships s FROM tech.ships s
LEFT OUTER JOIN tech.buildable_requirements r LEFT OUTER JOIN tech.buildable_requirements r
ON r.buildable_id = s.buildable_id ON r.buildable_id = s.buildable_id
LEFT OUTER JOIN tech.levels l LEFT OUTER JOIN tech.technologies l
ON l.id = r.level_id ON l.name_id = r.technology_id
LEFT OUTER JOIN emp.technologies t LEFT OUTER JOIN emp.researched_technologies t
ON t.empire_id = e_id AND t.line_id = l.line_id AND t.level > l.level ON t.empire_id = e_id AND t.technology_id = l.name_id
WHERE s.buildable_id = s_id; WHERE s.buildable_id = s_id;
IF NOT FOUND OR ( has_level IS NULL AND dep_level IS NOT NULL ) THEN IF NOT FOUND OR ( has_level IS NULL AND dep_level IS NOT NULL ) THEN
RETURN; RETURN;
@ -765,10 +764,10 @@ BEGIN
FROM tech.buildings b FROM tech.buildings b
LEFT OUTER JOIN tech.buildable_requirements r LEFT OUTER JOIN tech.buildable_requirements r
ON r.buildable_id = b.buildable_id ON r.buildable_id = b.buildable_id
LEFT OUTER JOIN tech.levels l LEFT OUTER JOIN tech.technologies l
ON l.id = r.level_id ON l.name_id = r.technology_id
LEFT OUTER JOIN emp.technologies t LEFT OUTER JOIN emp.researched_technologies t
ON t.empire_id = e_id AND t.line_id = l.line_id AND t.level > l.level ON t.empire_id = e_id AND t.technology_id = l.name_id
WHERE b.buildable_id = b_id; WHERE b.buildable_id = b_id;
IF NOT FOUND OR ( has_level IS NULL AND dep_level IS NOT NULL ) THEN IF NOT FOUND OR ( has_level IS NULL AND dep_level IS NOT NULL ) THEN
RETURN; RETURN;
@ -979,7 +978,7 @@ $$ LANGUAGE plpgsql;
-- tick Current tick -- tick Current tick
-- --
CREATE OR REPLACE FUNCTION verse.inflict_battle_damage( p_id INT , t_power BIGINT , dmg REAL , b_id BIGINT , tick BIGINT ) CREATE OR REPLACE FUNCTION verse.inflict_battle_damage( p_id INT , t_power BIGINT , dmg DOUBLE PRECISION , b_id BIGINT , tick BIGINT )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY INVOKER
@ -987,7 +986,7 @@ CREATE OR REPLACE FUNCTION verse.inflict_battle_damage( p_id INT , t_power BIGIN
DECLARE DECLARE
rec RECORD; rec RECORD;
bp_id BIGINT; bp_id BIGINT;
st_dmg REAL; st_dmg DOUBLE PRECISION;
n_dest INT; n_dest INT;
BEGIN BEGIN
PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Inflicting ' || dmg PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'Inflicting ' || dmg
@ -1038,18 +1037,18 @@ $$ LANGUAGE plpgsql;
-- d_ratio Debt damage ratio -- d_ratio Debt damage ratio
-- --
CREATE OR REPLACE FUNCTION verse.handle_debt( e_id INT , t_upkeep REAL , debt REAL , d_ratio REAL ) CREATE OR REPLACE FUNCTION verse.handle_debt( e_id INT , t_upkeep DOUBLE PRECISION , debt DOUBLE PRECISION , d_ratio DOUBLE PRECISION )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
tick BIGINT; tick BIGINT;
tot_damage REAL; tot_damage DOUBLE PRECISION;
p_rec RECORD; p_rec RECORD;
b_rec RECORD; b_rec RECORD;
bp_id BIGINT; bp_id BIGINT;
b_damage REAL; b_damage DOUBLE PRECISION;
n_destroy INT; n_destroy INT;
BEGIN BEGIN
tick := sys.get_tick( ) - 1; tick := sys.get_tick( ) - 1;
@ -1066,7 +1065,7 @@ BEGIN
bp_id := NULL; bp_id := NULL;
FOR b_rec IN SELECT b.building_id AS building , b.amount AS amount , FOR b_rec IN SELECT b.building_id AS building , b.amount AS amount ,
( b.amount * bb.upkeep )::REAL AS upkeep , b.amount * bb.upkeep AS upkeep ,
b.damage AS damage , ( bd.output_type = 'DEF' ) AS is_def b.damage AS damage , ( bd.output_type = 'DEF' ) AS is_def
FROM verse.planet_buildings b FROM verse.planet_buildings b
INNER JOIN tech.buildables bb ON bb.name_id = b.building_id INNER JOIN tech.buildables bb ON bb.name_id = b.building_id

View file

@ -626,7 +626,7 @@ $$ LANGUAGE plpgsql;
-- tick Current tick identifier -- tick Current tick identifier
-- --
CREATE OR REPLACE FUNCTION battles.inflict_damage( b_id BIGINT , dmg REAL , att BOOLEAN , tick BIGINT ) CREATE OR REPLACE FUNCTION battles.inflict_damage( b_id BIGINT , dmg DOUBLE PRECISION , att BOOLEAN , tick BIGINT )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY INVOKER
@ -654,9 +654,9 @@ BEGIN
st_power := battles.get_defence_power( b_id , tick ); st_power := battles.get_defence_power( b_id , tick );
tot_power := tot_power + st_power; tot_power := tot_power + st_power;
PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'About to inflict planet damage; total power: ' || tot_power PERFORM sys.write_log( 'BattleUpdate' , 'TRACE'::log_level , 'About to inflict planet damage; total power: ' || tot_power
|| '; planet power: ' || st_power || '; computed damage: ' || ( dmg * st_power / tot_power )::REAL ); || '; planet power: ' || st_power || '; computed damage: ' || ( dmg * st_power / tot_power ) );
IF st_power <> 0 THEN IF st_power <> 0 THEN
PERFORM verse.inflict_battle_damage( planet , st_power , ( dmg * st_power / tot_power )::REAL , b_id , tick ); PERFORM verse.inflict_battle_damage( planet , st_power , dmg * st_power / tot_power , b_id , tick );
END IF; END IF;
END IF; END IF;
@ -668,7 +668,7 @@ BEGIN
LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id LEFT OUTER JOIN fleets.movements m ON m.fleet_id = f.id
WHERE b.id = b_id AND m.fleet_id IS NULL AND f.attacking = att WHERE b.id = b_id AND m.fleet_id IS NULL AND f.attacking = att
LOOP LOOP
PERFORM fleets.inflict_battle_damage( rec.id , ( dmg * rec.power / tot_power )::REAL , b_id , tick ); PERFORM fleets.inflict_battle_damage( rec.id , dmg * rec.power / tot_power , b_id , tick );
END LOOP; END LOOP;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;

View file

@ -256,8 +256,8 @@ CREATE VIEW battles.buildings_history
WHEN rbp.raw_power = 0 THEN WHEN rbp.raw_power = 0 THEN
rbh.raw_power rbh.raw_power
ELSE ELSE
rbh.raw_power::REAL * rbp.actual_power::REAL / rbp.raw_power::REAL rbh.raw_power * rbp.actual_power / rbp.raw_power
END )::REAL AS power END ) AS power
FROM battles.empire_list_view elv FROM battles.empire_list_view elv
INNER JOIN battles.raw_buildings_history rbh USING (battle) INNER JOIN battles.raw_buildings_history rbh USING (battle)
INNER JOIN battles.raw_buildings_power rbp USING (battle,tick) INNER JOIN battles.raw_buildings_power rbp USING (battle,tick)

View file

@ -55,7 +55,7 @@ $$ LANGUAGE plpgsql;
-- the in-system movement's duration -- the in-system movement's duration
-- --
CREATE OR REPLACE FUNCTION fleets.compute_insystem_duration( f_time INT , s_orbit REAL , d_orbit REAL ) CREATE OR REPLACE FUNCTION fleets.compute_insystem_duration( f_time INT , s_orbit DOUBLE PRECISION , d_orbit DOUBLE PRECISION )
RETURNS INT RETURNS INT
STRICT IMMUTABLE STRICT IMMUTABLE
SECURITY INVOKER SECURITY INVOKER
@ -84,7 +84,7 @@ $$ LANGUAGE plpgsql;
-- the outer space movement's duration -- the outer space movement's duration
-- --
CREATE OR REPLACE FUNCTION fleets.compute_outerspace_duration( f_time INT , s_x REAL , s_y REAL , d_x REAL , d_y REAL ) CREATE OR REPLACE FUNCTION fleets.compute_outerspace_duration( f_time INT , s_x DOUBLE PRECISION , s_y DOUBLE PRECISION , d_x DOUBLE PRECISION , d_y DOUBLE PRECISION )
RETURNS INT RETURNS INT
STRICT IMMUTABLE STRICT IMMUTABLE
SECURITY INVOKER SECURITY INVOKER
@ -115,16 +115,16 @@ $$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION fleets.compute_current_orbit( CREATE OR REPLACE FUNCTION fleets.compute_current_orbit(
f_time INT , rp_orbit INT , outwards BOOLEAN , past_rp BOOLEAN , ft_left INT ) f_time INT , rp_orbit INT , outwards BOOLEAN , past_rp BOOLEAN , ft_left INT )
RETURNS REAL RETURNS DOUBLE PRECISION
STRICT IMMUTABLE STRICT IMMUTABLE
SECURITY INVOKER SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
dist REAL; dist DOUBLE PRECISION;
dir REAL; dir DOUBLE PRECISION;
rloc REAL; rloc DOUBLE PRECISION;
BEGIN BEGIN
dist := 1.0 - ft_left::REAL / f_time::REAL; dist := 1.0 - ft_left::DOUBLE PRECISION / f_time::DOUBLE PRECISION;
dir := ( CASE WHEN outwards THEN 0.5 ELSE -0.5 END ); dir := ( CASE WHEN outwards THEN 0.5 ELSE -0.5 END );
IF past_rp THEN IF past_rp THEN
rloc := rp_orbit; rloc := rp_orbit;
@ -157,13 +157,14 @@ $$ LANGUAGE plpgsql;
-- --
CREATE OR REPLACE FUNCTION fleets.compute_current_location( CREATE OR REPLACE FUNCTION fleets.compute_current_location(
f_time INT , s_x REAL , s_y REAL , d_x REAL , d_y REAL , r_time INT , f_time INT , s_x DOUBLE PRECISION , s_y DOUBLE PRECISION ,
OUT c_x REAL , OUT c_y REAL ) d_x DOUBLE PRECISION , d_y DOUBLE PRECISION , r_time INT ,
OUT c_x DOUBLE PRECISION , OUT c_y DOUBLE PRECISION )
STRICT IMMUTABLE STRICT IMMUTABLE
SECURITY INVOKER SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
tot_time REAL; tot_time DOUBLE PRECISION;
BEGIN BEGIN
tot_time := fleets.compute_outerspace_duration( f_time , s_x , s_y , d_x , d_y ); tot_time := fleets.compute_outerspace_duration( f_time , s_x , s_y , d_x , d_y );
c_x := s_x + ( d_x - s_x ) * ( 1 - r_time / tot_time ); c_x := s_x + ( d_x - s_x ) * ( 1 - r_time / tot_time );
@ -251,7 +252,7 @@ $$ LANGUAGE plpgsql;
-- --
CREATE OR REPLACE FUNCTION fleets.compute_insystem_redirect( CREATE OR REPLACE FUNCTION fleets.compute_insystem_redirect(
f_time INT , s_sys INT , s_orbit REAL , d_id INT , f_time INT , s_sys INT , s_orbit DOUBLE PRECISION , d_id INT ,
OUT duration INT , OUT direction BOOLEAN , OUT s_duration INT , OUT duration INT , OUT direction BOOLEAN , OUT s_duration INT ,
OUT ref_point INT , OUT past_rp BOOLEAN ) OUT ref_point INT , OUT past_rp BOOLEAN )
STRICT IMMUTABLE STRICT IMMUTABLE
@ -260,7 +261,7 @@ CREATE OR REPLACE FUNCTION fleets.compute_insystem_redirect(
DECLARE DECLARE
s_rec RECORD; s_rec RECORD;
d_rec RECORD; d_rec RECORD;
torb REAL; torb DOUBLE PRECISION;
rporb INT; rporb INT;
BEGIN BEGIN
-- Get destination planet coordinates, orbit and system ID -- Get destination planet coordinates, orbit and system ID
@ -294,9 +295,9 @@ BEGIN
ELSE ELSE
torb := floor( torb ); torb := floor( torb );
END IF; END IF;
s_duration := fleets.compute_insystem_duration( f_time , s_orbit , ( torb / 2 )::REAL ); s_duration := fleets.compute_insystem_duration( f_time , s_orbit , torb / 2 );
rporb := round( s_orbit ); rporb := round( s_orbit );
past_rp := ( CASE WHEN direction THEN ( rporb::REAL <= s_orbit ) ELSE ( rporb::REAL >= s_orbit ) END ); past_rp := ( CASE WHEN direction THEN ( rporb <= s_orbit ) ELSE ( rporb >= s_orbit ) END );
END IF; END IF;
SELECT INTO ref_point name_id FROM verse.planets p SELECT INTO ref_point name_id FROM verse.planets p
WHERE p.system_id = s_sys AND orbit = rporb; WHERE p.system_id = s_sys AND orbit = rporb;
@ -322,7 +323,7 @@ $$ LANGUAGE plpgsql;
-- --
CREATE OR REPLACE FUNCTION fleets.compute_outerspace_redirect( CREATE OR REPLACE FUNCTION fleets.compute_outerspace_redirect(
f_time INT , s_x REAL , s_y REAL , d_id INT , f_time INT , s_x DOUBLE PRECISION , s_y DOUBLE PRECISION , d_id INT ,
OUT duration INT , OUT s_duration INT ) OUT duration INT , OUT s_duration INT )
STRICT IMMUTABLE STRICT IMMUTABLE
SECURITY INVOKER SECURITY INVOKER
@ -365,8 +366,8 @@ DECLARE
dir BOOLEAN; dir BOOLEAN;
rpid INT; rpid INT;
prp BOOLEAN; prp BOOLEAN;
cx REAL; cx DOUBLE PRECISION;
cy REAL; cy DOUBLE PRECISION;
BEGIN BEGIN
-- Lock fleets and planets -- Lock fleets and planets
PERFORM * FROM fleets.fleets f PERFORM * FROM fleets.fleets f
@ -676,10 +677,10 @@ DECLARE
old_ft INT; old_ft INT;
new_ft INT; new_ft INT;
sp_ft INT; sp_ft INT;
x REAL; x DOUBLE PRECISION;
y REAL; y DOUBLE PRECISION;
cx REAL; cx DOUBLE PRECISION;
cy REAL; cy DOUBLE PRECISION;
sid INT; sid INT;
BEGIN BEGIN
SELECT INTO main * FROM fleet_split_main; SELECT INTO main * FROM fleet_split_main;
@ -705,7 +706,7 @@ BEGIN
IF new_ft <> old_ft THEN IF new_ft <> old_ft THEN
IF ism_rec IS NULL THEN IF ism_rec IS NULL THEN
-- Outer space movement -- Outer space movement
SELECT INTO x , y s.x::REAL , s.y::REAL SELECT INTO x , y s.x , s.y
FROM verse.planets p FROM verse.planets p
INNER JOIN verse.systems s ON s.id = p.system_id INNER JOIN verse.systems s ON s.id = p.system_id
WHERE p.name_id = main.location; WHERE p.name_id = main.location;
@ -754,7 +755,7 @@ BEGIN
IF sp_ft <> old_ft THEN IF sp_ft <> old_ft THEN
IF ism_rec IS NULL THEN IF ism_rec IS NULL THEN
-- Outer space movement -- Outer space movement
SELECT INTO x , y s.x::REAL , s.y::REAL SELECT INTO x , y s.x , s.y
FROM verse.planets p FROM verse.planets p
INNER JOIN verse.systems s ON s.id = p.system_id INNER JOIN verse.systems s ON s.id = p.system_id
WHERE p.name_id = main.location; WHERE p.name_id = main.location;
@ -983,7 +984,7 @@ GRANT EXECUTE ON FUNCTION fleets.disband( INT , BIGINT[] ) TO :dbuser;
-- tick Current tick -- tick Current tick
-- --
CREATE OR REPLACE FUNCTION fleets.inflict_battle_damage( f_id BIGINT , dmg REAL , b_id BIGINT , tick BIGINT ) CREATE OR REPLACE FUNCTION fleets.inflict_battle_damage( f_id BIGINT , dmg DOUBLE PRECISION , b_id BIGINT , tick BIGINT )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY INVOKER
@ -995,7 +996,7 @@ DECLARE
bp_id BIGINT; bp_id BIGINT;
bf_id BIGINT; bf_id BIGINT;
rec RECORD; rec RECORD;
st_dmg REAL; st_dmg DOUBLE PRECISION;
n_dest INT; n_dest INT;
found INT; found INT;
deleted INT; deleted INT;
@ -1066,19 +1067,19 @@ $$ LANGUAGE plpgsql;
-- d_ratio Debt damage ratio -- d_ratio Debt damage ratio
-- --
CREATE OR REPLACE FUNCTION fleets.handle_debt( e_id INT , t_upkeep REAL , debt REAL , d_ratio REAL ) CREATE OR REPLACE FUNCTION fleets.handle_debt( e_id INT , t_upkeep DOUBLE PRECISION , debt DOUBLE PRECISION , d_ratio DOUBLE PRECISION )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
tot_damage REAL; tot_damage DOUBLE PRECISION;
f_rec RECORD; f_rec RECORD;
s_rec RECORD; s_rec RECORD;
n_found INT; n_found INT;
n_killed INT; n_killed INT;
s_killed INT; s_killed INT;
s_damage REAL; s_damage DOUBLE PRECISION;
n_ships INT; n_ships INT;
tick BIGINT; tick BIGINT;
bp_id BIGINT; bp_id BIGINT;
@ -1086,10 +1087,10 @@ DECLARE
mv_rec fleets.movements%ROWTYPE; mv_rec fleets.movements%ROWTYPE;
ism_rec fleets.ms_system%ROWTYPE; ism_rec fleets.ms_system%ROWTYPE;
osm_rec fleets.ms_space%ROWTYPE; osm_rec fleets.ms_space%ROWTYPE;
x REAL; x DOUBLE PRECISION;
y REAL; y DOUBLE PRECISION;
cx REAL; cx DOUBLE PRECISION;
cy REAL; cy DOUBLE PRECISION;
sid INT; sid INT;
BEGIN BEGIN
tick := sys.get_tick( ) - 1; tick := sys.get_tick( ) - 1;
@ -1120,7 +1121,7 @@ BEGIN
n_killed := 0; n_killed := 0;
s_killed := 0; s_killed := 0;
FOR s_rec IN SELECT s.ship_id AS ship , s.amount AS amount , s.damage AS damage , FOR s_rec IN SELECT s.ship_id AS ship , s.amount AS amount , s.damage AS damage ,
( d.upkeep * s.amount )::REAL AS upkeep d.upkeep * s.amount AS upkeep
FROM fleets.ships s FROM fleets.ships s
INNER JOIN tech.buildables d ON d.name_id = s.ship_id INNER JOIN tech.buildables d ON d.name_id = s.ship_id
WHERE s.fleet_id = f_rec.fleet WHERE s.fleet_id = f_rec.fleet
@ -1174,7 +1175,7 @@ BEGIN
IF ism_rec IS NULL THEN IF ism_rec IS NULL THEN
-- Outer space movement -- Outer space movement
SELECT INTO x , y s.x::REAL , s.y::REAL SELECT INTO x , y s.x , s.y
FROM verse.planets p FROM verse.planets p
INNER JOIN verse.systems s ON s.id = p.system_id INNER JOIN verse.systems s ON s.id = p.system_id
WHERE p.name_id = f_rec.location; WHERE p.name_id = f_rec.location;
@ -1386,7 +1387,7 @@ GRANT SELECT ON fleets.static_fleets TO :dbuser;
CREATE VIEW fleets.outer_space_fleets CREATE VIEW fleets.outer_space_fleets
AS SELECT s.movement_id AS id , m.state_time_left AS time_left , AS SELECT s.movement_id AS id , m.state_time_left AS time_left ,
s.start_x AS x0 , s.start_y AS y0 , s.start_x AS x0 , s.start_y AS y0 ,
ts.x::REAL AS x1 , ts.y::REAL AS y1 ts.x::DOUBLE PRECISION AS x1 , ts.y::DOUBLE PRECISION AS y1
FROM fleets.ms_space s FROM fleets.ms_space s
INNER JOIN fleets.movements m ON m.fleet_id = s.movement_id INNER JOIN fleets.movements m ON m.fleet_id = s.movement_id
INNER JOIN fleets.fleets f ON m.fleet_id = f.id INNER JOIN fleets.fleets f ON m.fleet_id = f.id
@ -1422,14 +1423,14 @@ CREATE VIEW fleets.moving_fleets
f.location_id AS to_id , dn.name AS to_name , f.location_id AS to_id , dn.name AS to_name ,
( CASE ( CASE
WHEN osf.id IS NULL THEN isf.x WHEN osf.id IS NULL THEN isf.x
ELSE ( osf.x1 - osf.time_left::REAL * ( osf.x1 - osf.x0 ) ELSE ( osf.x1 - osf.time_left * ( osf.x1 - osf.x0 )
/ fleets.compute_outerspace_duration( fs.flight_time , osf.x0 , osf.y0 , osf.x1 , osf.y1 ) ) / fleets.compute_outerspace_duration( fs.flight_time , osf.x0 , osf.y0 , osf.x1 , osf.y1 ) )
END )::REAL AS cx , END )::DOUBLE PRECISION AS cx ,
( CASE ( CASE
WHEN osf.id IS NULL THEN isf.y WHEN osf.id IS NULL THEN isf.y
ELSE ( osf.y1 - osf.time_left::REAL * ( osf.y1 - osf.y0 ) ELSE ( osf.y1 - osf.time_left * ( osf.y1 - osf.y0 )
/ fleets.compute_outerspace_duration( fs.flight_time , osf.x0 , osf.y0 , osf.x1 , osf.y1 ) ) / fleets.compute_outerspace_duration( fs.flight_time , osf.x0 , osf.y0 , osf.x1 , osf.y1 ) )
END )::REAL AS cy , END )::DOUBLE PRECISION AS cy ,
( CASE ( CASE
WHEN osf.id IS NULL THEN isf.planet WHEN osf.id IS NULL THEN isf.planet
ELSE NULL ELSE NULL
@ -1487,7 +1488,7 @@ GRANT SELECT ON fleets.ships_view TO :dbuser;
CREATE VIEW fleets.short_static_fleets CREATE VIEW fleets.short_static_fleets
AS SELECT sf.empire , sf.location AS location_id , AS SELECT sf.empire , sf.location AS location_id ,
fl.name AS location_name , fl.name AS location_name ,
fl.x::REAL AS x , fl.y::REAL AS y , fl.x::DOUBLE PRECISION AS x , fl.y::DOUBLE PRECISION AS y ,
sf.id , sf.name , sf.status , sf.penalty , sf.id , sf.name , sf.status , sf.penalty ,
fl.attacking , sf.power , sf.flight_time fl.attacking , sf.power , sf.flight_time
FROM fleets.static_fleets sf FROM fleets.static_fleets sf

View file

@ -15,7 +15,7 @@ CREATE VIEW emp.planets_list_basic
AS SELECT e.name_id AS empire , AS SELECT e.name_id AS empire ,
p.name_id AS id , n.name , p.name_id AS id , n.name ,
s.x , s.y , p.orbit , s.x , s.y , p.orbit ,
p.population , ph.current / p.population::REAL AS happiness , p.population , ph.current / p.population AS happiness ,
floor( pm.income )::BIGINT AS income , floor( pm.income )::BIGINT AS income ,
floor( pm.upkeep )::BIGINT AS upkeep floor( pm.upkeep )::BIGINT AS upkeep
FROM emp.empires e FROM emp.empires e

View file

@ -860,7 +860,7 @@ CREATE VIEW events.empire_events_view
AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , s.name AS technology AS SELECT e.event_id AS id , e.evt_type , e.evt_subtype , e.tick , e.real_time , s.name AS technology
FROM events.events e FROM events.events e
LEFT OUTER JOIN events.empire_events ed USING (event_id) LEFT OUTER JOIN events.empire_events ed USING (event_id)
LEFT OUTER JOIN tech.levels tl ON tl.id = ed.technology_id LEFT OUTER JOIN tech.technologies tl ON tl.name_id = ed.technology_id
LEFT OUTER JOIN defs.strings s ON s.id = tl.name_id LEFT OUTER JOIN defs.strings s ON s.id = tl.name_id
WHERE e.evt_type = 'EMPIRE'; WHERE e.evt_type = 'EMPIRE';

View file

@ -1196,18 +1196,24 @@ GRANT SELECT ON bugs.dump_main_view TO :dbuser;
CREATE VIEW bugs.dump_research_view CREATE VIEW bugs.dump_research_view
AS SELECT et.empire_id , et.line_id AS line_id , et.level AS level , AS SELECT r.empire_id , ns.name , r.accumulated , r.priority
tst.name AS name , et.accumulated AS accumulated FROM emp.research r
FROM emp.technologies et INNER JOIN defs.strings ns ON ns.id = r.technology_id;
LEFT OUTER JOIN tech.levels tlv ON tlv.line_id = et.line_id AND tlv.level = et.level
LEFT OUTER JOIN defs.strings tst ON tst.id = tlv.name_id;
GRANT SELECT ON bugs.dump_research_view TO :dbuser; GRANT SELECT ON bugs.dump_research_view TO :dbuser;
CREATE VIEW bugs.dump_technologies_view
AS SELECT et.empire_id , ns.name , et.implemented
FROM emp.researched_technologies et
INNER JOIN defs.strings ns ON ns.id = et.technology_id;
GRANT SELECT ON bugs.dump_technologies_view TO :dbuser;
CREATE VIEW bugs.dump_planets_view CREATE VIEW bugs.dump_planets_view
AS SELECT ep.empire_id , ep.planet_id , p.population , AS SELECT ep.empire_id , ep.planet_id , p.population ,
( ph.current / p.population )::REAL AS current_happiness , ph.target AS target_happiness , ph.current / p.population AS current_happiness , ph.target AS target_happiness ,
cq.money AS civ_money , cq.work AS civ_work , cq.money AS civ_money , cq.work AS civ_work ,
mq.money AS mil_money , mq.work AS mil_work mq.money AS mil_money , mq.work AS mil_work
FROM emp.planets ep FROM emp.planets ep

View file

@ -52,7 +52,7 @@ GRANT EXECUTE ON FUNCTION sys.start_tick( ) TO :dbuser;
CREATE OR REPLACE FUNCTION sys.end_tick( IN tick_id BIGINT ) CREATE OR REPLACE FUNCTION sys.end_tick( IN tick_id BIGINT )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY DEFINER
AS $$ AS $$
BEGIN BEGIN
UPDATE events.events SET status = 'READY' UPDATE events.events SET status = 'READY'
@ -62,6 +62,8 @@ BEGIN
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION sys.end_tick( BIGINT ) TO :dbuser;
-- --
@ -103,70 +105,78 @@ GRANT EXECUTE ON FUNCTION sys.check_stuck_tick( ) TO :dbuser;
-- --
-- Process game updates -- Prepare game updates
-- --
-- Parameters: -- Parameters:
-- c_tick Current tick -- u_id Current update identifier
-- u_type Type of game updates to prepare
-- --
-- Returns: -- Returns:
-- TRUE if the function must be called again, FALSE otherwise -- has_more TRUE if there are more updates, FALSE otherwise
-- --
CREATE OR REPLACE FUNCTION sys.process_updates( IN c_tick BIGINT , OUT has_more BOOLEAN ) CREATE OR REPLACE FUNCTION sys.prepare_updates( IN u_id BIGINT , IN u_type update_type , OUT has_more BOOLEAN )
STRICT VOLATILE STRICT VOLATILE
SECURITY DEFINER SECURITY DEFINER
AS $$ AS $$
DECLARE
b_size INT;
p_utype update_type;
utype update_type;
uid BIGINT;
BEGIN BEGIN
b_size := sys.get_constant( 'game.batchSize' ); UPDATE sys.updates SET status = 'PROCESSING'
p_utype := NULL; WHERE id IN (
SELECT id FROM sys.updates
WHERE gu_type = u_type
AND last_tick = u_id
AND status = 'FUTURE'
ORDER BY id
LIMIT sys.get_constant( 'game.batchSize' )::BIGINT
);
-- Mark at most b_size entries as being updated has_more := FOUND;
FOR uid , utype IN SELECT id , gu_type FROM sys.updates
WHERE last_tick = c_tick AND status = 'FUTURE'
ORDER BY gu_type LIMIT b_size
LOOP
IF p_utype IS NULL THEN
p_utype := utype;
END IF;
EXIT WHEN utype <> p_utype;
UPDATE sys.updates SET status = 'PROCESSING' WHERE id = uid;
END LOOP;
has_more := p_utype IS NOT NULL;
IF has_more THEN
-- Execute actual updates
EXECUTE 'SELECT sys.process_' || lower( p_utype::TEXT ) || '_updates( $1 )'
USING c_tick;
UPDATE sys.updates SET status = 'PROCESSED'
WHERE status = 'PROCESSING' AND last_tick = c_tick;
ELSE
-- If nothing was found, we're done
PERFORM sys.end_tick( c_tick );
END IF;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION sys.process_updates( BIGINT ) TO :dbuser; GRANT EXECUTE ON FUNCTION sys.prepare_updates( BIGINT , update_type ) TO :dbuser;
--
-- Execute procedural game updates
--
-- Parameters:
-- c_tick Current tick identifier
-- u_type Type of updates to execute
--
CREATE OR REPLACE FUNCTION sys.exec_update_proc( IN c_tick BIGINT , IN u_type update_type )
RETURNS VOID
STRICT VOLATILE
SECURITY DEFINER
AS $$
BEGIN
EXECUTE 'SELECT sys.process_' || lower( u_type::TEXT ) || '_updates( $1 )'
USING c_tick;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION sys.exec_update_proc( BIGINT , update_type ) TO :dbuser;
--
-- Mark updates as processed
--
-- Parameters:
-- c_tick Current tick identifier
-- u_type Type of updates to execute
--
CREATE OR REPLACE FUNCTION sys.updates_processed( IN c_tick BIGINT , IN u_type update_type )
RETURNS VOID
STRICT VOLATILE
SECURITY DEFINER
AS $$
UPDATE sys.updates SET status = 'PROCESSED'
WHERE status = 'PROCESSING'
AND last_tick = $1
AND gu_type = $2
$$ LANGUAGE SQL;
GRANT EXECUTE ON FUNCTION sys.updates_processed( BIGINT , update_type ) TO :dbuser;

View file

@ -14,8 +14,8 @@ CREATE OR REPLACE FUNCTION sys.process_empire_money_updates( c_tick BIGINT )
AS $$ AS $$
DECLARE DECLARE
rec RECORD; rec RECORD;
c_cash REAL; c_cash DOUBLE PRECISION;
c_debt REAL; c_debt DOUBLE PRECISION;
BEGIN BEGIN
-- Lock empires for update -- Lock empires for update
PERFORM e.name_id FROM sys.updates su PERFORM e.name_id FROM sys.updates su

View file

@ -7,15 +7,22 @@
-- -------------------------------------------------------- -- --------------------------------------------------------
CREATE OR REPLACE FUNCTION sys.process_empire_research_updates( c_tick BIGINT )
--
-- Prepare the research update
--
-- Parameters:
-- update_id The current update's identifier
--
-- Returns:
-- a set of tech._research_update_input records
--
CREATE OR REPLACE FUNCTION emp.prepare_research_update( update_id BIGINT )
RETURNS VOID RETURNS VOID
STRICT VOLATILE STRICT VOLATILE
SECURITY INVOKER SECURITY DEFINER
AS $$ AS $$
DECLARE
rec RECORD;
r_points REAL;
tu_rec RECORD;
BEGIN BEGIN
-- Lock empires for update and planets for share -- Lock empires for update and planets for share
PERFORM e.name_id FROM sys.updates su PERFORM e.name_id FROM sys.updates su
@ -23,14 +30,80 @@ BEGIN
INNER JOIN emp.empires e ON eu.empire_id = e.name_id INNER JOIN emp.empires e ON eu.empire_id = e.name_id
INNER JOIN emp.planets ep ON ep.empire_id = e.name_id INNER JOIN emp.planets ep ON ep.empire_id = e.name_id
INNER JOIN verse.planets p ON p.name_id = ep.planet_id INNER JOIN verse.planets p ON p.name_id = ep.planet_id
WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' WHERE su.last_tick = update_id AND su.status = 'PROCESSING'
AND su.gu_type = 'EMPIRE_RESEARCH' AND su.gu_type = 'EMPIRE_RESEARCH'
FOR UPDATE OF e FOR UPDATE OF e
FOR SHARE OF ep , p; FOR SHARE OF ep , p;
-- Process empires -- Create temporary table for update output and grant INSERT privilege
FOR rec IN SELECT e.name_id AS id , ( v.status = 'PROCESSED' ) AS on_vacation , -- to session user.
sum( p.population ) AS population CREATE TEMPORARY TABLE research_update_output(
empire_id INT ,
technology TEXT ,
creation BOOLEAN ,
points DOUBLE PRECISION ,
priority INT
);
IF session_user <> current_user THEN
EXECUTE 'GRANT INSERT ON research_update_output TO ' || session_user;
END IF;
END;
$$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION emp.prepare_research_update( update_id BIGINT ) TO :dbuser;
--
-- Research update input views
--
CREATE VIEW emp.rui_inprogress_view
AS SELECT su.last_tick AS update_id , er.empire_id , ns.name AS technology ,
er.accumulated AS points , er.priority AS priority
FROM sys.updates su
INNER JOIN emp.updates eu ON eu.update_id = su.id
INNER JOIN emp.research er ON er.empire_id = eu.empire_id
INNER JOIN defs.strings ns ON ns.id = er.technology_id
WHERE su.status = 'PROCESSING'
AND su.gu_type = 'EMPIRE_RESEARCH';
CREATE VIEW emp.rui_researched_view
AS SELECT su.last_tick AS update_id , er.empire_id , ns.name AS technology ,
er.implemented AS implemented
FROM sys.updates su
INNER JOIN emp.updates eu ON eu.update_id = su.id
INNER JOIN emp.researched_technologies er
ON er.empire_id = eu.empire_id
INNER JOIN defs.strings ns ON ns.id = er.technology_id
WHERE su.status = 'PROCESSING'
AND su.gu_type = 'EMPIRE_RESEARCH';
CREATE VIEW emp.research_update_input_view
AS SELECT update_id , empire_id , technology ,
NULL::BOOLEAN AS implemented , points , priority
FROM emp.rui_inprogress_view
UNION ALL SELECT update_id , empire_id , technology ,
implemented , NULL::DOUBLE PRECISION AS points ,
NULL::INT AS priority
FROM emp.rui_researched_view;
GRANT SELECT ON emp.research_update_input_view TO :dbuser;
--
-- Research points production view
--
CREATE VIEW emp.research_points_production
AS SELECT su.last_tick AS update_id , e.name_id AS empire_id ,
( sum( p.population ) * sys.get_constant( 'game.research.perPopUnit' )
/ ( sys.get_constant( 'game.updatesPerDay' ) * ( CASE
WHEN v.status = 'PROCESSED' THEN
sys.get_constant( 'game.research.perPopUnit' )
ELSE
1.0
END ) ) ) AS points
FROM sys.updates su FROM sys.updates su
INNER JOIN emp.updates eu ON eu.update_id = su.id INNER JOIN emp.updates eu ON eu.update_id = su.id
INNER JOIN emp.empires e ON eu.empire_id = e.name_id INNER JOIN emp.empires e ON eu.empire_id = e.name_id
@ -38,49 +111,56 @@ BEGIN
INNER JOIN verse.planets p ON p.name_id = ep.planet_id INNER JOIN verse.planets p ON p.name_id = ep.planet_id
INNER JOIN naming.empire_names en ON en.id = e.name_id INNER JOIN naming.empire_names en ON en.id = e.name_id
LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id
WHERE su.last_tick = c_tick AND su.status = 'PROCESSING' WHERE su.status = 'PROCESSING' AND su.gu_type = 'EMPIRE_RESEARCH'
AND su.gu_type = 'EMPIRE_RESEARCH' GROUP BY su.last_tick , e.name_id , v.status;
GROUP BY e.name_id , v.status
LOOP
-- Insert any missing tech line
INSERT INTO emp.technologies ( empire_id , line_id )
SELECT rec.id , l.name_id
FROM tech.lines l
LEFT OUTER JOIN emp.technologies t
ON t.line_id = l.name_id AND t.empire_id = rec.id
WHERE t.empire_id IS NULL;
-- Compute research output GRANT SELECT ON emp.research_points_production TO :dbuser;
r_points := rec.population * sys.get_constant( 'game.work.rpPerPopUnit' ) / 1440.0;
IF rec.on_vacation
THEN
r_points := r_points / sys.get_constant( 'vacation.researchDivider' );
END IF;
-- Update technologies where:
-- 1) the level actually exists and
-- 2) accumulated points haven't reach the level's
FOR tu_rec IN SELECT t.line_id AS line_id , t.accumulated AS accumulated ,
l.points AS points , ( l.points - t.accumulated ) AS diff ,
l.id AS level_id
FROM emp.technologies t
INNER JOIN tech.levels l ON l.line_id = t.line_id
AND l.level = t.level AND t.accumulated < l.points
WHERE t.empire_id = rec.id
FOR UPDATE OF t
LOOP
UPDATE emp.technologies t SET accumulated = ( CASE
WHEN tu_rec.diff <= r_points THEN tu_rec.points
ELSE tu_rec.accumulated + r_points
END )
WHERE t.line_id = tu_rec.line_id AND t.empire_id = rec.id;
-- Send message
IF tu_rec.diff <= r_points --
THEN -- Submit the contents of the research update table
PERFORM events.tech_ready_event( rec.id , tu_rec.level_id ); --
END IF;
END LOOP; CREATE OR REPLACE FUNCTION emp.submit_research_update( )
END LOOP; RETURNS VOID
STRICT VOLATILE
SECURITY DEFINER
AS $$
BEGIN
-- Delete finished research topics
DELETE FROM emp.research er
USING research_update_output ruo , defs.strings ns
WHERE er.empire_id = ruo.empire_id
AND er.technology_id = ns.id AND ns.name = ruo.technology
AND ruo.points IS NULL;
-- Insert researched technologies
INSERT INTO emp.researched_technologies ( empire_id , technology_id , implemented )
SELECT ruo.empire_id , ns.id , FALSE
FROM research_update_output ruo
INNER JOIN defs.strings ns ON ns.name = ruo.technology
WHERE ruo.points IS NULL;
-- Insert new research topics
INSERT INTO emp.research ( empire_id , technology_id , accumulated , priority )
SELECT ruo.empire_id , ns.id , ruo.points , ruo.priority
FROM research_update_output ruo
INNER JOIN defs.strings ns ON ns.name = ruo.technology
WHERE ruo.points IS NOT NULL AND ruo.creation;
-- Update existing research topics
UPDATE emp.research er
SET accumulated = ruo.points , priority = ruo.priority
FROM research_update_output ruo , defs.strings ns
WHERE ruo.points IS NOT NULL AND NOT ruo.creation
AND ns.name = ruo.technology
AND er.technology_id = ns.id
AND er.empire_id = ruo.empire_id;
-- Drop temporary table
DROP TABLE research_update_output;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
GRANT EXECUTE ON FUNCTION emp.submit_research_update( ) TO :dbuser;

View file

@ -15,11 +15,11 @@ CREATE OR REPLACE FUNCTION sys.process_empire_debt_updates( c_tick BIGINT )
SECURITY INVOKER SECURITY INVOKER
AS $$ AS $$
DECLARE DECLARE
fleet_dr REAL; fleet_dr DOUBLE PRECISION;
bld_dr REAL; bld_dr DOUBLE PRECISION;
empire INT; empire INT;
debt REAL; debt DOUBLE PRECISION;
upkeep REAL; upkeep DOUBLE PRECISION;
BEGIN BEGIN
fleet_dr := sys.get_constant( 'game.debt.fleet'); fleet_dr := sys.get_constant( 'game.debt.fleet');
bld_dr := sys.get_constant( 'game.debt.buildings'); bld_dr := sys.get_constant( 'game.debt.buildings');

View file

@ -42,17 +42,17 @@ CREATE OR REPLACE FUNCTION sys.process_planet_battle_main_updates( c_tick BIGINT
AS $$ AS $$
DECLARE DECLARE
ttfi INT; ttfi INT;
initi REAL; initi DOUBLE PRECISION;
dbonus REAL; dbonus DOUBLE PRECISION;
dmg REAL; dmg DOUBLE PRECISION;
rdmg REAL; rdmg DOUBLE PRECISION;
rec RECORD; rec RECORD;
a_power BIGINT; a_power BIGINT;
d_power BIGINT; d_power BIGINT;
p_power BIGINT; p_power BIGINT;
bmod REAL; bmod DOUBLE PRECISION;
a_dmg REAL; a_dmg DOUBLE PRECISION;
d_dmg REAL; d_dmg DOUBLE PRECISION;
BEGIN BEGIN
ttfi := floor( sys.get_constant( 'game.battle.timeToFullIntensity' ) )::INT; ttfi := floor( sys.get_constant( 'game.battle.timeToFullIntensity' ) )::INT;
initi := sys.get_constant( 'game.battle.initialIntensity' ); initi := sys.get_constant( 'game.battle.initialIntensity' );
@ -61,7 +61,7 @@ BEGIN
rdmg := sys.get_constant( 'game.battle.randomDamage' ); rdmg := sys.get_constant( 'game.battle.randomDamage' );
FOR rec IN SELECT b.id AS battle , b.first_tick AS first_tick , FOR rec IN SELECT b.id AS battle , b.first_tick AS first_tick ,
b.location_id AS location , ( ph.current / p.population )::REAL AS happiness b.location_id AS location , ph.current / p.population AS happiness
FROM sys.updates su FROM sys.updates su
INNER JOIN verse.updates vu ON vu.update_id = su.id INNER JOIN verse.updates vu ON vu.update_id = su.id
INNER JOIN verse.planets p ON vu.planet_id = p.name_id INNER JOIN verse.planets p ON vu.planet_id = p.name_id

View file

@ -14,20 +14,20 @@ CREATE OR REPLACE FUNCTION sys.process_planet_construction_updates( c_tick BIGIN
AS $$ AS $$
DECLARE DECLARE
rec RECORD; rec RECORD;
wu_per_pop REAL; wu_per_pop DOUBLE PRECISION;
dest_work REAL; dest_work DOUBLE PRECISION;
dest_rec REAL; dest_rec DOUBLE PRECISION;
cur_empire INT; cur_empire INT;
cur_cash REAL; cur_cash DOUBLE PRECISION;
cur_planet INT; cur_planet INT;
p_finished BOOLEAN; p_finished BOOLEAN;
cur_wus REAL; cur_wus DOUBLE PRECISION;
cur_acc_c REAL; cur_acc_c DOUBLE PRECISION;
n_found INT; n_found INT;
n_removed INT; n_removed INT;
i_work REAL; i_work DOUBLE PRECISION;
i_cost REAL; i_cost DOUBLE PRECISION;
can_do REAL; can_do DOUBLE PRECISION;
must_do INT; must_do INT;
BEGIN BEGIN
-- Get constants -- Get constants
@ -39,7 +39,7 @@ BEGIN
cur_empire := NULL; cur_empire := NULL;
cur_planet := NULL; cur_planet := NULL;
FOR rec IN SELECT p.name_id AS id , p.population AS pop , FOR rec IN SELECT p.name_id AS id , p.population AS pop ,
( ph.current / p.population )::REAL AS happiness , ph.current / p.population AS happiness ,
e.name_id AS owner , e.cash AS cash , e.name_id AS owner , e.cash AS cash ,
q.money AS acc_cash , q.work AS acc_work , q.money AS acc_cash , q.work AS acc_work ,
qi.queue_order AS qorder , qi.amount AS amount , qi.queue_order AS qorder , qi.amount AS amount ,
@ -100,10 +100,7 @@ BEGIN
IF cur_planet IS NULL THEN IF cur_planet IS NULL THEN
cur_planet := rec.id; cur_planet := rec.id;
cur_cash := cur_cash + rec.acc_cash; cur_cash := cur_cash + rec.acc_cash;
cur_wus := rec.acc_work + verse.adjust_production( cur_wus := rec.acc_work + verse.adjust_production( rec.pop * wu_per_pop , rec.happiness );
( rec.pop * wu_per_pop )::REAL ,
rec.happiness
);
n_found := 1; n_found := 1;
n_removed := 0; n_removed := 0;
cur_acc_c := 0; cur_acc_c := 0;

View file

@ -15,14 +15,14 @@ CREATE OR REPLACE FUNCTION sys.process_planet_military_updates( c_tick BIGINT )
DECLARE DECLARE
rec RECORD; rec RECORD;
cur_empire INT; cur_empire INT;
cur_cash REAL; cur_cash DOUBLE PRECISION;
cur_planet INT; cur_planet INT;
p_finished BOOLEAN; p_finished BOOLEAN;
cur_wus REAL; cur_wus DOUBLE PRECISION;
cur_acc_c REAL; cur_acc_c DOUBLE PRECISION;
n_found INT; n_found INT;
n_removed INT; n_removed INT;
can_do REAL; can_do DOUBLE PRECISION;
must_do INT; must_do INT;
fl_id BIGINT; fl_id BIGINT;
BEGIN BEGIN
@ -38,7 +38,7 @@ BEGIN
cur_empire := NULL; cur_empire := NULL;
cur_planet := NULL; cur_planet := NULL;
FOR rec IN SELECT p.name_id AS id , FOR rec IN SELECT p.name_id AS id ,
( ph.current / p.population )::REAL AS happiness , ph.current / p.population AS happiness ,
e.name_id AS owner , e.cash AS cash , e.name_id AS owner , e.cash AS cash ,
q.money AS acc_cash , q.work AS acc_work , q.money AS acc_cash , q.work AS acc_work ,
qi.queue_order AS qorder , qi.amount AS amount , qi.queue_order AS qorder , qi.amount AS amount ,

View file

@ -14,16 +14,16 @@ CREATE OR REPLACE FUNCTION sys.process_planet_population_updates( c_tick BIGINT
AS $$ AS $$
DECLARE DECLARE
rec RECORD; rec RECORD;
rel_ch REAL; rel_ch DOUBLE PRECISION;
abs_ch REAL; abs_ch DOUBLE PRECISION;
g_fact REAL; g_fact DOUBLE PRECISION;
gf_inc REAL; gf_inc DOUBLE PRECISION;
n_happ REAL; n_happ DOUBLE PRECISION;
t_happ REAL; t_happ DOUBLE PRECISION;
temp REAL; temp DOUBLE PRECISION;
growth REAL; growth DOUBLE PRECISION;
workers REAL; workers DOUBLE PRECISION;
str_thr REAL; str_thr DOUBLE PRECISION;
BEGIN BEGIN
-- Get constants -- Get constants
rel_ch := sys.get_constant( 'game.happiness.relativeChange' ); rel_ch := sys.get_constant( 'game.happiness.relativeChange' );
@ -35,7 +35,7 @@ BEGIN
-- Process planets -- Process planets
FOR rec IN SELECT p.name_id AS id , p.population AS pop , FOR rec IN SELECT p.name_id AS id , p.population AS pop ,
ph.target AS target , ph.current AS happy_pop , ph.target AS target , ph.current AS happy_pop ,
( ph.current / p.population )::REAL AS current ph.current / p.population AS current
FROM sys.updates su FROM sys.updates su
INNER JOIN verse.updates vu ON vu.update_id = su.id INNER JOIN verse.updates vu ON vu.update_id = su.id
INNER JOIN verse.planets p ON vu.planet_id = p.name_id INNER JOIN verse.planets p ON vu.planet_id = p.name_id

View file

@ -14,10 +14,10 @@ CREATE OR REPLACE FUNCTION sys.process_planet_money_updates( c_tick BIGINT )
AS $$ AS $$
DECLARE DECLARE
rec RECORD; rec RECORD;
incme REAL; incme DOUBLE PRECISION;
BEGIN BEGIN
FOR rec IN SELECT p.name_id AS id , p.population AS pop , FOR rec IN SELECT p.name_id AS id , p.population AS pop ,
( ph.current / p.population )::REAL AS happiness , ph.current / p.population AS happiness ,
( ea.planet_id IS NULL ) AS produces_income ( ea.planet_id IS NULL ) AS produces_income
FROM sys.updates su FROM sys.updates su
INNER JOIN verse.updates vu ON vu.update_id = su.id INNER JOIN verse.updates vu ON vu.update_id = su.id

View file

@ -4,13 +4,13 @@
<parent> <parent>
<artifactId>legacyworlds-server</artifactId> <artifactId>legacyworlds-server</artifactId>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<version>5.99.1</version> <version>5.99.2</version>
</parent> </parent>
<groupId>com.deepclone.lw</groupId> <groupId>com.deepclone.lw</groupId>
<artifactId>legacyworlds-server-data</artifactId> <artifactId>legacyworlds-server-data</artifactId>
<name>Legacy Worlds server data</name> <name>Legacy Worlds server data</name>
<version>5.99.1</version> <version>5.99.2</version>
<description>This package contains all data access classes for the Legacy Worlds server.</description> <description>This package contains all data access classes for the Legacy Worlds server.</description>
<dependencies> <dependencies>

View file

@ -1,66 +0,0 @@
package com.deepclone.lw.sqld.game;
import java.util.LinkedList;
import java.util.List;
public class EmpireTechLine
{
private int id;
private String name;
private String description;
private List< EmpireTechnology > technologies = new LinkedList< EmpireTechnology >( );
public int getId( )
{
return id;
}
public void setId( int id )
{
this.id = id;
}
public String getName( )
{
return name;
}
public void setName( String name )
{
this.name = name;
}
public String getDescription( )
{
return description;
}
public void setDescription( String description )
{
this.description = description;
}
public List< EmpireTechnology > getTechnologies( )
{
return technologies;
}
public void addTechnology( EmpireTechnology eTech )
{
this.technologies.add( eTech );
}
}

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