1
0
forked from 0ad/0ad

# Fixes for simulation speed in scenario edtior. Various code cleanups.

Game, Simulation, etc: Separated 'update' and 'interpolate', and made
'update' return whether it's going fast enough (so callers can decide to
do more updates per render). Changed some time variables to 'double' so
they have enough precision in long games.
Atlas: Added "Fast" playback button. Made simulation sometimes go at
real-time speed, if it's just slightly too slow at rendering.
VertexBuffer: Removed some non-useful glGetError calls.
Entity: Commented out redundant Tick code. Fixed syntax error in
disabled code that confused the IDE.
Aura: Changed string code again, to simply use ASCII instead of UTF-16.
(SpiderMonkey seems to handle it just as efficiently, for small
strings.)
Misc: Some more minor header-file cleanup.
SVN log: Added feed link.

This was SVN commit r4807.
This commit is contained in:
Ykkrosh 2007-01-24 20:17:28 +00:00
parent 5f45e08799
commit ee3243ff92
28 changed files with 251 additions and 168 deletions

View File

@ -9,6 +9,7 @@
#include "MapWriter.h"
#include "Model.h"
#include "ObjectBase.h"
#include "ObjectEntry.h"
#include "ObjectManager.h"
#include "Patch.h"
#include "Terrain.h"
@ -571,5 +572,3 @@ void CMapWriter::RewriteAllMaps(CTerrain* pTerrain, CUnitManager* pUnitMan,
writer.SaveMap(n, pTerrain, pUnitMan, pWaterMan, pSkyMan, pLightEnv, pCamera, pCinema);
}
}

View File

@ -14,7 +14,6 @@
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "simulation/EntityManager.h"
#include "simulation/Entity.h"
#include "TerrainProperties.h"

View File

@ -9,12 +9,12 @@
#include "lib/res/graphics/unifont.h"
#include "lib/sysdep/sysdep.h"
#include "maths/MathUtil.h"
#include "network/Client.h"
#include "network/Server.h"
#include "ps/CLogger.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include "ps/Interact.h"
#include "network/Client.h"
#include "network/Server.h"
#include "ps/Pyrogenesis.h"
#include "scripting/ScriptingHost.h"
#include "simulation/Entity.h"

View File

@ -157,27 +157,30 @@ PSRETURN CGame::StartGame(CGameAttributes *pAttribs)
return 0;
}
void CGame::Update(double deltaTime)
bool CGame::Update(double deltaTime, bool doInterpolate)
{
if( m_Paused )
{
return;
}
if (m_Paused)
return true;
deltaTime *= m_SimRate;
m_Time += deltaTime;
m_Simulation->Update(deltaTime);
bool ok = m_Simulation->Update(deltaTime);
if (doInterpolate)
m_Simulation->Interpolate(deltaTime);
// TODO Detect game over and bring up the summary screen or something
// ^ Quick game over hack is implemented, no summary screen however
if ( m_World->GetEntityManager()->GetDeath() )
if (m_World->GetEntityManager().GetDeath())
{
UpdateGameStatus();
if (GameStatus != 0)
EndGame();
}
//reset death event flag
m_World->GetEntityManager()->SetDeath(false);
m_World->GetEntityManager().SetDeath(false);
return ok;
}
void CGame::UpdateGameStatus()
@ -188,7 +191,7 @@ void CGame::UpdateGameStatus()
for (int i=0; i<MAX_HANDLES; i++)
{
CHandle *handle = m_World->GetEntityManager()->getHandle(i);
CHandle *handle = m_World->GetEntityManager().getHandle(i);
if ( !handle )
continue;
CPlayer *tmpPlayer = handle->m_entity->GetPlayer();

View File

@ -2,7 +2,6 @@
#define _ps_Game_H
#include "ps/Errors.h"
#include "maths/MathUtil.h"
#include <vector>
class CWorld;
@ -28,7 +27,7 @@ class CGame
bool m_GameStarted;
float m_Time;
double m_Time; // needs to be double to get enough precision
float m_SimRate;
enum EOG
@ -58,7 +57,14 @@ public:
/*
Perform all per-frame updates
*/
void Update(double deltaTime);
// Returns false if it can't keep up with the desired simulation rate
// (indicating that you might want to render less frequently, or something).
// TODO: doInterpolate is optional because Atlas interpolates explicitly,
// so that it has more control over the update rate. The game might want to
// do the same, and then doInterpolate should be redundant and removed.
bool Update(double deltaTime, bool doInterpolate = true);
void UpdateGameStatus();
void EndGame();
@ -90,11 +96,11 @@ public:
inline CSimulation *GetSimulation()
{ return m_Simulation; }
inline float GetTime()
inline double GetTime()
{ return m_Time; }
inline void SetSimRate(float simRate)
{ m_SimRate=clamp(simRate, 0.0f, simRate); }
{ m_SimRate = std::max(simRate, 0.0f); }
inline float GetSimRate()
{ return m_SimRate; }

View File

@ -48,8 +48,8 @@ public:
{ return m_Terrain; }
inline CUnitManager &GetUnitManager()
{ return *m_UnitManager; }
inline CEntityManager *GetEntityManager()
{ return m_EntityManager; }
inline CEntityManager &GetEntityManager()
{ return *m_EntityManager; }
inline CProjectileManager &GetProjectileManager()
{ return *m_ProjectileManager; }
inline CLOSManager *GetLOSManager()

View File

@ -49,14 +49,19 @@ CVertexBuffer::CVertexBuffer(size_t vertexSize,bool dynamic)
// (and copy all old VBOs into there, because it needs to be
// consistent).
glGetError(); // clear the error state
// (PT: Disabled the VBOFailed test because it's not very useful at the
// moment (it'll just cause the program to terminate, and I don't think
// it has ever helped to discover any problems, and a later oglCheck()
// will tell us if there were any VBO issues anyway), and so it's a
// waste of time to call glGetError so frequently.)
// glGetError(); // clear the error state
pglGenBuffersARB(1,&m_Handle);
pglBindBufferARB(GL_ARRAY_BUFFER_ARB,m_Handle);
if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
// if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
pglBufferDataARB(GL_ARRAY_BUFFER_ARB,size,0,m_Dynamic ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB);
if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
// if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
} else {
m_SysMem=new u8[size];
@ -198,10 +203,10 @@ void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk,void* data)
{
if (g_Renderer.m_Caps.m_VBO) {
debug_assert(m_Handle);
glGetError(); // clear the error state
// glGetError(); // clear the error state
pglBindBufferARB(GL_ARRAY_BUFFER_ARB,m_Handle);
pglBufferSubDataARB(GL_ARRAY_BUFFER_ARB,chunk->m_Index*m_VertexSize,chunk->m_Count*m_VertexSize,data);
if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
// if (glGetError() != GL_NO_ERROR) throw PSERROR_Renderer_VBOFailed();
} else {
debug_assert(m_SysMem);
memcpy2(m_SysMem+chunk->m_Index*m_VertexSize,data,chunk->m_Count*m_VertexSize);

View File

@ -7,17 +7,6 @@
#include <algorithm>
namespace
{
// Avoid creating strings at runtime
#define ACTION(n) \
const char n##Name[] = "on" #n; \
utf16string n##Name16(n##Name, n##Name + ARRAY_SIZE(n##Name)-1)
ACTION(Enter);
ACTION(Exit);
ACTION(Tick);
}
CAura::CAura( JSContext* cx, CEntity* source, CStrW& name, float radius, size_t tickRate, const CVector4D& color, JSObject* handler )
: m_cx(cx), m_source(source), m_name(name), m_radius(radius), m_handler(handler),
m_tickRate(tickRate), m_tickCyclePos(0), m_color(color)
@ -70,7 +59,7 @@ void CAura::Update( size_t timestep )
// Call onEnter on any new unit that has entered the aura
jsval enterFunction;
if( JS_GetUCProperty( m_cx, m_handler, EnterName16.c_str(), EnterName16.length(), &enterFunction )
if( JS_GetProperty( m_cx, m_handler, "onEnter", &enterFunction )
&& enterFunction != JSVAL_VOID)
{
std::back_insert_iterator<std::vector<CEntity*> > ins( entered );
@ -87,7 +76,7 @@ void CAura::Update( size_t timestep )
// Call onExit on any unit that has exited the aura
jsval exitFunction;
if( JS_GetUCProperty( m_cx, m_handler, ExitName16.c_str(), ExitName16.length(), &exitFunction )
if( JS_GetProperty( m_cx, m_handler, "onExit", &exitFunction )
&& exitFunction != JSVAL_VOID )
{
std::back_insert_iterator<std::vector<CEntity*> > ins( exited );
@ -108,7 +97,7 @@ void CAura::Update( size_t timestep )
{
// It's time to tick; call OnTick on any unit that is in the aura
jsval tickFunction;
if( JS_GetUCProperty( m_cx, m_handler, TickName16.c_str(), TickName16.length(), &tickFunction )
if( JS_GetProperty( m_cx, m_handler, "onTick", &tickFunction )
&& tickFunction != JSVAL_VOID )
{
for( std::vector<CEntity*>::iterator it = curInfluenced.begin(); it != curInfluenced.end(); it++ )
@ -128,7 +117,7 @@ void CAura::RemoveAll()
jsval rval;
jsval argv[1];
jsval exitFunction;
if( JS_GetUCProperty( m_cx, m_handler, ExitName16.c_str(), ExitName16.length(), &exitFunction )
if( JS_GetProperty( m_cx, m_handler, "onExit", &exitFunction )
&& exitFunction != JSVAL_VOID )
{
// Call the exit function on everything in our influence
@ -151,7 +140,7 @@ void CAura::Remove( CEntity* ent )
jsval rval;
jsval argv[1];
jsval exitFunction;
if( JS_GetUCProperty( m_cx, m_handler, ExitName16.c_str(), ExitName16.length(), &exitFunction )
if( JS_GetProperty( m_cx, m_handler, "onExit", &exitFunction )
&& exitFunction != JSVAL_VOID )
{
// Call the exit function on it

View File

@ -328,7 +328,7 @@ void CEntity::update( size_t timestep )
m_position_previous = m_position;
m_orientation_previous = m_orientation;
CalculateRegen( timestep );
if ( entf_get(ENTF_TRIGGER_RUN) )
@ -658,7 +658,7 @@ void UpdateAuras_Normal( SAura& aura, CEntity* e )
return( false );
return( true );
}
}
#endif
bool CEntity::Initialize()
@ -689,11 +689,13 @@ bool CEntity::Initialize()
return true;
}
/*
void CEntity::Tick()
{
CEventTick evt;
DispatchEvent( &evt );
}
*/
void CEntity::clearOrders()
{
@ -869,6 +871,8 @@ void CEntity::interpolate( float relativeoffset )
CVector3D old_graphics_position = m_graphics_position;
CVector3D old_graphics_orientation = m_graphics_orientation;
relativeoffset = clamp( relativeoffset, 0.f, 1.f );
m_graphics_position = Interpolate<CVector3D>( m_position_previous, m_position, relativeoffset );
// Avoid wraparound glitches for interpolating angles.

View File

@ -140,8 +140,8 @@ public:
int m_frameCheck; //counts the frame
float m_lastCombatTime;
float m_lastRunTime;
double m_lastCombatTime;
double m_lastRunTime;
// Building to convert to if this is a foundation, or "" otherwise
CStrW m_building;
@ -256,7 +256,9 @@ public:
// Updates gameplay information for the specified timestep
void update( size_t timestep_millis );
// Updates graphical information for a point between the last and current simulation frame; 0 < relativeoffset < 1.
// Updates graphical information for a point between the last and current
// simulation frame; should be 0 <= relativeoffset <= 1 (else it'll be
// clamped)
void interpolate( float relativeoffset );
// Forces update of actor information during next call to 'interpolate'.
@ -274,7 +276,7 @@ public:
void initAuraData();
// Process tick.
void Tick();
// void Tick(); // (see comment in CEntityManager::updateAll)
// Calculate distances along the terrain

View File

@ -26,6 +26,7 @@ CEntityFormation::CEntityFormation( CFormation*& base, size_t index )
m_index = (int)index;
}
CEntityFormation::~CEntityFormation()
{
for ( int i=0; i<m_base->m_numSlots; ++i )
@ -38,6 +39,12 @@ CEntityFormation::~CEntityFormation()
}
}
}
int CEntityFormation::GetSlotCount()
{
return m_base->m_numSlots;
}
void CEntityFormation::SwitchBase( CFormation*& base )
{
std::vector<CEntity*> copy;

View File

@ -7,13 +7,13 @@
#ifndef ENTITYFORMATION_INCLUDED
#define ENTITYFORMATION_INCLUDED
#include "Formation.h"
#include "ps/Vector2D.h"
class CVector2D;
class CEntity;
struct CEntityList;
class CClassSet;
class CFormation;
class CEntityFormation
{
@ -24,7 +24,7 @@ public:
int GetEntityCount() { return m_numEntities; }
float GetSpeed() { return m_speed; }
int GetSlotCount() { return m_base->m_numSlots; }
int GetSlotCount();
CEntityList GetEntityList();
CVector2D GetSlotPosition( int order );
@ -38,7 +38,7 @@ public:
inline bool IsDuplication() { return m_duplication; }
inline void SetLock( bool lock ){ m_locked=lock; }
inline bool IsLocked() { return m_locked; }
inline bool IsValidOrder(int order) { return ( order >= 0 && order < m_base->m_numSlots ); }
inline bool IsValidOrder(int order) { return ( order >= 0 && order < GetSlotCount() ); }
private:
int m_numEntities;

View File

@ -272,12 +272,14 @@ void CEntityManager::InitializeAll()
}
}
/*
void CEntityManager::TickAll()
{
for( int i = 0; i < MAX_HANDLES; i++ )
if( isEntityRefd(i) && m_entities[i].m_entity->m_extant )
m_entities[i].m_entity->Tick();
}
*/
void CEntityManager::updateAll( size_t timestep )
{

View File

@ -20,24 +20,21 @@
#include <set>
#include "ps/Singleton.h"
#include "EntityHandles.h"
#include "EntityPredicate.h"
#include "EntityMessage.h"
#include "ps/Game.h"
#include "ps/World.h"
#include "maths/Vector3D.h"
class CEntityTemplate;
class CPlayer;
class CStrW;
class CVector3D;
#define MAX_HANDLES 4096
// collision patch size, in graphics units, not tiles (1 tile = 4 units)
#define COLLISION_PATCH_SIZE 8
#define g_EntityManager (*(g_Game->GetWorld()->GetEntityManager()))
#define g_EntityManager g_Game->GetWorld()->GetEntityManager()
class CEntityManager
{
@ -92,7 +89,7 @@ public:
void updateAll( size_t timestep );
void interpolateAll( float relativeoffset );
void InitializeAll();
void TickAll();
// void TickAll();
void renderAll();
void conformAll();
void invalidateAll();

View File

@ -5,10 +5,6 @@
#include "ps/CStr.h"
#include "EntityHandles.h"
class CEntityManager;
struct SEntityAction
{
int m_Id;
@ -33,11 +29,11 @@ class CClassSet
public:
CClassSet() : m_Parent(NULL) {}
bool IsMember( const CStrW& Test );
bool IsMember(const CStrW& Test);
void Rebuild();
inline void SetParent( CClassSet* Parent )
inline void SetParent(CClassSet* Parent)
{ m_Parent = Parent; Rebuild(); }
CStrW getMemberList();

View File

@ -18,7 +18,6 @@
#define BASE_ENTITY_INCLUDED
#include "ps/CStr.h"
#include "graphics/ObjectEntry.h"
#include "scripting/ScriptableComplex.h"
#include "scripting/DOMEvent.h"

View File

@ -21,11 +21,13 @@ public:
CEventDeath() : CScriptEvent( L"death", EVENT_DEATH, false ) {}
};
/*
class CEventTick : public CScriptEvent
{
public:
CEventTick() : CScriptEvent( L"tick", EVENT_TICK, false ) {}
};
*/
class CEventGeneric : public CScriptEvent
{

View File

@ -118,7 +118,7 @@ void CLOSManager::Update()
// Set visibility for each entity
std::vector<CEntity*> extant;
g_Game->GetWorld()->GetEntityManager()->GetExtant(extant);
g_EntityManager.GetExtant(extant);
for(size_t i=0; i<extant.size(); i++)
{
CEntity* e = extant[i];

View File

@ -2,33 +2,30 @@
#include <vector>
#include "EntityFormation.h"
#include "EntityManager.h"
#include "LOSManager.h"
#include "Projectile.h"
#include "Scheduler.h"
#include "Simulation.h"
#include "TurnManager.h"
#include "graphics/Model.h"
#include "graphics/Terrain.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "lib/timer.h"
#include "maths/MathUtil.h"
#include "network/NetMessage.h"
#include "ps/CLogger.h"
#include "ps/Game.h"
#include "ps/GameAttributes.h"
#include "ps/Loader.h"
#include "ps/LoaderThunks.h"
#include "network/NetMessage.h"
#include "ps/Profile.h"
#include "renderer/Renderer.h"
#include "renderer/WaterManager.h"
#include "simulation/Entity.h"
#include "simulation/LOSManager.h"
#include "simulation/TerritoryManager.h"
#include "simulation/EntityFormation.h"
#include "simulation/EntityManager.h"
#include "simulation/EntityTemplateCollection.h"
#include "gui/CGUI.h"
#include "simulation/LOSManager.h"
#include "simulation/Projectile.h"
#include "simulation/Scheduler.h"
#include "simulation/Simulation.h"
#include "simulation/TerritoryManager.h"
#include "simulation/TurnManager.h"
CSimulation::CSimulation(CGame *pGame):
m_pGame(pGame),
@ -75,39 +72,59 @@ void CSimulation::RegisterInit(CGameAttributes *pAttribs)
void CSimulation::Update(double frameTime)
bool CSimulation::Update(double frameTime)
{
bool ok = true;
m_DeltaTime += frameTime;
if( m_DeltaTime >= 0.0 && frameTime )
if (m_DeltaTime >= 0.0)
{
PROFILE( "simulation turn" );
// A new simulation frame is required.
MICROLOG( L"calculate simulation" );
PROFILE( "simulation turn" );
Simulate();
m_DeltaTime -= (m_pTurnManager->GetTurnLength()/1000.0);
if( m_DeltaTime >= 0.0 )
double turnLength = m_pTurnManager->GetTurnLength() / 1000.0;
m_DeltaTime -= turnLength;
if (m_DeltaTime >= 0.0)
{
// The desired sim frame rate can't be achieved. Settle for process & render
// frames as fast as possible.
frameTime -= m_DeltaTime; // so the animation stays in sync with the sim
m_DeltaTime = 0.0;
// The desired sim frame rate can't be achieved - we're being called
// with average(frameTime) > turnLength.
// Let the caller know we can't go fast enough - they should try
// cutting down on Interpolate and rendering, and call us a few times
// with frameTime == 0 to give us a chance to catch up.
ok = false;
}
}
PROFILE_START( "simulation interpolation" );
Interpolate(frameTime, ((1000.0*m_DeltaTime) / (float)m_pTurnManager->GetTurnLength()) + 1.0);
PROFILE_END( "simulation interpolation" );
return ok;
}
void CSimulation::Interpolate(double frameTime)
{
double turnLength = m_pTurnManager->GetTurnLength()/1000.0;
// 'offset' should be how far we are between the previous and next
// simulation frames.
// m_DeltaTime/turnLength will usually be between -1 and 0, indicating
// the time until the next frame, so we can use that easily.
// If the simulation is going too slowly and hasn't been giving a chance
// to catch up before Interpolate is called, then m_DeltaTime > 0, and
// we'll just end up being clamped to offset=1 inside CEntity::interpolate,
// which is alright.
Interpolate(frameTime, m_DeltaTime / turnLength + 1.0);
}
void CSimulation::Interpolate(double frameTime, double offset)
{
const std::vector<CUnit*>& units=m_pWorld->GetUnitManager().GetUnits();
for (uint i=0;i<units.size();++i)
PROFILE( "simulation interpolation" );
const std::vector<CUnit*>& units = m_pWorld->GetUnitManager().GetUnits();
for (size_t i = 0; i < units.size(); ++i)
units[i]->GetModel()->Update((float)frameTime);
g_EntityManager.interpolateAll( (float)offset );
m_pWorld->GetProjectileManager().InterpolateAll( (float)offset );
g_EntityManager.interpolateAll(offset);
m_pWorld->GetProjectileManager().InterpolateAll(frameTime);
g_Renderer.GetWaterManager()->m_WaterTexTimer += frameTime;
}

View File

@ -39,10 +39,13 @@ public:
void RegisterInit(CGameAttributes *pGameAttributes);
int Initialize(CGameAttributes *pGameAttributes);
// Perform all CSimulation updates for the specified elapsed time.
// (If frameTime=0, no simulation updates are done, but the graphics
// are interpolated.)
void Update(double frameTime);
// Perform simulation updates for the specified elapsed time. If it is
// shorter than the time until the next simulation turn, nothing happens.
// Returns false if it can't keep up with the desired simulation rate.
bool Update(double frameTime);
// Update the graphical representations of the simulation by the given time.
void Interpolate(double frameTime);
// Calculate the message mask of a message to be queued
static uint GetMessageMask(CNetMessage *, uint oldMask, void *userdata);

View File

@ -1,7 +1,6 @@
#ifndef __STANCE_H__
#define __STANCE_H__
#include "EntityHandles.h"
#include "ps/Vector2D.h"
class CEntity;

View File

@ -12,6 +12,7 @@
#include "lib/ogl.h"
#include "lib/timer.h"
#include "maths/Bound.h"
#include "maths/MathUtil.h"
#include "ps/Game.h"
#include "ps/Player.h"
#include "ps/Profile.h"

View File

@ -14,6 +14,7 @@ enum
ID_GenerateMap,
ID_GenerateRMS,
ID_SimPlay,
ID_SimFast,
ID_SimPause,
ID_SimReset
};
@ -22,6 +23,7 @@ enum
{
SimInactive,
SimPlaying,
SimPlayingFast,
SimPaused
};
@ -44,6 +46,7 @@ MapSidebar::MapSidebar(wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
{
wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Simulation test"));
sizer->Add(new wxButton(this, ID_SimPlay, _("Play")), wxSizerFlags().Proportion(1));
sizer->Add(new wxButton(this, ID_SimFast, _("Fast")), wxSizerFlags().Proportion(1));
sizer->Add(new wxButton(this, ID_SimPause, _("Pause")), wxSizerFlags().Proportion(1));
sizer->Add(new wxButton(this, ID_SimReset, _("Reset")), wxSizerFlags().Proportion(1));
UpdateSimButtons();
@ -78,34 +81,46 @@ void MapSidebar::UpdateSimButtons()
wxCHECK(button, );
button->Enable(m_SimState != SimPlaying);
button = wxDynamicCast(FindWindow(ID_SimFast), wxButton);
wxCHECK(button, );
button->Enable(m_SimState != SimPlayingFast);
button = wxDynamicCast(FindWindow(ID_SimPause), wxButton);
wxCHECK(button, );
button->Enable(m_SimState == SimPlaying);
button->Enable(m_SimState == SimPlaying || m_SimState == SimPlayingFast);
button = wxDynamicCast(FindWindow(ID_SimReset), wxButton);
wxCHECK(button, );
button->Enable(m_SimState != SimInactive);
}
void MapSidebar::OnSimPlay(wxCommandEvent& WXUNUSED(event))
void MapSidebar::OnSimPlay(wxCommandEvent& event)
{
float speed = 1.f;
int newState = SimPlaying;
if (event.GetId() == ID_SimFast)
{
speed = 8.f;
newState = SimPlayingFast;
}
if (m_SimState == SimInactive)
{
POST_MESSAGE(SimStateSave, (L"default", true));
POST_MESSAGE(SimPlay, (1.f));
m_SimState = SimPlaying;
POST_MESSAGE(SimPlay, (speed));
m_SimState = newState;
}
else if (m_SimState == SimPaused)
else // paused or already playing at a different speed
{
POST_MESSAGE(SimPlay, (1.f));
m_SimState = SimPlaying;
POST_MESSAGE(SimPlay, (speed));
m_SimState = newState;
}
UpdateSimButtons();
}
void MapSidebar::OnSimPause(wxCommandEvent& WXUNUSED(event))
{
if (m_SimState == SimPlaying)
if (m_SimState == SimPlaying || m_SimState == SimPlayingFast)
{
POST_MESSAGE(SimPlay, (0.f));
m_SimState = SimPaused;
@ -115,7 +130,7 @@ void MapSidebar::OnSimPause(wxCommandEvent& WXUNUSED(event))
void MapSidebar::OnSimReset(wxCommandEvent& WXUNUSED(event))
{
if (m_SimState == SimPlaying)
if (m_SimState == SimPlaying || m_SimState == SimPlayingFast)
{
POST_MESSAGE(SimPlay, (0.f));
POST_MESSAGE(SimStateRestore, (L"default"));
@ -133,6 +148,7 @@ BEGIN_EVENT_TABLE(MapSidebar, Sidebar)
EVT_BUTTON(ID_GenerateMap, MapSidebar::GenerateMap)
EVT_BUTTON(ID_GenerateRMS, MapSidebar::GenerateRMS)
EVT_BUTTON(ID_SimPlay, MapSidebar::OnSimPlay)
EVT_BUTTON(ID_SimFast, MapSidebar::OnSimPlay)
EVT_BUTTON(ID_SimPause, MapSidebar::OnSimPause)
EVT_BUTTON(ID_SimReset, MapSidebar::OnSimReset)
END_EVENT_TABLE();

View File

@ -9,6 +9,7 @@
#include "ps/CStr.h"
#include "ps/CLogger.h"
#include "ps/VFSUtil.h"
#include "maths/MathUtil.h"
#include "maths/Quaternion.h"
#include "lib/res/graphics/ogl_tex.h"

View File

@ -17,43 +17,51 @@
#include "simulation/LOSManager.h"
#include "simulation/Simulation.h"
namespace
{
void InitGame(const CStrW& map)
{
if (g_Game)
{
delete g_Game;
g_Game = NULL;
}
// Set attributes for the game:
g_GameAttributes.m_MapFile = map;
// Make all players locally controlled
for (int i = 1; i < 8; ++i)
g_GameAttributes.GetSlot(i)->AssignLocal();
// Make the whole world visible
g_GameAttributes.m_LOSSetting = 2;
g_GameAttributes.m_FogOfWar = false;
// Don't use screenshot mode, because we want working AI for the
// simulation-testing. Outside that simulation-testing, we avoid having
// the units move into attack mode by never calling CEntity::update.
g_GameAttributes.m_ScreenshotMode = false;
// Initialise the game:
g_Game = new CGame();
}
void StartGame()
{
PSRETURN ret = g_Game->StartGame(&g_GameAttributes);
debug_assert(ret == PSRETURN_OK);
LDR_NonprogressiveLoad();
ret = g_Game->ReallyStartGame();
debug_assert(ret == PSRETURN_OK);
// Make sure entities get rendered in the correct location
g_Game->GetSimulation()->Interpolate(0.0);
}
}
namespace AtlasMessage {
static void InitGame(std::wstring map)
{
if (g_Game)
delete g_Game;
// Set attributes for the game:
g_GameAttributes.m_MapFile = map;
// Make all players locally controlled
for (int i=1; i<8; ++i)
g_GameAttributes.GetSlot(i)->AssignLocal();
// Make the whole world visible
g_GameAttributes.m_LOSSetting = 2;
g_GameAttributes.m_FogOfWar = false;
// Disable unit AI (and other things that may interfere with making things look nice)
g_GameAttributes.m_ScreenshotMode = false;
// Initialise the game:
g_Game = new CGame();
}
static void StartGame()
{
PSRETURN ret = g_Game->StartGame(&g_GameAttributes);
debug_assert(ret == PSRETURN_OK);
LDR_NonprogressiveLoad();
ret = g_Game->ReallyStartGame();
debug_assert(ret == PSRETURN_OK);
// Make sure entities get rendered in the correct location
g_Game->GetSimulation()->Update(0.0);
}
MESSAGEHANDLER(GenerateMap)
{
InitGame(L"");
@ -84,17 +92,20 @@ MESSAGEHANDLER(GenerateMap)
Handle tex = texentry ? texentry->GetHandle() : 0;
int patches = terrain->GetPatchesPerSide();
for (int pz = 0; pz < patches; ++pz) {
for (int px = 0; px < patches; ++px) {
for (int pz = 0; pz < patches; ++pz)
{
for (int px = 0; px < patches; ++px)
{
CPatch* patch = terrain->GetPatch(px, pz);
for (int z = 0; z < PATCH_SIZE; ++z)
{
for (int x = 0; x < PATCH_SIZE; ++x)
{
patch->m_MiniPatches[z][x].Tex1 = tex;
patch->m_MiniPatches[z][x].Tex1Priority = 0;
}
}
}
}

View File

@ -574,7 +574,11 @@ BEGIN_COMMAND(MoveObject)
if (unit->GetEntity())
{
// Set the current position, and also set the previous position so
// CEntity::interpolate puts the entity in the right place (without
// having to call CEntity::update before it'll look right)
unit->GetEntity()->m_position = pos;
unit->GetEntity()->m_position_previous = pos;
if (unit->GetEntity()->m_base->m_isTerritoryCentre)
g_Game->GetWorld()->GetTerritoryManager()->DelayedRecalculate();

View File

@ -10,9 +10,12 @@
#include "graphics/GameView.h"
#include "graphics/Model.h"
#include "graphics/ObjectBase.h"
#include "graphics/ObjectEntry.h"
#include "graphics/SColor.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "lib/timer.h"
#include "maths/MathUtil.h"
#include "ps/Game.h"
#include "ps/GameSetup/GameSetup.h"
#include "ps/Player.h"
@ -169,20 +172,36 @@ ViewGame::~ViewGame()
void ViewGame::Update(float frameLength)
{
float actualFrameLength = frameLength * m_SpeedMultiplier;
if (m_SpeedMultiplier == 0.f)
{
// TODO: I don't think this line is necessary, but I'm not positive...
// g_EntityManager.updateAll(0);
// Update unit interpolation
g_Game->GetSimulation()->Update(0.0);
g_Game->GetSimulation()->Interpolate(0.0);
}
else
{
// Update the whole world
g_Game->Update(m_SpeedMultiplier * frameLength);
// (Tell the game update not to interpolate graphics - we'll do that
// ourselves)
bool ok = g_Game->Update(actualFrameLength, false);
if (! ok)
{
// Whoops, we're trying to go faster than the simulation can manage.
// It's probably better to run at the right sim rate, at the expense
// of framerate, so let's try simulating a few more times.
double t = get_time();
while (!ok && get_time() < t + 0.1) // don't go much worse than 10fps
{
ok = g_Game->Update(0.0, false); // don't add on any extra sim time
}
}
// Interpolate the graphics - we only want to do it once per visual frame,
// not in every call to g_Game->Update
g_Game->GetSimulation()->Interpolate(actualFrameLength);
if (g_Game->GetView()->GetCinema()->IsPlaying())
g_Game->GetView()->GetCinema()->Update(m_SpeedMultiplier * frameLength);
g_Game->GetView()->GetCinema()->Update(actualFrameLength);
}
}
@ -316,23 +335,23 @@ void ViewGame::RestoreState(const std::wstring& label)
g_EntityManager.InitializeAll();
if (simState->onlyEntities)
return;
for (size_t i = 0; i < simState->nonentities.size(); ++i)
if (! simState->onlyEntities)
{
SimState::Nonentity& n = simState->nonentities[i];
CUnit* unit = unitMan.CreateUnit(n.actorName, NULL, n.selections);
if (unit)
for (size_t i = 0; i < simState->nonentities.size(); ++i)
{
CMatrix3D m;
m.SetYRotation(n.angle + PI);
m.Translate(n.position);
unit->GetModel()->SetTransform(m);
SimState::Nonentity& n = simState->nonentities[i];
unit->SetID(n.unitID);
CUnit* unit = unitMan.CreateUnit(n.actorName, NULL, n.selections);
if (unit)
{
CMatrix3D m;
m.SetYRotation(n.angle + PI);
m.Translate(n.position);
unit->GetModel()->SetTransform(m);
unit->SetID(n.unitID);
}
}
}
}

View File

@ -8,6 +8,8 @@ use File::Remote;
use XML::Atom::SimpleFeed;
use Data::UUID;
my $feed_url = 'http://www.wildfiregames.com/~philip/svnlog.xml';
sub doupdate : Local
{
my ($self, $c) = @_;
@ -110,7 +112,7 @@ sub generate_text
{
my @logentries = SVNLog::Model::CDBI::Logentry->recent(7);
my $out = '';
my $out = qq{<a href="$feed_url"><img alt="Atom feed" title="Subscribe to feed of revision log (Atom 1.0 format)" src="/images/feed-icon-16x16.png" style="float: right"></a>};
for (@logentries)
{
my ($revision, $author, $date, $msg) = ($_->revision, $_->author, $_->date, $_->public_msg);
@ -143,7 +145,7 @@ sub generate_feed
my $feed = new XML::Atom::SimpleFeed(
title => "0 A.D. Revision Log",
link => "http://www.wildfiregames.com/0ad/",
link => { rel => 'self', href => 'http://www.wildfiregames.com/~philip/svnlog.xml' },
link => { rel => 'self', href => $feed_url },
id => "urn:uuid:" . $uid_gen->create_from_name_str('WFG SVN feed', 'feed'),
);